Coverage for manila/share/driver.py: 86%
468 statements
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2026-02-18 22:19 +0000
1# Copyright 2012 NetApp
2# Copyright 2015 Mirantis inc.
3# All Rights Reserved.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License. You may obtain
7# a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations
15# under the License.
16"""
17Drivers for shares.
19"""
21import time
23from oslo_config import cfg
24from oslo_config import types
25from oslo_log import log
27from manila.common import constants
28from manila import exception
29from manila.i18n import _
30from manila import network
31from manila import utils
33LOG = log.getLogger(__name__)
35share_opts = [
36 # NOTE(rushiagr): Reasonable to define this option at only one place.
37 cfg.IntOpt(
38 'num_shell_tries',
39 default=3,
40 help='Number of times to attempt to run flakey shell commands.'),
41 cfg.IntOpt(
42 'reserved_share_percentage',
43 default=0,
44 help="The percentage of backend capacity reserved. Used for shares "
45 "which are not created from the snapshot."),
46 cfg.IntOpt(
47 'reserved_share_from_snapshot_percentage',
48 default=0,
49 help="The percentage of backend capacity reserved. Used for shares "
50 "created from the snapshot. On some platforms, shares can only "
51 "be created from the snapshot on the host where snapshot was "
52 "taken, so we can set a lower value in this option compared to "
53 "reserved_share_percentage, and allow to create shares from the "
54 "snapshot on the same host up to a higher threshold."),
55 cfg.IntOpt(
56 'reserved_share_extend_percentage',
57 default=0,
58 help="The percentage of backend capacity reserved for share extend "
59 "operation. When existing limit of 'reserved_share_percentage' "
60 "is hit, we do not want user to create a new share but existing "
61 "shares can be extended based on value of this parameter."),
62 cfg.StrOpt(
63 'share_backend_name',
64 help='The backend name for a given driver implementation.'),
65 cfg.StrOpt(
66 'network_config_group',
67 help="Name of the configuration group in the Manila conf file "
68 "to look for network config options."
69 "If not set, the share backend's config group will be used."
70 "If an option is not found within provided group, then "
71 "'DEFAULT' group will be used for search of option."),
72 cfg.BoolOpt(
73 'driver_handles_share_servers',
74 help="There are two possible approaches for share drivers in Manila. "
75 "First is when share driver is able to handle share-servers and "
76 "second when not. Drivers can support either both or only one "
77 "of these approaches. So, set this opt to True if share driver "
78 "is able to handle share servers and it is desired mode else set "
79 "False. It is set to None by default to make this choice "
80 "intentional."),
81 cfg.FloatOpt(
82 'max_over_subscription_ratio',
83 default=20.0,
84 min=1.0,
85 help='Float representation of the over subscription ratio '
86 'when thin provisioning is involved. Default ratio is '
87 '20.0, meaning provisioned capacity can be 20 times '
88 'the total physical capacity. If the ratio is 10.5, it '
89 'means provisioned capacity can be 10.5 times the '
90 'total physical capacity. A ratio of 1.0 means '
91 'provisioned capacity cannot exceed the total physical '
92 'capacity. A ratio lower than 1.0 is invalid.'),
93 cfg.ListOpt(
94 'migration_ignore_files',
95 default=['lost+found'],
96 help="List of files and folders to be ignored when migrating shares. "
97 "Items should be names (not including any path)."),
98 cfg.StrOpt(
99 'share_mount_template',
100 default='mount -vt %(proto)s %(options)s %(export)s %(path)s',
101 help="The template for mounting shares for this backend. Must specify "
102 "the executable with all necessary parameters for the protocol "
103 "supported. 'proto' template element may not be required if "
104 "included in the command. 'export' and 'path' template elements "
105 "are required. It is advisable to separate different commands "
106 "per backend."),
107 cfg.StrOpt(
108 'share_unmount_template',
109 default='umount -v %(path)s',
110 help="The template for unmounting shares for this backend. Must "
111 "specify the executable with all necessary parameters for the "
112 "protocol supported. 'path' template element is required. It is "
113 "advisable to separate different commands per backend."),
114 cfg.Opt(
115 'protocol_access_mapping',
116 type=types.Dict(types.List(types.String(), bounds=True)),
117 default={
118 'ip': ['nfs'],
119 'user': ['cifs'],
120 },
121 help="Protocol access mapping for this backend. Should be a "
122 "dictionary comprised of "
123 "{'access_type1': ['share_proto1', 'share_proto2'],"
124 " 'access_type2': ['share_proto2', 'share_proto3']}."),
125 cfg.StrOpt(
126 "admin_network_config_group",
127 help="If share driver requires to setup admin network for share, then "
128 "define network plugin config options in some separate config "
129 "group and set its name here. Used only with another "
130 "option 'driver_handles_share_servers' set to 'True'."),
131 # Replication option/s
132 cfg.StrOpt(
133 "replication_domain",
134 help="A string specifying the replication domain that the backend "
135 "belongs to. This option needs to be specified the same in the "
136 "configuration sections of all backends that support "
137 "replication between each other. If this option is not "
138 "specified in the group, it means that replication is not "
139 "enabled on the backend."),
140 cfg.StrOpt('backend_availability_zone',
141 default=None,
142 help='Availability zone for this share backend. If not set, '
143 'the ``storage_availability_zone`` option from the '
144 '``[DEFAULT]`` section is used.'),
145 cfg.StrOpt('filter_function',
146 help='String representation for an equation that will be '
147 'used to filter hosts.'),
148 cfg.StrOpt('goodness_function',
149 help='String representation for an equation that will be '
150 'used to determine the goodness of a host.'),
151 cfg.IntOpt('max_shares_per_share_server',
152 default=-1,
153 help="Maximum number of share instances created in a share "
154 "server."),
155 cfg.IntOpt('max_share_server_size',
156 default=-1,
157 help="Maximum sum of gigabytes a share server can have "
158 "considering all its share instances and snapshots.")
159]
161ssh_opts = [
162 cfg.IntOpt(
163 'ssh_conn_timeout',
164 default=60,
165 help='Backend server SSH connection timeout.'),
166 cfg.IntOpt(
167 'ssh_min_pool_conn',
168 default=1,
169 help='Minimum number of connections in the SSH pool.'),
170 cfg.IntOpt(
171 'ssh_max_pool_conn',
172 default=10,
173 help='Maximum number of connections in the SSH pool.'),
174]
176ganesha_opts = [
177 cfg.StrOpt('ganesha_config_dir',
178 default='/etc/ganesha',
179 help='Directory where Ganesha config files are stored.'),
180 cfg.StrOpt('ganesha_config_path',
181 default='$ganesha_config_dir/ganesha.conf',
182 help='Path to main Ganesha config file.'),
183 cfg.StrOpt('ganesha_service_name',
184 default='ganesha.nfsd',
185 help='Name of the ganesha nfs service.'),
186 cfg.StrOpt('ganesha_db_path',
187 default='$state_path/manila-ganesha.db',
188 help='Location of Ganesha database file. '
189 '(Ganesha module only.)'),
190 cfg.StrOpt('ganesha_export_dir',
191 default='$ganesha_config_dir/export.d',
192 help='Path to directory containing Ganesha export '
193 'configuration. (Ganesha module only.)'),
194 cfg.StrOpt('ganesha_export_template_dir',
195 default='/etc/manila/ganesha-export-templ.d',
196 help='Path to directory containing Ganesha export '
197 'block templates. (Ganesha module only.)'),
198 cfg.BoolOpt('ganesha_rados_store_enable',
199 default=False,
200 help='Persist Ganesha exports and export counter '
201 'in Ceph RADOS objects, highly available storage.'),
202 cfg.StrOpt('ganesha_rados_store_pool_name',
203 help='Name of the Ceph RADOS pool to store Ganesha exports '
204 'and export counter.'),
205 cfg.StrOpt('ganesha_rados_export_counter',
206 default='ganesha-export-counter',
207 help='Name of the Ceph RADOS object used as the Ganesha '
208 'export counter.'),
209 cfg.StrOpt('ganesha_rados_export_index',
210 default='ganesha-export-index',
211 help='Name of the Ceph RADOS object used to store a list '
212 'of the export RADOS object URLS.'),
213]
215CONF = cfg.CONF
216CONF.register_opts(share_opts)
217CONF.register_opts(ssh_opts)
218CONF.register_opts(ganesha_opts)
221class ExecuteMixin(object):
222 """Provides an executable functionality to a driver class."""
224 def init_execute_mixin(self, *args, **kwargs):
225 if self.configuration: 225 ↛ 227line 225 didn't jump to line 227 because the condition on line 225 was always true
226 self.configuration.append_config_values(ssh_opts)
227 self.set_execute(kwargs.pop('execute', utils.execute))
229 def set_execute(self, execute):
230 self._execute = execute
232 def _try_execute(self, *command, **kwargs):
233 # NOTE(vish): Volume commands can partially fail due to timing, but
234 # running them a second time on failure will usually
235 # recover nicely.
236 tries = 0
237 while True:
238 try:
239 self._execute(*command, **kwargs)
240 return True
241 except exception.ProcessExecutionError:
242 tries += 1
243 if tries >= self.configuration.num_shell_tries:
244 raise
245 LOG.exception("Recovering from a failed execute. "
246 "Try number %s", tries)
247 time.sleep(tries ** 2)
250class GaneshaMixin(object):
251 """Augment derived classes with Ganesha configuration."""
253 def init_ganesha_mixin(self, *args, **kwargs):
254 if self.configuration: 254 ↛ exitline 254 didn't return from function 'init_ganesha_mixin' because the condition on line 254 was always true
255 self.configuration.append_config_values(ganesha_opts)
258class ShareDriver(object):
259 """Class defines interface of NAS driver."""
261 def __init__(self, driver_handles_share_servers, *args, **kwargs):
262 """Implements base functionality for share drivers.
264 :param driver_handles_share_servers: expected boolean value or
265 tuple/list/set of boolean values.
266 There are two possible approaches for share drivers in Manila.
267 First is when share driver is able to handle share-servers and
268 second when not.
269 Drivers can support either both (indicated by a tuple/set/list with
270 (True, False)) or only one of these approaches. So, it is allowed
271 to be 'True' when share driver does support handling of share
272 servers and allowed to be 'False' when it does support usage of
273 unhandled share-servers that are not tracked by Manila.
274 Share drivers are allowed to work only in one of two possible
275 driver modes, that is why only one should be chosen.
276 :param config_opts: tuple, list or set of config option lists
277 that should be registered in driver's configuration right after
278 this attribute is created. Useful for usage with mixin classes.
279 """
280 super(ShareDriver, self).__init__()
281 self.configuration = kwargs.get('configuration', None)
282 self.initialized = False
283 self._stats = {}
284 self.ip_versions = None
285 self.ipv6_implemented = False
286 # Indicates whether a driver supports update of security services for
287 # in-use share networks. This property will be saved in every new share
288 # server.
289 self.security_service_update_support = False
290 # Indicates whether a driver supports adding subnet with its
291 # allocations to an in-use share network availability zone. This
292 # property will be saved in every new share server.
293 self.restore_to_target_support = False
294 # Indicates whether a driver supports out of place restores
295 # to a share other then the source of a given backup.
296 self.network_allocation_update_support = False
297 self.dhss_mandatory_security_service_association = {}
298 self.share_replicas_migration_support = False
299 self.encryption_support = None
301 self.pools = []
302 if self.configuration:
303 self.configuration.append_config_values(share_opts)
304 network_config_group = (self.configuration.network_config_group or
305 self.configuration.config_group)
306 admin_network_config_group = (
307 self.configuration.admin_network_config_group)
308 else:
309 network_config_group = None
310 admin_network_config_group = (
311 CONF.admin_network_config_group)
313 self._verify_share_server_handling(driver_handles_share_servers)
314 if self.driver_handles_share_servers:
315 # Enable common network
316 self.network_api = network.API(
317 config_group_name=network_config_group)
319 # Enable admin network
320 if admin_network_config_group:
321 self._admin_network_api = network.API(
322 config_group_name=admin_network_config_group,
323 label='admin')
325 for config_opt_set in kwargs.get('config_opts', []):
326 self.configuration.append_config_values(config_opt_set)
328 if hasattr(self, 'init_execute_mixin'):
329 # Instance with 'ExecuteMixin'
330 # pylint: disable=no-member
331 self.init_execute_mixin(*args, **kwargs)
332 if hasattr(self, 'init_ganesha_mixin'):
333 # Instance with 'GaneshaMixin'
334 # pylint: disable=no-member
335 self.init_ganesha_mixin(*args, **kwargs)
337 @property
338 def admin_network_api(self):
339 if hasattr(self, '_admin_network_api'):
340 return self._admin_network_api
342 @property
343 def driver_handles_share_servers(self):
344 if self.configuration:
345 return self.configuration.safe_get('driver_handles_share_servers')
346 return CONF.driver_handles_share_servers
348 @property
349 def replication_domain(self):
350 if self.configuration: 350 ↛ 352line 350 didn't jump to line 352 because the condition on line 350 was always true
351 return self.configuration.safe_get('replication_domain')
352 return CONF.replication_domain
354 @property
355 def max_shares_per_share_server(self):
356 if self.configuration: 356 ↛ 359line 356 didn't jump to line 359 because the condition on line 356 was always true
357 return self.configuration.safe_get(
358 'max_shares_per_share_server') or -1
359 return CONF.max_shares_per_share_server
361 @property
362 def max_share_server_size(self):
363 if self.configuration: 363 ↛ 365line 363 didn't jump to line 365 because the condition on line 363 was always true
364 return self.configuration.safe_get('max_share_server_size') or -1
365 return CONF.max_share_server_size
367 def _verify_share_server_handling(self, driver_handles_share_servers):
368 """Verifies driver_handles_share_servers and given configuration."""
369 if not isinstance(self.driver_handles_share_servers, bool):
370 raise exception.ManilaException(
371 "Config opt 'driver_handles_share_servers' has improper "
372 "value - '%s'. Please define it as boolean." %
373 self.driver_handles_share_servers)
374 elif isinstance(driver_handles_share_servers, bool):
375 driver_handles_share_servers = [driver_handles_share_servers]
376 elif not isinstance(driver_handles_share_servers, (tuple, list, set)): 376 ↛ 377line 376 didn't jump to line 377 because the condition on line 376 was never true
377 raise exception.ManilaException(
378 "Improper data provided for 'driver_handles_share_servers' - "
379 "%s" % driver_handles_share_servers)
381 if any(not isinstance(v, bool) for v in driver_handles_share_servers):
382 raise exception.ManilaException(
383 "Provided wrong data: %s" % driver_handles_share_servers)
385 if (self.driver_handles_share_servers not in
386 driver_handles_share_servers):
387 raise exception.ManilaException(
388 "Driver does not support mode 'driver_handles_share_servers="
389 "%(actual)s'. It can be used only with value '%(allowed)s'." %
390 {'actual': self.driver_handles_share_servers,
391 'allowed': driver_handles_share_servers})
393 def migration_check_compatibility(
394 self, context, source_share, destination_share,
395 share_server=None, destination_share_server=None):
396 """Checks destination compatibility for migration of a given share.
398 .. note::
399 Is called to test compatibility with destination backend.
401 Driver should check if it is compatible with destination backend so
402 driver-assisted migration can proceed.
404 :param context: The 'context.RequestContext' object for the request.
405 :param source_share: Reference to the share to be migrated.
406 :param destination_share: Reference to the share model to be used by
407 migrated share.
408 :param share_server: Share server model or None.
409 :param destination_share_server: Destination Share server model or
410 None.
411 :return: A dictionary containing values indicating if destination
412 backend is compatible, if share can remain writable during
413 migration, if it can preserve all file metadata and if it can
414 perform migration of given share non-disruptively.
416 Example::
418 {
419 'compatible': True,
420 'writable': True,
421 'preserve_metadata': True,
422 'nondisruptive': True,
423 'preserve_snapshots': True,
424 }
426 """
427 return {
428 'compatible': False,
429 'writable': False,
430 'preserve_metadata': False,
431 'nondisruptive': False,
432 'preserve_snapshots': False,
433 }
435 def migration_start(
436 self, context, source_share, destination_share,
437 source_snapshots, snapshot_mappings, share_server=None,
438 destination_share_server=None):
439 """Starts migration of a given share to another host.
441 .. note::
442 Is called in source share's backend to start migration.
444 Driver should implement this method if willing to perform migration
445 in a driver-assisted way, useful for when source share's backend driver
446 is compatible with destination backend driver. This method should
447 start the migration procedure in the backend and end. Following steps
448 should be done in 'migration_continue'.
450 :param context: The 'context.RequestContext' object for the request.
451 :param source_share: Reference to the original share model.
452 :param destination_share: Reference to the share model to be used by
453 migrated share.
454 :param source_snapshots: List of snapshots owned by the source share.
455 :param snapshot_mappings: Mapping of source snapshot IDs to
456 destination snapshot models.
457 :param share_server: Share server model or None.
458 :param destination_share_server: Destination Share server model or
459 None.
460 """
461 raise NotImplementedError()
463 def migration_continue(
464 self, context, source_share, destination_share, source_snapshots,
465 snapshot_mappings, share_server=None,
466 destination_share_server=None):
467 """Continues migration of a given share to another host.
469 .. note::
470 Is called in source share's backend to continue migration.
472 Driver should implement this method to continue monitor the migration
473 progress in storage and perform following steps until 1st phase is
474 completed.
476 :param context: The 'context.RequestContext' object for the request.
477 :param source_share: Reference to the original share model.
478 :param destination_share: Reference to the share model to be used by
479 migrated share.
480 :param source_snapshots: List of snapshots owned by the source share.
481 :param snapshot_mappings: Mapping of source snapshot IDs to
482 destination snapshot models.
483 :param share_server: Share server model or None.
484 :param destination_share_server: Destination Share server model or
485 None.
486 :return: Boolean value to indicate if 1st phase is finished.
487 """
488 raise NotImplementedError()
490 def migration_complete(
491 self, context, source_share, destination_share, source_snapshots,
492 snapshot_mappings, share_server=None,
493 destination_share_server=None):
494 """Completes migration of a given share to another host.
496 .. note::
497 Is called in source share's backend to complete migration.
499 If driver is implementing 2-phase migration, this method should
500 perform the disruptive tasks related to the 2nd phase of migration,
501 thus completing it. Driver should also delete all original share data
502 from source backend.
504 :param context: The 'context.RequestContext' object for the request.
505 :param source_share: Reference to the original share model.
506 :param destination_share: Reference to the share model to be used by
507 migrated share.
508 :param source_snapshots: List of snapshots owned by the source share.
509 :param snapshot_mappings: Mapping of source snapshot IDs to
510 destination snapshot models.
511 :param share_server: Share server model or None.
512 :param destination_share_server: Destination Share server model or
513 None.
514 :return: If the migration changes the share export locations, snapshot
515 provider locations or snapshot export locations, this method should
516 return a dictionary with the relevant info. In such case, a
517 dictionary containing a list of export locations and a list of
518 model updates for each snapshot indexed by their IDs.
520 Example::
522 {
523 'export_locations':
524 [
525 {
526 'path': '1.2.3.4:/foo',
527 'metadata': {},
528 'is_admin_only': False
529 },
530 {
531 'path': '5.6.7.8:/foo',
532 'metadata': {},
533 'is_admin_only': True
534 },
535 ],
536 'snapshot_updates':
537 {
538 'bc4e3b28-0832-4168-b688-67fdc3e9d408':
539 {
540 'provider_location': '/snapshots/foo/bar_1',
541 'export_locations':
542 [
543 {
544 'path': '1.2.3.4:/snapshots/foo/bar_1',
545 'is_admin_only': False,
546 },
547 {
548 'path': '5.6.7.8:/snapshots/foo/bar_1',
549 'is_admin_only': True,
550 },
551 ],
552 },
553 '2e62b7ea-4e30-445f-bc05-fd523ca62941':
554 {
555 'provider_location': '/snapshots/foo/bar_2',
556 'export_locations':
557 [
558 {
559 'path': '1.2.3.4:/snapshots/foo/bar_2',
560 'is_admin_only': False,
561 },
562 {
563 'path': '5.6.7.8:/snapshots/foo/bar_2',
564 'is_admin_only': True,
565 },
566 ],
567 },
568 },
569 }
571 """
572 raise NotImplementedError()
574 def migration_cancel(
575 self, context, source_share, destination_share, source_snapshots,
576 snapshot_mappings, share_server=None,
577 destination_share_server=None):
578 """Cancels migration of a given share to another host.
580 .. note::
581 Is called in source share's backend to cancel migration.
583 If possible, driver can implement a way to cancel an in-progress
584 migration.
586 :param context: The 'context.RequestContext' object for the request.
587 :param source_share: Reference to the original share model.
588 :param destination_share: Reference to the share model to be used by
589 migrated share.
590 :param source_snapshots: List of snapshots owned by the source share.
591 :param snapshot_mappings: Mapping of source snapshot IDs to
592 destination snapshot models.
593 :param share_server: Share server model or None.
594 :param destination_share_server: Destination Share server model or
595 None.
596 """
597 raise NotImplementedError()
599 def transfer_accept(self, context, share, new_user, new_project,
600 access_rules=None, share_server=None):
601 """Backend update project and user info if stored on the backend.
603 :param context: The 'context.RequestContext' object for the request.
604 :param share: Share instance model.
605 :param access_rules: A list of access rules for given share.
606 :param new_user: the share will be updated with the new user id .
607 :param new_project: the share will be updated with the new project id.
608 :param share_server: share server for given share.
609 """
610 pass
612 def migration_get_progress(
613 self, context, source_share, destination_share, source_snapshots,
614 snapshot_mappings, share_server=None,
615 destination_share_server=None):
616 """Obtains progress of migration of a given share to another host.
618 .. note::
619 Is called in source share's backend to obtain migration progress.
621 If possible, driver can implement a way to return migration progress
622 information.
624 :param context: The 'context.RequestContext' object for the request.
625 :param source_share: Reference to the original share model.
626 :param destination_share: Reference to the share model to be used by
627 migrated share.
628 :param source_snapshots: List of snapshots owned by the source share.
629 :param snapshot_mappings: Mapping of source snapshot IDs to
630 destination snapshot models.
631 :param share_server: Share server model or None.
632 :param destination_share_server: Destination Share server model or
633 None.
634 :return: A dictionary with at least 'total_progress' field containing
635 the percentage value.
636 """
637 raise NotImplementedError()
639 def connection_get_info(self, context, share, share_server=None):
640 """Is called to provide necessary generic migration logic.
642 :param context: The 'context.RequestContext' object for the request.
643 :param share: Reference to the share being migrated.
644 :param share_server: Share server model or None.
645 :return: A dictionary with migration information.
646 """
647 mount_template = self._get_mount_command(context, share, share_server)
649 unmount_template = self._get_unmount_command(context, share,
650 share_server)
652 access_mapping = self._get_access_mapping(context, share, share_server)
654 info = {
655 'mount': mount_template,
656 'unmount': unmount_template,
657 'access_mapping': access_mapping,
658 }
660 LOG.debug("Migration info obtained for share %(share_id)s: %(info)s.",
661 {'share_id': share['id'], 'info': str(info)})
663 return info
665 def _get_access_mapping(self, context, share, share_server):
667 mapping = self.configuration.safe_get('protocol_access_mapping') or {}
668 result = {}
669 share_proto = share['share_proto'].lower()
670 for access_type, protocols in mapping.items():
671 if share_proto in [y.lower() for y in protocols]:
672 result[access_type] = result.get(access_type, [])
673 result[access_type].append(share_proto)
674 return result
676 def _get_mount_command(self, context, share_instance, share_server=None):
677 """Is called to delegate mounting share logic."""
679 mount_template = self.configuration.safe_get('share_mount_template')
681 mount_export = self._get_mount_export(share_instance, share_server)
683 format_template = {
684 'proto': share_instance['share_proto'].lower(),
685 'export': mount_export,
686 'path': '%(path)s',
687 'options': '%(options)s',
688 }
690 return mount_template % format_template
692 def _get_mount_export(self, share_instance, share_server=None):
693 # NOTE(ganso): If drivers want to override the export_location IP,
694 # they can do so using this configuration. This method can also be
695 # overridden if necessary.
696 path = next((x['path'] for x in share_instance['export_locations']
697 if x['is_admin_only']), None)
698 if not path:
699 path = share_instance['export_locations'][0]['path']
700 return path
702 def _get_unmount_command(self, context, share_instance,
703 share_server=None):
704 return self.configuration.safe_get('share_unmount_template')
706 def create_share(self, context, share, share_server=None):
707 """Is called to create share."""
708 raise NotImplementedError()
710 def create_share_from_snapshot(self, context, share, snapshot,
711 share_server=None, parent_share=None):
712 """Is called to create share from snapshot.
714 Creating a share from snapshot can take longer than a simple clone
715 operation if data copy is required from one host to another. For this
716 reason driver will be able complete this creation asynchronously, by
717 providing a 'creating_from_snapshot' status in the model update.
719 When answering asynchronously, drivers must implement the call
720 'get_share_status' in order to provide updates for shares with
721 'creating_from_snapshot' status.
723 It is expected that the driver returns a model update to the share
724 manager that contains: share status and a list of export_locations.
725 A list of 'export_locations' is mandatory only for share in 'available'
726 status.
727 The current supported status are 'available' and
728 'creating_from_snapshot'.
730 :param context: Current context
731 :param share: Share instance model with share data.
732 :param snapshot: Snapshot instance model .
733 :param share_server: Share server model or None.
734 :param parent_share: Share model from parent snapshot with share data
735 and share server model.
737 :returns: a dictionary of updates containing current share status and
738 its export_location (if available).
740 Example::
742 {
743 'status': 'available',
744 'export_locations': [{...}, {...}],
745 }
747 :raises: ShareBackendException.
748 A ShareBackendException in this method will set the instance to
749 'error' and the operation will end.
750 """
751 raise NotImplementedError()
753 def create_snapshot(self, context, snapshot, share_server=None):
754 """Is called to create snapshot.
756 :param context: Current context
757 :param snapshot: Snapshot model. Share model could be
758 retrieved through snapshot['share'].
759 :param share_server: Share server model or None.
760 :return: None or a dictionary with key 'export_locations' containing
761 a list of export locations, if snapshots can be mounted.
762 """
763 raise NotImplementedError()
765 def delete_share(self, context, share, share_server=None):
766 """Is called to remove share."""
767 raise NotImplementedError()
769 def delete_snapshot(self, context, snapshot, share_server=None):
770 """Is called to remove snapshot.
772 :param context: Current context
773 :param snapshot: Snapshot model. Share model could be
774 retrieved through snapshot['share'].
775 :param share_server: Share server model or None.
776 """
777 raise NotImplementedError()
779 def get_pool(self, share):
780 """Return pool name where the share resides on.
782 :param share: The share hosted by the driver.
783 """
785 def ensure_share(self, context, share, share_server=None):
786 """Invoked to ensure that share is exported.
788 Driver can use this method to update the list of export locations of
789 the share if it changes. To do that, you should return list with
790 export locations.
792 It is preferred if the driver implements "get_backend_info" and
793 "ensure_shares" instead of this routine.
795 :return: None or list with export locations
796 """
797 raise NotImplementedError()
799 def allow_access(self, context, share, access, share_server=None):
800 """Allow access to the share."""
801 raise NotImplementedError()
803 def deny_access(self, context, share, access, share_server=None):
804 """Deny access to the share."""
805 raise NotImplementedError()
807 def update_access(self, context, share, access_rules, add_rules,
808 delete_rules, update_rules, share_server=None):
809 """Update access rules for given share.
811 ``access_rules`` contains all access_rules that need to be on the
812 share. If the driver can make bulk access rule updates, it can
813 safely ignore the ``add_rules`` and ``delete_rules`` parameters.
815 If the driver cannot make bulk access rule changes, it can rely on
816 new rules to be present in ``add_rules`` and rules that need to be
817 removed to be present in ``delete_rules``.
819 When a rule in ``delete_rules`` was never applied, drivers must not
820 raise an exception, or attempt to set the rule to ``error`` state.
822 ``add_rules`` and ``delete_rules`` can be empty lists, in this
823 situation, drivers should ensure that the rules present in
824 ``access_rules`` are the same as those on the back end. One scenario
825 where this situation is forced is when the access_level is changed for
826 all existing rules (share migration and for readable replicas).
828 Drivers must be mindful of this call for share replicas. When
829 'update_access' is called on one of the replicas, the call is likely
830 propagated to all replicas belonging to the share, especially when
831 individual rules are added or removed. If a particular access rule
832 does not make sense to the driver in the context of a given replica,
833 the driver should be careful to report a correct behavior, and take
834 meaningful action. For example, if R/W access is requested on a
835 replica that is part of a "readable" type replication; R/O access
836 may be added by the driver instead of R/W. Note that raising an
837 exception *will* result in the access_rules_status on the replica,
838 and the share itself being "out_of_sync". Drivers can sync on the
839 valid access rules that are provided on the ``create_replica`` and
840 ``promote_replica`` calls.
842 :param context: Current context
843 :param share: Share model with share data.
844 :param access_rules: A list of access rules for given share
845 :param add_rules: Empty List or List of access rules which should be
846 added. access_rules already contains these rules.
847 :param delete_rules: Empty List or List of access rules which should be
848 removed. access_rules doesn't contain these rules.
849 :param update_rules: Empty List or List of access rules which should be
850 updated. access_rules already contains these rules.
851 :param share_server: None or Share server model
852 :returns: None, or a dictionary of updates in the format::
854 {
856 '09960614-8574-4e03-89cf-7cf267b0bd08': {
858 'access_key': 'alice31493e5441b8171d2310d80e37e',
859 'state': 'error',
861 },
863 '28f6eabb-4342-486a-a7f4-45688f0c0295': {
865 'access_key': 'bob0078aa042d5a7325480fd13228b',
866 'state': 'active',
868 },
870 }
872 The top level keys are 'access_id' fields of the access rules that
873 need to be updated. ``access_key``s are credentials (str) of the
874 entities granted access. Any rule in the ``access_rules`` parameter
875 can be updated.
877 .. important::
879 Raising an exception in this method will force *all* rules in
880 'applying' and 'denying' states to 'error'.
882 An access rule can be set to 'error' state, either explicitly
883 via this return parameter or because of an exception raised in
884 this method. Such an access rule will no longer be sent to the
885 driver on subsequent access rule updates. When users deny that
886 rule however, the driver will be asked to deny access to the
887 client/s represented by the rule. We expect that a
888 rule that was error-ed at the driver should never exist on the
889 back end. So, do not fail the deletion request.
891 Also, it is possible that the driver may receive a request to
892 add a rule that is already present on the back end.
893 This can happen if the share manager service goes down
894 while the driver is committing access rule changes. Since we
895 cannot determine if the rule was applied successfully by the driver
896 before the disruption, we will treat all 'applying' transitional
897 rules as new rules and repeat the request.
898 """
899 raise NotImplementedError()
901 def check_for_setup_error(self):
902 """Check for setup error."""
903 pass
905 def do_setup(self, context):
906 """Any initialization the share driver does while starting."""
908 def get_share_stats(self, refresh=False):
909 """Get share status.
911 If 'refresh' is True, run update the stats first.
912 """
913 if refresh:
914 self._update_share_stats()
916 return self._stats
918 def get_network_allocations_number(self):
919 """Returns number of network allocations for creating VIFs.
921 Drivers that use Nova for share servers should return zero (0) here
922 same as Generic driver does.
923 Because Nova will handle network resources allocation.
924 Drivers that handle networking itself should calculate it according
925 to their own requirements. It can have 1+ network interfaces.
926 """
927 raise NotImplementedError()
929 def get_admin_network_allocations_number(self):
930 return 0
932 def update_network_allocation(self, context, share_server):
933 """Update network allocation after share server creation."""
934 self.network_api.update_network_allocation(context, share_server)
936 def update_admin_network_allocation(self, context, share_server):
937 """Update admin network allocation after share server creation."""
938 if (self.get_admin_network_allocations_number() and 938 ↛ 940line 938 didn't jump to line 940 because the condition on line 938 was never true
939 self.admin_network_api):
940 self.admin_network_api.update_network_allocation(context,
941 share_server)
943 def allocate_network(self, context, share_server, share_network,
944 share_network_subnet, count=None, **kwargs):
945 """Allocate network resources using given network information."""
946 if count is None:
947 count = self.get_network_allocations_number()
948 if count:
949 kwargs.update(count=count)
950 self.network_api.allocate_network(
951 context, share_server, share_network=share_network,
952 share_network_subnet=share_network_subnet, **kwargs)
954 def allocate_admin_network(self, context, share_server, count=None,
955 **kwargs):
956 """Allocate admin network resources using given network information."""
957 if count is None:
958 count = self.get_admin_network_allocations_number()
959 if count and not self.admin_network_api:
960 msg = _("Admin network plugin is not set up.")
961 raise exception.NetworkBadConfigurationException(reason=msg)
962 elif count:
963 kwargs.update(count=count)
964 self.admin_network_api.allocate_network(
965 context, share_server, **kwargs)
967 def deallocate_network(self, context, share_server_id, share_network=None,
968 share_network_subnet=None):
969 """Deallocate network resources for the given share server."""
970 if self.get_network_allocations_number(): 970 ↛ exitline 970 didn't return from function 'deallocate_network' because the condition on line 970 was always true
971 self.network_api.deallocate_network(
972 context, share_server_id, share_network=share_network,
973 share_network_subnet=share_network_subnet)
975 def choose_share_server_compatible_with_share(self, context, share_servers,
976 share, snapshot=None,
977 share_group=None,
978 encryption_key_ref=None):
979 """Method that allows driver to choose share server for provided share.
981 If compatible share-server is not found, method should return None.
983 :param context: Current context
984 :param share_servers: list with share-server models
985 :param share: share model
986 :param snapshot: snapshot model
987 :param share_group: ShareGroup model with shares
988 :param encryption_key_ref: Encryption key reference
989 :returns: share-server or None
990 """
991 # If creating in a share group, use its share server
992 if share_group: 992 ↛ 993line 992 didn't jump to line 993 because the condition on line 992 was never true
993 for share_server in share_servers:
994 if (share_group.get('share_server_id') ==
995 share_server['id']):
996 return share_server
997 return None
999 return share_servers[0] if share_servers else None
1001 def choose_share_server_compatible_with_share_group(
1002 self, context, share_servers, share_group_ref,
1003 share_group_snapshot=None):
1005 return share_servers[0] if share_servers else None
1007 def setup_server(self, *args, **kwargs):
1008 if self.driver_handles_share_servers:
1009 return self._setup_server(*args, **kwargs)
1010 else:
1011 LOG.debug(
1012 "Skipping step 'setup share server', because driver is "
1013 "enabled with mode when Manila does not handle share servers.")
1015 def _setup_server(self, network_info, metadata=None):
1016 """Sets up and configures share server with given network parameters.
1018 Redefine it within share driver when it is going to handle share
1019 servers.
1021 :param metadata: a dictionary, for now containing a key 'request_host'
1022 """
1023 raise NotImplementedError()
1025 def manage_existing(self, share, driver_options):
1026 """Brings an existing share under Manila management.
1028 If the provided share is not valid, then raise a
1029 ManageInvalidShare exception, specifying a reason for the failure.
1031 If the provided share is not in a state that can be managed, such as
1032 being replicated on the backend, the driver *MUST* raise
1033 ManageInvalidShare exception with an appropriate message.
1035 The share has a share_type, and the driver can inspect that and
1036 compare against the properties of the referenced backend share.
1037 If they are incompatible, raise a
1038 ManageExistingShareTypeMismatch, specifying a reason for the failure.
1040 This method is invoked when the share is being managed with
1041 a share type that has ``driver_handles_share_servers``
1042 extra-spec set to False.
1044 :param share: Share model
1045 :param driver_options: Driver-specific options provided by admin.
1046 :return: share_update dictionary with required key 'size',
1047 which should contain size of the share.
1048 """
1049 raise NotImplementedError()
1051 def manage_existing_with_server(
1052 self, share, driver_options, share_server=None):
1053 """Brings an existing share under Manila management.
1055 If the provided share is not valid, then raise a
1056 ManageInvalidShare exception, specifying a reason for the failure.
1058 If the provided share is not in a state that can be managed, such as
1059 being replicated on the backend, the driver *MUST* raise
1060 ManageInvalidShare exception with an appropriate message.
1062 The share has a share_type, and the driver can inspect that and
1063 compare against the properties of the referenced backend share.
1064 If they are incompatible, raise a
1065 ManageExistingShareTypeMismatch, specifying a reason for the failure.
1067 This method is invoked when the share is being managed with
1068 a share type that has ``driver_handles_share_servers``
1069 extra-spec set to True.
1071 :param share: Share model
1072 :param driver_options: Driver-specific options provided by admin.
1073 :param share_server: Share server model or None.
1074 :return: share_update dictionary with required key 'size',
1075 which should contain size of the share.
1076 """
1077 raise NotImplementedError()
1079 def unmanage(self, share):
1080 """Removes the specified share from Manila management.
1082 Does not delete the underlying backend share.
1084 For most drivers, this will not need to do anything. However, some
1085 drivers might use this call as an opportunity to clean up any
1086 Manila-specific configuration that they have associated with the
1087 backend share.
1089 If provided share cannot be unmanaged, then raise an
1090 UnmanageInvalidShare exception, specifying a reason for the failure.
1092 This method is invoked when the share is being unmanaged with
1093 a share type that has ``driver_handles_share_servers``
1094 extra-spec set to False.
1095 """
1097 def unmanage_with_server(self, share, share_server=None):
1098 """Removes the specified share from Manila management.
1100 Does not delete the underlying backend share.
1102 For most drivers, this will not need to do anything. However, some
1103 drivers might use this call as an opportunity to clean up any
1104 Manila-specific configuration that they have associated with the
1105 backend share.
1107 If provided share cannot be unmanaged, then raise an
1108 UnmanageInvalidShare exception, specifying a reason for the failure.
1110 This method is invoked when the share is being unmanaged with
1111 a share type that has ``driver_handles_share_servers``
1112 extra-spec set to True.
1113 """
1115 def manage_existing_snapshot(self, snapshot, driver_options):
1116 """Brings an existing snapshot under Manila management.
1118 If provided snapshot is not valid, then raise a
1119 ManageInvalidShareSnapshot exception, specifying a reason for
1120 the failure.
1122 This method is invoked when the snapshot that is being managed
1123 belongs to a share that has its share type with
1124 ``driver_handles_share_servers`` extra-spec set to False.
1126 :param snapshot: ShareSnapshotInstance model with ShareSnapshot data.
1128 Example::
1129 {
1130 'id': <instance id>,
1131 'snapshot_id': < snapshot id>,
1132 'provider_location': <location>,
1133 ...
1134 }
1136 :param driver_options: Optional driver-specific options provided
1137 by admin.
1139 Example::
1141 {
1142 'key': 'value',
1143 ...
1144 }
1146 :return: model_update dictionary with required key 'size',
1147 which should contain size of the share snapshot, and key
1148 'export_locations' containing a list of export locations, if
1149 snapshots can be mounted.
1150 """
1151 raise NotImplementedError()
1153 def manage_existing_snapshot_with_server(self, snapshot, driver_options,
1154 share_server=None):
1155 """Brings an existing snapshot under Manila management.
1157 If provided snapshot is not valid, then raise a
1158 ManageInvalidShareSnapshot exception, specifying a reason for
1159 the failure.
1161 This method is invoked when the snapshot that is being managed
1162 belongs to a share that has its share type with
1163 ``driver_handles_share_servers`` extra-spec set to True.
1165 :param snapshot: ShareSnapshotInstance model with ShareSnapshot data.
1167 Example::
1168 {
1169 'id': <instance id>,
1170 'snapshot_id': < snapshot id>,
1171 'provider_location': <location>,
1172 ...
1173 }
1175 :param driver_options: Optional driver-specific options provided
1176 by admin.
1178 Example::
1180 {
1181 'key': 'value',
1182 ...
1183 }
1185 :param share_server: Share server model or None.
1186 :return: model_update dictionary with required key 'size',
1187 which should contain size of the share snapshot, and key
1188 'export_locations' containing a list of export locations, if
1189 snapshots can be mounted.
1190 """
1191 raise NotImplementedError()
1193 def unmanage_snapshot(self, snapshot):
1194 """Removes the specified snapshot from Manila management.
1196 Does not delete the underlying backend share snapshot.
1198 For most drivers, this will not need to do anything. However, some
1199 drivers might use this call as an opportunity to clean up any
1200 Manila-specific configuration that they have associated with the
1201 backend share snapshot.
1203 If provided share snapshot cannot be unmanaged, then raise an
1204 UnmanageInvalidShareSnapshot exception, specifying a reason for
1205 the failure.
1207 This method is invoked when the snapshot that is being unmanaged
1208 belongs to a share that has its share type with
1209 ``driver_handles_share_servers`` extra-spec set to False.
1210 """
1212 def unmanage_snapshot_with_server(self, snapshot, share_server=None):
1213 """Removes the specified snapshot from Manila management.
1215 Does not delete the underlying backend share snapshot.
1217 For most drivers, this will not need to do anything. However, some
1218 drivers might use this call as an opportunity to clean up any
1219 Manila-specific configuration that they have associated with the
1220 backend share snapshot.
1222 If provided share snapshot cannot be unmanaged, then raise an
1223 UnmanageInvalidShareSnapshot exception, specifying a reason for
1224 the failure.
1226 This method is invoked when the snapshot that is being unmanaged
1227 belongs to a share that has its share type with
1228 ``driver_handles_share_servers`` extra-spec set to True.
1229 """
1231 def revert_to_snapshot(self, context, snapshot, share_access_rules,
1232 snapshot_access_rules, share_server=None):
1233 """Reverts a share (in place) to the specified snapshot.
1235 Does not delete the share snapshot. The share and snapshot must both
1236 be 'available' for the restore to be attempted. The snapshot must be
1237 the most recent one taken by Manila; the API layer performs this check
1238 so the driver doesn't have to.
1240 The share must be reverted in place to the contents of the snapshot.
1241 Application admins should quiesce or otherwise prepare the application
1242 for the shared file system contents to change suddenly.
1244 :param context: Current context
1245 :param snapshot: The snapshot to be restored
1246 :param share_access_rules: List of all access rules for the affected
1247 share
1248 :param snapshot_access_rules: List of all access rules for the affected
1249 snapshot
1250 :param share_server: Optional -- Share server model or None
1251 """
1252 raise NotImplementedError()
1254 def extend_share(self, share, new_size, share_server=None):
1255 """Extends size of existing share.
1257 :param share: Share model
1258 :param new_size: New size of share (new_size > share['size'])
1259 :param share_server: Optional -- Share server model
1260 """
1261 raise NotImplementedError()
1263 def shrink_share(self, share, new_size, share_server=None):
1264 """Shrinks size of existing share.
1266 If consumed space on share larger than new_size driver should raise
1267 ShareShrinkingPossibleDataLoss exception:
1268 raise ShareShrinkingPossibleDataLoss(share_id=share['id'])
1270 :param share: Share model
1271 :param new_size: New size of share (new_size < share['size'])
1272 :param share_server: Optional -- Share server model
1274 :raises ShareShrinkingPossibleDataLoss, NotImplementedError
1275 """
1276 raise NotImplementedError()
1278 def teardown_server(self, *args, **kwargs):
1279 if self.driver_handles_share_servers:
1280 return self._teardown_server(*args, **kwargs)
1281 else:
1282 LOG.debug(
1283 "Skipping step 'teardown share server', because driver is "
1284 "enabled with mode when Manila does not handle share servers.")
1286 def _teardown_server(self, server_details, security_services=None):
1287 """Tears down share server.
1289 Redefine it within share driver when it is going to handle share
1290 servers.
1291 """
1292 raise NotImplementedError()
1294 def _has_redefined_driver_methods(self, methods):
1295 """Returns boolean as a result of methods presence and redefinition."""
1296 if not isinstance(methods, (set, list, tuple)): 1296 ↛ 1297line 1296 didn't jump to line 1297 because the condition on line 1296 was never true
1297 methods = (methods, )
1298 for method_name in methods:
1299 method = getattr(type(self), method_name, None)
1300 if (not method or method == getattr(ShareDriver, method_name)):
1301 return False
1302 return True
1304 @property
1305 def snapshots_are_supported(self):
1306 if not hasattr(self, '_snapshots_are_supported'):
1307 methods = ('create_snapshot', 'delete_snapshot')
1308 # NOTE(vponomaryov): calculate default value for
1309 # stat 'snapshot_support' based on implementation of
1310 # appropriate methods of this base driver class.
1311 self._snapshots_are_supported = self._has_redefined_driver_methods(
1312 methods)
1313 return self._snapshots_are_supported
1315 @property
1316 def creating_shares_from_snapshots_is_supported(self):
1317 """Calculate default value for create_share_from_snapshot_support."""
1319 if not hasattr(self, '_creating_shares_from_snapshots_is_supported'):
1320 methods = ('create_share_from_snapshot', )
1321 self._creating_shares_from_snapshots_is_supported = (
1322 self._has_redefined_driver_methods(methods))
1324 return (
1325 self._creating_shares_from_snapshots_is_supported and
1326 self.snapshots_are_supported
1327 )
1329 def _update_share_stats(self, data=None):
1330 """Retrieve stats info from share group.
1332 :param data: dict -- dict with key-value pairs to redefine common ones.
1333 """
1335 LOG.debug("Updating share stats.")
1336 backend_name = (self.configuration.safe_get('share_backend_name') or
1337 CONF.share_backend_name)
1339 # Note(zhiteng): These information are driver/backend specific,
1340 # each driver may define these values in its own config options
1341 # or fetch from driver specific configuration file.
1342 common = dict(
1343 share_backend_name=backend_name or 'Generic_NFS',
1344 driver_handles_share_servers=self.driver_handles_share_servers,
1345 vendor_name='Open Source',
1346 driver_version='1.0',
1347 storage_protocol=None,
1348 total_capacity_gb='unknown',
1349 free_capacity_gb='unknown',
1350 reserved_percentage=0,
1351 reserved_snapshot_percentage=0,
1352 reserved_share_extend_percentage=0,
1353 qos=False,
1354 pools=self.pools or None,
1355 snapshot_support=self.snapshots_are_supported,
1356 create_share_from_snapshot_support=(
1357 self.creating_shares_from_snapshots_is_supported),
1358 revert_to_snapshot_support=False,
1359 mount_snapshot_support=False,
1360 replication_domain=self.replication_domain,
1361 filter_function=self.get_filter_function(),
1362 goodness_function=self.get_goodness_function(),
1363 security_service_update_support=(
1364 self.security_service_update_support),
1365 network_allocation_update_support=(
1366 self.network_allocation_update_support),
1367 share_server_multiple_subnet_support=False,
1368 mount_point_name_support=False,
1369 share_replicas_migration_support=(
1370 self.share_replicas_migration_support),
1371 encryption_support=self.encryption_support,
1372 )
1373 if isinstance(data, dict):
1374 common.update(data)
1376 if self.driver_handles_share_servers:
1377 common.update({
1378 'max_shares_per_share_server':
1379 self.max_shares_per_share_server,
1380 'max_share_server_size': self.max_share_server_size
1381 })
1383 sg_stats = data.get('share_group_stats', {}) if data else {}
1384 common['share_group_stats'] = {
1385 'consistent_snapshot_support': sg_stats.get(
1386 'consistent_snapshot_support'),
1387 }
1389 self.add_ip_version_capability(common)
1390 self._stats = common
1392 def get_share_server_pools(self, share_server):
1393 """Return list of pools related to a particular share server.
1395 :param share_server: ShareServer class instance.
1396 """
1397 return []
1399 def create_share_group(self, context, share_group_dict, share_server=None):
1400 """Create a share group.
1402 :param context:
1403 :param share_group_dict: The share group details
1404 EXAMPLE:
1405 {
1406 'status': 'creating',
1407 'project_id': '13c0be6290934bd98596cfa004650049',
1408 'user_id': 'a0314a441ca842019b0952224aa39192',
1409 'description': None,
1410 'deleted': 'False',
1411 'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),
1412 'updated_at': None,
1413 'source_share_group_snapshot_id': 'some_fake_uuid',
1414 'share_group_type_id': 'some_fake_uuid',
1415 'host': 'hostname@backend_name',
1416 'share_network_id': None,
1417 'share_server_id': None,
1418 'deleted_at': None,
1419 'share_types': [<models.ShareGroupShareTypeMapping>],
1420 'id': 'some_fake_uuid',
1421 'name': None
1422 }
1423 :returns: (share_group_model_update, share_update_list)
1424 share_group_model_update - a dict containing any values to be
1425 updated for the SG in the database. This value may be None.
1427 """
1428 LOG.debug('Created a Share Group with ID: %s.', share_group_dict['id'])
1430 def create_share_group_from_share_group_snapshot(
1431 self, context, share_group_dict, share_group_snapshot_dict,
1432 share_server=None):
1433 """Create a share group from a share group snapshot.
1435 When creating a share from snapshot operation takes longer than a
1436 simple clone operation, drivers will be able to complete this creation
1437 asynchronously, by providing a 'creating_from_snapshot' status in the
1438 returned model update. The current supported status are 'available' and
1439 'creating_from_snapshot'.
1441 In order to provide updates for shares with 'creating_from_snapshot'
1442 status, drivers must implement the call 'get_share_status'.
1444 :param context:
1445 :param share_group_dict: The share group details
1446 EXAMPLE:
1447 .. code::
1449 {
1450 'status': 'creating',
1451 'project_id': '13c0be6290934bd98596cfa004650049',
1452 'user_id': 'a0314a441ca842019b0952224aa39192',
1453 'description': None,
1454 'deleted': 'False',
1455 'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),
1456 'updated_at': None,
1457 'source_share_group_snapshot_id':
1458 'f6aa3b59-57eb-421e-965c-4e182538e36a',
1459 'host': 'hostname@backend_name',
1460 'deleted_at': None,
1461 'shares': [<models.Share>], # The new shares being created
1462 'share_types': [<models.ShareGroupShareTypeMapping>],
1463 'id': 'some_fake_uuid',
1464 'name': None
1465 }
1466 :param share_group_snapshot_dict: The share group snapshot details
1467 EXAMPLE:
1468 .. code::
1470 {
1471 'status': 'available',
1472 'project_id': '13c0be6290934bd98596cfa004650049',
1473 'user_id': 'a0314a441ca842019b0952224aa39192',
1474 'description': None,
1475 'deleted': '0',
1476 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1477 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1478 'share_group_id': 'some_fake_uuid',
1479 'share_share_group_snapshot_members': [
1480 {
1481 'status': 'available',
1482 'user_id': 'a0314a441ca842019b0952224aa39192',
1483 'deleted': 'False',
1484 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1485 'share': <models.Share>,
1486 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1487 'share_proto': 'NFS',
1488 'project_id': '13c0be6290934bd98596cfa004650049',
1489 'share_group_snapshot_id': 'some_fake_uuid',
1490 'deleted_at': None,
1491 'id': 'some_fake_uuid',
1492 'size': 1
1493 }
1494 ],
1495 'deleted_at': None,
1496 'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',
1497 'name': None
1498 }
1499 :return: (share_group_model_update, share_update_list)
1500 share_group_model_update - a dict containing any values to be
1501 updated for the share group in the database. This value may be None
1503 share_update_list - a list of dictionaries containing dicts for
1504 every share created in the share group. Any share dicts should at a
1505 minimum contain the 'id' key and, for synchronous creation, the
1506 'export_locations'. For asynchronous share creation this dict
1507 must also contain the key 'status' with the value set to
1508 'creating_from_snapshot'. The current supported status are
1509 'available' and 'creating_from_snapshot'.
1510 Export locations should be in the same format as returned by
1511 a share_create. This list may be empty or None. EXAMPLE:
1512 .. code::
1514 [
1515 {
1516 'id': 'uuid',
1517 'export_locations': [{...}, {...}],
1518 },
1519 {
1520 'id': 'uuid',
1521 'export_locations': [],
1522 'status': 'creating_from_snapshot',
1523 },
1524 ]
1526 """
1527 # Ensure that the share group snapshot has members
1528 if not share_group_snapshot_dict['share_group_snapshot_members']:
1529 return None, None
1531 clone_list = self._collate_share_group_snapshot_info(
1532 share_group_dict, share_group_snapshot_dict)
1533 share_update_list = []
1535 LOG.debug('Creating share group from group snapshot %s.',
1536 share_group_snapshot_dict['id'])
1537 for clone in clone_list:
1538 kwargs = {}
1539 share_update_info = {}
1540 if self.driver_handles_share_servers:
1541 kwargs['share_server'] = share_server
1542 model_update = (
1543 self.create_share_from_snapshot(
1544 context, clone['share'], clone['snapshot'], **kwargs))
1545 if isinstance(model_update, dict):
1546 status = model_update.get('status')
1547 # NOTE(dviroel): share status is mandatory when answering
1548 # a model update. If not provided, won't be possible to
1549 # determine if was successfully created.
1550 if status is None: 1550 ↛ 1551line 1550 didn't jump to line 1551 because the condition on line 1550 was never true
1551 msg = _("Driver didn't provide a share status.")
1552 raise exception.InvalidShareInstance(reason=msg)
1553 if status not in [constants.STATUS_AVAILABLE,
1554 constants.STATUS_CREATING_FROM_SNAPSHOT]:
1555 msg = _('Driver returned an invalid status: %s') % status
1556 raise exception.InvalidShareInstance(reason=msg)
1557 share_update_info.update({'status': status})
1558 export_locations = model_update.get('export_locations', [])
1559 else:
1560 # NOTE(dviroel): the driver that doesn't implement the new
1561 # model_update will return only the export locations
1562 export_locations = model_update
1564 share_update_info.update({
1565 'id': clone['share']['id'],
1566 'export_locations': export_locations,
1567 })
1568 share_update_list.append(share_update_info)
1569 return None, share_update_list
1571 def delete_share_group(self, context, share_group_dict, share_server=None):
1572 """Delete a share group
1574 :param context: The request context
1575 :param share_group_dict: The share group details
1576 EXAMPLE:
1577 .. code::
1579 {
1580 'status': 'creating',
1581 'project_id': '13c0be6290934bd98596cfa004650049',
1582 'user_id': 'a0314a441ca842019b0952224aa39192',
1583 'description': None,
1584 'deleted': 'False',
1585 'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),
1586 'updated_at': None,
1587 'source_share_group_snapshot_id': 'some_fake_uuid',
1588 'share_share_group_type_id': 'some_fake_uuid',
1589 'host': 'hostname@backend_name',
1590 'deleted_at': None,
1591 'shares': [<models.Share>], # The new shares being created
1592 'share_types': [<models.ShareGroupShareTypeMapping>],
1593 'id': 'some_fake_uuid',
1594 'name': None
1595 }
1596 :return: share_group_model_update
1597 share_group_model_update - a dict containing any values to be
1598 updated for the group in the database. This value may be None.
1599 """
1601 def _cleanup_group_share_snapshot(self, context, share_snapshot,
1602 share_server):
1603 """Deletes the snapshot of a share belonging to a group."""
1605 try:
1606 self.delete_snapshot(
1607 context, share_snapshot, share_server=share_server)
1608 except exception.ManilaException:
1609 msg = ('Could not delete share group snapshot member %(snap)s '
1610 'for share %(share)s.')
1611 LOG.error(msg, {
1612 'snap': share_snapshot['id'],
1613 'share': share_snapshot['share_id'],
1614 })
1615 raise
1617 def create_share_group_snapshot(self, context, snap_dict,
1618 share_server=None):
1619 """Create a share group snapshot.
1621 :param context:
1622 :param snap_dict: The share group snapshot details
1623 EXAMPLE:
1624 .. code::
1626 {
1627 'status': 'available',
1628 'project_id': '13c0be6290934bd98596cfa004650049',
1629 'user_id': 'a0314a441ca842019b0952224aa39192',
1630 'description': None,
1631 'deleted': '0',
1632 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1633 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1634 'share_group_id': 'some_fake_uuid',
1635 'share_group_snapshot_members': [
1636 {
1637 'status': 'available',
1638 'share_type_id': 'some_fake_uuid',
1639 'user_id': 'a0314a441ca842019b0952224aa39192',
1640 'deleted': 'False',
1641 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1642 'share': <models.Share>,
1643 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1644 'share_proto': 'NFS',
1645 'share_name': 'share_some_fake_uuid',
1646 'name': 'share-snapshot-some_fake_uuid',
1647 'project_id': '13c0be6290934bd98596cfa004650049',
1648 'share_group_snapshot_id': 'some_fake_uuid',
1649 'deleted_at': None,
1650 'share_id': 'some_fake_uuid',
1651 'id': 'some_fake_uuid',
1652 'size': 1,
1653 'provider_location': None,
1654 }
1655 ],
1656 'deleted_at': None,
1657 'id': 'some_fake_uuid',
1658 'name': None
1659 }
1660 :return: (share_group_snapshot_update, member_update_list)
1661 share_group_snapshot_update - a dict containing any values to be
1662 updated for the CGSnapshot in the database. This value may be None.
1664 member_update_list - a list of dictionaries containing for every
1665 member of the share group snapshot. Each dict should contains
1666 values to be updated for the ShareGroupSnapshotMember in
1667 the database. This list may be empty or None.
1668 """
1669 LOG.debug('Attempting to create a share group snapshot %s.',
1670 snap_dict['id'])
1672 snapshot_members = snap_dict.get('share_group_snapshot_members', [])
1673 if not self._stats.get('snapshot_support'):
1674 raise exception.ShareGroupSnapshotNotSupported(
1675 share_group=snap_dict['share_group_id'])
1676 elif not snapshot_members:
1677 LOG.warning('No shares in share group to create snapshot.')
1678 return None, None
1679 else:
1680 share_snapshots = []
1681 snapshot_members_updates = []
1682 for member in snapshot_members:
1683 share_snapshot = {
1684 'snapshot_id': member['share_group_snapshot_id'],
1685 'share_id': member['share_id'],
1686 'share_instance_id': member['share']['id'],
1687 'id': member['id'],
1688 'share': member['share'],
1689 'share_name': member['share_name'],
1690 'name': member['name'],
1691 'size': member['share']['size'],
1692 'share_size': member['share']['size'],
1693 'share_proto': member['share']['share_proto'],
1694 'provider_location': None,
1695 }
1696 try:
1697 member_update = self.create_snapshot(
1698 context, share_snapshot, share_server=share_server)
1699 if member_update:
1700 member_update['id'] = member['id']
1701 snapshot_members_updates.append(member_update)
1702 share_snapshots.append(share_snapshot)
1703 except exception.ManilaException as e:
1704 msg = ('Could not create share group snapshot. Failed '
1705 'to create share snapshot %(snap)s for '
1706 'share %(share)s.')
1707 LOG.exception(msg, {
1708 'snap': share_snapshot['id'],
1709 'share': share_snapshot['share_id']
1710 })
1712 # clean up any share snapshots previously created
1713 LOG.debug(
1714 'Attempting to clean up snapshots due to failure.')
1715 for share_snapshot in share_snapshots:
1716 self._cleanup_group_share_snapshot(
1717 context, share_snapshot, share_server)
1718 raise e
1720 LOG.debug('Successfully created share group snapshot %s.',
1721 snap_dict['id'])
1722 return None, snapshot_members_updates
1724 def delete_share_group_snapshot(self, context, snap_dict,
1725 share_server=None):
1726 """Delete a share group snapshot
1728 :param context:
1729 :param snap_dict: The share group snapshot details
1730 EXAMPLE:
1731 .. code::
1733 {
1734 'status': 'available',
1735 'project_id': '13c0be6290934bd98596cfa004650049',
1736 'user_id': 'a0314a441ca842019b0952224aa39192',
1737 'description': None,
1738 'deleted': '0',
1739 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1740 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1741 'share_group_id': 'some_fake_uuid',
1742 'share_group_snapshot_members': [
1743 {
1744 'status': 'available',
1745 'share_type_id': 'some_fake_uuid',
1746 'share_id': 'some_fake_uuid',
1747 'user_id': 'a0314a441ca842019b0952224aa39192',
1748 'deleted': 'False',
1749 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1750 'share': <models.Share>,
1751 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1752 'share_proto': 'NFS',
1753 'share_name':'share_some_fake_uuid',
1754 'name': 'share-snapshot-some_fake_uuid',
1755 'project_id': '13c0be6290934bd98596cfa004650049',
1756 'share_group_snapshot_id': 'some_fake_uuid',
1757 'deleted_at': None,
1758 'id': 'some_fake_uuid',
1759 'size': 1,
1760 'provider_location': 'fake_provider_location_value',
1761 }
1762 ],
1763 'deleted_at': None,
1764 'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',
1765 'name': None
1766 }
1767 :return: (share_group_snapshot_update, member_update_list)
1768 share_group_snapshot_update - a dict containing any values
1769 to be updated for the ShareGroupSnapshot in the database.
1770 This value may be None.
1771 """
1772 snapshot_members = snap_dict.get('share_group_snapshot_members', [])
1773 LOG.debug('Deleting share group snapshot %s.', snap_dict['id'])
1774 for member in snapshot_members:
1775 share_snapshot = {
1776 'snapshot_id': member['share_group_snapshot_id'],
1777 'share_id': member['share_id'],
1778 'share_instance_id': member['share']['id'],
1779 'id': member['id'],
1780 'share': member['share'],
1781 'size': member['share']['size'],
1782 'share_name': member['share_name'],
1783 'name': member['name'],
1784 'share_size': member['share']['size'],
1785 'share_proto': member['share']['share_proto'],
1786 'provider_location': member['provider_location'],
1787 }
1788 self.delete_snapshot(
1789 context, share_snapshot, share_server=share_server)
1791 LOG.debug('Deleted share group snapshot %s.', snap_dict['id'])
1792 return None, None
1794 def _collate_share_group_snapshot_info(self, share_group_dict,
1795 share_group_snapshot_dict):
1796 """Collate the data for a clone of the SG snapshot.
1798 Given two data structures, a share group snapshot (
1799 share_group_snapshot_dict) and a new share to be cloned from
1800 the snapshot (share_group_dict), match up both structures into a list
1801 of dicts (share & snapshot) suitable for use by existing method
1802 that clones individual share snapshots.
1803 """
1804 clone_list = []
1805 for share in share_group_dict['shares']:
1806 clone_info = {'share': share}
1807 for share_group_snapshot_member in share_group_snapshot_dict[ 1807 ↛ 1814line 1807 didn't jump to line 1814 because the loop on line 1807 didn't complete
1808 'share_group_snapshot_members']:
1809 if (share['source_share_group_snapshot_member_id'] ==
1810 share_group_snapshot_member['id']):
1811 clone_info['snapshot'] = share_group_snapshot_member
1812 break
1814 if len(clone_info) != 2: 1814 ↛ 1815line 1814 didn't jump to line 1815 because the condition on line 1814 was never true
1815 msg = _(
1816 "Invalid data supplied for creating share group from "
1817 "share group snapshot "
1818 "%s.") % share_group_snapshot_dict['id']
1819 raise exception.InvalidShareGroup(reason=msg)
1821 clone_list.append(clone_info)
1823 return clone_list
1825 def get_periodic_hook_data(self, context, share_instances):
1826 """Dedicated for update/extend of data for existing share instances.
1828 Redefine this method in share driver to be able to update/change/extend
1829 share instances data that will be used by periodic hook action.
1830 One of possible updates is add-on of "automount" CLI commands for each
1831 share instance for case of notification is enabled using 'hook'
1832 approach.
1834 :param context: Current context
1835 :param share_instances: share instances list provided by share manager
1836 :return: list of share instances.
1837 """
1838 return share_instances
1840 def create_replica(self, context, replica_list, new_replica,
1841 access_rules, replica_snapshots, share_server=None):
1842 """Replicate the active replica to a new replica on this backend.
1844 .. note::
1845 This call is made on the host that the new replica is being created
1846 upon.
1848 :param context: Current context
1849 :param replica_list: List of all replicas for a particular share.
1850 This list also contains the replica to be created. The 'active'
1851 replica will have its 'replica_state' attr set to 'active'.
1853 Example::
1855 [
1856 {
1857 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
1858 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1859 'replica_state': 'in_sync',
1860 ...
1861 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
1862 'share_server': <models.ShareServer> or None,
1863 },
1864 {
1865 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
1866 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1867 'replica_state': 'active',
1868 ...
1869 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
1870 'share_server': <models.ShareServer> or None,
1871 },
1872 {
1873 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
1874 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1875 'replica_state': 'in_sync',
1876 ...
1877 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',
1878 'share_server': <models.ShareServer> or None,
1879 },
1880 ...
1881 ]
1883 :param new_replica: The share replica dictionary.
1885 Example::
1887 {
1888 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
1889 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1890 'deleted': False,
1891 'host': 'openstack2@cmodeSSVMNFS2',
1892 'status': 'creating',
1893 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1894 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1895 'terminated_at': None,
1896 'replica_state': 'out_of_sync',
1897 'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',
1898 'export_locations': [
1899 models.ShareInstanceExportLocations,
1900 ],
1901 'access_rules_status': 'out_of_sync',
1902 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',
1903 'share_server_id': 'e6155221-ea00-49ef-abf9-9f89b7dd900a',
1904 'share_server': <models.ShareServer> or None,
1905 }
1907 :param access_rules: A list of access rules.
1908 These are rules that other instances of the share already obey.
1909 Drivers are expected to apply access rules to the new replica or
1910 disregard access rules that don't apply.
1912 Example::
1914 [
1915 {
1916 'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',
1917 'deleted' = False,
1918 'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1919 'access_type' = 'ip',
1920 'access_to' = '172.16.20.1',
1921 'access_level' = 'rw',
1922 }
1923 ]
1925 :param replica_snapshots: List of dictionaries of snapshot instances.
1926 This includes snapshot instances of every snapshot of the share
1927 whose 'aggregate_status' property was reported to be 'available'
1928 when the share manager initiated this request. Each list member
1929 will have two sub dictionaries: 'active_replica_snapshot' and
1930 'share_replica_snapshot'. The 'active' replica snapshot corresponds
1931 to the instance of the snapshot on any of the 'active' replicas of
1932 the share while share_replica_snapshot corresponds to the snapshot
1933 instance for the specific replica that will need to exist on the
1934 new share replica that is being created. The driver needs to ensure
1935 that this snapshot instance is truly available before transitioning
1936 the replica from 'out_of_sync' to 'in_sync'. Snapshots instances
1937 for snapshots that have an 'aggregate_status' of 'creating' or
1938 'deleting' will be polled for in the ``update_replicated_snapshot``
1939 method.
1941 Example::
1943 [
1944 {
1945 'active_replica_snapshot': {
1946 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
1947 'share_instance_id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
1948 'status': 'available',
1949 'provider_location': '/newton/share-snapshot-10e49c3e-aca9',
1950 ...
1951 },
1952 'share_replica_snapshot': {
1953 'id': '',
1954 'share_instance_id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
1955 'status': 'available',
1956 'provider_location': None,
1957 ...
1958 },
1959 }
1960 ]
1962 :param share_server: <models.ShareServer> or None
1963 Share server of the replica being created.
1964 :return: None or a dictionary.
1965 The dictionary can contain export_locations replica_state and
1966 access_rules_status. export_locations is a list of paths and
1967 replica_state is one of 'active', 'in_sync', 'out_of_sync' or
1968 'error'.
1970 .. important::
1972 A backend supporting 'writable' type replication should return
1973 'active' as the replica_state.
1975 Export locations should be in the same format as returned during the
1976 ``create_share`` call.
1978 Example::
1980 {
1981 'export_locations': [
1982 {
1983 'path': '172.16.20.22/sample/export/path',
1984 'is_admin_only': False,
1985 'metadata': {'some_key': 'some_value'},
1986 },
1987 ],
1988 'replica_state': 'in_sync',
1989 'access_rules_status': 'in_sync',
1990 }
1992 """
1993 raise NotImplementedError()
1995 def delete_replica(self, context, replica_list, replica_snapshots,
1996 replica, share_server=None):
1997 """Delete a replica.
1999 .. note::
2000 This call is made on the host that hosts the replica being
2001 deleted.
2003 :param context: Current context
2004 :param replica_list: List of all replicas for a particular share
2005 This list also contains the replica to be deleted. The 'active'
2006 replica will have its 'replica_state' attr set to 'active'.
2008 Example::
2010 [
2011 {
2012 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2013 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2014 'replica_state': 'in_sync',
2015 ...
2016 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2017 'share_server': <models.ShareServer> or None,
2018 },
2019 {
2020 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2021 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2022 'replica_state': 'active',
2023 ...
2024 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
2025 'share_server': <models.ShareServer> or None,
2026 },
2027 {
2028 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
2029 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2030 'replica_state': 'in_sync',
2031 ...
2032 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',
2033 'share_server': <models.ShareServer> or None,
2034 },
2035 ...
2036 ]
2038 :param replica: Dictionary of the share replica being deleted.
2040 Example::
2042 {
2043 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
2044 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2045 'deleted': False,
2046 'host': 'openstack2@cmodeSSVMNFS2',
2047 'status': 'available',
2048 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2049 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2050 'terminated_at': None,
2051 'replica_state': 'in_sync',
2052 'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',
2053 'export_locations': [
2054 models.ShareInstanceExportLocations
2055 ],
2056 'access_rules_status': 'out_of_sync',
2057 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',
2058 'share_server_id': '53099868-65f1-11e5-9d70-feff819cdc9f',
2059 'share_server': <models.ShareServer> or None,
2060 }
2062 :param replica_snapshots: List of dictionaries of snapshot instances.
2063 The dict contains snapshot instances that are associated with the
2064 share replica being deleted.
2065 No model updates to snapshot instances are possible in this method.
2066 The driver should return when the cleanup is completed on the
2067 backend for both, the snapshots and the replica itself. Drivers
2068 must handle situations where the snapshot may not yet have
2069 finished 'creating' on this replica.
2071 Example::
2073 [
2074 {
2075 'id': '89dafd00-0999-4d23-8614-13eaa6b02a3b',
2076 'snapshot_id': '3ce1caf7-0945-45fd-a320-714973e949d3',
2077 'status: 'available',
2078 'share_instance_id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f'
2079 ...
2080 },
2081 {
2082 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
2083 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2084 'status: 'creating',
2085 'share_instance_id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f'
2086 ...
2087 },
2088 ...
2089 ]
2091 :param share_server: <models.ShareServer> or None
2092 Share server of the replica to be deleted.
2093 :return: None.
2094 :raises: Exception.
2095 Any exception raised will set the share replica's 'status' and
2096 'replica_state' attributes to 'error_deleting'. It will not affect
2097 snapshots belonging to this replica.
2098 """
2099 raise NotImplementedError()
2101 def promote_replica(self, context, replica_list, replica, access_rules,
2102 share_server=None, quiesce_wait_time=None):
2103 """Promote a replica to 'active' replica state.
2105 .. note::
2106 This call is made on the host that hosts the replica being
2107 promoted.
2109 :param context: Current context
2110 :param replica_list: List of all replicas for a particular share
2111 This list also contains the replica to be promoted. The 'active'
2112 replica will have its 'replica_state' attr set to 'active'.
2114 Example::
2116 [
2117 {
2118 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2119 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2120 'replica_state': 'in_sync',
2121 ...
2122 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2123 'share_server': <models.ShareServer> or None,
2124 },
2125 {
2126 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2127 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2128 'replica_state': 'active',
2129 ...
2130 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
2131 'share_server': <models.ShareServer> or None,
2132 },
2133 {
2134 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
2135 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2136 'replica_state': 'in_sync',
2137 ...
2138 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',
2139 'share_server': <models.ShareServer> or None,
2140 },
2141 ...
2142 ]
2144 :param replica: Dictionary of the replica to be promoted.
2146 Example::
2148 {
2149 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
2150 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2151 'deleted': False,
2152 'host': 'openstack2@cmodeSSVMNFS2',
2153 'status': 'available',
2154 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2155 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2156 'terminated_at': None,
2157 'replica_state': 'in_sync',
2158 'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',
2159 'export_locations': [
2160 models.ShareInstanceExportLocations
2161 ],
2162 'access_rules_status': 'in_sync',
2163 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',
2164 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',
2165 'share_server': <models.ShareServer> or None,
2166 }
2168 :param access_rules: A list of access rules
2169 These access rules are obeyed by other instances of the share
2171 Example::
2173 [
2174 {
2175 'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',
2176 'deleted' = False,
2177 'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2178 'access_type' = 'ip',
2179 'access_to' = '172.16.20.1',
2180 'access_level' = 'rw',
2181 }
2182 ]
2184 :param share_server: <models.ShareServer> or None
2185 Share server of the replica to be promoted.
2186 :param quiesce_wait_time: time in seconds or None
2187 Share replica promote quiesce wait time.
2188 :return: updated_replica_list or None.
2189 The driver can return the updated list as in the request
2190 parameter. Changes that will be updated to the Database are:
2191 'export_locations', 'access_rules_status' and 'replica_state'.
2192 :raises: Exception.
2193 This can be any exception derived from BaseException. This is
2194 re-raised by the manager after some necessary cleanup. If the
2195 driver raises an exception during promotion, it is assumed that
2196 all of the replicas of the share are in an inconsistent state.
2197 Recovery is only possible through the periodic update call and/or
2198 administrator intervention to correct the 'status' of the affected
2199 replicas if they become healthy again.
2200 """
2201 raise NotImplementedError()
2203 def update_replica_state(self, context, replica_list, replica,
2204 access_rules, replica_snapshots,
2205 share_server=None):
2206 """Update the replica_state of a replica.
2208 .. note::
2209 This call is made on the host which hosts the replica being
2210 updated.
2212 Drivers should fix replication relationships that were broken if
2213 possible inside this method.
2215 This method is called periodically by the share manager; and
2216 whenever requested by the administrator through the 'resync' API.
2218 :param context: Current context
2219 :param replica_list: List of all replicas for a particular share
2220 This list also contains the replica to be updated. The 'active'
2221 replica will have its 'replica_state' attr set to 'active'.
2223 Example::
2225 [
2226 {
2227 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2228 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2229 'replica_state': 'in_sync',
2230 ...
2231 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2232 'share_server': <models.ShareServer> or None,
2233 },
2234 {
2235 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2236 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2237 'replica_state': 'active',
2238 ...
2239 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
2240 'share_server': <models.ShareServer> or None,
2241 },
2242 {
2243 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
2244 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2245 'replica_state': 'in_sync',
2246 ...
2247 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',
2248 'share_server': <models.ShareServer> or None,
2249 },
2250 ...
2251 ]
2253 :param replica: Dictionary of the replica being updated
2254 Replica state will always be 'in_sync', 'out_of_sync', or 'error'.
2255 Replicas in 'active' state will not be passed via this parameter.
2257 Example::
2259 {
2260 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2261 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2262 'deleted': False,
2263 'host': 'openstack2@cmodeSSVMNFS1',
2264 'status': 'available',
2265 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2266 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2267 'terminated_at': None,
2268 'replica_state': 'in_sync',
2269 'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',
2270 'export_locations': [
2271 models.ShareInstanceExportLocations,
2272 ],
2273 'access_rules_status': 'in_sync',
2274 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',
2275 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2276 }
2278 :param access_rules: A list of access rules
2279 These access rules are obeyed by other instances of the share. The
2280 driver could attempt to sync on any un-applied access_rules.
2282 Example::
2284 [
2285 {
2286 'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',
2287 'deleted' = False,
2288 'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2289 'access_type' = 'ip',
2290 'access_to' = '172.16.20.1',
2291 'access_level' = 'rw',
2292 }
2293 ]
2295 :param replica_snapshots: List of dictionaries of snapshot instances.
2296 This includes snapshot instances of every snapshot of the share
2297 whose 'aggregate_status' property was reported to be 'available'
2298 when the share manager initiated this request. Each list member
2299 will have two sub dictionaries: 'active_replica_snapshot' and
2300 'share_replica_snapshot'. The 'active' replica snapshot corresponds
2301 to the instance of the snapshot on any of the 'active' replicas of
2302 the share while share_replica_snapshot corresponds to the snapshot
2303 instance for the specific replica being updated. The driver needs
2304 to ensure that this snapshot instance is truly available before
2305 transitioning from 'out_of_sync' to 'in_sync'. Snapshots instances
2306 for snapshots that have an 'aggregate_status' of 'creating' or
2307 'deleting' will be polled for in the update_replicated_snapshot
2308 method.
2310 Example::
2312 [
2313 {
2314 'active_replica_snapshot': {
2315 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
2316 'share_instance_id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2317 'status': 'available',
2318 'provider_location': '/newton/share-snapshot-10e49c3e-aca9',
2319 ...
2320 },
2321 'share_replica_snapshot': {
2322 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2323 'share_instance_id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2324 'status': 'creating',
2325 'provider_location': None,
2326 ...
2327 },
2328 }
2329 ]
2331 :param share_server: <models.ShareServer> or None
2332 :return: replica_state: a str value denoting the replica_state.
2333 Valid values are 'in_sync' and 'out_of_sync' or None (to leave the
2334 current replica_state unchanged).
2335 """
2336 raise NotImplementedError()
2338 def create_replicated_snapshot(self, context, replica_list,
2339 replica_snapshots,
2340 share_server=None):
2341 """Create a snapshot on active instance and update across the replicas.
2343 .. note::
2344 This call is made on the 'active' replica's host. Drivers are
2345 expected to transfer the snapshot created to the respective
2346 replicas.
2348 The driver is expected to return model updates to the share manager.
2349 If it was able to confirm the creation of any number of the snapshot
2350 instances passed in this interface, it can set their status to
2351 'available' as a cue for the share manager to set the progress attr
2352 to '100%'.
2354 :param context: Current context
2355 :param replica_list: List of all replicas for a particular share
2356 The 'active' replica will have its 'replica_state' attr set to
2357 'active'.
2359 Example::
2361 [
2362 {
2363 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2364 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2365 'replica_state': 'in_sync',
2366 ...
2367 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2368 'share_server': <models.ShareServer> or None,
2369 },
2370 {
2371 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2372 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2373 'replica_state': 'active',
2374 ...
2375 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
2376 'share_server': <models.ShareServer> or None,
2377 },
2378 ...
2379 ]
2381 :param replica_snapshots: List of dictionaries of snapshot instances.
2382 These snapshot instances track the snapshot across the replicas.
2383 All the instances will have their status attribute set to
2384 'creating'.
2386 Example::
2388 [
2389 {
2390 'id': 'd3931a93-3984-421e-a9e7-d9f71895450a',
2391 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2392 'status: 'creating',
2393 'progress': '0%',
2394 ...
2395 },
2396 {
2397 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
2398 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2399 'status: 'creating',
2400 'progress': '0%',
2401 ...
2402 },
2403 ...
2404 ]
2406 :param share_server: <models.ShareServer> or None
2407 :return: List of dictionaries of snapshot instances.
2408 The dictionaries can contain values that need to be updated on the
2409 database for the snapshot instances being created.
2410 :raises: Exception.
2411 Any exception in this method will set all instances to 'error'.
2412 """
2413 raise NotImplementedError()
2415 def revert_to_replicated_snapshot(self, context, active_replica,
2416 replica_list, active_replica_snapshot,
2417 replica_snapshots, share_access_rules,
2418 snapshot_access_rules,
2419 share_server=None):
2420 """Reverts a replicated share (in place) to the specified snapshot.
2422 .. note::
2423 This call is made on the 'active' replica's host, since drivers may
2424 not be able to revert snapshots on individual replicas.
2426 Does not delete the share snapshot. The share and snapshot must both
2427 be 'available' for the restore to be attempted. The snapshot must be
2428 the most recent one taken by Manila; the API layer performs this check
2429 so the driver doesn't have to.
2431 The share must be reverted in place to the contents of the snapshot.
2432 Application admins should quiesce or otherwise prepare the application
2433 for the shared file system contents to change suddenly.
2435 :param context: Current context
2436 :param active_replica: The current active replica
2437 :param replica_list: List of all replicas for a particular share
2438 The 'active' replica will have its 'replica_state' attr set to
2439 'active' and its 'status' set to 'reverting'.
2440 :param active_replica_snapshot: snapshot to be restored
2441 :param replica_snapshots: List of dictionaries of snapshot instances.
2442 These snapshot instances track the snapshot across the replicas.
2443 The snapshot of the active replica to be restored with have its
2444 status attribute set to 'restoring'.
2445 :param share_access_rules: List of access rules for the affected share.
2446 :param snapshot_access_rules: List of access rules for the affected
2447 snapshot.
2448 :param share_server: Optional -- Share server model
2449 """
2450 raise NotImplementedError()
2452 def delete_replicated_snapshot(self, context, replica_list,
2453 replica_snapshots, share_server=None):
2454 """Delete a snapshot by deleting its instances across the replicas.
2456 .. note::
2457 This call is made on the 'active' replica's host, since
2458 drivers may not be able to delete the snapshot from an individual
2459 replica.
2461 The driver is expected to return model updates to the share manager.
2462 If it was able to confirm the removal of any number of the snapshot
2463 instances passed in this interface, it can set their status to
2464 'deleted' as a cue for the share manager to clean up that instance
2465 from the database.
2467 :param context: Current context
2468 :param replica_list: List of all replicas for a particular share
2469 The 'active' replica will have its 'replica_state' attr set to
2470 'active'.
2472 Example::
2474 [
2475 {
2476 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2477 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2478 'replica_state': 'in_sync',
2479 ...
2480 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2481 'share_server': <models.ShareServer> or None,
2482 },
2483 {
2484 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2485 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2486 'replica_state': 'active',
2487 ...
2488 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
2489 'share_server': <models.ShareServer> or None,
2490 },
2491 ...
2492 ]
2494 :param replica_snapshots: List of dictionaries of snapshot instances.
2495 These snapshot instances track the snapshot across the replicas.
2496 All the instances will have their status attribute set to
2497 'deleting'.
2499 Example::
2501 [
2502 {
2503 'id': 'd3931a93-3984-421e-a9e7-d9f71895450a',
2504 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2505 'status': 'deleting',
2506 'progress': '100%',
2507 ...
2508 },
2509 {
2510 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
2511 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2512 'status: 'deleting',
2513 'progress': '100%',
2514 ...
2515 },
2516 ...
2517 ]
2519 :param share_server: <models.ShareServer> or None
2520 :return: List of dictionaries of snapshot instances.
2521 The dictionaries can contain values that need to be updated on the
2522 database for the snapshot instances being deleted. To confirm the
2523 deletion of the snapshot instance, set the 'status' attribute of
2524 the instance to 'deleted' (constants.STATUS_DELETED)
2525 :raises: Exception.
2526 Any exception in this method will set the status attribute of all
2527 snapshot instances to 'error_deleting'.
2528 """
2529 raise NotImplementedError()
2531 def update_replicated_snapshot(self, context, replica_list,
2532 share_replica, replica_snapshots,
2533 replica_snapshot, share_server=None):
2534 """Update the status of a snapshot instance that lives on a replica.
2536 .. note::
2537 For DR and Readable styles of replication, this call is made on
2538 the replica's host and not the 'active' replica's host.
2540 This method is called periodically by the share manager. It will
2541 query for snapshot instances that track the parent snapshot across
2542 non-'active' replicas. Drivers can expect the status of the instance to
2543 be 'creating' or 'deleting'. If the driver sees that a snapshot
2544 instance has been removed from the replica's backend and the
2545 instance status was set to 'deleting', it is expected to raise a
2546 SnapshotResourceNotFound exception. All other exceptions will set the
2547 snapshot instance status to 'error'. If the instance was not in
2548 'deleting' state, raising a SnapshotResourceNotFound will set the
2549 instance status to 'error'.
2551 :param context: Current context
2552 :param replica_list: List of all replicas for a particular share
2553 The 'active' replica will have its 'replica_state' attr set to
2554 'active'.
2556 Example::
2558 [
2559 {
2560 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2561 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2562 'replica_state': 'in_sync',
2563 ...
2564 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2565 'share_server': <models.ShareServer> or None,
2566 },
2567 {
2568 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2569 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2570 'replica_state': 'active',
2571 ...
2572 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
2573 'share_server': <models.ShareServer> or None,
2574 },
2575 ...
2576 ]
2578 :param share_replica: Share replica dictionary.
2579 This replica is associated with the snapshot instance whose
2580 status is being updated. Replicas in 'active' replica_state will
2581 not be passed via this parameter.
2583 Example::
2585 {
2586 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2587 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2588 'deleted': False,
2589 'host': 'openstack2@cmodeSSVMNFS1',
2590 'status': 'available',
2591 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2592 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2593 'terminated_at': None,
2594 'replica_state': 'in_sync',
2595 'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',
2596 'export_locations': [
2597 models.ShareInstanceExportLocations,
2598 ],
2599 'access_rules_status': 'in_sync',
2600 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',
2601 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2602 }
2604 :param replica_snapshots: List of dictionaries of snapshot instances.
2605 These snapshot instances track the snapshot across the replicas.
2606 This will include the snapshot instance being updated as well.
2608 Example::
2610 [
2611 {
2612 'id': 'd3931a93-3984-421e-a9e7-d9f71895450a',
2613 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2614 ...
2615 },
2616 {
2617 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
2618 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2619 ...
2620 },
2621 ...
2622 ]
2624 :param replica_snapshot: Dictionary of the snapshot instance.
2625 This is the instance to be updated. It will be in 'creating' or
2626 'deleting' state when sent via this parameter.
2628 Example::
2630 {
2631 'name': 'share-snapshot-18825630-574f-4912-93bb-af4611ef35a2',
2632 'share_id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2633 'share_name': 'share-d487b88d-e428-4230-a465-a800c2cce5f8',
2634 'status': 'creating',
2635 'id': '18825630-574f-4912-93bb-af4611ef35a2',
2636 'deleted': False,
2637 'created_at': datetime.datetime(2016, 8, 3, 0, 5, 58),
2638 'share': <models.ShareInstance>,
2639 'updated_at': datetime.datetime(2016, 8, 3, 0, 5, 58),
2640 'share_instance_id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2641 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2642 'progress': '0%',
2643 'deleted_at': None,
2644 'provider_location': None,
2645 }
2647 :param share_server: <models.ShareServer> or None
2648 :return: replica_snapshot_model_update: a dictionary.
2649 The dictionary must contain values that need to be updated on the
2650 database for the snapshot instance that represents the snapshot on
2651 the replica.
2652 :raises: exception.SnapshotResourceNotFound
2653 Raise this exception for snapshots that are not found on the
2654 backend and their status was 'deleting'.
2655 """
2656 raise NotImplementedError()
2658 def get_filter_function(self, pool=None):
2659 """Get filter_function string.
2661 Returns either the string from the driver instance or global section
2662 in manila.conf. If nothing is specified in manila.conf, then try to
2663 find the default filter_function. When None is returned the scheduler
2664 will always pass the driver instance.
2666 :param pool: pool name to get the filter or None
2667 :return: a filter_function string or None
2668 """
2669 ret_function = self.configuration.filter_function
2670 if not ret_function:
2671 ret_function = CONF.filter_function
2672 if not ret_function:
2673 kwargs = {'pool': pool} if pool else {}
2674 # pylint: disable=assignment-from-none
2675 ret_function = self.get_default_filter_function(**kwargs)
2676 # pylint: enable=assignment-from-none
2677 return ret_function
2679 def get_goodness_function(self):
2680 """Get good_function string.
2682 Returns either the string from the driver instance or global section
2683 in manila.conf. If nothing is specified in manila.conf, then try to
2684 find the default goodness_function. When None is returned the scheduler
2685 will give the lowest score to the driver instance.
2687 :return: a goodness_function string or None
2688 """
2689 ret_function = self.configuration.goodness_function
2690 if not ret_function:
2691 ret_function = CONF.goodness_function
2692 if not ret_function:
2693 # pylint: disable=assignment-from-none
2694 ret_function = self.get_default_goodness_function()
2695 # pylint: enable=assignment-from-none
2696 return ret_function
2698 def get_default_filter_function(self, pool=None):
2699 """Get the default filter_function string.
2701 Each driver could overwrite the method to return a well-known
2702 default string if it is available.
2704 :param pool: pool name to get the filter or None
2705 :return: None
2706 """
2707 return None
2709 def get_default_goodness_function(self):
2710 """Get the default goodness_function string.
2712 Each driver could overwrite the method to return a well-known
2713 default string if it is available.
2715 :return: None
2716 """
2717 return None
2719 def snapshot_update_access(self, context, snapshot, access_rules,
2720 add_rules, delete_rules, share_server=None):
2721 """Update access rules for given snapshot.
2723 ``access_rules`` contains all access_rules that need to be on the
2724 share. If the driver can make bulk access rule updates, it can
2725 safely ignore the ``add_rules`` and ``delete_rules`` parameters.
2727 If the driver cannot make bulk access rule changes, it can rely on
2728 new rules to be present in ``add_rules`` and rules that need to be
2729 removed to be present in ``delete_rules``.
2731 When a rule in ``add_rules`` already exists in the back end, drivers
2732 must not raise an exception. When a rule in ``delete_rules`` was never
2733 applied, drivers must not raise an exception, or attempt to set the
2734 rule to ``error`` state.
2736 ``add_rules`` and ``delete_rules`` can be empty lists, in this
2737 situation, drivers should ensure that the rules present in
2738 ``access_rules`` are the same as those on the back end.
2740 :param context: Current context
2741 :param snapshot: Snapshot model with snapshot data.
2742 :param access_rules: All access rules for given snapshot
2743 :param add_rules: Empty List or List of access rules which should be
2744 added. access_rules already contains these rules.
2745 :param delete_rules: Empty List or List of access rules which should be
2746 removed. access_rules doesn't contain these rules.
2747 :param share_server: None or Share server model
2748 """
2749 raise NotImplementedError()
2751 def update_share_usage_size(self, context, shares):
2752 """Invoked to get the usage size of given shares.
2754 Driver can use this method to update the share usage size of
2755 the shares. To do that, a dictionary of shares should be
2756 returned.
2757 :param shares: None or a list of all shares for updates.
2758 :returns: An empty list or a list of dictionary of updates in the
2759 following format. The value of "used_size" can be specified in GiB
2760 units, as a floating point number::
2762 [
2763 {
2764 'id': '09960614-8574-4e03-89cf-7cf267b0bd08',
2765 'used_size': '200',
2766 'gathered_at': datetime.datetime(2017, 8, 10, 15, 14, 6),
2767 },
2768 ]
2770 """
2771 LOG.debug("This backend does not support gathering 'used_size' of "
2772 "shares created on it.")
2773 return []
2775 def get_configured_ip_versions(self):
2776 """"Get allowed IP versions.
2778 The supported versions are returned with list, possible
2779 values are: [4], [6], or [4, 6]
2781 Drivers that assert ipv6_implemented = True must override
2782 this method. If the returned list includes 4, then shares
2783 created by this driver must have an IPv4 export location.
2784 If the list includes 6, then shares created by the driver
2785 must have an IPv6 export location.
2787 Drivers should check that their storage controller actually
2788 has IPv4/IPv6 enabled and configured properly.
2789 """
2791 # For drivers that haven't implemented IPv6, assume legacy behavior
2792 if not self.ipv6_implemented: 2792 ↛ 2795line 2792 didn't jump to line 2795 because the condition on line 2792 was always true
2793 return [4]
2795 raise NotImplementedError()
2797 def add_ip_version_capability(self, data):
2798 """Add IP version support capabilities.
2800 When DHSS is true, the capabilities are determined by driver
2801 and configured network plugin.
2802 When DHSS is false, the capabilities are determined by driver
2803 only.
2804 :param data: the capability dictionary
2805 :returns: capability data
2806 """
2807 self.ip_versions = self.get_configured_ip_versions()
2808 if isinstance(self.ip_versions, list): 2808 ↛ 2811line 2808 didn't jump to line 2811 because the condition on line 2808 was always true
2809 self.ip_versions = set(self.ip_versions)
2810 else:
2811 self.ip_versions = set(list(self.ip_versions))
2813 if not self.ip_versions: 2813 ↛ 2814line 2813 didn't jump to line 2814 because the condition on line 2813 was never true
2814 LOG.error("Backend %s supports neither IPv4 nor IPv6.",
2815 data['share_backend_name'])
2817 if self.driver_handles_share_servers:
2818 network_versions = self.network_api.enabled_ip_versions
2819 self.ip_versions = self.ip_versions & network_versions
2820 if not self.ip_versions:
2821 LOG.error("The enabled IP version of the network plugin is "
2822 "not compatible with the version supported by "
2823 "backend %s.", data['share_backend_name'])
2825 data['ipv4_support'] = (4 in self.ip_versions)
2826 data['ipv6_support'] = (6 in self.ip_versions)
2827 return data
2829 def get_backend_info(self, context):
2830 """Get driver and array configuration parameters.
2832 Driver can use this method to get the special configuration info and
2833 return for assessment. The share manager service uses this
2834 assessment to invoke "ensure_shares" during service startup.
2836 :returns: A dictionary containing driver-specific info.
2838 Example::
2840 {
2841 'version': '2.23'
2842 'port': '80',
2843 'logicalportip': '1.1.1.1',
2844 ...
2845 }
2847 """
2848 raise NotImplementedError()
2850 def get_optional_share_creation_data(self, share, share_server=None):
2851 """Get info to set in shares after their creation.
2853 Driver can use this method to get the special info and
2854 return for assessment. The share manager service uses this
2855 assessment to set this info to shares after the creation.
2857 :returns: A dictionary containing driver-specific info.
2859 Example::
2861 {
2862 'metadata': {'__mount_options': 'fake_key=fake_val'}
2863 ...
2864 }
2866 """
2867 return {}
2869 def ensure_shares(self, context, shares):
2870 """Invoked to ensure that shares are exported.
2872 Driver can use this method to update the "status" and/or list of
2873 export locations of the shares if they change. To do that,
2874 a dictionary of shares should be returned. In addition, the driver can
2875 seek to "reapply_access_rules" (boolean) on a per-share basis. When
2876 this property exists and is set to True, the share manager service
2877 will invoke "update_access" with all the access rules from the
2878 service database.
2879 :shares: A list of all shares for updates.
2880 :returns: None or a dictionary of updates in the format.
2882 Example::
2884 {
2885 '09960614-8574-4e03-89cf-7cf267b0bd08': {
2886 'export_locations': [{...}, {...}],
2887 'status': 'error',
2888 'reapply_access_rules': False,
2889 },
2891 '28f6eabb-4342-486a-a7f4-45688f0c0295': {
2892 'export_locations': [{...}, {...}],
2893 'status': 'available',
2894 'reapply_access_rules': True,
2895 },
2897 }
2899 """
2900 raise NotImplementedError()
2902 def get_share_server_network_info(
2903 self, context, share_server, identifier, driver_options):
2904 """Obtain network allocations used by share server.
2906 :param context: Current context.
2907 :param share_server: Share server model.
2908 :param identifier: A driver-specific share server identifier
2909 :param driver_options: Dictionary of driver options to assist managing
2910 the share server
2911 :return: A list containing IP addresses allocated in the backend.
2913 Example::
2915 ['10.10.10.10', 'fd11::2000', '192.168.10.10']
2917 """
2918 raise NotImplementedError()
2920 def manage_server(self, context, share_server, identifier, driver_options):
2921 """Manage the share server and return compiled back end details.
2923 :param context: Current context.
2924 :param share_server: Share server model.
2925 :param identifier: A driver-specific share server identifier
2926 :param driver_options: Dictionary of driver options to assist managing
2927 the share server
2928 :return: Identifier and dictionary with back end details to be saved
2929 in the database.
2931 Example::
2933 'my_new_server_identifier',{'server_name': 'my_old_server'}
2935 """
2936 raise NotImplementedError()
2938 def unmanage_server(self, server_details, security_services=None):
2939 """Unmanages the share server.
2941 If a driver supports unmanaging of share servers, the driver must
2942 override this method and return successfully.
2944 :param server_details: share server backend details.
2945 :param security_services: list of security services configured with
2946 this share server.
2947 """
2948 raise NotImplementedError()
2950 def get_share_status(self, share, share_server=None):
2951 """Invoked periodically to get the current status of a given share.
2953 Driver can use this method to update the status of a share that is
2954 still pending from other operations.
2955 This method is expected to be called in a periodic interval set by the
2956 'periodic_interval' configuration in seconds.
2958 :param share: share to get updated status from.
2959 :param share_server: share server model or None.
2960 :returns: a dictionary of updates with the current share status, that
2961 must be 'available', 'creating_from_snapshot' or 'error', a list of
2962 export locations, if available, and a progress field which
2963 indicates the completion of the share creation operation.
2964 EXAMPLE::
2966 {
2967 'status': 'available',
2968 'export_locations': [{...}, {...}],
2969 'progress': '50%'
2970 }
2972 :raises: ShareBackendException.
2973 A ShareBackendException in this method will set the instance status
2974 to 'error'.
2975 """
2976 raise NotImplementedError()
2978 def share_server_migration_start(self, context, src_share_server,
2979 dest_share_server, shares, snapshots):
2980 """Starts migration of a given share server to another host.
2982 .. note::
2983 Is called in destination share server's backend to start migration.
2985 Driver should implement this method if willing to perform a server
2986 migration in driver-assisted way, useful when source share server's
2987 backend driver is compatible with destination backend driver. This
2988 method should start the migration procedure in the backend and return
2989 immediately.
2990 Following steps should be done in 'share_server_migration_continue'.
2992 :param context: The 'context.RequestContext' object for the request.
2993 :param src_share_server: Reference to the original share server.
2994 :param dest_share_server: Reference to the share server to be used by
2995 as destination.
2996 :param shares: All shares in the source share server that should be
2997 migrated.
2998 :param snapshots: All snapshots in the source share server that should
2999 be migrated.
3000 :return: Dict with migration information to be set in the destination
3001 share server.
3003 Example::
3005 {
3006 'backend_details': {
3007 'migration_info_key': 'migration_info_value',
3008 }
3009 }
3010 """
3011 raise NotImplementedError()
3013 def share_server_migration_continue(self, context, src_share_server,
3014 dest_share_server, shares, snapshots):
3015 """Continues migration of a given share server to another host.
3017 .. note::
3018 Is called in destination share server's backend to continue
3019 migration.
3021 Driver should implement this method to continue monitor the migration
3022 progress in storage and perform following steps until 1st phase is
3023 completed.
3025 :param context: The 'context.RequestContext' object for the request.
3026 :param src_share_server: Reference to the original share server.
3027 :param dest_share_server: Reference to the share server to be used as
3028 destination.
3029 :param shares: All shares in the source share server that should be
3030 migrated.
3031 :param snapshots: All snapshots in the source share server that should
3032 be migrated.
3033 :return: Boolean value to indicate if 1st phase is finished.
3034 """
3035 raise NotImplementedError()
3037 def share_server_migration_get_progress(self, context, src_share_server,
3038 dest_share_server, shares,
3039 snapshots):
3040 """Obtains progress of migration of a share server to another host.
3042 .. note::
3043 Is called in destination share's backend to obtain migration
3044 progress.
3046 If possible, driver can implement a way to return migration progress
3047 information.
3049 :param context: The 'context.RequestContext' object for the request.
3050 :param src_share_server: Reference to the original share server.
3051 :param dest_share_server: Reference to the share server to be used as
3052 destination.
3053 :param shares: All shares in the source share server that should be
3054 migrated.
3055 :param snapshots: All snapshots in the source share server that should
3056 be migrated.
3057 :return: A dictionary with at least 'total_progress' field containing
3058 the percentage value.
3059 """
3060 raise NotImplementedError()
3062 def share_server_migration_cancel(self, context, src_share_server,
3063 dest_share_server, shares, snapshots):
3064 """Cancels migration of a given share server to another host.
3066 .. note::
3067 Is called in destination share server's backend to continue
3068 migration.
3070 If possible, driver can implement a way to cancel an in-progress
3071 migration.
3073 :param context: The 'context.RequestContext' object for the request.
3074 :param src_share_server: Reference to the original share server.
3075 :param dest_share_server: Reference to the share server to be used as
3076 destination.
3077 :param shares: All shares in the source share server that should be
3078 migrated.
3079 :param snapshots: All snapshots in the source share server that should
3080 be migrated.
3081 """
3082 raise NotImplementedError()
3084 def share_server_migration_check_compatibility(
3085 self, context, share_server, dest_host, old_share_network,
3086 new_share_network, shares_request_spec):
3087 """Checks destination compatibility for migration of a share server.
3089 .. note::
3090 Is called in destination share server's backend to continue
3091 migration. Can be called by an admin to check if a given host is
3092 compatible or by the share manager to test compatibility with
3093 destination backend.
3095 Driver should check if it is compatible with destination backend so
3096 driver-assisted migration can proceed.
3098 :param context: The 'context.RequestContext' object for the request.
3099 :param share_server: Share server model.
3100 :param dest_host: Reference to the hos to be used by the migrated
3101 share server.
3102 :param old_share_network: Share network model where the source share
3103 server is placed.
3104 :param new_share_network: Share network model where the share
3105 server is going to be migrated to.
3106 :param shares_request_spec: Dict. Contains information about all shares
3107 and share types that belong to the source share server. The drivers
3108 can use this information to check if the capabilities match with
3109 the destination backend and if there is available space to hold the
3110 new share server and all its resource.
3112 Example::
3114 {
3115 'shares_size': 100,
3116 'snapshots_size': 100,
3117 'shares_req_spec':
3118 [
3119 {
3120 'share_properties':
3121 {
3122 'size': 10
3123 'user_id': '2f5c1df4-5203-444e-b68e-1e60f3f26fc3'
3124 'project_id': '0b82b278-51d6-4357-b273-0d7263982c31'
3125 'snapshot_support': True
3126 'create_share_from_snapshot_support': True
3127 'revert_to_snapshot_support': False
3128 'mount_snapshot_support': False
3129 'share_proto': NFS
3130 'share_type_id': '360e01c1-a4f7-4782-9676-dc013f1a2f21'
3131 'is_public': False
3132 'share_group_id': None
3133 'source_share_group_snapshot_member_id': None
3134 'snapshot_id': None
3135 },
3136 'share_instance_properties':
3137 {
3138 'availability_zone_id':
3139 '02377ad7-381c-4b25-a04c-6fd218f22a91',
3140 'share_network_id': '691544aa-da83-4669-8522-22719f236e16',
3141 'share_server_id': 'cd658413-d02c-4d1b-ac8a-b6b972e76bac',
3142 'share_id': 'e42fec45-781e-4dcc-a4d2-44354ad5ae91',
3143 'host': 'hostA@backend1#pool0',
3144 'status': 'available',
3145 },
3146 'share_type':
3147 {
3148 'id': '360e01c1-a4f7-4782-9676-dc013f1a2f21',
3149 'name': 'dhss_false',
3150 'is_public': False,
3151 'extra_specs':
3152 {
3153 'driver_handles_share_servers': False,
3154 }
3155 },
3156 'share_id': e42fec45-781e-4dcc-a4d2-44354ad5ae91,
3157 },
3158 ],
3159 }
3161 :return: A dictionary containing values indicating if destination
3162 backend is compatible, if share can remain writable during
3163 migration, if it can preserve all file metadata and if it can
3164 perform migration of given share non-disruptively.
3166 Example::
3168 {
3169 'compatible': True,
3170 'writable': True,
3171 'nondisruptive': True,
3172 'preserve_snapshots': True,
3173 'migration_cancel': True,
3174 'migration_get_progress': False,
3175 }
3177 """
3178 return {
3179 'compatible': False,
3180 'writable': False,
3181 'nondisruptive': False,
3182 'preserve_snapshots': False,
3183 'migration_cancel': False,
3184 'migration_get_progress': False,
3185 }
3187 def share_server_migration_complete(self, context, src_share_server,
3188 dest_share_server, shares, snapshots,
3189 new_network_info):
3190 """Completes migration of a given share server to another host.
3192 .. note::
3193 Is called in destination share server's backend to complete
3194 migration.
3196 If driver is implementing 2-phase migration, this method should
3197 perform the disruptive tasks related to the 2nd phase of migration,
3198 thus completing it. Driver should also delete all original data from
3199 source backend.
3201 It expected that all shares and snapshots will be available at the
3202 destination share server in the end of the migration complete and all
3203 updates provided in the returned model update.
3205 :param context: The 'context.RequestContext' object for the request.
3206 :param src_share_server: Reference to the original share server.
3207 :param dest_share_server: Reference to the share server to be used as
3208 destination.
3209 :param shares: All shares in the source share server that should be
3210 migrated.
3211 :param snapshots: All snapshots in the source share server that should
3212 be migrated.
3213 :param new_network_info: Network allocation associated to the
3214 destination share server.
3215 :return: If the migration changes the shares export locations,
3216 snapshots provider locations or snapshots export locations, this
3217 method should return a dictionary containing a list of share
3218 instances and snapshot instances indexed by their id's, where each
3219 instance should provide a dict with the relevant information that
3220 need to be updated.
3222 Example::
3224 {
3225 'share_updates':
3226 {
3227 '4363eb92-23ca-4888-9e24-502387816e2a':
3228 {
3229 'export_locations':
3230 [
3231 {
3232 'path': '1.2.3.4:/foo',
3233 'metadata': {},
3234 'is_admin_only': False
3235 },
3236 {
3237 'path': '5.6.7.8:/foo',
3238 'metadata': {},
3239 'is_admin_only': True
3240 },
3241 ],
3242 'pool_name': 'poolA',
3243 },
3244 },
3245 'snapshot_updates':
3246 {
3247 'bc4e3b28-0832-4168-b688-67fdc3e9d408':
3248 {
3249 'provider_location': '/snapshots/foo/bar_1',
3250 'export_locations':
3251 [
3252 {
3253 'path': '1.2.3.4:/snapshots/foo/bar_1',
3254 'is_admin_only': False,
3255 },
3256 {
3257 'path': '5.6.7.8:/snapshots/foo/bar_1',
3258 'is_admin_only': True,
3259 },
3260 ],
3261 },
3262 '2e62b7ea-4e30-445f-bc05-fd523ca62941':
3263 {
3264 'provider_location': '/snapshots/foo/bar_2',
3265 'export_locations':
3266 [
3267 {
3268 'path': '1.2.3.4:/snapshots/foo/bar_2',
3269 'is_admin_only': False,
3270 },
3271 {
3272 'path': '5.6.7.8:/snapshots/foo/bar_2',
3273 'is_admin_only': True,
3274 },
3275 ],
3276 },
3277 }
3278 'backend_details':
3279 {
3280 'new_share_server_info_key':
3281 'new_share_server_info_value',
3282 },
3283 }
3285 """
3286 raise NotImplementedError()
3288 def update_share_server_security_service(
3289 self, context, share_server, network_info, share_instances,
3290 share_instance_rules, new_security_service,
3291 current_security_service=None):
3292 """Updates share server security service configuration.
3294 If the driver supports different security services, the user can
3295 request the addition of a new security service, with a different type.
3296 If the user wants to update the current security service configuration,
3297 the driver will receive both current and new security services, which
3298 will always be of the same type.
3300 :param context: The 'context.RequestContext' object for the request.
3301 :param share_server: Reference to the share server object that will be
3302 updated.
3303 :param network_info: All network allocation associated with the share
3304 server that will be updated.
3305 :param share_instances: A list of share instances that belong to the
3306 share server that is being updated.
3307 :param share_instance_rules: A list of access rules, grouped by share
3308 instance, in the following format.
3310 Example::
3312 [
3313 {
3314 'share_instance_id': '3bc10d67-2598-4122-bb62-0bdeaa8c6db3',
3315 'access_rules':
3316 [
3317 {
3318 'access_id':'906d0094-3e34-4d6c-a184-d08a908033e3',
3319 'access_type':'ip',
3320 'access_key':None,
3321 'access_to':'10.0.0.1',
3322 'access_level':'rw'
3323 ...
3324 },
3325 ],
3326 },
3327 ]
3329 :param new_security_service: New security service object to be
3330 configured in the share server.
3331 :param current_security_service: When provided, represents the current
3332 security service that will be replaced by the
3333 'new_security_service'.
3335 :raises: ShareBackendException.
3336 A ShareBackendException should only be raised if the share server
3337 failed to update the security service, compromising all its access
3338 rules. By raising an exception, the share server and all its share
3339 instances will be set to 'error'.
3340 :return: None, or a dictionary of updates in the following format.
3342 Example::
3344 {
3345 '3bc10d67-2598-4122-bb62-0bdeaa8c6db3':
3346 {
3347 '09960614-8574-4e03-89cf-7cf267b0bd08':
3348 {
3349 'access_key': 'alice31493e5441b8171d2310d80e37e',
3350 'state': 'error',
3351 },
3352 '28f6eabb-4342-486a-a7f4-45688f0c0295':
3353 {
3354 'access_key': 'bob0078aa042d5a7325480fd13228b',
3355 'state': 'active',
3356 },
3357 },
3358 }
3360 The top level keys are share_instance_id's which should provide
3361 another dictionary of access rules to be updated, indexed by their
3362 'access_id'. The inner access rules dictionary should only contain the
3363 access rules that need to be updated.
3364 """
3365 raise NotImplementedError()
3367 def check_update_share_server_security_service(
3368 self, context, share_server, network_info, share_instances,
3369 share_instance_rules, new_security_service,
3370 current_security_service=None):
3371 """Check if the current share server security service is supported.
3373 If the driver supports different security services, the user can
3374 request the addition of a new security service, with a different type.
3375 If the user wants to update the current security service configuration,
3376 the driver will receive both current and new security services, which
3377 will always be of the same type.
3379 :param context: The 'context.RequestContext' object for the request.
3380 :param share_server: Reference to the share server object that will be
3381 updated.
3382 :param network_info: All network allocation associated with the share
3383 server that will be updated.
3384 :param share_instances: A list of share instances that belong to the
3385 share server that is affected by the update.
3386 :param share_instance_rules: A list of access rules, grouped by share
3387 instance, in the following format.
3389 Example::
3391 [
3392 {
3393 'share_instance_id': '3bc10d67-2598-4122-bb62-0bdeaa8c6db3',
3394 'access_rules':
3395 [
3396 {
3397 'access_id':'906d0094-3e34-4d6c-a184-d08a908033e3',
3398 'access_type':'ip',
3399 'access_key':None,
3400 'access_to':'10.0.0.1',
3401 'access_level':'rw'
3402 ...
3403 },
3404 ],
3405 },
3406 ]
3408 :param new_security_service: New security service object to be
3409 configured in the share server.
3410 :param current_security_service: When provided, represents the current
3411 security service that will be replaced by the
3412 'new_security_service'.
3414 :return: 'True' if the driver support the requested update, 'False'
3415 otherwise.
3416 """
3417 raise NotImplementedError()
3419 def check_update_share_server_network_allocations(
3420 self, context, share_server, current_network_allocations,
3421 new_share_network_subnet, security_services, share_instances,
3422 share_instances_rules):
3423 """"Check if the share server network allocation update is supported.
3425 :param context: The 'context.RequestContext' object for the request.
3426 :param share_server: Reference to the share server object that will be
3427 updated.
3428 :param current_network_allocations: All network allocations associated
3429 with the share server that will be updated:
3431 Example::
3433 {
3434 'admin_network_allocations':
3435 [
3436 {
3437 'ip_address': '10.193.154.11',
3438 'ip_version': 4,
3439 'cidr': '10.193.154.0/28',
3440 'gateway': '10.193.154.1',
3441 'mtu': 1500,
3442 'network_type': 'vlan',
3443 'segmentation_id': 3000,
3444 'mac_address': ' AA:AA:AA:AA:AA:AA',
3445 ...
3446 },
3447 ],
3448 'subnets':
3449 [
3450 {
3451 'share_network_subnet_id': '0bdeaa8c6db3-3bc10d67',
3452 'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3',
3453 'neutron_subnet_id': '3bc10d67-2598-4122-bb62',
3454 'network_allocations':
3455 [
3456 {
3457 'ip_address': '10.193.154.10',
3458 'ip_version': 4,
3459 'cidr': '10.193.154.0/28',
3460 'gateway': '10.193.154.1',
3461 'mtu': 1500,
3462 'network_type': 'vlan',
3463 'segmentation_id': 3000,
3464 'mac_address': ' AA:AA:AA:AA:AA:AA',
3465 ...
3466 },
3467 ],
3468 },
3469 ],
3470 }
3472 :param new_share_network_subnet: dict containing the subnet data that
3473 has to be checked if it can be added to the share server:
3475 Example::
3477 {
3478 'availability_zone_id': '0bdeaa8c6db3-3bc10d67',
3479 'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3',
3480 'neutron_subnet_id': '3bc10d67-2598-4122-bb62',
3481 'ip_version': 4,
3482 'cidr': '10.193.154.0/28',
3483 'gateway': '10.193.154.1',
3484 'mtu': 1500,
3485 'network_type': 'vlan',
3486 'segmentation_id': 3000,
3487 }
3489 :param security_services: list of security services configured with
3490 this share server.
3491 :param share_instances: A list of share instances that belong to the
3492 share server that is affected by the update.
3493 :param share_instances_rules: A list of access rules, grouped by share
3494 instance, in the following format.
3496 Example::
3498 [
3499 {
3500 'share_instance_id': '3bc10d67-2598-4122-bb62-0bdeaa8c6db3',
3501 'access_rules':
3502 [
3503 {
3504 'access_id':'906d0094-3e34-4d6c-a184-d08a908033e3',
3505 'access_type':'ip',
3506 'access_key':None,
3507 'access_to':'10.0.0.1',
3508 'access_level':'rw'
3509 ...
3510 },
3511 ],
3512 },
3513 ]
3515 :return Boolean indicating whether the update is possible or not. It is
3516 the driver responsibility to log the reason why not accepting the
3517 update.
3518 """
3519 raise NotImplementedError()
3521 def update_share_server_network_allocations(
3522 self, context, share_server, current_network_allocations,
3523 new_network_allocations, security_services, shares, snapshots):
3524 """Updates a share server's network allocations.
3526 :param context: The 'context.RequestContext' object for the request.
3527 :param share_server: reference to the share server that have to update
3528 network allocations.
3529 :param current_network_allocations: all network allocations associated
3530 with the share server that will be updated
3532 Example::
3534 {
3535 'admin_network_allocations':
3536 [
3537 {
3538 'ip_address': '10.193.154.11',
3539 'ip_version': 4,
3540 'cidr': '10.193.154.0/28',
3541 'gateway': '10.193.154.1',
3542 'mtu': 1500,
3543 'network_type': 'vlan',
3544 'segmentation_id': 3000,
3545 'mac_address': ' AA:AA:AA:AA:AA:AA',
3546 },
3547 ...
3548 ],
3549 'subnets':
3550 [
3551 {
3552 'share_network_subnet_id': '0bdeaa8c6db3-3bc10d67',
3553 'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3',
3554 'neutron_subnet_id': '3bc10d67-2598-4122-bb62',
3555 'network_allocations':
3556 [
3557 {
3558 'ip_address': '10.193.154.10',
3559 'ip_version': 4,
3560 'cidr': '10.193.154.0/28',
3561 'gateway': '10.193.154.1',
3562 'mtu': 1500,
3563 'network_type': 'vlan',
3564 'segmentation_id': 3000,
3565 'mac_address': ' AA:AA:AA:AA:AA:AA',
3566 },
3567 ...
3568 ],
3569 },
3570 ],
3571 }
3573 :param new_network_allocations: allocations that must be configured in
3574 the share server.
3576 Example::
3578 {
3579 'share_network_subnet_id': '0bdeaa8c6db3-3bc10d67',
3580 'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3',
3581 'neutron_subnet_id': '3bc10d67-2598-4122-bb62',
3582 'network_allocations':
3583 [
3584 {
3585 'ip_address': '10.193.154.10',
3586 'ip_version': 4,
3587 'cidr': '10.193.154.0/28',
3588 'gateway': '10.193.154.1',
3589 'mtu': 1500,
3590 'network_type': 'vlan',
3591 'segmentation_id': 3000,
3592 'mac_address': 'AA:AA:AA:AA:AA:AA',
3593 ...
3594 },
3595 ],
3596 },
3598 :param security_services: list of security services configured with
3599 this share server.
3600 :param shares: All shares in the share server.
3601 :param snapshots: All snapshots in the share server.
3603 :raises: Exception.
3604 By raising an exception, the share server and all its shares and
3605 snapshots instances will be set to 'error'. The error can contain
3606 the field 'details_data' as a dict with the key 'server_details'
3607 containing the backend details dict that will be saved to share
3608 server.
3610 :return If the update changes the shares export locations or snapshots
3611 export locations, this method should return a dictionary
3612 containing a list of share instances and snapshot instances
3613 indexed by their id's, where each instance should provide a
3614 dict with the relevant information that need to be updated.
3615 Also, the returned dict can contain the updated back end
3616 details to be saved in the database.
3618 Example::
3620 {
3621 'share_updates':
3622 {
3623 '4363eb92-23ca-4888-9e24-502387816e2a':
3624 [
3625 {
3626 'path': '1.2.3.4:/foo',
3627 'metadata': {},
3628 'is_admin_only': False
3629 },
3630 {
3631 'path': '5.6.7.8:/foo',
3632 'metadata': {},
3633 'is_admin_only': True
3634 },
3635 ],
3636 ...
3637 },
3638 'snapshot_updates':
3639 {
3640 'bc4e3b28-0832-4168-b688-67fdc3e9d408':
3641 {
3642 'provider_location': '/snapshots/foo/bar_1',
3643 'export_locations':
3644 [
3645 {
3646 'path': '1.2.3.4:/snapshots/foo/bar_1',
3647 'is_admin_only': False,
3648 },
3649 {
3650 'path': '5.6.7.8:/snapshots/foo/bar_1',
3651 'is_admin_only': True,
3652 },
3653 ],
3654 },
3655 '2e62b7ea-4e30-445f-bc05-fd523ca62941':
3656 {
3657 'provider_location': '/snapshots/foo/bar_2',
3658 'export_locations':
3659 [
3660 {
3661 'path': '1.2.3.4:/snapshots/foo/bar_2',
3662 'is_admin_only': False,
3663 },
3664 {
3665 'path': '5.6.7.8:/snapshots/foo/bar_2',
3666 'is_admin_only': True,
3667 },
3668 ],
3669 },
3670 }
3671 'server_details':
3672 {
3673 'new_share_server_info_key':
3674 'new_share_server_info_value',
3675 },
3676 }
3678 """
3679 raise NotImplementedError()
3681 def create_backup(self, context, share_instance, backup,
3682 share_server=None):
3683 """Starts backup of a given share_instance into backup.
3685 Driver should implement this method if willing to perform backup of
3686 share_instance. This method should start the backup procedure in the
3687 backend and end. Following steps should be done in
3688 'create_backup_continue'.
3690 :param context: The 'context.RequestContext' object for the request.
3691 :param share_instance: Reference to the original share instance.
3692 :param backup: Share backup model.
3693 :param share_server: share server in case of dhss_true
3694 """
3695 raise NotImplementedError()
3697 def create_backup_continue(self, context, share_instance, backup,
3698 share_server=None):
3699 """Continue backup of a given share_instance into backup.
3701 Driver must implement this method if it supports 'create_backup'
3702 method. This method should continue the remaining backup procedure
3703 in the backend and report the progress of backup.
3705 :param context: The 'context.RequestContext' object for the request.
3706 :param share_instance: Reference to the original share instance.
3707 :param backup: Share backup model.
3708 :param share_server: share server in case of dhss_true
3709 """
3710 raise NotImplementedError()
3712 def delete_backup(self, context, backup, share_instance,
3713 share_server=None):
3714 """Is called to remove backup."""
3715 raise NotImplementedError()
3717 def restore_backup(self, context, backup, share_instance,
3718 share_server=None):
3719 """Starts restoring backup into a given share_instance.
3721 Driver should implement this method if willing to perform restore of
3722 backup into a share_instance. This method should start the backup
3723 restore procedure in the backend and end. Following steps should be
3724 done in 'restore_backup_continue'.
3726 :param context: The 'context.RequestContext' object for the request.
3727 :param share_instance: Reference to the original share instance.
3728 :param backup: Share backup model.
3729 :param share_server: share server in case of dhss_true
3730 """
3731 raise NotImplementedError()
3733 def restore_backup_continue(self, context, backup, share_instance,
3734 share_server=None):
3735 """Continue restore of a given backup into share_instance.
3737 Driver must implement this method if it supports 'restore_backup'
3738 method. This method should continue the remaining restore procedure
3739 in the backend and report the progress of backup restore.
3741 :param context: The 'context.RequestContext' object for the request.
3742 :param share_instance: Reference to the original share instance.
3743 :param backup: Share backup model.
3744 :param share_server: share server in case of dhss_true
3745 """
3746 raise NotImplementedError()
3748 def update_share_from_metadata(self, context, share, metadata,
3749 share_server=None):
3750 """Update the share from metadata.
3752 Driver must implement this method if needs to perform some action
3753 on given resource (i.e. share) based on provided metadata.
3755 :param context: The 'context.RequestContext' object for the request.
3756 :param share: Share instance model with share data.
3757 :param metadata: Dict contains key-value pair where driver will
3758 perform necessary action based on key.
3759 :param share_server: Reference to the share server.
3760 """
3761 raise NotImplementedError()
3763 def update_share_network_subnet_from_metadata(self, context,
3764 share_network,
3765 share_network_subnet,
3766 share_server, metadata):
3767 """Update the share network subnet from metadata.
3769 Driver must implement this method if it can perform some action on
3770 given resource (i.e. share network subnet) based on provided metadata.
3772 :param context: The 'context.RequestContext' object for the request.
3773 :param share_network: share network model
3774 :param share_network_subnet: share network subnet model
3775 :param share_server: share-server model.
3776 :param metadata: Dict contains key-value pair where driver will
3777 perform necessary action based on key.
3778 """
3779 raise NotImplementedError()