94e04c8de2
When taking a snapshot of a replicated share, users would expect the snapshot to be available across the replicas. Currently, Manila assumes that drivers will take snapshots along with the share data. Different backends implement replication differently. Many of them assume that replicas are 'in_sync' with the primary if they have been synchronized within a particular window of time (sometimes referred to as 'recovery point objective'). Since snapshots are point in time actions on a share, drivers must ensure that the replication of a snapshot begins as soon as it is available on the primary/'active' instance. To ensure that snapshots are indeed available across replicas: 1) Track snapshots across replicas as different snapshot instances. 2) Make an 'aggregate_status' property to convey the availability of a snapshot across all the active/in_sync replicas of a share. 3) Provide all the information necessary for drivers to: - Create a snapshot on the primary and send it across to all replicas - Delete a snapshot on the primary and ensure that it is deleted on the replicas as well. 4) Set snapshot instance to 'error' if it was in any transitional state when its replica was 'promoted' to become an 'active' instance. 5) Pass down snapshot instances during create, delete and update replica driver calls. 6) Update replica interfaces to pass in snapshot instance data. Always include 'available' snapshots in the update_replica call to ensure that drivers confirm their presence on the replica in order to report that the replica is 'in_sync'. Also, grab the share_type afresh from parent share/snapshot to allow 'replication_key' to be copied to the share model during share creation. Rename SnapshotNotFound to SnapshotResourceNotFound to signify a missing snapshot object on backends. APIImpact The 'status' attribute of the snapshot is now the 'aggregate_status' of the instances of the snapshot. No key changes have been made in the JSON response. However, API actions will be gated against 'aggregate_status' of the snapshot instances when more than one instance exists. Closes-Bug: #1546303 Closes-Bug: #1551064 Change-Id: I63203df00904d209e9e92eda7c79206e5ef8d611
210 lines
6.2 KiB
Python
210 lines
6.2 KiB
Python
# Copyright 2015 Mirantis Inc.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import copy
|
|
|
|
from manila.common import constants
|
|
from manila import context
|
|
from manila import db
|
|
|
|
|
|
def _create_db_row(method, default_values, custom_values):
|
|
override_defaults = custom_values.pop('override_defaults', None)
|
|
if override_defaults:
|
|
default_values = custom_values
|
|
else:
|
|
default_values.update(copy.deepcopy(custom_values))
|
|
return method(context.get_admin_context(), default_values)
|
|
|
|
|
|
def create_consistency_group(**kwargs):
|
|
"""Create a consistency group object."""
|
|
cg = {
|
|
'share_network_id': None,
|
|
'share_server_id': None,
|
|
'user_id': 'fake',
|
|
'project_id': 'fake',
|
|
'status': constants.STATUS_CREATING,
|
|
'host': 'fake_host'
|
|
}
|
|
return _create_db_row(db.consistency_group_create, cg, kwargs)
|
|
|
|
|
|
def create_cgsnapshot(cg_id, **kwargs):
|
|
"""Create a cgsnapshot object."""
|
|
snapshot = {
|
|
'consistency_group_id': cg_id,
|
|
'user_id': 'fake',
|
|
'project_id': 'fake',
|
|
'status': constants.STATUS_CREATING,
|
|
}
|
|
return _create_db_row(db.cgsnapshot_create, snapshot, kwargs)
|
|
|
|
|
|
def create_cgsnapshot_member(cgsnapshot_id, **kwargs):
|
|
"""Create a cgsnapshot member object."""
|
|
member = {
|
|
'share_proto': "NFS",
|
|
'size': 0,
|
|
'share_id': None,
|
|
'share_instance_id': None,
|
|
'user_id': 'fake',
|
|
'project_id': 'fake',
|
|
'status': 'creating',
|
|
'cgsnapshot_id': cgsnapshot_id,
|
|
}
|
|
return _create_db_row(db.cgsnapshot_member_create, member, kwargs)
|
|
|
|
|
|
def create_share(**kwargs):
|
|
"""Create a share object."""
|
|
share = {
|
|
'share_proto': "NFS",
|
|
'size': 0,
|
|
'snapshot_id': None,
|
|
'share_network_id': None,
|
|
'share_server_id': None,
|
|
'user_id': 'fake',
|
|
'project_id': 'fake',
|
|
'metadata': {'fake_key': 'fake_value'},
|
|
'availability_zone': 'fake_availability_zone',
|
|
'status': constants.STATUS_CREATING,
|
|
'host': 'fake_host'
|
|
}
|
|
return _create_db_row(db.share_create, share, kwargs)
|
|
|
|
|
|
def create_share_instance(**kwargs):
|
|
"""Create a share instance object."""
|
|
instance = {
|
|
'host': 'fake',
|
|
'status': constants.STATUS_CREATING,
|
|
}
|
|
instance.update(kwargs)
|
|
|
|
return db.share_instance_create(context.get_admin_context(),
|
|
kwargs.pop('share_id'), kwargs)
|
|
|
|
|
|
def create_share_replica(**kwargs):
|
|
"""Create a share replica object."""
|
|
replica = {
|
|
'host': 'fake',
|
|
'status': constants.STATUS_CREATING,
|
|
}
|
|
replica.update(kwargs)
|
|
|
|
if 'share_id' not in kwargs:
|
|
share = create_share()
|
|
kwargs['share_id'] = share['id']
|
|
|
|
return db.share_instance_create(context.get_admin_context(),
|
|
kwargs.pop('share_id'), kwargs)
|
|
|
|
|
|
def create_snapshot(**kwargs):
|
|
"""Create a snapshot object."""
|
|
with_share = kwargs.pop('with_share', False)
|
|
|
|
share = None
|
|
if with_share:
|
|
share = create_share(status=constants.STATUS_AVAILABLE,
|
|
size=kwargs.get('size', 0))
|
|
|
|
snapshot = {
|
|
'share_proto': "NFS",
|
|
'size': 0,
|
|
'share_id': share['id'] if with_share else None,
|
|
'user_id': 'fake',
|
|
'project_id': 'fake',
|
|
'status': 'creating',
|
|
'provider_location': 'fake',
|
|
}
|
|
snapshot.update(kwargs)
|
|
return db.share_snapshot_create(context.get_admin_context(), snapshot)
|
|
|
|
|
|
def create_snapshot_instance(snapshot_id, **kwargs):
|
|
"""Create a share snapshot instance object."""
|
|
|
|
snapshot_instance = {
|
|
'provider_location': 'fake_provider_location',
|
|
'progress': '0%',
|
|
'status': constants.STATUS_CREATING,
|
|
}
|
|
|
|
snapshot_instance.update(kwargs)
|
|
return db.share_snapshot_instance_create(
|
|
context.get_admin_context(), snapshot_id, snapshot_instance)
|
|
|
|
|
|
def create_access(**kwargs):
|
|
"""Create a access rule object."""
|
|
access = {
|
|
'access_type': 'fake_type',
|
|
'access_to': 'fake_IP',
|
|
'share_id': None,
|
|
}
|
|
return _create_db_row(db.share_access_create, access, kwargs)
|
|
|
|
|
|
def create_share_server(**kwargs):
|
|
"""Create a share server object."""
|
|
backend_details = kwargs.pop('backend_details', {})
|
|
srv = {
|
|
'host': 'host1',
|
|
'share_network_id': 'fake_srv_id',
|
|
'status': constants.STATUS_ACTIVE
|
|
}
|
|
share_srv = _create_db_row(db.share_server_create, srv, kwargs)
|
|
if backend_details:
|
|
db.share_server_backend_details_set(
|
|
context.get_admin_context(), share_srv['id'], backend_details)
|
|
return db.share_server_get(context.get_admin_context(),
|
|
share_srv['id'])
|
|
|
|
|
|
def create_share_network(**kwargs):
|
|
"""Create a share network object."""
|
|
net = {
|
|
'user_id': 'fake',
|
|
'project_id': 'fake',
|
|
'neutron_net_id': 'fake-neutron-net',
|
|
'neutron_subnet_id': 'fake-neutron-subnet',
|
|
'status': 'new',
|
|
'network_type': 'vlan',
|
|
'segmentation_id': 1000,
|
|
'cidr': '10.0.0.0/24',
|
|
'ip_version': 4,
|
|
'name': 'whatever',
|
|
'description': 'fake description',
|
|
}
|
|
return _create_db_row(db.share_network_create, net, kwargs)
|
|
|
|
|
|
def create_security_service(**kwargs):
|
|
share_network_id = kwargs.pop('share_network_id', None)
|
|
service = {
|
|
'type': "FAKE",
|
|
'project_id': 'fake-project-id',
|
|
}
|
|
service_ref = _create_db_row(db.security_service_create, service, kwargs)
|
|
|
|
if share_network_id:
|
|
db.share_network_add_security_service(context.get_admin_context(),
|
|
share_network_id,
|
|
service_ref['id'])
|
|
return service_ref
|