Merge "Allow configuration of a back end specific availability zone"

This commit is contained in:
Zuul 2019-01-24 11:52:28 +00:00 committed by Gerrit Code Review
commit 49afbfc0fc
10 changed files with 64 additions and 19 deletions

View File

@ -122,7 +122,7 @@ The following examples have been implemented with the ZFSonLinux driver that
is a reference implementation in the Shared File Systems service. It operates is a reference implementation in the Shared File Systems service. It operates
in ``driver_handles_share_servers=False`` mode and supports the ``readable`` in ``driver_handles_share_servers=False`` mode and supports the ``readable``
type of replication. In the example, we assume a configuration of two type of replication. In the example, we assume a configuration of two
Availability Zones (configuration option: ``storage_availability_zone``), Availability Zones [1]_,
called `availability_zone_1` and `availability_zone_2`. called `availability_zone_1` and `availability_zone_2`.
Multiple availability zones are not necessary to use the replication feature. Multiple availability zones are not necessary to use the replication feature.
@ -598,3 +598,14 @@ replica's ID to delete a share replica.
.. note:: .. note::
You cannot delete the last ``active`` replica with this command. You should You cannot delete the last ``active`` replica with this command. You should
use the :command:`manila delete` command to remove the share. use the :command:`manila delete` command to remove the share.
.. [1] When running in a multi-backend configuration, until the Stein
release, deployers could only configure one Availability Zone per manila
configuration file. This is achieved with the option
``storage_availability_zone`` defined under the ``[DEFAULT]`` section.
Beyond the Stein release, the option ``backend_availability_zone``
can be specified in each back end stanza. The value of this
configuration option will override any configuration of the
``storage_availability_zone`` from the ``[DEFAULT]`` section.

View File

@ -56,8 +56,9 @@ pools, manila would allow for replication between two pools on the same
backend. backend.
The ``replication_domain`` option is meant to be used in conjunction with the The ``replication_domain`` option is meant to be used in conjunction with the
``storage_availability_zone`` option to utilize this solution for Data ``storage_availability_zone`` (or back end specific
Protection/Disaster Recovery. ``backend_availability_zone``) option to utilize
this solution for Data Protection/Disaster Recovery.
Replication types Replication types

View File

@ -91,6 +91,7 @@ class Manager(base.Base, PeriodicTasks):
host = CONF.host host = CONF.host
self.host = host self.host = host
self.additional_endpoints = [] self.additional_endpoints = []
self.availability_zone = CONF.storage_availability_zone
super(Manager, self).__init__(db_driver) super(Manager, self).__init__(db_driver)
def periodic_tasks(self, context, raise_on_error=False): def periodic_tasks(self, context, raise_on_error=False):

View File

@ -92,6 +92,7 @@ class Service(service.Service):
self.manager = manager_class(host=self.host, self.manager = manager_class(host=self.host,
service_name=service_name, service_name=service_name,
*args, **kwargs) *args, **kwargs)
self.availability_zone = self.manager.availability_zone
self.report_interval = report_interval self.report_interval = report_interval
self.periodic_interval = periodic_interval self.periodic_interval = periodic_interval
self.periodic_fuzzy_delay = periodic_fuzzy_delay self.periodic_fuzzy_delay = periodic_fuzzy_delay
@ -145,13 +146,14 @@ class Service(service.Service):
self.timers.append(periodic) self.timers.append(periodic)
def _create_service_ref(self, context): def _create_service_ref(self, context):
zone = CONF.storage_availability_zone service_args = {
service_ref = db.service_create(context, 'host': self.host,
{'host': self.host,
'binary': self.binary, 'binary': self.binary,
'topic': self.topic, 'topic': self.topic,
'report_count': 0, 'report_count': 0,
'availability_zone': zone}) 'availability_zone': self.availability_zone
}
service_ref = db.service_create(context, service_args)
self.service_id = service_ref['id'] self.service_id = service_ref['id']
def __getattr__(self, key): def __getattr__(self, key):
@ -244,7 +246,6 @@ class Service(service.Service):
def report_state(self): def report_state(self):
"""Update the state of this service in the datastore.""" """Update the state of this service in the datastore."""
ctxt = context.get_admin_context() ctxt = context.get_admin_context()
zone = CONF.storage_availability_zone
state_catalog = {} state_catalog = {}
try: try:
try: try:
@ -256,8 +257,9 @@ class Service(service.Service):
service_ref = db.service_get(ctxt, self.service_id) service_ref = db.service_get(ctxt, self.service_id)
state_catalog['report_count'] = service_ref['report_count'] + 1 state_catalog['report_count'] = service_ref['report_count'] + 1
if zone != service_ref['availability_zone']['name']: if (self.availability_zone !=
state_catalog['availability_zone'] = zone service_ref['availability_zone']['name']):
state_catalog['availability_zone'] = self.availability_zone
db.service_update(ctxt, db.service_update(ctxt,
self.service_id, state_catalog) self.service_id, state_catalog)

View File

@ -126,6 +126,11 @@ share_opts = [
"replication between each other. If this option is not " "replication between each other. If this option is not "
"specified in the group, it means that replication is not " "specified in the group, it means that replication is not "
"enabled on the backend."), "enabled on the backend."),
cfg.StrOpt('backend_availability_zone',
default=None,
help='Availability zone for this share backend. If not set, '
'the ``storage_availability_zone`` option from the '
'``[DEFAULT]`` section is used.'),
cfg.StrOpt('filter_function', cfg.StrOpt('filter_function',
help='String representation for an equation that will be ' help='String representation for an equation that will be '
'used to filter hosts.'), 'used to filter hosts.'),

View File

