"Fossies" - the Fresh Open Source Software Archive 
Member "manila-8.1.4/manila/share/driver.py" (19 Nov 2020, 116596 Bytes) of package /linux/misc/openstack/manila-8.1.4.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "driver.py" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
8.1.3_vs_8.1.4.
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 """
17 Drivers for shares.
18
19 """
20
21 import six
22 import time
23
24 from oslo_config import cfg
25 from oslo_log import log
26
27 from manila import exception
28 from manila.i18n import _
29 from manila import network
30 from manila import utils
31
32 LOG = log.getLogger(__name__)
33
34 share_opts = [
35 # NOTE(rushiagr): Reasonable to define this option at only one place.
36 cfg.IntOpt(
37 'num_shell_tries',
38 default=3,
39 help='Number of times to attempt to run flakey shell commands.'),
40 cfg.IntOpt(
41 'reserved_share_percentage',
42 default=0,
43 help='The percentage of backend capacity reserved.'),
44 cfg.StrOpt(
45 'share_backend_name',
46 help='The backend name for a given driver implementation.'),
47 cfg.StrOpt(
48 'network_config_group',
49 help="Name of the configuration group in the Manila conf file "
50 "to look for network config options."
51 "If not set, the share backend's config group will be used."
52 "If an option is not found within provided group, then "
53 "'DEFAULT' group will be used for search of option."),
54 cfg.BoolOpt(
55 'driver_handles_share_servers',
56 help="There are two possible approaches for share drivers in Manila. "
57 "First is when share driver is able to handle share-servers and "
58 "second when not. Drivers can support either both or only one "
59 "of these approaches. So, set this opt to True if share driver "
60 "is able to handle share servers and it is desired mode else set "
61 "False. It is set to None by default to make this choice "
62 "intentional."),
63 cfg.FloatOpt(
64 'max_over_subscription_ratio',
65 default=20.0,
66 help='Float representation of the over subscription ratio '
67 'when thin provisioning is involved. Default ratio is '
68 '20.0, meaning provisioned capacity can be 20 times '
69 'the total physical capacity. If the ratio is 10.5, it '
70 'means provisioned capacity can be 10.5 times the '
71 'total physical capacity. A ratio of 1.0 means '
72 'provisioned capacity cannot exceed the total physical '
73 'capacity. A ratio lower than 1.0 is invalid.'),
74 cfg.ListOpt(
75 'migration_ignore_files',
76 default=['lost+found'],
77 help="List of files and folders to be ignored when migrating shares. "
78 "Items should be names (not including any path)."),
79 cfg.StrOpt(
80 'share_mount_template',
81 default='mount -vt %(proto)s %(options)s %(export)s %(path)s',
82 help="The template for mounting shares for this backend. Must specify "
83 "the executable with all necessary parameters for the protocol "
84 "supported. 'proto' template element may not be required if "
85 "included in the command. 'export' and 'path' template elements "
86 "are required. It is advisable to separate different commands "
87 "per backend."),
88 cfg.StrOpt(
89 'share_unmount_template',
90 default='umount -v %(path)s',
91 help="The template for unmounting shares for this backend. Must "
92 "specify the executable with all necessary parameters for the "
93 "protocol supported. 'path' template element is required. It is "
94 "advisable to separate different commands per backend."),
95 cfg.DictOpt(
96 'protocol_access_mapping',
97 default={
98 'ip': ['nfs'],
99 'user': ['cifs'],
100 },
101 help="Protocol access mapping for this backend. Should be a "
102 "dictionary comprised of "
103 "{'access_type1': ['share_proto1', 'share_proto2'],"
104 " 'access_type2': ['share_proto2', 'share_proto3']}."),
105 cfg.BoolOpt(
106 'migration_readonly_rules_support',
107 default=True,
108 deprecated_for_removal=True,
109 deprecated_reason="All drivers are now required to support read-only "
110 "access rules.",
111 deprecated_name='migration_readonly_support',
112 help="Specify whether read only access rule mode is supported in this "
113 "backend. Obsolete."),
114 cfg.StrOpt(
115 "admin_network_config_group",
116 help="If share driver requires to setup admin network for share, then "
117 "define network plugin config options in some separate config "
118 "group and set its name here. Used only with another "
119 "option 'driver_handles_share_servers' set to 'True'."),
120 # Replication option/s
121 cfg.StrOpt(
122 "replication_domain",
123 help="A string specifying the replication domain that the backend "
124 "belongs to. This option needs to be specified the same in the "
125 "configuration sections of all backends that support "
126 "replication between each other. If this option is not "
127 "specified in the group, it means that replication is not "
128 "enabled on the backend."),
129 cfg.StrOpt('backend_availability_zone',
130 default=None,
131 help='Availability zone for this share backend. If not set, '
132 'the ``storage_availability_zone`` option from the '
133 '``[DEFAULT]`` section is used.'),
134 cfg.StrOpt('filter_function',
135 help='String representation for an equation that will be '
136 'used to filter hosts.'),
137 cfg.StrOpt('goodness_function',
138 help='String representation for an equation that will be '
139 'used to determine the goodness of a host.'),
140 ]
141
142 ssh_opts = [
143 cfg.IntOpt(
144 'ssh_conn_timeout',
145 default=60,
146 help='Backend server SSH connection timeout.'),
147 cfg.IntOpt(
148 'ssh_min_pool_conn',
149 default=1,
150 help='Minimum number of connections in the SSH pool.'),
151 cfg.IntOpt(
152 'ssh_max_pool_conn',
153 default=10,
154 help='Maximum number of connections in the SSH pool.'),
155 ]
156
157 ganesha_opts = [
158 cfg.StrOpt('ganesha_config_dir',
159 default='/etc/ganesha',
160 help='Directory where Ganesha config files are stored.'),
161 cfg.StrOpt('ganesha_config_path',
162 default='$ganesha_config_dir/ganesha.conf',
163 help='Path to main Ganesha config file.'),
164 cfg.StrOpt('ganesha_service_name',
165 default='ganesha.nfsd',
166 help='Name of the ganesha nfs service.'),
167 cfg.StrOpt('ganesha_db_path',
168 default='$state_path/manila-ganesha.db',
169 help='Location of Ganesha database file. '
170 '(Ganesha module only.)'),
171 cfg.StrOpt('ganesha_export_dir',
172 default='$ganesha_config_dir/export.d',
173 help='Path to directory containing Ganesha export '
174 'configuration. (Ganesha module only.)'),
175 cfg.StrOpt('ganesha_export_template_dir',
176 default='/etc/manila/ganesha-export-templ.d',
177 help='Path to directory containing Ganesha export '
178 'block templates. (Ganesha module only.)'),
179 cfg.BoolOpt('ganesha_rados_store_enable',
180 default=False,
181 help='Persist Ganesha exports and export counter '
182 'in Ceph RADOS objects, highly available storage.'),
183 cfg.StrOpt('ganesha_rados_store_pool_name',
184 help='Name of the Ceph RADOS pool to store Ganesha exports '
185 'and export counter.'),
186 cfg.StrOpt('ganesha_rados_export_counter',
187 default='ganesha-export-counter',
188 help='Name of the Ceph RADOS object used as the Ganesha '
189 'export counter.'),
190 cfg.StrOpt('ganesha_rados_export_index',
191 default='ganesha-export-index',
192 help='Name of the Ceph RADOS object used to store a list '
193 'of the export RADOS object URLS.'),
194 ]
195
196 CONF = cfg.CONF
197 CONF.register_opts(share_opts)
198 CONF.register_opts(ssh_opts)
199 CONF.register_opts(ganesha_opts)
200
201
202 class ExecuteMixin(object):
203 """Provides an executable functionality to a driver class."""
204
205 def init_execute_mixin(self, *args, **kwargs):
206 if self.configuration:
207 self.configuration.append_config_values(ssh_opts)
208 self.set_execute(kwargs.pop('execute', utils.execute))
209
210 def set_execute(self, execute):
211 self._execute = execute
212
213 def _try_execute(self, *command, **kwargs):
214 # NOTE(vish): Volume commands can partially fail due to timing, but
215 # running them a second time on failure will usually
216 # recover nicely.
217 tries = 0
218 while True:
219 try:
220 self._execute(*command, **kwargs)
221 return True
222 except exception.ProcessExecutionError:
223 tries += 1
224 if tries >= self.configuration.num_shell_tries:
225 raise
226 LOG.exception("Recovering from a failed execute. "
227 "Try number %s", tries)
228 time.sleep(tries ** 2)
229
230
231 class GaneshaMixin(object):
232 """Augment derived classes with Ganesha configuration."""
233
234 def init_ganesha_mixin(self, *args, **kwargs):
235 if self.configuration:
236 self.configuration.append_config_values(ganesha_opts)
237
238
239 class ShareDriver(object):
240 """Class defines interface of NAS driver."""
241
242 def __init__(self, driver_handles_share_servers, *args, **kwargs):
243 """Implements base functionality for share drivers.
244
245 :param driver_handles_share_servers: expected boolean value or
246 tuple/list/set of boolean values.
247 There are two possible approaches for share drivers in Manila.
248 First is when share driver is able to handle share-servers and
249 second when not.
250 Drivers can support either both (indicated by a tuple/set/list with
251 (True, False)) or only one of these approaches. So, it is allowed
252 to be 'True' when share driver does support handling of share
253 servers and allowed to be 'False' when it does support usage of
254 unhandled share-servers that are not tracked by Manila.
255 Share drivers are allowed to work only in one of two possible
256 driver modes, that is why only one should be chosen.
257 :param config_opts: tuple, list or set of config option lists
258 that should be registered in driver's configuration right after
259 this attribute is created. Useful for usage with mixin classes.
260 """
261 super(ShareDriver, self).__init__()
262 self.configuration = kwargs.get('configuration', None)
263 self.initialized = False
264 self._stats = {}
265 self.ip_versions = None
266 self.ipv6_implemented = False
267
268 self.pools = []
269 if self.configuration:
270 self.configuration.append_config_values(share_opts)
271 network_config_group = (self.configuration.network_config_group or
272 self.configuration.config_group)
273 admin_network_config_group = (
274 self.configuration.admin_network_config_group)
275 else:
276 network_config_group = None
277 admin_network_config_group = (
278 CONF.admin_network_config_group)
279
280 self._verify_share_server_handling(driver_handles_share_servers)
281 if self.driver_handles_share_servers:
282 # Enable common network
283 self.network_api = network.API(
284 config_group_name=network_config_group)
285
286 # Enable admin network
287 if admin_network_config_group:
288 self._admin_network_api = network.API(
289 config_group_name=admin_network_config_group,
290 label='admin')
291
292 for config_opt_set in kwargs.get('config_opts', []):
293 self.configuration.append_config_values(config_opt_set)
294
295 if hasattr(self, 'init_execute_mixin'):
296 # Instance with 'ExecuteMixin'
297 # pylint: disable=no-member
298 self.init_execute_mixin(*args, **kwargs)
299 if hasattr(self, 'init_ganesha_mixin'):
300 # Instance with 'GaneshaMixin'
301 # pylint: disable=no-member
302 self.init_ganesha_mixin(*args, **kwargs)
303
304 @property
305 def admin_network_api(self):
306 if hasattr(self, '_admin_network_api'):
307 return self._admin_network_api
308
309 @property
310 def driver_handles_share_servers(self):
311 if self.configuration:
312 return self.configuration.safe_get('driver_handles_share_servers')
313 return CONF.driver_handles_share_servers
314
315 @property
316 def replication_domain(self):
317 if self.configuration:
318 return self.configuration.safe_get('replication_domain')
319 return CONF.replication_domain
320
321 def _verify_share_server_handling(self, driver_handles_share_servers):
322 """Verifies driver_handles_share_servers and given configuration."""
323 if not isinstance(self.driver_handles_share_servers, bool):
324 raise exception.ManilaException(
325 "Config opt 'driver_handles_share_servers' has improper "
326 "value - '%s'. Please define it as boolean." %
327 self.driver_handles_share_servers)
328 elif isinstance(driver_handles_share_servers, bool):
329 driver_handles_share_servers = [driver_handles_share_servers]
330 elif not isinstance(driver_handles_share_servers, (tuple, list, set)):
331 raise exception.ManilaException(
332 "Improper data provided for 'driver_handles_share_servers' - "
333 "%s" % driver_handles_share_servers)
334
335 if any(not isinstance(v, bool) for v in driver_handles_share_servers):
336 raise exception.ManilaException(
337 "Provided wrong data: %s" % driver_handles_share_servers)
338
339 if (self.driver_handles_share_servers not in
340 driver_handles_share_servers):
341 raise exception.ManilaException(
342 "Driver does not support mode 'driver_handles_share_servers="
343 "%(actual)s'. It can be used only with value '%(allowed)s'." %
344 {'actual': self.driver_handles_share_servers,
345 'allowed': driver_handles_share_servers})
346
347 def migration_check_compatibility(
348 self, context, source_share, destination_share,
349 share_server=None, destination_share_server=None):
350 """Checks destination compatibility for migration of a given share.
351
352 .. note::
353 Is called to test compatibility with destination backend.
354
355 Driver should check if it is compatible with destination backend so
356 driver-assisted migration can proceed.
357
358 :param context: The 'context.RequestContext' object for the request.
359 :param source_share: Reference to the share to be migrated.
360 :param destination_share: Reference to the share model to be used by
361 migrated share.
362 :param share_server: Share server model or None.
363 :param destination_share_server: Destination Share server model or
364 None.
365 :return: A dictionary containing values indicating if destination
366 backend is compatible, if share can remain writable during
367 migration, if it can preserve all file metadata and if it can
368 perform migration of given share non-disruptively.
369
370 Example::
371
372 {
373 'compatible': True,
374 'writable': True,
375 'preserve_metadata': True,
376 'nondisruptive': True,
377 'preserve_snapshots': True,
378 }
379
380 """
381 return {
382 'compatible': False,
383 'writable': False,
384 'preserve_metadata': False,
385 'nondisruptive': False,
386 'preserve_snapshots': False,
387 }
388
389 def migration_start(
390 self, context, source_share, destination_share,
391 source_snapshots, snapshot_mappings, share_server=None,
392 destination_share_server=None):
393 """Starts migration of a given share to another host.
394
395 .. note::
396 Is called in source share's backend to start migration.
397
398 Driver should implement this method if willing to perform migration
399 in a driver-assisted way, useful for when source share's backend driver
400 is compatible with destination backend driver. This method should
401 start the migration procedure in the backend and end. Following steps
402 should be done in 'migration_continue'.
403
404 :param context: The 'context.RequestContext' object for the request.
405 :param source_share: Reference to the original share model.
406 :param destination_share: Reference to the share model to be used by
407 migrated share.
408 :param source_snapshots: List of snapshots owned by the source share.
409 :param snapshot_mappings: Mapping of source snapshot IDs to
410 destination snapshot models.
411 :param share_server: Share server model or None.
412 :param destination_share_server: Destination Share server model or
413 None.
414 """
415 raise NotImplementedError()
416
417 def migration_continue(
418 self, context, source_share, destination_share, source_snapshots,
419 snapshot_mappings, share_server=None,
420 destination_share_server=None):
421 """Continues migration of a given share to another host.
422
423 .. note::
424 Is called in source share's backend to continue migration.
425
426 Driver should implement this method to continue monitor the migration
427 progress in storage and perform following steps until 1st phase is
428 completed.
429
430 :param context: The 'context.RequestContext' object for the request.
431 :param source_share: Reference to the original share model.
432 :param destination_share: Reference to the share model to be used by
433 migrated share.
434 :param source_snapshots: List of snapshots owned by the source share.
435 :param snapshot_mappings: Mapping of source snapshot IDs to
436 destination snapshot models.
437 :param share_server: Share server model or None.
438 :param destination_share_server: Destination Share server model or
439 None.
440 :return: Boolean value to indicate if 1st phase is finished.
441 """
442 raise NotImplementedError()
443
444 def migration_complete(
445 self, context, source_share, destination_share, source_snapshots,
446 snapshot_mappings, share_server=None,
447 destination_share_server=None):
448 """Completes migration of a given share to another host.
449
450 .. note::
451 Is called in source share's backend to complete migration.
452
453 If driver is implementing 2-phase migration, this method should
454 perform the disruptive tasks related to the 2nd phase of migration,
455 thus completing it. Driver should also delete all original share data
456 from source backend.
457
458 :param context: The 'context.RequestContext' object for the request.
459 :param source_share: Reference to the original share model.
460 :param destination_share: Reference to the share model to be used by
461 migrated share.
462 :param source_snapshots: List of snapshots owned by the source share.
463 :param snapshot_mappings: Mapping of source snapshot IDs to
464 destination snapshot models.
465 :param share_server: Share server model or None.
466 :param destination_share_server: Destination Share server model or
467 None.
468 :return: If the migration changes the share export locations, snapshot
469 provider locations or snapshot export locations, this method should
470 return a dictionary with the relevant info. In such case, a
471 dictionary containing a list of export locations and a list of
472 model updates for each snapshot indexed by their IDs.
473
474 Example::
475
476 {
477 'export_locations':
478 [
479 {
480 'path': '1.2.3.4:/foo',
481 'metadata': {},
482 'is_admin_only': False
483 },
484 {
485 'path': '5.6.7.8:/foo',
486 'metadata': {},
487 'is_admin_only': True
488 },
489 ],
490 'snapshot_updates':
491 {
492 'bc4e3b28-0832-4168-b688-67fdc3e9d408':
493 {
494 'provider_location': '/snapshots/foo/bar_1',
495 'export_locations':
496 [
497 {
498 'path': '1.2.3.4:/snapshots/foo/bar_1',
499 'is_admin_only': False,
500 },
501 {
502 'path': '5.6.7.8:/snapshots/foo/bar_1',
503 'is_admin_only': True,
504 },
505 ],
506 },
507 '2e62b7ea-4e30-445f-bc05-fd523ca62941':
508 {
509 'provider_location': '/snapshots/foo/bar_2',
510 'export_locations':
511 [
512 {
513 'path': '1.2.3.4:/snapshots/foo/bar_2',
514 'is_admin_only': False,
515 },
516 {
517 'path': '5.6.7.8:/snapshots/foo/bar_2',
518 'is_admin_only': True,
519 },
520 ],
521 },
522 },
523 }
524
525 """
526 raise NotImplementedError()
527
528 def migration_cancel(
529 self, context, source_share, destination_share, source_snapshots,
530 snapshot_mappings, share_server=None,
531 destination_share_server=None):
532 """Cancels migration of a given share to another host.
533
534 .. note::
535 Is called in source share's backend to cancel migration.
536
537 If possible, driver can implement a way to cancel an in-progress
538 migration.
539
540 :param context: The 'context.RequestContext' object for the request.
541 :param source_share: Reference to the original share model.
542 :param destination_share: Reference to the share model to be used by
543 migrated share.
544 :param source_snapshots: List of snapshots owned by the source share.
545 :param snapshot_mappings: Mapping of source snapshot IDs to
546 destination snapshot models.
547 :param share_server: Share server model or None.
548 :param destination_share_server: Destination Share server model or
549 None.
550 """
551 raise NotImplementedError()
552
553 def migration_get_progress(
554 self, context, source_share, destination_share, source_snapshots,
555 snapshot_mappings, share_server=None,
556 destination_share_server=None):
557 """Obtains progress of migration of a given share to another host.
558
559 .. note::
560 Is called in source share's backend to obtain migration progress.
561
562 If possible, driver can implement a way to return migration progress
563 information.
564
565 :param context: The 'context.RequestContext' object for the request.
566 :param source_share: Reference to the original share model.
567 :param destination_share: Reference to the share model to be used by
568 migrated share.
569 :param source_snapshots: List of snapshots owned by the source share.
570 :param snapshot_mappings: Mapping of source snapshot IDs to
571 destination snapshot models.
572 :param share_server: Share server model or None.
573 :param destination_share_server: Destination Share server model or
574 None.
575 :return: A dictionary with at least 'total_progress' field containing
576 the percentage value.
577 """
578 raise NotImplementedError()
579
580 def connection_get_info(self, context, share, share_server=None):
581 """Is called to provide necessary generic migration logic.
582
583 :param context: The 'context.RequestContext' object for the request.
584 :param share: Reference to the share being migrated.
585 :param share_server: Share server model or None.
586 :return: A dictionary with migration information.
587 """
588 mount_template = self._get_mount_command(context, share, share_server)
589
590 unmount_template = self._get_unmount_command(context, share,
591 share_server)
592
593 access_mapping = self._get_access_mapping(context, share, share_server)
594
595 info = {
596 'mount': mount_template,
597 'unmount': unmount_template,
598 'access_mapping': access_mapping,
599 }
600
601 LOG.debug("Migration info obtained for share %(share_id)s: %(info)s.",
602 {'share_id': share['id'], 'info': six.text_type(info)})
603
604 return info
605
606 def _get_access_mapping(self, context, share, share_server):
607
608 mapping = self.configuration.safe_get('protocol_access_mapping') or {}
609 result = {}
610 share_proto = share['share_proto'].lower()
611 for access_type, protocols in mapping.items():
612 if share_proto in [y.lower() for y in protocols]:
613 result[access_type] = result.get(access_type, [])
614 result[access_type].append(share_proto)
615 return result
616
617 def _get_mount_command(self, context, share_instance, share_server=None):
618 """Is called to delegate mounting share logic."""
619
620 mount_template = self.configuration.safe_get('share_mount_template')
621
622 mount_export = self._get_mount_export(share_instance, share_server)
623
624 format_template = {
625 'proto': share_instance['share_proto'].lower(),
626 'export': mount_export,
627 'path': '%(path)s',
628 'options': '%(options)s',
629 }
630
631 return mount_template % format_template
632
633 def _get_mount_export(self, share_instance, share_server=None):
634 # NOTE(ganso): If drivers want to override the export_location IP,
635 # they can do so using this configuration. This method can also be
636 # overridden if necessary.
637 path = next((x['path'] for x in share_instance['export_locations']
638 if x['is_admin_only']), None)
639 if not path:
640 path = share_instance['export_locations'][0]['path']
641 return path
642
643 def _get_unmount_command(self, context, share_instance,
644 share_server=None):
645 return self.configuration.safe_get('share_unmount_template')
646
647 def create_share(self, context, share, share_server=None):
648 """Is called to create share."""
649 raise NotImplementedError()
650
651 def create_share_from_snapshot(self, context, share, snapshot,
652 share_server=None):
653 """Is called to create share from snapshot."""
654 raise NotImplementedError()
655
656 def create_snapshot(self, context, snapshot, share_server=None):
657 """Is called to create snapshot.
658
659 :param context: Current context
660 :param snapshot: Snapshot model. Share model could be
661 retrieved through snapshot['share'].
662 :param share_server: Share server model or None.
663 :return: None or a dictionary with key 'export_locations' containing
664 a list of export locations, if snapshots can be mounted.
665 """
666 raise NotImplementedError()
667
668 def delete_share(self, context, share, share_server=None):
669 """Is called to remove share."""
670 raise NotImplementedError()
671
672 def delete_snapshot(self, context, snapshot, share_server=None):
673 """Is called to remove snapshot.
674
675 :param context: Current context
676 :param snapshot: Snapshot model. Share model could be
677 retrieved through snapshot['share'].
678 :param share_server: Share server model or None.
679 """
680 raise NotImplementedError()
681
682 def get_pool(self, share):
683 """Return pool name where the share resides on.
684
685 :param share: The share hosted by the driver.
686 """
687
688 def ensure_share(self, context, share, share_server=None):
689 """Invoked to ensure that share is exported.
690
691 Driver can use this method to update the list of export locations of
692 the share if it changes. To do that, you should return list with
693 export locations.
694
695 :return: None or list with export locations
696 """
697 raise NotImplementedError()
698
699 def allow_access(self, context, share, access, share_server=None):
700 """Allow access to the share."""
701 raise NotImplementedError()
702
703 def deny_access(self, context, share, access, share_server=None):
704 """Deny access to the share."""
705 raise NotImplementedError()
706
707 def update_access(self, context, share, access_rules, add_rules,
708 delete_rules, share_server=None):
709 """Update access rules for given share.
710
711 ``access_rules`` contains all access_rules that need to be on the
712 share. If the driver can make bulk access rule updates, it can
713 safely ignore the ``add_rules`` and ``delete_rules`` parameters.
714
715 If the driver cannot make bulk access rule changes, it can rely on
716 new rules to be present in ``add_rules`` and rules that need to be
717 removed to be present in ``delete_rules``.
718
719 When a rule in ``delete_rules`` was never applied, drivers must not
720 raise an exception, or attempt to set the rule to ``error`` state.
721
722 ``add_rules`` and ``delete_rules`` can be empty lists, in this
723 situation, drivers should ensure that the rules present in
724 ``access_rules`` are the same as those on the back end. One scenario
725 where this situation is forced is when the access_level is changed for
726 all existing rules (share migration and for readable replicas).
727
728 Drivers must be mindful of this call for share replicas. When
729 'update_access' is called on one of the replicas, the call is likely
730 propagated to all replicas belonging to the share, especially when
731 individual rules are added or removed. If a particular access rule
732 does not make sense to the driver in the context of a given replica,
733 the driver should be careful to report a correct behavior, and take
734 meaningful action. For example, if R/W access is requested on a
735 replica that is part of a "readable" type replication; R/O access
736 may be added by the driver instead of R/W. Note that raising an
737 exception *will* result in the access_rules_status on the replica,
738 and the share itself being "out_of_sync". Drivers can sync on the
739 valid access rules that are provided on the ``create_replica`` and
740 ``promote_replica`` calls.
741
742 :param context: Current context
743 :param share: Share model with share data.
744 :param access_rules: A list of access rules for given share
745 :param add_rules: Empty List or List of access rules which should be
746 added. access_rules already contains these rules.
747 :param delete_rules: Empty List or List of access rules which should be
748 removed. access_rules doesn't contain these rules.
749 :param share_server: None or Share server model
750 :returns: None, or a dictionary of updates in the format::
751
752 {
753
754 '09960614-8574-4e03-89cf-7cf267b0bd08': {
755
756 'access_key': 'alice31493e5441b8171d2310d80e37e',
757 'state': 'error',
758
759 },
760
761 '28f6eabb-4342-486a-a7f4-45688f0c0295': {
762
763 'access_key': 'bob0078aa042d5a7325480fd13228b',
764 'state': 'active',
765
766 },
767
768 }
769
770 The top level keys are 'access_id' fields of the access rules that
771 need to be updated. ``access_key``s are credentials (str) of the
772 entities granted access. Any rule in the ``access_rules`` parameter
773 can be updated.
774
775 .. important::
776
777 Raising an exception in this method will force *all* rules in
778 'applying' and 'denying' states to 'error'.
779
780 An access rule can be set to 'error' state, either explicitly
781 via this return parameter or because of an exception raised in
782 this method. Such an access rule will no longer be sent to the
783 driver on subsequent access rule updates. When users deny that
784 rule however, the driver will be asked to deny access to the
785 client/s represented by the rule. We expect that a
786 rule that was error-ed at the driver should never exist on the
787 back end. So, do not fail the deletion request.
788
789 Also, it is possible that the driver may receive a request to
790 add a rule that is already present on the back end.
791 This can happen if the share manager service goes down
792 while the driver is committing access rule changes. Since we
793 cannot determine if the rule was applied successfully by the driver
794 before the disruption, we will treat all 'applying' transitional
795 rules as new rules and repeat the request.
796 """
797 raise NotImplementedError()
798
799 def check_for_setup_error(self):
800 """Check for setup error."""
801 max_ratio = self.configuration.safe_get('max_over_subscription_ratio')
802 if not max_ratio or float(max_ratio) < 1.0:
803 msg = (_("Invalid max_over_subscription_ratio '%s'. "
804 "Valid value should be >= 1.0.") % max_ratio)
805 raise exception.InvalidParameterValue(err=msg)
806
807 def do_setup(self, context):
808 """Any initialization the share driver does while starting."""
809
810 def get_share_stats(self, refresh=False):
811 """Get share status.
812
813 If 'refresh' is True, run update the stats first.
814 """
815 if refresh:
816 self._update_share_stats()
817
818 return self._stats
819
820 def get_network_allocations_number(self):
821 """Returns number of network allocations for creating VIFs.
822
823 Drivers that use Nova for share servers should return zero (0) here
824 same as Generic driver does.
825 Because Nova will handle network resources allocation.
826 Drivers that handle networking itself should calculate it according
827 to their own requirements. It can have 1+ network interfaces.
828 """
829 raise NotImplementedError()
830
831 def get_admin_network_allocations_number(self):
832 return 0
833
834 def update_network_allocation(self, context, share_server):
835 """Update network allocation after share server creation."""
836 self.network_api.update_network_allocation(context, share_server)
837
838 def update_admin_network_allocation(self, context, share_server):
839 """Update admin network allocation after share server creation."""
840 if (self.get_admin_network_allocations_number() and
841 self.admin_network_api):
842 self.admin_network_api.update_network_allocation(context,
843 share_server)
844
845 def allocate_network(self, context, share_server, share_network,
846 count=None, **kwargs):
847 """Allocate network resources using given network information."""
848 if count is None:
849 count = self.get_network_allocations_number()
850 if count:
851 kwargs.update(count=count)
852 self.network_api.allocate_network(
853 context, share_server, share_network, **kwargs)
854
855 def allocate_admin_network(self, context, share_server, count=None,
856 **kwargs):
857 """Allocate admin network resources using given network information."""
858 if count is None:
859 count = self.get_admin_network_allocations_number()
860 if count and not self.admin_network_api:
861 msg = _("Admin network plugin is not set up.")
862 raise exception.NetworkBadConfigurationException(reason=msg)
863 elif count:
864 kwargs.update(count=count)
865 self.admin_network_api.allocate_network(
866 context, share_server, **kwargs)
867
868 def deallocate_network(self, context, share_server_id):
869 """Deallocate network resources for the given share server."""
870 if self.get_network_allocations_number():
871 self.network_api.deallocate_network(context, share_server_id)
872
873 def choose_share_server_compatible_with_share(self, context, share_servers,
874 share, snapshot=None,
875 share_group=None):
876 """Method that allows driver to choose share server for provided share.
877
878 If compatible share-server is not found, method should return None.
879
880 :param context: Current context
881 :param share_servers: list with share-server models
882 :param share: share model
883 :param snapshot: snapshot model
884 :param share_group: ShareGroup model with shares
885 :returns: share-server or None
886 """
887 # If creating in a share group, use its share server
888 if share_group:
889 for share_server in share_servers:
890 if (share_group.get('share_server_id') ==
891 share_server['id']):
892 return share_server
893 return None
894
895 return share_servers[0] if share_servers else None
896
897 def choose_share_server_compatible_with_share_group(
898 self, context, share_servers, share_group_ref,
899 share_group_snapshot=None):
900
901 return share_servers[0] if share_servers else None
902
903 def setup_server(self, *args, **kwargs):
904 if self.driver_handles_share_servers:
905 return self._setup_server(*args, **kwargs)
906 else:
907 LOG.debug(
908 "Skipping step 'setup share server', because driver is "
909 "enabled with mode when Manila does not handle share servers.")
910
911 def _setup_server(self, network_info, metadata=None):
912 """Sets up and configures share server with given network parameters.
913
914 Redefine it within share driver when it is going to handle share
915 servers.
916
917 :param metadata: a dictionary, for now containing a key 'request_host'
918 """
919 raise NotImplementedError()
920
921 def manage_existing(self, share, driver_options):
922 """Brings an existing share under Manila management.
923
924 If the provided share is not valid, then raise a
925 ManageInvalidShare exception, specifying a reason for the failure.
926
927 If the provided share is not in a state that can be managed, such as
928 being replicated on the backend, the driver *MUST* raise
929 ManageInvalidShare exception with an appropriate message.
930
931 The share has a share_type, and the driver can inspect that and
932 compare against the properties of the referenced backend share.
933 If they are incompatible, raise a
934 ManageExistingShareTypeMismatch, specifying a reason for the failure.
935
936 This method is invoked when the share is being managed with
937 a share type that has ``driver_handles_share_servers``
938 extra-spec set to False.
939
940 :param share: Share model
941 :param driver_options: Driver-specific options provided by admin.
942 :return: share_update dictionary with required key 'size',
943 which should contain size of the share.
944 """
945 raise NotImplementedError()
946
947 def manage_existing_with_server(
948 self, share, driver_options, share_server=None):
949 """Brings an existing share under Manila management.
950
951 If the provided share is not valid, then raise a
952 ManageInvalidShare exception, specifying a reason for the failure.
953
954 If the provided share is not in a state that can be managed, such as
955 being replicated on the backend, the driver *MUST* raise
956 ManageInvalidShare exception with an appropriate message.
957
958 The share has a share_type, and the driver can inspect that and
959 compare against the properties of the referenced backend share.
960 If they are incompatible, raise a
961 ManageExistingShareTypeMismatch, specifying a reason for the failure.
962
963 This method is invoked when the share is being managed with
964 a share type that has ``driver_handles_share_servers``
965 extra-spec set to True.
966
967 :param share: Share model
968 :param driver_options: Driver-specific options provided by admin.
969 :param share_server: Share server model or None.
970 :return: share_update dictionary with required key 'size',
971 which should contain size of the share.
972 """
973 raise NotImplementedError()
974
975 def unmanage(self, share):
976 """Removes the specified share from Manila management.
977
978 Does not delete the underlying backend share.
979
980 For most drivers, this will not need to do anything. However, some
981 drivers might use this call as an opportunity to clean up any
982 Manila-specific configuration that they have associated with the
983 backend share.
984
985 If provided share cannot be unmanaged, then raise an
986 UnmanageInvalidShare exception, specifying a reason for the failure.
987
988 This method is invoked when the share is being unmanaged with
989 a share type that has ``driver_handles_share_servers``
990 extra-spec set to False.
991 """
992
993 def unmanage_with_server(self, share, share_server=None):
994 """Removes the specified share from Manila management.
995
996 Does not delete the underlying backend share.
997
998 For most drivers, this will not need to do anything. However, some
999 drivers might use this call as an opportunity to clean up any
1000 Manila-specific configuration that they have associated with the
1001 backend share.
1002
1003 If provided share cannot be unmanaged, then raise an
1004 UnmanageInvalidShare exception, specifying a reason for the failure.
1005
1006 This method is invoked when the share is being unmanaged with
1007 a share type that has ``driver_handles_share_servers``
1008 extra-spec set to True.
1009 """
1010
1011 def manage_existing_snapshot(self, snapshot, driver_options):
1012 """Brings an existing snapshot under Manila management.
1013
1014 If provided snapshot is not valid, then raise a
1015 ManageInvalidShareSnapshot exception, specifying a reason for
1016 the failure.
1017
1018 This method is invoked when the snapshot that is being managed
1019 belongs to a share that has its share type with
1020 ``driver_handles_share_servers`` extra-spec set to False.
1021
1022 :param snapshot: ShareSnapshotInstance model with ShareSnapshot data.
1023
1024 Example::
1025 {
1026 'id': <instance id>,
1027 'snapshot_id': < snapshot id>,
1028 'provider_location': <location>,
1029 ...
1030 }
1031
1032 :param driver_options: Optional driver-specific options provided
1033 by admin.
1034
1035 Example::
1036
1037 {
1038 'key': 'value',
1039 ...
1040 }
1041
1042 :return: model_update dictionary with required key 'size',
1043 which should contain size of the share snapshot, and key
1044 'export_locations' containing a list of export locations, if
1045 snapshots can be mounted.
1046 """
1047 raise NotImplementedError()
1048
1049 def manage_existing_snapshot_with_server(self, snapshot, driver_options,
1050 share_server=None):
1051 """Brings an existing snapshot under Manila management.
1052
1053 If provided snapshot is not valid, then raise a
1054 ManageInvalidShareSnapshot exception, specifying a reason for
1055 the failure.
1056
1057 This method is invoked when the snapshot that is being managed
1058 belongs to a share that has its share type with
1059 ``driver_handles_share_servers`` extra-spec set to True.
1060
1061 :param snapshot: ShareSnapshotInstance model with ShareSnapshot data.
1062
1063 Example::
1064 {
1065 'id': <instance id>,
1066 'snapshot_id': < snapshot id>,
1067 'provider_location': <location>,
1068 ...
1069 }
1070
1071 :param driver_options: Optional driver-specific options provided
1072 by admin.
1073
1074 Example::
1075
1076 {
1077 'key': 'value',
1078 ...
1079 }
1080
1081 :param share_server: Share server model or None.
1082 :return: model_update dictionary with required key 'size',
1083 which should contain size of the share snapshot, and key
1084 'export_locations' containing a list of export locations, if
1085 snapshots can be mounted.
1086 """
1087 raise NotImplementedError()
1088
1089 def unmanage_snapshot(self, snapshot):
1090 """Removes the specified snapshot from Manila management.
1091
1092 Does not delete the underlying backend share snapshot.
1093
1094 For most drivers, this will not need to do anything. However, some
1095 drivers might use this call as an opportunity to clean up any
1096 Manila-specific configuration that they have associated with the
1097 backend share snapshot.
1098
1099 If provided share snapshot cannot be unmanaged, then raise an
1100 UnmanageInvalidShareSnapshot exception, specifying a reason for
1101 the failure.
1102
1103 This method is invoked when the snapshot that is being unmanaged
1104 belongs to a share that has its share type with
1105 ``driver_handles_share_servers`` extra-spec set to False.
1106 """
1107
1108 def unmanage_snapshot_with_server(self, snapshot, share_server=None):
1109 """Removes the specified snapshot from Manila management.
1110
1111 Does not delete the underlying backend share snapshot.
1112
1113 For most drivers, this will not need to do anything. However, some
1114 drivers might use this call as an opportunity to clean up any
1115 Manila-specific configuration that they have associated with the
1116 backend share snapshot.
1117
1118 If provided share snapshot cannot be unmanaged, then raise an
1119 UnmanageInvalidShareSnapshot exception, specifying a reason for
1120 the failure.
1121
1122 This method is invoked when the snapshot that is being unmanaged
1123 belongs to a share that has its share type with
1124 ``driver_handles_share_servers`` extra-spec set to True.
1125 """
1126
1127 def revert_to_snapshot(self, context, snapshot, share_access_rules,
1128 snapshot_access_rules, share_server=None):
1129 """Reverts a share (in place) to the specified snapshot.
1130
1131 Does not delete the share snapshot. The share and snapshot must both
1132 be 'available' for the restore to be attempted. The snapshot must be
1133 the most recent one taken by Manila; the API layer performs this check
1134 so the driver doesn't have to.
1135
1136 The share must be reverted in place to the contents of the snapshot.
1137 Application admins should quiesce or otherwise prepare the application
1138 for the shared file system contents to change suddenly.
1139
1140 :param context: Current context
1141 :param snapshot: The snapshot to be restored
1142 :param share_access_rules: List of all access rules for the affected
1143 share
1144 :param snapshot_access_rules: List of all access rules for the affected
1145 snapshot
1146 :param share_server: Optional -- Share server model or None
1147 """
1148 raise NotImplementedError()
1149
1150 def extend_share(self, share, new_size, share_server=None):
1151 """Extends size of existing share.
1152
1153 :param share: Share model
1154 :param new_size: New size of share (new_size > share['size'])
1155 :param share_server: Optional -- Share server model
1156 """
1157 raise NotImplementedError()
1158
1159 def shrink_share(self, share, new_size, share_server=None):
1160 """Shrinks size of existing share.
1161
1162 If consumed space on share larger than new_size driver should raise
1163 ShareShrinkingPossibleDataLoss exception:
1164 raise ShareShrinkingPossibleDataLoss(share_id=share['id'])
1165
1166 :param share: Share model
1167 :param new_size: New size of share (new_size < share['size'])
1168 :param share_server: Optional -- Share server model
1169
1170 :raises ShareShrinkingPossibleDataLoss, NotImplementedError
1171 """
1172 raise NotImplementedError()
1173
1174 def teardown_server(self, *args, **kwargs):
1175 if self.driver_handles_share_servers:
1176 return self._teardown_server(*args, **kwargs)
1177 else:
1178 LOG.debug(
1179 "Skipping step 'teardown share server', because driver is "
1180 "enabled with mode when Manila does not handle share servers.")
1181
1182 def _teardown_server(self, server_details, security_services=None):
1183 """Tears down share server.
1184
1185 Redefine it within share driver when it is going to handle share
1186 servers.
1187 """
1188 raise NotImplementedError()
1189
1190 def _has_redefined_driver_methods(self, methods):
1191 """Returns boolean as a result of methods presence and redefinition."""
1192 if not isinstance(methods, (set, list, tuple)):
1193 methods = (methods, )
1194 for method_name in methods:
1195 method = getattr(type(self), method_name, None)
1196 if (not method or method == getattr(ShareDriver, method_name)):
1197 return False
1198 return True
1199
1200 @property
1201 def snapshots_are_supported(self):
1202 if not hasattr(self, '_snapshots_are_supported'):
1203 methods = ('create_snapshot', 'delete_snapshot')
1204 # NOTE(vponomaryov): calculate default value for
1205 # stat 'snapshot_support' based on implementation of
1206 # appropriate methods of this base driver class.
1207 self._snapshots_are_supported = self._has_redefined_driver_methods(
1208 methods)
1209 return self._snapshots_are_supported
1210
1211 @property
1212 def creating_shares_from_snapshots_is_supported(self):
1213 """Calculate default value for create_share_from_snapshot_support."""
1214
1215 if not hasattr(self, '_creating_shares_from_snapshots_is_supported'):
1216 methods = ('create_share_from_snapshot', )
1217 self._creating_shares_from_snapshots_is_supported = (
1218 self._has_redefined_driver_methods(methods))
1219
1220 return (
1221 self._creating_shares_from_snapshots_is_supported and
1222 self.snapshots_are_supported
1223 )
1224
1225 def _update_share_stats(self, data=None):
1226 """Retrieve stats info from share group.
1227
1228 :param data: dict -- dict with key-value pairs to redefine common ones.
1229 """
1230
1231 LOG.debug("Updating share stats.")
1232 backend_name = (self.configuration.safe_get('share_backend_name') or
1233 CONF.share_backend_name)
1234
1235 # Note(zhiteng): These information are driver/backend specific,
1236 # each driver may define these values in its own config options
1237 # or fetch from driver specific configuration file.
1238 common = dict(
1239 share_backend_name=backend_name or 'Generic_NFS',
1240 driver_handles_share_servers=self.driver_handles_share_servers,
1241 vendor_name='Open Source',
1242 driver_version='1.0',
1243 storage_protocol=None,
1244 total_capacity_gb='unknown',
1245 free_capacity_gb='unknown',
1246 reserved_percentage=0,
1247 qos=False,
1248 pools=self.pools or None,
1249 snapshot_support=self.snapshots_are_supported,
1250 create_share_from_snapshot_support=(
1251 self.creating_shares_from_snapshots_is_supported),
1252 revert_to_snapshot_support=False,
1253 mount_snapshot_support=False,
1254 replication_domain=self.replication_domain,
1255 filter_function=self.get_filter_function(),
1256 goodness_function=self.get_goodness_function(),
1257 )
1258 if isinstance(data, dict):
1259 common.update(data)
1260
1261 sg_stats = data.get('share_group_stats', {}) if data else {}
1262 common['share_group_stats'] = {
1263 'consistent_snapshot_support': sg_stats.get(
1264 'consistent_snapshot_support'),
1265 }
1266
1267 self.add_ip_version_capability(common)
1268 self._stats = common
1269
1270 def get_share_server_pools(self, share_server):
1271 """Return list of pools related to a particular share server.
1272
1273 :param share_server: ShareServer class instance.
1274 """
1275 return []
1276
1277 def create_share_group(self, context, share_group_dict, share_server=None):
1278 """Create a share group.
1279
1280 :param context:
1281 :param share_group_dict: The share group details
1282 EXAMPLE:
1283 {
1284 'status': 'creating',
1285 'project_id': '13c0be6290934bd98596cfa004650049',
1286 'user_id': 'a0314a441ca842019b0952224aa39192',
1287 'description': None,
1288 'deleted': 'False',
1289 'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),
1290 'updated_at': None,
1291 'source_share_group_snapshot_id': 'some_fake_uuid',
1292 'share_group_type_id': 'some_fake_uuid',
1293 'host': 'hostname@backend_name',
1294 'share_network_id': None,
1295 'share_server_id': None,
1296 'deleted_at': None,
1297 'share_types': [<models.ShareGroupShareTypeMapping>],
1298 'id': 'some_fake_uuid',
1299 'name': None
1300 }
1301 :returns: (share_group_model_update, share_update_list)
1302 share_group_model_update - a dict containing any values to be
1303 updated for the SG in the database. This value may be None.
1304
1305 """
1306 LOG.debug('Created a Share Group with ID: %s.', share_group_dict['id'])
1307
1308 def create_share_group_from_share_group_snapshot(
1309 self, context, share_group_dict, share_group_snapshot_dict,
1310 share_server=None):
1311 """Create a share group from a share group snapshot.
1312
1313 :param context:
1314 :param share_group_dict: The share group details
1315 EXAMPLE:
1316 .. code::
1317
1318 {
1319 'status': 'creating',
1320 'project_id': '13c0be6290934bd98596cfa004650049',
1321 'user_id': 'a0314a441ca842019b0952224aa39192',
1322 'description': None,
1323 'deleted': 'False',
1324 'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),
1325 'updated_at': None,
1326 'source_share_group_snapshot_id':
1327 'f6aa3b59-57eb-421e-965c-4e182538e36a',
1328 'host': 'hostname@backend_name',
1329 'deleted_at': None,
1330 'shares': [<models.Share>], # The new shares being created
1331 'share_types': [<models.ShareGroupShareTypeMapping>],
1332 'id': 'some_fake_uuid',
1333 'name': None
1334 }
1335 :param share_group_snapshot_dict: The share group snapshot details
1336 EXAMPLE:
1337 .. code::
1338
1339 {
1340 'status': 'available',
1341 'project_id': '13c0be6290934bd98596cfa004650049',
1342 'user_id': 'a0314a441ca842019b0952224aa39192',
1343 'description': None,
1344 'deleted': '0',
1345 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1346 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1347 'share_group_id': 'some_fake_uuid',
1348 'share_share_group_snapshot_members': [
1349 {
1350 'status': 'available',
1351 'user_id': 'a0314a441ca842019b0952224aa39192',
1352 'deleted': 'False',
1353 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1354 'share': <models.Share>,
1355 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1356 'share_proto': 'NFS',
1357 'project_id': '13c0be6290934bd98596cfa004650049',
1358 'share_group_snapshot_id': 'some_fake_uuid',
1359 'deleted_at': None,
1360 'id': 'some_fake_uuid',
1361 'size': 1
1362 }
1363 ],
1364 'deleted_at': None,
1365 'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',
1366 'name': None
1367 }
1368 :return: (share_group_model_update, share_update_list)
1369 share_group_model_update - a dict containing any values to be
1370 updated for the share group in the database. This value may be None
1371
1372 share_update_list - a list of dictionaries containing dicts for
1373 every share created in the share group. Any share dicts should at a
1374 minimum contain the 'id' key and 'export_locations'.
1375 Export locations should be in the same format as returned by
1376 a share_create. This list may be empty or None. EXAMPLE:
1377 .. code::
1378
1379 [{'id': 'uuid', 'export_locations': [{...}, {...}]}]
1380 """
1381 # Ensure that the share group snapshot has members
1382 if not share_group_snapshot_dict['share_group_snapshot_members']:
1383 return None, None
1384
1385 clone_list = self._collate_share_group_snapshot_info(
1386 share_group_dict, share_group_snapshot_dict)
1387 share_update_list = []
1388
1389 LOG.debug('Creating share group from group snapshot %s.',
1390 share_group_snapshot_dict['id'])
1391
1392 for clone in clone_list:
1393 kwargs = {}
1394 if self.driver_handles_share_servers:
1395 kwargs['share_server'] = share_server
1396 export_locations = (
1397 self.create_share_from_snapshot(
1398 context, clone['share'], clone['snapshot'], **kwargs))
1399 share_update_list.append({
1400 'id': clone['share']['id'],
1401 'export_locations': export_locations,
1402 })
1403 return None, share_update_list
1404
1405 def delete_share_group(self, context, share_group_dict, share_server=None):
1406 """Delete a share group
1407
1408 :param context: The request context
1409 :param share_group_dict: The share group details
1410 EXAMPLE:
1411 .. code::
1412
1413 {
1414 'status': 'creating',
1415 'project_id': '13c0be6290934bd98596cfa004650049',
1416 'user_id': 'a0314a441ca842019b0952224aa39192',
1417 'description': None,
1418 'deleted': 'False',
1419 'created_at': datetime.datetime(2015, 8, 10, 15, 14, 6),
1420 'updated_at': None,
1421 'source_share_group_snapshot_id': 'some_fake_uuid',
1422 'share_share_group_type_id': 'some_fake_uuid',
1423 'host': 'hostname@backend_name',
1424 'deleted_at': None,
1425 'shares': [<models.Share>], # The new shares being created
1426 'share_types': [<models.ShareGroupShareTypeMapping>],
1427 'id': 'some_fake_uuid',
1428 'name': None
1429 }
1430 :return: share_group_model_update
1431 share_group_model_update - a dict containing any values to be
1432 updated for the group in the database. This value may be None.
1433 """
1434
1435 def _cleanup_group_share_snapshot(self, context, share_snapshot,
1436 share_server):
1437 """Deletes the snapshot of a share belonging to a group."""
1438
1439 try:
1440 self.delete_snapshot(
1441 context, share_snapshot, share_server=share_server)
1442 except exception.ManilaException:
1443 msg = ('Could not delete share group snapshot member %(snap)s '
1444 'for share %(share)s.')
1445 LOG.error(msg, {
1446 'snap': share_snapshot['id'],
1447 'share': share_snapshot['share_id'],
1448 })
1449 raise
1450
1451 def create_share_group_snapshot(self, context, snap_dict,
1452 share_server=None):
1453 """Create a share group snapshot.
1454
1455 :param context:
1456 :param snap_dict: The share group snapshot details
1457 EXAMPLE:
1458 .. code::
1459
1460 {
1461 'status': 'available',
1462 'project_id': '13c0be6290934bd98596cfa004650049',
1463 'user_id': 'a0314a441ca842019b0952224aa39192',
1464 'description': None,
1465 'deleted': '0',
1466 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1467 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1468 'share_group_id': 'some_fake_uuid',
1469 'share_group_snapshot_members': [
1470 {
1471 'status': 'available',
1472 'share_type_id': 'some_fake_uuid',
1473 'user_id': 'a0314a441ca842019b0952224aa39192',
1474 'deleted': 'False',
1475 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1476 'share': <models.Share>,
1477 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1478 'share_proto': 'NFS',
1479 'share_name': 'share_some_fake_uuid',
1480 'name': 'share-snapshot-some_fake_uuid',
1481 'project_id': '13c0be6290934bd98596cfa004650049',
1482 'share_group_snapshot_id': 'some_fake_uuid',
1483 'deleted_at': None,
1484 'share_id': 'some_fake_uuid',
1485 'id': 'some_fake_uuid',
1486 'size': 1,
1487 'provider_location': None,
1488 }
1489 ],
1490 'deleted_at': None,
1491 'id': 'some_fake_uuid',
1492 'name': None
1493 }
1494 :return: (share_group_snapshot_update, member_update_list)
1495 share_group_snapshot_update - a dict containing any values to be
1496 updated for the CGSnapshot in the database. This value may be None.
1497
1498 member_update_list - a list of dictionaries containing for every
1499 member of the share group snapshot. Each dict should contains
1500 values to be updated for the ShareGroupSnapshotMember in
1501 the database. This list may be empty or None.
1502 """
1503 LOG.debug('Attempting to create a share group snapshot %s.',
1504 snap_dict['id'])
1505
1506 snapshot_members = snap_dict.get('share_group_snapshot_members', [])
1507 if not self._stats.get('snapshot_support'):
1508 raise exception.ShareGroupSnapshotNotSupported(
1509 share_group=snap_dict['share_group_id'])
1510 elif not snapshot_members:
1511 LOG.warning('No shares in share group to create snapshot.')
1512 return None, None
1513 else:
1514 share_snapshots = []
1515 snapshot_members_updates = []
1516 for member in snapshot_members:
1517 share_snapshot = {
1518 'snapshot_id': member['share_group_snapshot_id'],
1519 'share_id': member['share_id'],
1520 'share_instance_id': member['share']['id'],
1521 'id': member['id'],
1522 'share': member['share'],
1523 'share_name': member['share_name'],
1524 'name': member['name'],
1525 'size': member['share']['size'],
1526 'share_size': member['share']['size'],
1527 'share_proto': member['share']['share_proto'],
1528 'provider_location': None,
1529 }
1530 try:
1531 member_update = self.create_snapshot(
1532 context, share_snapshot, share_server=share_server)
1533 if member_update:
1534 member_update['id'] = member['id']
1535 snapshot_members_updates.append(member_update)
1536 share_snapshots.append(share_snapshot)
1537 except exception.ManilaException as e:
1538 msg = ('Could not create share group snapshot. Failed '
1539 'to create share snapshot %(snap)s for '
1540 'share %(share)s.')
1541 LOG.exception(msg, {
1542 'snap': share_snapshot['id'],
1543 'share': share_snapshot['share_id']
1544 })
1545
1546 # clean up any share snapshots previously created
1547 LOG.debug(
1548 'Attempting to clean up snapshots due to failure.')
1549 for share_snapshot in share_snapshots:
1550 self._cleanup_group_share_snapshot(
1551 context, share_snapshot, share_server)
1552 raise e
1553
1554 LOG.debug('Successfully created share group snapshot %s.',
1555 snap_dict['id'])
1556 return None, snapshot_members_updates
1557
1558 def delete_share_group_snapshot(self, context, snap_dict,
1559 share_server=None):
1560 """Delete a share group snapshot
1561
1562 :param context:
1563 :param snap_dict: The share group snapshot details
1564 EXAMPLE:
1565 .. code::
1566
1567 {
1568 'status': 'available',
1569 'project_id': '13c0be6290934bd98596cfa004650049',
1570 'user_id': 'a0314a441ca842019b0952224aa39192',
1571 'description': None,
1572 'deleted': '0',
1573 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1574 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1575 'share_group_id': 'some_fake_uuid',
1576 'share_group_snapshot_members': [
1577 {
1578 'status': 'available',
1579 'share_type_id': 'some_fake_uuid',
1580 'share_id': 'some_fake_uuid',
1581 'user_id': 'a0314a441ca842019b0952224aa39192',
1582 'deleted': 'False',
1583 'created_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1584 'share': <models.Share>,
1585 'updated_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1586 'share_proto': 'NFS',
1587 'share_name':'share_some_fake_uuid',
1588 'name': 'share-snapshot-some_fake_uuid',
1589 'project_id': '13c0be6290934bd98596cfa004650049',
1590 'share_group_snapshot_id': 'some_fake_uuid',
1591 'deleted_at': None,
1592 'id': 'some_fake_uuid',
1593 'size': 1,
1594 'provider_location': 'fake_provider_location_value',
1595 }
1596 ],
1597 'deleted_at': None,
1598 'id': 'f6aa3b59-57eb-421e-965c-4e182538e36a',
1599 'name': None
1600 }
1601 :return: (share_group_snapshot_update, member_update_list)
1602 share_group_snapshot_update - a dict containing any values
1603 to be updated for the ShareGroupSnapshot in the database.
1604 This value may be None.
1605 """
1606 snapshot_members = snap_dict.get('share_group_snapshot_members', [])
1607 LOG.debug('Deleting share group snapshot %s.', snap_dict['id'])
1608 for member in snapshot_members:
1609 share_snapshot = {
1610 'snapshot_id': member['share_group_snapshot_id'],
1611 'share_id': member['share_id'],
1612 'share_instance_id': member['share']['id'],
1613 'id': member['id'],
1614 'share': member['share'],
1615 'size': member['share']['size'],
1616 'share_name': member['share_name'],
1617 'name': member['name'],
1618 'share_size': member['share']['size'],
1619 'share_proto': member['share']['share_proto'],
1620 'provider_location': member['provider_location'],
1621 }
1622 self.delete_snapshot(
1623 context, share_snapshot, share_server=share_server)
1624
1625 LOG.debug('Deleted share group snapshot %s.', snap_dict['id'])
1626 return None, None
1627
1628 def _collate_share_group_snapshot_info(self, share_group_dict,
1629 share_group_snapshot_dict):
1630 """Collate the data for a clone of the SG snapshot.
1631
1632 Given two data structures, a share group snapshot (
1633 share_group_snapshot_dict) and a new share to be cloned from
1634 the snapshot (share_group_dict), match up both structures into a list
1635 of dicts (share & snapshot) suitable for use by existing method
1636 that clones individual share snapshots.
1637 """
1638 clone_list = []
1639 for share in share_group_dict['shares']:
1640 clone_info = {'share': share}
1641 for share_group_snapshot_member in share_group_snapshot_dict[
1642 'share_group_snapshot_members']:
1643 if (share['source_share_group_snapshot_member_id'] ==
1644 share_group_snapshot_member['id']):
1645 clone_info['snapshot'] = share_group_snapshot_member
1646 break
1647
1648 if len(clone_info) != 2:
1649 msg = _(
1650 "Invalid data supplied for creating share group from "
1651 "share group snapshot "
1652 "%s.") % share_group_snapshot_dict['id']
1653 raise exception.InvalidShareGroup(reason=msg)
1654
1655 clone_list.append(clone_info)
1656
1657 return clone_list
1658
1659 def get_periodic_hook_data(self, context, share_instances):
1660 """Dedicated for update/extend of data for existing share instances.
1661
1662 Redefine this method in share driver to be able to update/change/extend
1663 share instances data that will be used by periodic hook action.
1664 One of possible updates is add-on of "automount" CLI commands for each
1665 share instance for case of notification is enabled using 'hook'
1666 approach.
1667
1668 :param context: Current context
1669 :param share_instances: share instances list provided by share manager
1670 :return: list of share instances.
1671 """
1672 return share_instances
1673
1674 def create_replica(self, context, replica_list, new_replica,
1675 access_rules, replica_snapshots, share_server=None):
1676 """Replicate the active replica to a new replica on this backend.
1677
1678 .. note::
1679 This call is made on the host that the new replica is being created
1680 upon.
1681
1682 :param context: Current context
1683 :param replica_list: List of all replicas for a particular share.
1684 This list also contains the replica to be created. The 'active'
1685 replica will have its 'replica_state' attr set to 'active'.
1686
1687 Example::
1688
1689 [
1690 {
1691 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
1692 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1693 'replica_state': 'in_sync',
1694 ...
1695 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
1696 'share_server': <models.ShareServer> or None,
1697 },
1698 {
1699 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
1700 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1701 'replica_state': 'active',
1702 ...
1703 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
1704 'share_server': <models.ShareServer> or None,
1705 },
1706 {
1707 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
1708 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1709 'replica_state': 'in_sync',
1710 ...
1711 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',
1712 'share_server': <models.ShareServer> or None,
1713 },
1714 ...
1715 ]
1716
1717 :param new_replica: The share replica dictionary.
1718
1719 Example::
1720
1721 {
1722 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
1723 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1724 'deleted': False,
1725 'host': 'openstack2@cmodeSSVMNFS2',
1726 'status': 'creating',
1727 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1728 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1729 'terminated_at': None,
1730 'replica_state': 'out_of_sync',
1731 'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',
1732 'export_locations': [
1733 models.ShareInstanceExportLocations,
1734 ],
1735 'access_rules_status': 'out_of_sync',
1736 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',
1737 'share_server_id': 'e6155221-ea00-49ef-abf9-9f89b7dd900a',
1738 'share_server': <models.ShareServer> or None,
1739 }
1740
1741 :param access_rules: A list of access rules.
1742 These are rules that other instances of the share already obey.
1743 Drivers are expected to apply access rules to the new replica or
1744 disregard access rules that don't apply.
1745
1746 Example::
1747
1748 [
1749 {
1750 'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',
1751 'deleted' = False,
1752 'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1753 'access_type' = 'ip',
1754 'access_to' = '172.16.20.1',
1755 'access_level' = 'rw',
1756 }
1757 ]
1758
1759 :param replica_snapshots: List of dictionaries of snapshot instances.
1760 This includes snapshot instances of every snapshot of the share
1761 whose 'aggregate_status' property was reported to be 'available'
1762 when the share manager initiated this request. Each list member
1763 will have two sub dictionaries: 'active_replica_snapshot' and
1764 'share_replica_snapshot'. The 'active' replica snapshot corresponds
1765 to the instance of the snapshot on any of the 'active' replicas of
1766 the share while share_replica_snapshot corresponds to the snapshot
1767 instance for the specific replica that will need to exist on the
1768 new share replica that is being created. The driver needs to ensure
1769 that this snapshot instance is truly available before transitioning
1770 the replica from 'out_of_sync' to 'in_sync'. Snapshots instances
1771 for snapshots that have an 'aggregate_status' of 'creating' or
1772 'deleting' will be polled for in the ``update_replicated_snapshot``
1773 method.
1774
1775 Example::
1776
1777 [
1778 {
1779 'active_replica_snapshot': {
1780 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
1781 'share_instance_id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
1782 'status': 'available',
1783 'provider_location': '/newton/share-snapshot-10e49c3e-aca9',
1784 ...
1785 },
1786 'share_replica_snapshot': {
1787 'id': '',
1788 'share_instance_id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
1789 'status': 'available',
1790 'provider_location': None,
1791 ...
1792 },
1793 }
1794 ]
1795
1796 :param share_server: <models.ShareServer> or None
1797 Share server of the replica being created.
1798 :return: None or a dictionary.
1799 The dictionary can contain export_locations replica_state and
1800 access_rules_status. export_locations is a list of paths and
1801 replica_state is one of 'active', 'in_sync', 'out_of_sync' or
1802 'error'.
1803
1804 .. important::
1805
1806 A backend supporting 'writable' type replication should return
1807 'active' as the replica_state.
1808
1809 Export locations should be in the same format as returned during the
1810 ``create_share`` call.
1811
1812 Example::
1813
1814 {
1815 'export_locations': [
1816 {
1817 'path': '172.16.20.22/sample/export/path',
1818 'is_admin_only': False,
1819 'metadata': {'some_key': 'some_value'},
1820 },
1821 ],
1822 'replica_state': 'in_sync',
1823 'access_rules_status': 'in_sync',
1824 }
1825
1826 """
1827 raise NotImplementedError()
1828
1829 def delete_replica(self, context, replica_list, replica_snapshots,
1830 replica, share_server=None):
1831 """Delete a replica.
1832
1833 .. note::
1834 This call is made on the host that hosts the replica being
1835 deleted.
1836
1837 :param context: Current context
1838 :param replica_list: List of all replicas for a particular share
1839 This list also contains the replica to be deleted. The 'active'
1840 replica will have its 'replica_state' attr set to 'active'.
1841
1842 Example::
1843
1844 [
1845 {
1846 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
1847 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1848 'replica_state': 'in_sync',
1849 ...
1850 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
1851 'share_server': <models.ShareServer> or None,
1852 },
1853 {
1854 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
1855 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1856 'replica_state': 'active',
1857 ...
1858 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
1859 'share_server': <models.ShareServer> or None,
1860 },
1861 {
1862 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
1863 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1864 'replica_state': 'in_sync',
1865 ...
1866 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',
1867 'share_server': <models.ShareServer> or None,
1868 },
1869 ...
1870 ]
1871
1872 :param replica: Dictionary of the share replica being deleted.
1873
1874 Example::
1875
1876 {
1877 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
1878 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1879 'deleted': False,
1880 'host': 'openstack2@cmodeSSVMNFS2',
1881 'status': 'available',
1882 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1883 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1884 'terminated_at': None,
1885 'replica_state': 'in_sync',
1886 'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',
1887 'export_locations': [
1888 models.ShareInstanceExportLocations
1889 ],
1890 'access_rules_status': 'out_of_sync',
1891 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',
1892 'share_server_id': '53099868-65f1-11e5-9d70-feff819cdc9f',
1893 'share_server': <models.ShareServer> or None,
1894 }
1895
1896 :param replica_snapshots: List of dictionaries of snapshot instances.
1897 The dict contains snapshot instances that are associated with the
1898 share replica being deleted.
1899 No model updates to snapshot instances are possible in this method.
1900 The driver should return when the cleanup is completed on the
1901 backend for both, the snapshots and the replica itself. Drivers
1902 must handle situations where the snapshot may not yet have
1903 finished 'creating' on this replica.
1904
1905 Example::
1906
1907 [
1908 {
1909 'id': '89dafd00-0999-4d23-8614-13eaa6b02a3b',
1910 'snapshot_id': '3ce1caf7-0945-45fd-a320-714973e949d3',
1911 'status: 'available',
1912 'share_instance_id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f'
1913 ...
1914 },
1915 {
1916 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
1917 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
1918 'status: 'creating',
1919 'share_instance_id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f'
1920 ...
1921 },
1922 ...
1923 ]
1924
1925 :param share_server: <models.ShareServer> or None
1926 Share server of the replica to be deleted.
1927 :return: None.
1928 :raises: Exception.
1929 Any exception raised will set the share replica's 'status' and
1930 'replica_state' attributes to 'error_deleting'. It will not affect
1931 snapshots belonging to this replica.
1932 """
1933 raise NotImplementedError()
1934
1935 def promote_replica(self, context, replica_list, replica, access_rules,
1936 share_server=None):
1937 """Promote a replica to 'active' replica state.
1938
1939 .. note::
1940 This call is made on the host that hosts the replica being
1941 promoted.
1942
1943 :param context: Current context
1944 :param replica_list: List of all replicas for a particular share
1945 This list also contains the replica to be promoted. The 'active'
1946 replica will have its 'replica_state' attr set to 'active'.
1947
1948 Example::
1949
1950 [
1951 {
1952 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
1953 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1954 'replica_state': 'in_sync',
1955 ...
1956 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
1957 'share_server': <models.ShareServer> or None,
1958 },
1959 {
1960 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
1961 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1962 'replica_state': 'active',
1963 ...
1964 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
1965 'share_server': <models.ShareServer> or None,
1966 },
1967 {
1968 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
1969 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1970 'replica_state': 'in_sync',
1971 ...
1972 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',
1973 'share_server': <models.ShareServer> or None,
1974 },
1975 ...
1976 ]
1977
1978 :param replica: Dictionary of the replica to be promoted.
1979
1980 Example::
1981
1982 {
1983 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
1984 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
1985 'deleted': False,
1986 'host': 'openstack2@cmodeSSVMNFS2',
1987 'status': 'available',
1988 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1989 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
1990 'terminated_at': None,
1991 'replica_state': 'in_sync',
1992 'availability_zone_id': 'f6e146d0-65f0-11e5-9d70-feff819cdc9f',
1993 'export_locations': [
1994 models.ShareInstanceExportLocations
1995 ],
1996 'access_rules_status': 'in_sync',
1997 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',
1998 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',
1999 'share_server': <models.ShareServer> or None,
2000 }
2001
2002 :param access_rules: A list of access rules
2003 These access rules are obeyed by other instances of the share
2004
2005 Example::
2006
2007 [
2008 {
2009 'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',
2010 'deleted' = False,
2011 'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2012 'access_type' = 'ip',
2013 'access_to' = '172.16.20.1',
2014 'access_level' = 'rw',
2015 }
2016 ]
2017
2018 :param share_server: <models.ShareServer> or None
2019 Share server of the replica to be promoted.
2020 :return: updated_replica_list or None.
2021 The driver can return the updated list as in the request
2022 parameter. Changes that will be updated to the Database are:
2023 'export_locations', 'access_rules_status' and 'replica_state'.
2024 :raises: Exception.
2025 This can be any exception derived from BaseException. This is
2026 re-raised by the manager after some necessary cleanup. If the
2027 driver raises an exception during promotion, it is assumed that
2028 all of the replicas of the share are in an inconsistent state.
2029 Recovery is only possible through the periodic update call and/or
2030 administrator intervention to correct the 'status' of the affected
2031 replicas if they become healthy again.
2032 """
2033 raise NotImplementedError()
2034
2035 def update_replica_state(self, context, replica_list, replica,
2036 access_rules, replica_snapshots,
2037 share_server=None):
2038 """Update the replica_state of a replica.
2039
2040 .. note::
2041 This call is made on the host which hosts the replica being
2042 updated.
2043
2044 Drivers should fix replication relationships that were broken if
2045 possible inside this method.
2046
2047 This method is called periodically by the share manager; and
2048 whenever requested by the administrator through the 'resync' API.
2049
2050 :param context: Current context
2051 :param replica_list: List of all replicas for a particular share
2052 This list also contains the replica to be updated. The 'active'
2053 replica will have its 'replica_state' attr set to 'active'.
2054
2055 Example::
2056
2057 [
2058 {
2059 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2060 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2061 'replica_state': 'in_sync',
2062 ...
2063 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2064 'share_server': <models.ShareServer> or None,
2065 },
2066 {
2067 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2068 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2069 'replica_state': 'active',
2070 ...
2071 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
2072 'share_server': <models.ShareServer> or None,
2073 },
2074 {
2075 'id': 'e82ff8b6-65f0-11e5-9d70-feff819cdc9f',
2076 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2077 'replica_state': 'in_sync',
2078 ...
2079 'share_server_id': '07574742-67ea-4dfd-9844-9fbd8ada3d87',
2080 'share_server': <models.ShareServer> or None,
2081 },
2082 ...
2083 ]
2084
2085 :param replica: Dictionary of the replica being updated
2086 Replica state will always be 'in_sync', 'out_of_sync', or 'error'.
2087 Replicas in 'active' state will not be passed via this parameter.
2088
2089 Example::
2090
2091 {
2092 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2093 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2094 'deleted': False,
2095 'host': 'openstack2@cmodeSSVMNFS1',
2096 'status': 'available',
2097 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2098 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2099 'terminated_at': None,
2100 'replica_state': 'in_sync',
2101 'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',
2102 'export_locations': [
2103 models.ShareInstanceExportLocations,
2104 ],
2105 'access_rules_status': 'in_sync',
2106 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',
2107 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2108 }
2109
2110 :param access_rules: A list of access rules
2111 These access rules are obeyed by other instances of the share. The
2112 driver could attempt to sync on any un-applied access_rules.
2113
2114 Example::
2115
2116 [
2117 {
2118 'id': 'f0875f6f-766b-4865-8b41-cccb4cdf1676',
2119 'deleted' = False,
2120 'share_id' = 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2121 'access_type' = 'ip',
2122 'access_to' = '172.16.20.1',
2123 'access_level' = 'rw',
2124 }
2125 ]
2126
2127 :param replica_snapshots: List of dictionaries of snapshot instances.
2128 This includes snapshot instances of every snapshot of the share
2129 whose 'aggregate_status' property was reported to be 'available'
2130 when the share manager initiated this request. Each list member
2131 will have two sub dictionaries: 'active_replica_snapshot' and
2132 'share_replica_snapshot'. The 'active' replica snapshot corresponds
2133 to the instance of the snapshot on any of the 'active' replicas of
2134 the share while share_replica_snapshot corresponds to the snapshot
2135 instance for the specific replica being updated. The driver needs
2136 to ensure that this snapshot instance is truly available before
2137 transitioning from 'out_of_sync' to 'in_sync'. Snapshots instances
2138 for snapshots that have an 'aggregate_status' of 'creating' or
2139 'deleting' will be polled for in the update_replicated_snapshot
2140 method.
2141
2142 Example::
2143
2144 [
2145 {
2146 'active_replica_snapshot': {
2147 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
2148 'share_instance_id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2149 'status': 'available',
2150 'provider_location': '/newton/share-snapshot-10e49c3e-aca9',
2151 ...
2152 },
2153 'share_replica_snapshot': {
2154 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2155 'share_instance_id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2156 'status': 'creating',
2157 'provider_location': None,
2158 ...
2159 },
2160 }
2161 ]
2162
2163 :param share_server: <models.ShareServer> or None
2164 :return: replica_state: a str value denoting the replica_state.
2165 Valid values are 'in_sync' and 'out_of_sync' or None (to leave the
2166 current replica_state unchanged).
2167 """
2168 raise NotImplementedError()
2169
2170 def create_replicated_snapshot(self, context, replica_list,
2171 replica_snapshots,
2172 share_server=None):
2173 """Create a snapshot on active instance and update across the replicas.
2174
2175 .. note::
2176 This call is made on the 'active' replica's host. Drivers are
2177 expected to transfer the snapshot created to the respective
2178 replicas.
2179
2180 The driver is expected to return model updates to the share manager.
2181 If it was able to confirm the creation of any number of the snapshot
2182 instances passed in this interface, it can set their status to
2183 'available' as a cue for the share manager to set the progress attr
2184 to '100%'.
2185
2186 :param context: Current context
2187 :param replica_list: List of all replicas for a particular share
2188 The 'active' replica will have its 'replica_state' attr set to
2189 'active'.
2190
2191 Example::
2192
2193 [
2194 {
2195 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2196 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2197 'replica_state': 'in_sync',
2198 ...
2199 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2200 'share_server': <models.ShareServer> or None,
2201 },
2202 {
2203 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2204 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2205 'replica_state': 'active',
2206 ...
2207 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
2208 'share_server': <models.ShareServer> or None,
2209 },
2210 ...
2211 ]
2212
2213 :param replica_snapshots: List of dictionaries of snapshot instances.
2214 These snapshot instances track the snapshot across the replicas.
2215 All the instances will have their status attribute set to
2216 'creating'.
2217
2218 Example::
2219
2220 [
2221 {
2222 'id': 'd3931a93-3984-421e-a9e7-d9f71895450a',
2223 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2224 'status: 'creating',
2225 'progress': '0%',
2226 ...
2227 },
2228 {
2229 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
2230 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2231 'status: 'creating',
2232 'progress': '0%',
2233 ...
2234 },
2235 ...
2236 ]
2237
2238 :param share_server: <models.ShareServer> or None
2239 :return: List of dictionaries of snapshot instances.
2240 The dictionaries can contain values that need to be updated on the
2241 database for the snapshot instances being created.
2242 :raises: Exception.
2243 Any exception in this method will set all instances to 'error'.
2244 """
2245 raise NotImplementedError()
2246
2247 def revert_to_replicated_snapshot(self, context, active_replica,
2248 replica_list, active_replica_snapshot,
2249 replica_snapshots, share_access_rules,
2250 snapshot_access_rules,
2251 share_server=None):
2252 """Reverts a replicated share (in place) to the specified snapshot.
2253
2254 .. note::
2255 This call is made on the 'active' replica's host, since drivers may
2256 not be able to revert snapshots on individual replicas.
2257
2258 Does not delete the share snapshot. The share and snapshot must both
2259 be 'available' for the restore to be attempted. The snapshot must be
2260 the most recent one taken by Manila; the API layer performs this check
2261 so the driver doesn't have to.
2262
2263 The share must be reverted in place to the contents of the snapshot.
2264 Application admins should quiesce or otherwise prepare the application
2265 for the shared file system contents to change suddenly.
2266
2267 :param context: Current context
2268 :param active_replica: The current active replica
2269 :param replica_list: List of all replicas for a particular share
2270 The 'active' replica will have its 'replica_state' attr set to
2271 'active' and its 'status' set to 'reverting'.
2272 :param active_replica_snapshot: snapshot to be restored
2273 :param replica_snapshots: List of dictionaries of snapshot instances.
2274 These snapshot instances track the snapshot across the replicas.
2275 The snapshot of the active replica to be restored with have its
2276 status attribute set to 'restoring'.
2277 :param share_access_rules: List of access rules for the affected share.
2278 :param snapshot_access_rules: List of access rules for the affected
2279 snapshot.
2280 :param share_server: Optional -- Share server model
2281 """
2282 raise NotImplementedError()
2283
2284 def delete_replicated_snapshot(self, context, replica_list,
2285 replica_snapshots, share_server=None):
2286 """Delete a snapshot by deleting its instances across the replicas.
2287
2288 .. note::
2289 This call is made on the 'active' replica's host, since
2290 drivers may not be able to delete the snapshot from an individual
2291 replica.
2292
2293 The driver is expected to return model updates to the share manager.
2294 If it was able to confirm the removal of any number of the snapshot
2295 instances passed in this interface, it can set their status to
2296 'deleted' as a cue for the share manager to clean up that instance
2297 from the database.
2298
2299 :param context: Current context
2300 :param replica_list: List of all replicas for a particular share
2301 The 'active' replica will have its 'replica_state' attr set to
2302 'active'.
2303
2304 Example::
2305
2306 [
2307 {
2308 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2309 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2310 'replica_state': 'in_sync',
2311 ...
2312 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2313 'share_server': <models.ShareServer> or None,
2314 },
2315 {
2316 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2317 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2318 'replica_state': 'active',
2319 ...
2320 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
2321 'share_server': <models.ShareServer> or None,
2322 },
2323 ...
2324 ]
2325
2326 :param replica_snapshots: List of dictionaries of snapshot instances.
2327 These snapshot instances track the snapshot across the replicas.
2328 All the instances will have their status attribute set to
2329 'deleting'.
2330
2331 Example::
2332
2333 [
2334 {
2335 'id': 'd3931a93-3984-421e-a9e7-d9f71895450a',
2336 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2337 'status': 'deleting',
2338 'progress': '100%',
2339 ...
2340 },
2341 {
2342 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
2343 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2344 'status: 'deleting',
2345 'progress': '100%',
2346 ...
2347 },
2348 ...
2349 ]
2350
2351 :param share_server: <models.ShareServer> or None
2352 :return: List of dictionaries of snapshot instances.
2353 The dictionaries can contain values that need to be updated on the
2354 database for the snapshot instances being deleted. To confirm the
2355 deletion of the snapshot instance, set the 'status' attribute of
2356 the instance to 'deleted' (constants.STATUS_DELETED)
2357 :raises: Exception.
2358 Any exception in this method will set the status attribute of all
2359 snapshot instances to 'error_deleting'.
2360 """
2361 raise NotImplementedError()
2362
2363 def update_replicated_snapshot(self, context, replica_list,
2364 share_replica, replica_snapshots,
2365 replica_snapshot, share_server=None):
2366 """Update the status of a snapshot instance that lives on a replica.
2367
2368 .. note::
2369 For DR and Readable styles of replication, this call is made on
2370 the replica's host and not the 'active' replica's host.
2371
2372 This method is called periodically by the share manager. It will
2373 query for snapshot instances that track the parent snapshot across
2374 non-'active' replicas. Drivers can expect the status of the instance to
2375 be 'creating' or 'deleting'. If the driver sees that a snapshot
2376 instance has been removed from the replica's backend and the
2377 instance status was set to 'deleting', it is expected to raise a
2378 SnapshotResourceNotFound exception. All other exceptions will set the
2379 snapshot instance status to 'error'. If the instance was not in
2380 'deleting' state, raising a SnapshotResourceNotFound will set the
2381 instance status to 'error'.
2382
2383 :param context: Current context
2384 :param replica_list: List of all replicas for a particular share
2385 The 'active' replica will have its 'replica_state' attr set to
2386 'active'.
2387
2388 Example::
2389
2390 [
2391 {
2392 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2393 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2394 'replica_state': 'in_sync',
2395 ...
2396 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2397 'share_server': <models.ShareServer> or None,
2398 },
2399 {
2400 'id': '10e49c3e-aca9-483b-8c2d-1c337b38d6af',
2401 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2402 'replica_state': 'active',
2403 ...
2404 'share_server_id': 'f63629b3-e126-4448-bec2-03f788f76094',
2405 'share_server': <models.ShareServer> or None,
2406 },
2407 ...
2408 ]
2409
2410 :param share_replica: Share replica dictionary.
2411 This replica is associated with the snapshot instance whose
2412 status is being updated. Replicas in 'active' replica_state will
2413 not be passed via this parameter.
2414
2415 Example::
2416
2417 {
2418 'id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2419 'share_id': 'f0e4bb5e-65f0-11e5-9d70-feff819cdc9f',
2420 'deleted': False,
2421 'host': 'openstack2@cmodeSSVMNFS1',
2422 'status': 'available',
2423 'scheduled_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2424 'launched_at': datetime.datetime(2015, 8, 10, 0, 5, 58),
2425 'terminated_at': None,
2426 'replica_state': 'in_sync',
2427 'availability_zone_id': 'e2c2db5c-cb2f-4697-9966-c06fb200cb80',
2428 'export_locations': [
2429 models.ShareInstanceExportLocations,
2430 ],
2431 'access_rules_status': 'in_sync',
2432 'share_network_id': '4ccd5318-65f1-11e5-9d70-feff819cdc9f',
2433 'share_server_id': '4ce78e7b-0ef6-4730-ac2a-fd2defefbd05',
2434 }
2435
2436 :param replica_snapshots: List of dictionaries of snapshot instances.
2437 These snapshot instances track the snapshot across the replicas.
2438 This will include the snapshot instance being updated as well.
2439
2440 Example::
2441
2442 [
2443 {
2444 'id': 'd3931a93-3984-421e-a9e7-d9f71895450a',
2445 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2446 ...
2447 },
2448 {
2449 'id': '8bda791c-7bb6-4e7b-9b64-fefff85ff13e',
2450 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2451 ...
2452 },
2453 ...
2454 ]
2455
2456 :param replica_snapshot: Dictionary of the snapshot instance.
2457 This is the instance to be updated. It will be in 'creating' or
2458 'deleting' state when sent via this parameter.
2459
2460 Example::
2461
2462 {
2463 'name': 'share-snapshot-18825630-574f-4912-93bb-af4611ef35a2',
2464 'share_id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2465 'share_name': 'share-d487b88d-e428-4230-a465-a800c2cce5f8',
2466 'status': 'creating',
2467 'id': '18825630-574f-4912-93bb-af4611ef35a2',
2468 'deleted': False,
2469 'created_at': datetime.datetime(2016, 8, 3, 0, 5, 58),
2470 'share': <models.ShareInstance>,
2471 'updated_at': datetime.datetime(2016, 8, 3, 0, 5, 58),
2472 'share_instance_id': 'd487b88d-e428-4230-a465-a800c2cce5f8',
2473 'snapshot_id': '13ee5cb5-fc53-4539-9431-d983b56c5c40',
2474 'progress': '0%',
2475 'deleted_at': None,
2476 'provider_location': None,
2477 }
2478
2479 :param share_server: <models.ShareServer> or None
2480 :return: replica_snapshot_model_update: a dictionary.
2481 The dictionary must contain values that need to be updated on the
2482 database for the snapshot instance that represents the snapshot on
2483 the replica.
2484 :raises: exception.SnapshotResourceNotFound
2485 Raise this exception for snapshots that are not found on the
2486 backend and their status was 'deleting'.
2487 """
2488 raise NotImplementedError()
2489
2490 def get_filter_function(self):
2491 """Get filter_function string.
2492
2493 Returns either the string from the driver instance or global section
2494 in manila.conf. If nothing is specified in manila.conf, then try to
2495 find the default filter_function. When None is returned the scheduler
2496 will always pass the driver instance.
2497
2498 :return: a filter_function string or None
2499 """
2500 ret_function = self.configuration.filter_function
2501 if not ret_function:
2502 ret_function = CONF.filter_function
2503 if not ret_function:
2504 # pylint: disable=assignment-from-none
2505 ret_function = self.get_default_filter_function()
2506 # pylint: enable=assignment-from-none
2507 return ret_function
2508
2509 def get_goodness_function(self):
2510 """Get good_function string.
2511
2512 Returns either the string from the driver instance or global section
2513 in manila.conf. If nothing is specified in manila.conf, then try to
2514 find the default goodness_function. When None is returned the scheduler
2515 will give the lowest score to the driver instance.
2516
2517 :return: a goodness_function string or None
2518 """
2519 ret_function = self.configuration.goodness_function
2520 if not ret_function:
2521 ret_function = CONF.goodness_function
2522 if not ret_function:
2523 # pylint: disable=assignment-from-none
2524 ret_function = self.get_default_goodness_function()
2525 # pylint: enable=assignment-from-none
2526 return ret_function
2527
2528 def get_default_filter_function(self):
2529 """Get the default filter_function string.
2530
2531 Each driver could overwrite the method to return a well-known
2532 default string if it is available.
2533
2534 :return: None
2535 """
2536 return None
2537
2538 def get_default_goodness_function(self):
2539 """Get the default goodness_function string.
2540
2541 Each driver could overwrite the method to return a well-known
2542 default string if it is available.
2543
2544 :return: None
2545 """
2546 return None
2547
2548 def snapshot_update_access(self, context, snapshot, access_rules,
2549 add_rules, delete_rules, share_server=None):
2550 """Update access rules for given snapshot.
2551
2552 ``access_rules`` contains all access_rules that need to be on the
2553 share. If the driver can make bulk access rule updates, it can
2554 safely ignore the ``add_rules`` and ``delete_rules`` parameters.
2555
2556 If the driver cannot make bulk access rule changes, it can rely on
2557 new rules to be present in ``add_rules`` and rules that need to be
2558 removed to be present in ``delete_rules``.
2559
2560 When a rule in ``add_rules`` already exists in the back end, drivers
2561 must not raise an exception. When a rule in ``delete_rules`` was never
2562 applied, drivers must not raise an exception, or attempt to set the
2563 rule to ``error`` state.
2564
2565 ``add_rules`` and ``delete_rules`` can be empty lists, in this
2566 situation, drivers should ensure that the rules present in
2567 ``access_rules`` are the same as those on the back end.
2568
2569 :param context: Current context
2570 :param snapshot: Snapshot model with snapshot data.
2571 :param access_rules: All access rules for given snapshot
2572 :param add_rules: Empty List or List of access rules which should be
2573 added. access_rules already contains these rules.
2574 :param delete_rules: Empty List or List of access rules which should be
2575 removed. access_rules doesn't contain these rules.
2576 :param share_server: None or Share server model
2577 """
2578 raise NotImplementedError()
2579
2580 def update_share_usage_size(self, context, shares):
2581 """Invoked to get the usage size of given shares.
2582
2583 Driver can use this method to update the share usage size of
2584 the shares. To do that, a dictionary of shares should be
2585 returned.
2586 :param shares: None or a list of all shares for updates.
2587 :returns: An empty list or a list of dictionary of updates in the
2588 following format. The value of "used_size" can be specified in GiB
2589 units, as a floating point number::
2590
2591 [
2592 {
2593 'id': '09960614-8574-4e03-89cf-7cf267b0bd08',
2594 'used_size': '200',
2595 'gathered_at': datetime.datetime(2017, 8, 10, 15, 14, 6),
2596 },
2597 ]
2598
2599 """
2600 LOG.debug("This backend does not support gathering 'used_size' of "
2601 "shares created on it.")
2602 return []
2603
2604 def get_configured_ip_versions(self):
2605 """"Get allowed IP versions.
2606
2607 The supported versions are returned with list, possible
2608 values are: [4], [6], or [4, 6]
2609
2610 Drivers that assert ipv6_implemented = True must override
2611 this method. If the returned list includes 4, then shares
2612 created by this driver must have an IPv4 export location.
2613 If the list includes 6, then shares created by the driver
2614 must have an IPv6 export location.
2615
2616 Drivers should check that their storage controller actually
2617 has IPv4/IPv6 enabled and configured properly.
2618 """
2619
2620 # For drivers that haven't implemented IPv6, assume legacy behavior
2621 if not self.ipv6_implemented:
2622 return [4]
2623
2624 raise NotImplementedError()
2625
2626 def add_ip_version_capability(self, data):
2627 """Add IP version support capabilities.
2628
2629 When DHSS is true, the capabilities are determined by driver
2630 and configured network plugin.
2631 When DHSS is false, the capabilities are determined by driver
2632 only.
2633 :param data: the capability dictionary
2634 :returns: capability data
2635 """
2636 self.ip_versions = self.get_configured_ip_versions()
2637 if isinstance(self.ip_versions, list):
2638 self.ip_versions = set(self.ip_versions)
2639 else:
2640 self.ip_versions = set(list(self.ip_versions))
2641
2642 if not self.ip_versions:
2643 LOG.error("Backend %s supports neither IPv4 nor IPv6.",
2644 data['share_backend_name'])
2645
2646 if self.driver_handles_share_servers:
2647 network_versions = self.network_api.enabled_ip_versions
2648 self.ip_versions = self.ip_versions & network_versions
2649 if not self.ip_versions:
2650 LOG.error("The enabled IP version of the network plugin is "
2651 "not compatible with the version supported by "
2652 "backend %s.", data['share_backend_name'])
2653
2654 data['ipv4_support'] = (4 in self.ip_versions)
2655 data['ipv6_support'] = (6 in self.ip_versions)
2656 return data
2657
2658 def get_backend_info(self, context):
2659 """Get driver and array configuration parameters.
2660
2661 Driver can use this method to get the special configuration info and
2662 return for assessment.
2663
2664 :returns: A dictionary containing driver-specific info.
2665
2666 Example::
2667
2668 {
2669 'version': '2.23'
2670 'port': '80',
2671 'logicalportip': '1.1.1.1',
2672 ...
2673 }
2674
2675 """
2676 raise NotImplementedError()
2677
2678 def ensure_shares(self, context, shares):
2679 """Invoked to ensure that shares are exported.
2680
2681 Driver can use this method to update the list of export locations of
2682 the shares if it changes. To do that, a dictionary of shares should
2683 be returned.
2684 :shares: A list of all shares for updates.
2685 :returns: None or a dictionary of updates in the format.
2686
2687 Example::
2688
2689 {
2690 '09960614-8574-4e03-89cf-7cf267b0bd08': {
2691 'export_locations': [{...}, {...}],
2692 'status': 'error',
2693 },
2694
2695 '28f6eabb-4342-486a-a7f4-45688f0c0295': {
2696 'export_locations': [{...}, {...}],
2697 'status': 'available',
2698 },
2699
2700 }
2701
2702 """
2703 raise NotImplementedError()
2704
2705 def get_share_server_network_info(
2706 self, context, share_server, identifier, driver_options):
2707 """Obtain network allocations used by share server.
2708
2709 :param context: Current context.
2710 :param share_server: Share server model.
2711 :param identifier: A driver-specific share server identifier
2712 :param driver_options: Dictionary of driver options to assist managing
2713 the share server
2714 :return: A list containing IP addresses allocated in the backend.
2715
2716 Example::
2717
2718 ['10.10.10.10', 'fd11::2000', '192.168.10.10']
2719
2720 """
2721 raise NotImplementedError()
2722
2723 def manage_server(self, context, share_server, identifier, driver_options):
2724 """Manage the share server and return compiled back end details.
2725
2726 :param context: Current context.
2727 :param share_server: Share server model.
2728 :param identifier: A driver-specific share server identifier
2729 :param driver_options: Dictionary of driver options to assist managing
2730 the share server
2731 :return: Identifier and dictionary with back end details to be saved
2732 in the database.
2733
2734 Example::
2735
2736 'my_new_server_identifier',{'server_name': 'my_old_server'}
2737
2738 """
2739 raise NotImplementedError()
2740
2741 def unmanage_server(self, server_details, security_services=None):
2742 """Unmanages the share server.
2743
2744 If a driver supports unmanaging of share servers, the driver must
2745 override this method and return successfully.
2746
2747 :param server_details: share server backend details.
2748 :param security_services: list of security services configured with
2749 this share server.
2750 """
2751 raise NotImplementedError()