"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()