@ -219,6 +219,9 @@ class ServiceInstanceManager(object):
self.max_time_to_build_instance = self.get_config_option( self.max_time_to_build_instance = self.get_config_option(
"max_time_to_build_instance") "max_time_to_build_instance")
self.availability_zone = self.get_config_option(
'backend_availability_zone') or CONF.storage_availability_zone
if self.get_config_option("driver_handles_share_servers"): if self.get_config_option("driver_handles_share_servers"):
self.path_to_public_key = self.get_config_option( self.path_to_public_key = self.get_config_option(
"path_to_public_key") "path_to_public_key")
@ -564,7 +567,7 @@ class ServiceInstanceManager(object):
flavor=self.get_config_option("service_instance_flavor_id"), flavor=self.get_config_option("service_instance_flavor_id"),
key_name=key_name, key_name=key_name,
nics=network_data['nics'], nics=network_data['nics'],
availability_zone=CONF.storage_availability_zone, availability_zone=self.availability_zone,
**create_kwargs) **create_kwargs)
fail_safe_data['instance_id'] = service_instance['id'] fail_safe_data['instance_id'] = service_instance['id']

View File

@ -239,6 +239,12 @@ class ShareManager(manager.SchedulerDependentManager):
configuration=self.configuration, configuration=self.configuration,
) )
backend_availability_zone = self.driver.configuration.safe_get(
'backend_availability_zone')
self.availability_zone = (
backend_availability_zone or CONF.storage_availability_zone
)
self.access_helper = access.ShareInstanceAccess(self.db, self.driver) self.access_helper = access.ShareInstanceAccess(self.db, self.driver)
self.snapshot_access_helper = ( self.snapshot_access_helper = (
snapshot_access.ShareSnapshotInstanceAccess(self.db, self.driver)) snapshot_access.ShareSnapshotInstanceAccess(self.db, self.driver))
@ -1659,7 +1665,7 @@ class ShareManager(manager.SchedulerDependentManager):
if not share_instance['availability_zone']: if not share_instance['availability_zone']:
share_instance = self.db.share_instance_update( share_instance = self.db.share_instance_update(
context, share_instance_id, context, share_instance_id,
{'availability_zone': CONF.storage_availability_zone}, {'availability_zone': self.availability_zone},
with_share_data=True with_share_data=True
) )
@ -1834,7 +1840,7 @@ class ShareManager(manager.SchedulerDependentManager):
if not share_replica['availability_zone']: if not share_replica['availability_zone']:
share_replica = self.db.share_replica_update( share_replica = self.db.share_replica_update(
context, share_replica['id'], context, share_replica['id'],
{'availability_zone': CONF.storage_availability_zone}, {'availability_zone': self.availability_zone},
with_share_data=True with_share_data=True
) )
@ -2400,7 +2406,7 @@ class ShareManager(manager.SchedulerDependentManager):
share_update.update({ share_update.update({
'status': constants.STATUS_AVAILABLE, 'status': constants.STATUS_AVAILABLE,
'launched_at': timeutils.utcnow(), 'launched_at': timeutils.utcnow(),
'availability_zone': CONF.storage_availability_zone, 'availability_zone': self.availability_zone,
}) })
# If the share was managed with `replication_type` extra-spec, the # If the share was managed with `replication_type` extra-spec, the
@ -3865,7 +3871,7 @@ class ShareManager(manager.SchedulerDependentManager):
def _get_az_for_share_group(self, context, share_group_ref): def _get_az_for_share_group(self, context, share_group_ref):
if not share_group_ref['availability_zone_id']: if not share_group_ref['availability_zone_id']:
return self.db.availability_zone_get( return self.db.availability_zone_get(
context, CONF.storage_availability_zone)['id'] context, self.availability_zone)['id']
return share_group_ref['availability_zone_id'] return share_group_ref['availability_zone_id']
@utils.require_driver_initialized @utils.require_driver_initialized

View File

@ -75,6 +75,8 @@ def fake_get_config_option(key):
return None return None
elif key == 'admin_subnet_id': elif key == 'admin_subnet_id':
return None return None
elif key == 'backend_availability_zone':
return None
else: else:
return mock.Mock() return mock.Mock()

View File

@ -990,7 +990,7 @@ class ShareManagerTestCase(test.TestCase):
replica_2 = fake_replica(id='fake2') replica_2 = fake_replica(id='fake2')
self.mock_object(db, 'share_replicas_get_all_by_share', self.mock_object(db, 'share_replicas_get_all_by_share',
mock.Mock(return_value=[replica, replica_2])) mock.Mock(return_value=[replica, replica_2]))
manager.CONF.set_default('storage_availability_zone', 'fake_az') self.share_manager.availability_zone = 'fake_az'
fake_access_rules = [{'id': '1'}, {'id': '2'}, {'id': '3'}] fake_access_rules = [{'id': '1'}, {'id': '2'}, {'id': '3'}]
self.mock_object(db, 'share_replica_get', self.mock_object(db, 'share_replica_get',
mock.Mock(return_value=replica)) mock.Mock(return_value=replica))

View File

@ -0,0 +1,14 @@
---
features:
- |
Availability zones may now be configured per backend in a multi-backend
configuration. Individual back end sections can now have the configuration
option ``backend_availability_zone`` set. If set, this value will override
the ``storage_availability_zone`` option from the [DEFAULT] section.
upgrade:
- The ``storage_availability_zone`` option can now be overridden per
backend by using the ``backend_availability_zone`` option within the
backend stanza. This allows enabling multiple storage backends that may
be deployed in different AZs in the same ``manila.conf`` file if
desired, simplifying service architecture around the Share Replication
feature.