Add DB changes for consistency-groups
This patch adds the database migrations and db api changes needed for the consistency groups feature. Partially implements bp manila-consistency-groups Change-Id: Id6fe4b77f0d31c3f0ade595b11d413cc6ac5f4c2
This commit is contained in:
parent
15a9d4c5a6
commit
9e9d904412
139
manila/db/api.py
139
manila/db/api.py
@ -330,6 +330,10 @@ def share_instances_get_all_by_share(context, share_id):
|
||||
return IMPL.share_instances_get_all_by_share_network(context, share_id)
|
||||
|
||||
|
||||
def share_instances_get_all_by_consistency_group_id(context, cg_id):
|
||||
"""Returns list of share instances that belong to given cg."""
|
||||
return IMPL.share_instances_get_all_by_consistency_group_id(context, cg_id)
|
||||
|
||||
###################
|
||||
|
||||
|
||||
@ -370,6 +374,23 @@ def share_get_all_by_project(context, project_id, filters=None,
|
||||
)
|
||||
|
||||
|
||||
def share_get_all_by_consistency_group_id(context, cg_id,
|
||||
filters=None, sort_key=None,
|
||||
sort_dir=None):
|
||||
"""Returns all shares with given project ID and CG id."""
|
||||
return IMPL.share_get_all_by_consistency_group_id(
|
||||
context, cg_id, filters=filters,
|
||||
sort_key=sort_key, sort_dir=sort_dir)
|
||||
|
||||
|
||||
def share_get_all_by_share_network(context, share_network_id, filters=None,
|
||||
sort_key=None, sort_dir=None):
|
||||
"""Returns list of shares that belong to given share network."""
|
||||
return IMPL.share_get_all_by_share_network(
|
||||
context, share_network_id, filters=filters, sort_key=sort_key,
|
||||
sort_dir=sort_dir)
|
||||
|
||||
|
||||
def share_get_all_by_share_server(context, share_server_id, filters=None,
|
||||
sort_key=None, sort_dir=None):
|
||||
"""Returns all shares with given share server ID."""
|
||||
@ -847,3 +868,121 @@ def availability_zone_get(context, id_or_name):
|
||||
def availability_zone_get_all(context):
|
||||
"""Get all active availability zones."""
|
||||
return IMPL.availability_zone_get_all(context)
|
||||
|
||||
|
||||
####################
|
||||
|
||||
def consistency_group_get(context, consistency_group_id):
|
||||
"""Get a consistency group or raise if it does not exist."""
|
||||
return IMPL.consistency_group_get(context, consistency_group_id)
|
||||
|
||||
|
||||
def consistency_group_get_all(context, detailed=True):
|
||||
"""Get all consistency groups."""
|
||||
return IMPL.consistency_group_get_all(context, detailed=detailed)
|
||||
|
||||
|
||||
def consistency_group_get_all_by_host(context, host, detailed=True):
|
||||
"""Get all consistency groups belonging to a host."""
|
||||
return IMPL.consistency_group_get_all_by_host(context, host,
|
||||
detailed=detailed)
|
||||
|
||||
|
||||
def consistency_group_create(context, values):
|
||||
"""Create a consistency group from the values dictionary."""
|
||||
return IMPL.consistency_group_create(context, values)
|
||||
|
||||
|
||||
def consistency_group_get_all_by_project(context, project_id, detailed=True):
|
||||
"""Get all consistency groups belonging to a project."""
|
||||
return IMPL.consistency_group_get_all_by_project(context, project_id,
|
||||
detailed=detailed)
|
||||
|
||||
|
||||
def consistency_group_update(context, consistency_group_id, values):
|
||||
"""Set the given properties on a consistency group and update it.
|
||||
|
||||
Raises NotFound if consistency group does not exist.
|
||||
"""
|
||||
return IMPL.consistency_group_update(context, consistency_group_id, values)
|
||||
|
||||
|
||||
def consistency_group_destroy(context, consistency_group_id):
|
||||
"""Destroy the consistency group or raise if it does not exist."""
|
||||
return IMPL.consistency_group_destroy(context, consistency_group_id)
|
||||
|
||||
|
||||
def count_shares_in_consistency_group(context, consistency_group_id):
|
||||
"""Returns the number of undeleted shares with the specified cg."""
|
||||
return IMPL.count_shares_in_consistency_group(context,
|
||||
consistency_group_id)
|
||||
|
||||
|
||||
def count_cgsnapshots_in_consistency_group(context, consistency_group_id):
|
||||
"""Returns the number of undeleted cgsnapshots with the specified cg."""
|
||||
return IMPL.count_cgsnapshots_in_consistency_group(context,
|
||||
consistency_group_id)
|
||||
|
||||
|
||||
def count_consistency_groups_in_share_network(context, share_network_id,
|
||||
session=None):
|
||||
"""Returns the number of undeleted cgs with the specified share network."""
|
||||
return IMPL.count_consistency_groups_in_share_network(context,
|
||||
share_network_id)
|
||||
|
||||
|
||||
def count_cgsnapshot_members_in_share(context, share_id, session=None):
|
||||
"""Returns the number of cgsnapshot members linked to the share."""
|
||||
return IMPL.count_cgsnapshot_members_in_share(context, share_id)
|
||||
|
||||
|
||||
def cgsnapshot_get(context, cgsnapshot_id):
|
||||
"""Get a cgsnapshot."""
|
||||
return IMPL.cgsnapshot_get(context, cgsnapshot_id)
|
||||
|
||||
|
||||
def cgsnapshot_get_all(context, detailed=True):
|
||||
"""Get all cgsnapshots."""
|
||||
return IMPL.cgsnapshot_get_all(context, detailed=detailed)
|
||||
|
||||
|
||||
def cgsnapshot_get_all_by_project(context, project_id, detailed=True):
|
||||
"""Get all cgsnapshots belonging to a project."""
|
||||
return IMPL.cgsnapshot_get_all_by_project(context, project_id,
|
||||
detailed=detailed)
|
||||
|
||||
|
||||
def cgsnapshot_create(context, values):
|
||||
"""Create a cgsnapshot from the values dictionary."""
|
||||
return IMPL.cgsnapshot_create(context, values)
|
||||
|
||||
|
||||
def cgsnapshot_update(context, cgsnapshot_id, values):
|
||||
"""Set the given properties on a cgsnapshot and update it.
|
||||
|
||||
Raises NotFound if cgsnapshot does not exist.
|
||||
"""
|
||||
return IMPL.cgsnapshot_update(context, cgsnapshot_id, values)
|
||||
|
||||
|
||||
def cgsnapshot_destroy(context, cgsnapshot_id):
|
||||
"""Destroy the cgsnapshot or raise if it does not exist."""
|
||||
return IMPL.cgsnapshot_destroy(context, cgsnapshot_id)
|
||||
|
||||
|
||||
def cgsnapshot_members_get_all(context, cgsnapshot_id):
|
||||
"""Return the members of a cgsnapshot."""
|
||||
return IMPL.cgsnapshot_members_get_all(context, cgsnapshot_id)
|
||||
|
||||
|
||||
def cgsnapshot_member_create(context, values):
|
||||
"""Create a cgsnapshot member from the values dictionary."""
|
||||
return IMPL.cgsnapshot_member_create(context, values)
|
||||
|
||||
|
||||
def cgsnapshot_member_update(context, member_id, values):
|
||||
"""Set the given properties on a cgsnapshot member and update it.
|
||||
|
||||
Raises NotFound if cgsnapshot member does not exist.
|
||||
"""
|
||||
return IMPL.cgsnapshot_member_update(context, member_id, values)
|
||||
|
@ -0,0 +1,200 @@
|
||||
# Copyright (c) 2015 Alex Meade
|
||||
# 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.
|
||||
|
||||
"""Create Consistency Groups Tables and Columns
|
||||
|
||||
Revision ID: 3651e16d7c43
|
||||
Revises: 55761e5f59c5
|
||||
Create Date: 2015-07-29 13:17:15.940454
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '3651e16d7c43'
|
||||
down_revision = '55761e5f59c5'
|
||||
|
||||
SHARE_NETWORK_FK_CONSTRAINT_NAME = "fk_cg_share_network_id"
|
||||
SHARE_SERVER_FK_CONSTRAINT_NAME = "fk_cg_share_server_id"
|
||||
SHARES_CG_FK_CONSTRAINT_NAME = "fk_shares_consistency_group_id"
|
||||
CG_MAP_FK_CONSTRAINT_NAME = "fk_cgstm_cg_id"
|
||||
SHARE_TYPE_FK_CONSTRAINT_NAME = "fk_cgstm_share_type_id"
|
||||
CGSNAP_CG_ID_FK_CONSTRAINT_NAME = "fk_cgsnapshots_consistency_group_id"
|
||||
CGSNAP_MEM_SHARETYPE_FK_CONSTRAINT_NAME = "fk_cgsnapshot_members_share_type_id"
|
||||
CGSNAP_MEM_SNAP_ID_FK_CONSTRAINT_NAME = "fk_cgsnapshot_members_cgsnapshot_id"
|
||||
CGSNAP_MEM_SHARE_FK_CONSTRAINT_NAME = "fk_cgsnapshot_members_share_id"
|
||||
CGSNAP_MEM_INST_FK_CONSTRAINT_NAME = "fk_cgsnapshot_members_share_instance_id"
|
||||
|
||||
from alembic import op
|
||||
from oslo_log import log
|
||||
import sqlalchemy as sa
|
||||
|
||||
from manila.i18n import _LE
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def upgrade():
|
||||
# New table - consistency_groups
|
||||
op.create_table(
|
||||
'consistency_groups',
|
||||
sa.Column('id', sa.String(36), primary_key=True, nullable=False),
|
||||
sa.Column('created_at', sa.DateTime),
|
||||
sa.Column('updated_at', sa.DateTime),
|
||||
sa.Column('deleted_at', sa.DateTime),
|
||||
sa.Column('deleted', sa.String(36), default='False'),
|
||||
|
||||
sa.Column('user_id', sa.String(length=255), nullable=False),
|
||||
sa.Column('project_id', sa.String(length=255), nullable=False),
|
||||
sa.Column('host', sa.String(length=255)),
|
||||
sa.Column('name', sa.String(length=255)),
|
||||
sa.Column('description', sa.String(length=255)),
|
||||
sa.Column('status', sa.String(length=255)),
|
||||
sa.Column('source_cgsnapshot_id', sa.String(length=36)),
|
||||
sa.Column('share_network_id', sa.String(length=36),
|
||||
sa.ForeignKey('share_networks.id',
|
||||
name=SHARE_NETWORK_FK_CONSTRAINT_NAME),
|
||||
nullable=True),
|
||||
sa.Column('share_server_id', sa.String(length=36),
|
||||
sa.ForeignKey('share_servers.id',
|
||||
name=SHARE_SERVER_FK_CONSTRAINT_NAME),
|
||||
nullable=True),
|
||||
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8')
|
||||
|
||||
op.add_column(
|
||||
'shares',
|
||||
sa.Column('consistency_group_id',
|
||||
sa.String(36),
|
||||
sa.ForeignKey('consistency_groups.id',
|
||||
name=SHARES_CG_FK_CONSTRAINT_NAME)))
|
||||
|
||||
op.add_column('shares',
|
||||
sa.Column('source_cgsnapshot_member_id', sa.String(36)))
|
||||
|
||||
op.create_table(
|
||||
'consistency_group_share_type_mappings',
|
||||
sa.Column('id', sa.String(36), primary_key=True, nullable=False),
|
||||
sa.Column('created_at', sa.DateTime),
|
||||
sa.Column('updated_at', sa.DateTime),
|
||||
sa.Column('deleted_at', sa.DateTime),
|
||||
sa.Column('deleted', sa.String(36), default='False'),
|
||||
|
||||
sa.Column('consistency_group_id', sa.String(length=36),
|
||||
sa.ForeignKey('consistency_groups.id',
|
||||
name=CG_MAP_FK_CONSTRAINT_NAME),
|
||||
nullable=False),
|
||||
sa.Column('share_type_id', sa.String(length=36),
|
||||
sa.ForeignKey('share_types.id',
|
||||
name=SHARE_TYPE_FK_CONSTRAINT_NAME),
|
||||
nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8')
|
||||
|
||||
op.create_table(
|
||||
'cgsnapshots',
|
||||
sa.Column('id', sa.String(36), primary_key=True, nullable=False),
|
||||
sa.Column('created_at', sa.DateTime),
|
||||
sa.Column('updated_at', sa.DateTime),
|
||||
sa.Column('deleted_at', sa.DateTime),
|
||||
sa.Column('deleted', sa.String(36), default='False'),
|
||||
sa.Column('user_id', sa.String(length=255), nullable=False),
|
||||
sa.Column('project_id', sa.String(length=255), nullable=False),
|
||||
|
||||
sa.Column('consistency_group_id', sa.String(length=36),
|
||||
sa.ForeignKey('consistency_groups.id',
|
||||
name=CGSNAP_CG_ID_FK_CONSTRAINT_NAME),
|
||||
nullable=False),
|
||||
|
||||
sa.Column('name', sa.String(length=255)),
|
||||
sa.Column('description', sa.String(length=255)),
|
||||
sa.Column('status', sa.String(length=255)),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8')
|
||||
|
||||
op.create_table(
|
||||
'cgsnapshot_members',
|
||||
sa.Column('id', sa.String(36), primary_key=True, nullable=False),
|
||||
sa.Column('created_at', sa.DateTime),
|
||||
sa.Column('updated_at', sa.DateTime),
|
||||
sa.Column('deleted_at', sa.DateTime),
|
||||
sa.Column('deleted', sa.String(36), default='False'),
|
||||
sa.Column('user_id', sa.String(length=255), nullable=False),
|
||||
sa.Column('project_id', sa.String(length=255), nullable=False),
|
||||
|
||||
sa.Column('cgsnapshot_id', sa.String(length=36),
|
||||
sa.ForeignKey('cgsnapshots.id',
|
||||
name=CGSNAP_MEM_SNAP_ID_FK_CONSTRAINT_NAME),
|
||||
nullable=False),
|
||||
sa.Column('share_instance_id', sa.String(length=36),
|
||||
sa.ForeignKey('share_instances.id',
|
||||
name=CGSNAP_MEM_INST_FK_CONSTRAINT_NAME),
|
||||
nullable=False),
|
||||
sa.Column('share_id', sa.String(length=36),
|
||||
sa.ForeignKey('shares.id',
|
||||
name=CGSNAP_MEM_SHARE_FK_CONSTRAINT_NAME),
|
||||
nullable=False),
|
||||
sa.Column('share_type_id', sa.String(length=36),
|
||||
sa.ForeignKey('share_types.id',
|
||||
name=CGSNAP_MEM_SHARETYPE_FK_CONSTRAINT_NAME),
|
||||
nullable=False),
|
||||
|
||||
sa.Column('size', sa.Integer),
|
||||
sa.Column('status', sa.String(length=255)),
|
||||
sa.Column('share_proto', sa.String(length=255)),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8')
|
||||
|
||||
|
||||
def downgrade():
|
||||
try:
|
||||
op.drop_table('cgsnapshot_members')
|
||||
except Exception:
|
||||
LOG.exception(_LE("Error Dropping 'cgsnapshot_members' table."))
|
||||
|
||||
try:
|
||||
op.drop_table('cgsnapshots')
|
||||
except Exception:
|
||||
LOG.exception(_LE("Error Dropping 'cgsnapshots' table."))
|
||||
|
||||
try:
|
||||
op.drop_table('consistency_group_share_type_mappings')
|
||||
except Exception:
|
||||
LOG.exception(_LE("Error Dropping "
|
||||
"'consistency_group_share_type_mappings' table."))
|
||||
|
||||
try:
|
||||
op.drop_column('shares', 'source_cgsnapshot_member_id')
|
||||
except Exception:
|
||||
LOG.exception(_LE("Error Dropping 'source_cgsnapshot_member_id' "
|
||||
"column from 'shares' table."))
|
||||
|
||||
try:
|
||||
op.drop_constraint(SHARES_CG_FK_CONSTRAINT_NAME,
|
||||
'shares',
|
||||
type_='foreignkey')
|
||||
except Exception:
|
||||
LOG.exception(_LE("Error Dropping '%s' constraint.") %
|
||||
SHARES_CG_FK_CONSTRAINT_NAME)
|
||||
|
||||
try:
|
||||
op.drop_column('shares', 'consistency_group_id')
|
||||
except Exception:
|
||||
LOG.exception(_LE("Error Dropping 'consistency_group_id' column "
|
||||
"from 'shares' table."))
|
||||
|
||||
try:
|
||||
op.drop_table('consistency_groups')
|
||||
except Exception:
|
||||
LOG.exception(_LE("Error Dropping 'consistency_groups' table."))
|
@ -21,6 +21,7 @@
|
||||
import copy
|
||||
import datetime
|
||||
import sys
|
||||
import uuid
|
||||
import warnings
|
||||
|
||||
# NOTE(uglide): Required to override default oslo_db Query class
|
||||
@ -1260,6 +1261,23 @@ def share_instances_get_all_by_share(context, share_id):
|
||||
return result
|
||||
|
||||
|
||||
@require_context
|
||||
def share_instances_get_all_by_consistency_group_id(context, cg_id):
|
||||
"""Returns list of share instances that belong to given cg."""
|
||||
result = (
|
||||
model_query(context, models.Share).filter(
|
||||
models.Share.consistency_group_id == cg_id,
|
||||
).all()
|
||||
)
|
||||
instances = []
|
||||
for share in result:
|
||||
instance = share.instance
|
||||
instance.set_share_data(share)
|
||||
instances.append(instance)
|
||||
|
||||
return instances
|
||||
|
||||
|
||||
################
|
||||
|
||||
|
||||
@ -1353,7 +1371,8 @@ def share_get(context, share_id, session=None):
|
||||
|
||||
@require_context
|
||||
def _share_get_all_with_filters(context, project_id=None, share_server_id=None,
|
||||
filters=None, is_public=False, sort_key=None,
|
||||
consistency_group_id=None, filters=None,
|
||||
is_public=False, sort_key=None,
|
||||
sort_dir=None):
|
||||
"""Returns sorted list of shares that satisfies filters.
|
||||
|
||||
@ -1389,6 +1408,10 @@ def _share_get_all_with_filters(context, project_id=None, share_server_id=None,
|
||||
query = query.filter(
|
||||
models.ShareInstance.share_server_id == share_server_id)
|
||||
|
||||
if consistency_group_id:
|
||||
query = query.filter(
|
||||
models.Share.consistency_group_id == consistency_group_id)
|
||||
|
||||
# Apply filters
|
||||
if not filters:
|
||||
filters = {}
|
||||
@ -1450,6 +1473,18 @@ def share_get_all_by_project(context, project_id, filters=None,
|
||||
return query
|
||||
|
||||
|
||||
@require_context
|
||||
def share_get_all_by_consistency_group_id(context, cg_id,
|
||||
filters=None, sort_key=None,
|
||||
sort_dir=None):
|
||||
"""Returns list of shares with given CG ID."""
|
||||
query = _share_get_all_with_filters(
|
||||
context, consistency_group_id=cg_id,
|
||||
filters=filters, sort_key=sort_key, sort_dir=sort_dir,
|
||||
)
|
||||
return query
|
||||
|
||||
|
||||
@require_context
|
||||
def share_get_all_by_share_server(context, share_server_id, filters=None,
|
||||
sort_key=None, sort_dir=None):
|
||||
@ -2364,6 +2399,7 @@ def share_server_get_all_unused_deletable(context, host, updated_before):
|
||||
)
|
||||
result = _server_get_query(context)\
|
||||
.filter_by(host=host)\
|
||||
.filter(~models.ShareServer.consistency_groups.any())\
|
||||
.filter(~models.ShareServer.share_instances.any())\
|
||||
.filter(models.ShareServer.status.in_(valid_server_status))\
|
||||
.filter(models.ShareServer.updated_at < updated_before).all()
|
||||
@ -2732,9 +2768,15 @@ def share_type_destroy(context, id):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
_share_type_get(context, id, session)
|
||||
results = model_query(context, models.Share, session=session). \
|
||||
filter_by(share_type_id=id).all()
|
||||
if results:
|
||||
results = model_query(context, models.Share, session=session,
|
||||
read_deleted="no").\
|
||||
filter_by(share_type_id=id).count()
|
||||
cg_count = model_query(context,
|
||||
models.ConsistencyGroupShareTypeMapping,
|
||||
read_deleted="no",
|
||||
session=session).\
|
||||
filter_by(share_type_id=id).count()
|
||||
if results or cg_count:
|
||||
LOG.error(_LE('ShareType %s deletion failed, ShareType in use.'),
|
||||
id)
|
||||
raise exception.ShareTypeInUse(share_type_id=id)
|
||||
@ -2939,3 +2981,318 @@ def availability_zone_get_all(context):
|
||||
read_deleted="no").filter(
|
||||
models.AvailabilityZone.id.in_(enabled_services)
|
||||
).all()
|
||||
|
||||
|
||||
####################
|
||||
|
||||
|
||||
def _consistency_group_get(context, consistency_group_id, session=None):
|
||||
session = session or get_session()
|
||||
result = model_query(context, models.ConsistencyGroup,
|
||||
session=session,
|
||||
project_only=True,
|
||||
read_deleted='no').\
|
||||
filter_by(id=consistency_group_id).\
|
||||
options(joinedload('share_types')).\
|
||||
first()
|
||||
|
||||
if not result:
|
||||
raise exception.ConsistencyGroupNotFound(
|
||||
consistency_group_id=consistency_group_id)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@require_context
|
||||
def consistency_group_get(context, consistency_group_id, session=None):
|
||||
return _consistency_group_get(context, consistency_group_id,
|
||||
session=session)
|
||||
|
||||
|
||||
def _consistency_group_get_all_query(context, session=None):
|
||||
session = session or get_session()
|
||||
return model_query(context, models.ConsistencyGroup, session=session,
|
||||
read_deleted='no')
|
||||
|
||||
|
||||
@require_admin_context
|
||||
def consistency_group_get_all(context, detailed=True):
|
||||
query = _consistency_group_get_all_query(context)
|
||||
if detailed:
|
||||
return query.options(joinedload('share_types')).all()
|
||||
else:
|
||||
query = query.with_entities(models.ConsistencyGroup.id,
|
||||
models.ConsistencyGroup.name)
|
||||
values = []
|
||||
for item in query.all():
|
||||
id, name = item
|
||||
values.append({"id": id, "name": name})
|
||||
return values
|
||||
|
||||
|
||||
@require_admin_context
|
||||
def consistency_group_get_all_by_host(context, host, detailed=True):
|
||||
query = _consistency_group_get_all_query(context).filter_by(host=host)
|
||||
if detailed:
|
||||
return query.options(joinedload('share_types')).all()
|
||||
else:
|
||||
query = query.with_entities(models.ConsistencyGroup.id,
|
||||
models.ConsistencyGroup.name)
|
||||
values = []
|
||||
for item in query.all():
|
||||
id, name = item
|
||||
values.append({"id": id, "name": name})
|
||||
return values
|
||||
|
||||
|
||||
@require_context
|
||||
def consistency_group_get_all_by_project(context, project_id, detailed=True):
|
||||
authorize_project_context(context, project_id)
|
||||
query = _consistency_group_get_all_query(context).filter_by(
|
||||
project_id=project_id)
|
||||
if detailed:
|
||||
return query.options(joinedload('share_types')).all()
|
||||
else:
|
||||
query = query.with_entities(models.ConsistencyGroup.id,
|
||||
models.ConsistencyGroup.name)
|
||||
values = []
|
||||
for item in query.all():
|
||||
id, name = item
|
||||
values.append({"id": id, "name": name})
|
||||
return values
|
||||
|
||||
|
||||
@require_context
|
||||
def consistency_group_create(context, values):
|
||||
consistency_group = models.ConsistencyGroup()
|
||||
if not values.get('id'):
|
||||
values['id'] = six.text_type(uuid.uuid4())
|
||||
|
||||
mappings = []
|
||||
for item in values.get('share_types') or []:
|
||||
mapping = models.ConsistencyGroupShareTypeMapping()
|
||||
mapping['id'] = six.text_type(uuid.uuid4())
|
||||
mapping['share_type_id'] = item
|
||||
mapping['consistency_group_id'] = values['id']
|
||||
mappings.append(mapping)
|
||||
|
||||
values['share_types'] = mappings
|
||||
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
consistency_group.update(values)
|
||||
session.add(consistency_group)
|
||||
|
||||
return _consistency_group_get(context, values['id'], session=session)
|
||||
|
||||
|
||||
@require_context
|
||||
def consistency_group_update(context, consistency_group_id, values):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
cg_ref = _consistency_group_get(context, consistency_group_id,
|
||||
session=session)
|
||||
|
||||
cg_ref.update(values)
|
||||
cg_ref.save(session=session)
|
||||
return cg_ref
|
||||
|
||||
|
||||
@require_admin_context
|
||||
def consistency_group_destroy(context, consistency_group_id):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
cg_ref = _consistency_group_get(context, consistency_group_id,
|
||||
session=session)
|
||||
cg_ref.soft_delete(session)
|
||||
|
||||
session.query(models.ConsistencyGroupShareTypeMapping).\
|
||||
filter_by(consistency_group_id=cg_ref['id']).soft_delete()
|
||||
|
||||
|
||||
@require_context
|
||||
def count_shares_in_consistency_group(context, consistency_group_id,
|
||||
session=None):
|
||||
session = session or get_session()
|
||||
return model_query(
|
||||
context, models.Share, session=session,
|
||||
project_only=True, read_deleted="no").\
|
||||
filter_by(consistency_group_id=consistency_group_id).\
|
||||
count()
|
||||
|
||||
|
||||
@require_context
|
||||
def count_cgsnapshots_in_consistency_group(context, consistency_group_id,
|
||||
session=None):
|
||||
session = session or get_session()
|
||||
return model_query(
|
||||
context, models.CGSnapshot, session=session,
|
||||
project_only=True, read_deleted="no").\
|
||||
filter_by(consistency_group_id=consistency_group_id).\
|
||||
count()
|
||||
|
||||
|
||||
@require_context
|
||||
def count_consistency_groups_in_share_network(context, share_network_id,
|
||||
session=None):
|
||||
session = session or get_session()
|
||||
return model_query(
|
||||
context, models.ConsistencyGroup, session=session,
|
||||
project_only=True, read_deleted="no").\
|
||||
filter_by(share_network_id=share_network_id).\
|
||||
count()
|
||||
|
||||
|
||||
@require_context
|
||||
def count_cgsnapshot_members_in_share(context, share_id, session=None):
|
||||
session = session or get_session()
|
||||
return model_query(
|
||||
context, models.CGSnapshotMember, session=session,
|
||||
project_only=True, read_deleted="no").\
|
||||
filter_by(share_id=share_id).\
|
||||
count()
|
||||
|
||||
|
||||
@require_context
|
||||
def _cgsnapshot_get(context, cgsnapshot_id, session=None):
|
||||
session = session or get_session()
|
||||
result = model_query(context, models.CGSnapshot, session=session,
|
||||
project_only=True, read_deleted='no').\
|
||||
options(joinedload('cgsnapshot_members')).\
|
||||
options(joinedload('consistency_group')).\
|
||||
filter_by(id=cgsnapshot_id).\
|
||||
first()
|
||||
|
||||
if not result:
|
||||
raise exception.CGSnapshotNotFound(cgsnapshot_id=cgsnapshot_id)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _cgsnapshot_get_all_query(context, session=None):
|
||||
session = session or get_session()
|
||||
return model_query(context, models.CGSnapshot, session=session,
|
||||
reade_deleted='no').\
|
||||
options(joinedload('cgsnapshot_members')).\
|
||||
options(joinedload('consistency_group'))
|
||||
|
||||
|
||||
@require_context
|
||||
def cgsnapshot_get(context, cgsnapshot_id, session=None):
|
||||
session = session or get_session()
|
||||
return _cgsnapshot_get(context, cgsnapshot_id, session=session)
|
||||
|
||||
|
||||
@require_admin_context
|
||||
def cgsnapshot_get_all(context, detailed=True):
|
||||
query = _cgsnapshot_get_all_query(context)
|
||||
if detailed:
|
||||
return query.all()
|
||||
else:
|
||||
query = query.with_entities(models.CGSnapshot.id,
|
||||
models.CGSnapshot.name)
|
||||
values = []
|
||||
for item in query.all():
|
||||
id, name = item
|
||||
values.append({"id": id, "name": name})
|
||||
return values
|
||||
|
||||
|
||||
@require_context
|
||||
def cgsnapshot_get_all_by_project(context, project_id, detailed=True):
|
||||
authorize_project_context(context, project_id)
|
||||
query = _cgsnapshot_get_all_query(context).filter_by(
|
||||
project_id=project_id)
|
||||
if detailed:
|
||||
return query.all()
|
||||
else:
|
||||
query = query.with_entities(models.CGSnapshot.id,
|
||||
models.CGSnapshot.name)
|
||||
values = []
|
||||
for item in query.all():
|
||||
id, name = item
|
||||
values.append({"id": id, "name": name})
|
||||
return values
|
||||
|
||||
|
||||
@require_context
|
||||
def cgsnapshot_create(context, values):
|
||||
cgsnapshot = models.CGSnapshot()
|
||||
if not values.get('id'):
|
||||
values['id'] = six.text_type(uuid.uuid4())
|
||||
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
cgsnapshot.update(values)
|
||||
session.add(cgsnapshot)
|
||||
|
||||
return _cgsnapshot_get(context, values['id'], session=session)
|
||||
|
||||
|
||||
@require_context
|
||||
def cgsnapshot_update(context, cgsnapshot_id, values):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
cg_ref = _cgsnapshot_get(context, cgsnapshot_id, session=session)
|
||||
|
||||
cg_ref.update(values)
|
||||
cg_ref.save(session=session)
|
||||
return cg_ref
|
||||
|
||||
|
||||
@require_admin_context
|
||||
def cgsnapshot_destroy(context, cgsnapshot_id):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
cgsnap_ref = _cgsnapshot_get(context, cgsnapshot_id, session=session)
|
||||
cgsnap_ref.soft_delete(session)
|
||||
|
||||
session.query(models.CGSnapshotMember).\
|
||||
filter_by(cgsnapshot_id=cgsnapshot_id).soft_delete()
|
||||
|
||||
|
||||
@require_context
|
||||
def cgsnapshot_members_get_all(context, cgsnapshot_id, session=None):
|
||||
session = session or get_session()
|
||||
query = model_query(context, models.CGSnapshotMember,
|
||||
session=session, read_deleted='no').filter_by(
|
||||
cgsnapshot_id=cgsnapshot_id)
|
||||
return query.all()
|
||||
|
||||
|
||||
@require_context
|
||||
def cgsnapshot_member_get(context, member_id, session=None):
|
||||
result = model_query(context, models.CGSnapshotMember, session=session,
|
||||
project_only=True, read_deleted='no').\
|
||||
filter_by(id=member_id).\
|
||||
first()
|
||||
|
||||
if not result:
|
||||
raise exception.CGSnapshotMemberNotFound(member_id=member_id)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@require_context
|
||||
def cgsnapshot_member_create(context, values):
|
||||
member = models.CGSnapshotMember()
|
||||
if not values.get('id'):
|
||||
values['id'] = six.text_type(uuid.uuid4())
|
||||
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
member.update(values)
|
||||
session.add(member)
|
||||
|
||||
return cgsnapshot_member_get(context, values['id'], session=session)
|
||||
|
||||
|
||||
@require_context
|
||||
def cgsnapshot_member_update(context, member_id, values):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
member = cgsnapshot_member_get(context, member_id, session=session)
|
||||
member.update(values)
|
||||
session.add(member)
|
||||
|
||||
return cgsnapshot_member_get(context, member_id, session=session)
|
||||
|
@ -225,7 +225,7 @@ class Share(BASE, ManilaBase):
|
||||
if item in proxified_properties:
|
||||
return getattr(self.instance, item, None)
|
||||
|
||||
raise AttributeError
|
||||
raise AttributeError(item)
|
||||
|
||||
@property
|
||||
def share_server_id(self):
|
||||
@ -250,6 +250,11 @@ class Share(BASE, ManilaBase):
|
||||
share_type_id = Column(String(36), ForeignKey('share_types.id'),
|
||||
nullable=True)
|
||||
is_public = Column(Boolean, default=False)
|
||||
consistency_group_id = Column(String(36),
|
||||
ForeignKey('consistency_groups.id'),
|
||||
nullable=True)
|
||||
|
||||
source_cgsnapshot_member_id = Column(String(36), nullable=True)
|
||||
|
||||
instances = orm.relationship(
|
||||
"ShareInstance",
|
||||
@ -271,7 +276,8 @@ class ShareInstance(BASE, ManilaBase):
|
||||
_proxified_properties = ('user_id', 'project_id', 'size',
|
||||
'display_name', 'display_description',
|
||||
'snapshot_id', 'share_proto', 'share_type_id',
|
||||
'is_public')
|
||||
'is_public', 'consistency_group_id',
|
||||
'source_cgsnapshot_member_id')
|
||||
|
||||
def set_share_data(self, share):
|
||||
for share_property in self._proxified_properties:
|
||||
@ -658,6 +664,11 @@ class ShareServer(BASE, ManilaBase):
|
||||
'ShareServer.id == ShareInstance.share_server_id,'
|
||||
'ShareInstance.deleted == "False")')
|
||||
|
||||
consistency_groups = orm.relationship(
|
||||
"ConsistencyGroup", backref='share_server', primaryjoin='and_('
|
||||
'ShareServer.id == ConsistencyGroup.share_server_id,'
|
||||
'ConsistencyGroup.deleted == "False")')
|
||||
|
||||
_backend_details = orm.relationship(
|
||||
"ShareServerBackendDetails",
|
||||
lazy='immediate',
|
||||
@ -728,6 +739,97 @@ class AvailabilityZone(BASE, ManilaBase):
|
||||
name = Column(String(255), nullable=False)
|
||||
|
||||
|
||||
class ConsistencyGroup(BASE, ManilaBase):
|
||||
"""Represents a consistency group."""
|
||||
__tablename__ = 'consistency_groups'
|
||||
id = Column(String(36), primary_key=True)
|
||||
|
||||
user_id = Column(String(255), nullable=False)
|
||||
project_id = Column(String(255), nullable=False)
|
||||
deleted = Column(String(36), default='False')
|
||||
|
||||
host = Column(String(255))
|
||||
name = Column(String(255))
|
||||
description = Column(String(255))
|
||||
status = Column(String(255))
|
||||
source_cgsnapshot_id = Column(String(36))
|
||||
share_network_id = Column(String(36), ForeignKey('share_networks.id'),
|
||||
nullable=True)
|
||||
share_server_id = Column(String(36), ForeignKey('share_servers.id'),
|
||||
nullable=True)
|
||||
|
||||
|
||||
class CGSnapshot(BASE, ManilaBase):
|
||||
"""Represents a cgsnapshot."""
|
||||
__tablename__ = 'cgsnapshots'
|
||||
id = Column(String(36), primary_key=True)
|
||||
|
||||
consistency_group_id = Column(String(36),
|
||||
ForeignKey('consistency_groups.id'))
|
||||
user_id = Column(String(255), nullable=False)
|
||||
project_id = Column(String(255), nullable=False)
|
||||
deleted = Column(String(36), default='False')
|
||||
|
||||
name = Column(String(255))
|
||||
description = Column(String(255))
|
||||
status = Column(String(255))
|
||||
|
||||
consistency_group = orm.relationship(
|
||||
ConsistencyGroup,
|
||||
backref="cgsnapshots",
|
||||
foreign_keys=consistency_group_id,
|
||||
primaryjoin=('and_('
|
||||
'CGSnapshot.consistency_group_id == ConsistencyGroup.id,'
|
||||
'CGSnapshot.deleted == "False")')
|
||||
)
|
||||
|
||||
|
||||
class ConsistencyGroupShareTypeMapping(BASE, ManilaBase):
|
||||
"""Represents the share types in a consistency group."""
|
||||
__tablename__ = 'consistency_group_share_type_mappings'
|
||||
id = Column(String(36), primary_key=True)
|
||||
deleted = Column(String(36), default='False')
|
||||
consistency_group_id = Column(String(36),
|
||||
ForeignKey('consistency_groups.id'),
|
||||
nullable=False)
|
||||
share_type_id = Column(String(36),
|
||||
ForeignKey('share_types.id'),
|
||||
nullable=False)
|
||||
|
||||
consistency_group = orm.relationship(
|
||||
ConsistencyGroup,
|
||||
backref="share_types",
|
||||
foreign_keys=consistency_group_id,
|
||||
primaryjoin=('and_('
|
||||
'ConsistencyGroupShareTypeMapping.consistency_group_id '
|
||||
'== ConsistencyGroup.id,'
|
||||
'ConsistencyGroupShareTypeMapping.deleted == "False")')
|
||||
)
|
||||
|
||||
|
||||
class CGSnapshotMember(BASE, ManilaBase):
|
||||
"""Represents the share snapshots in a consistency group snapshot."""
|
||||
__tablename__ = 'cgsnapshot_members'
|
||||
id = Column(String(36), primary_key=True)
|
||||
cgsnapshot_id = Column(String(36), ForeignKey('cgsnapshots.id'))
|
||||
share_id = Column(String(36), ForeignKey('shares.id'))
|
||||
share_instance_id = Column(String(36), ForeignKey('share_instances.id'))
|
||||
size = Column(Integer)
|
||||
status = Column(String(255))
|
||||
share_proto = Column(String(255))
|
||||
share_type_id = Column(String(36), ForeignKey('share_types.id'),
|
||||
nullable=True)
|
||||
user_id = Column(String(255))
|
||||
project_id = Column(String(255))
|
||||
deleted = Column(String(36), default='False')
|
||||
|
||||
cgsnapshot = orm.relationship(
|
||||
CGSnapshot,
|
||||
backref="cgsnapshot_members",
|
||||
foreign_keys=cgsnapshot_id,
|
||||
primaryjoin='CGSnapshot.id == CGSnapshotMember.cgsnapshot_id')
|
||||
|
||||
|
||||
def register_models():
|
||||
"""Register Models and create metadata.
|
||||
|
||||
|
@ -644,3 +644,26 @@ class SSHInjectionThreat(ManilaException):
|
||||
|
||||
class HNASBackendException(ManilaException):
|
||||
message = _("HNAS Backend Exception: %(msg)s")
|
||||
|
||||
|
||||
# ConsistencyGroup
|
||||
class ConsistencyGroupNotFound(NotFound):
|
||||
message = _("ConsistencyGroup %(consistency_group_id)s could not be "
|
||||
"found.")
|
||||
|
||||
|
||||
class CGSnapshotNotFound(NotFound):
|
||||
message = _("Consistency group snapshot %(cgsnapshot_id)s could not be "
|
||||
"found.")
|
||||
|
||||
|
||||
class CGSnapshotMemberNotFound(NotFound):
|
||||
message = _("CG snapshot %(member_id)s could not be found.")
|
||||
|
||||
|
||||
class InvalidConsistencyGroup(Invalid):
|
||||
message = _("Invalid ConsistencyGroup: %(reason)s")
|
||||
|
||||
|
||||
class InvalidCGSnapshot(Invalid):
|
||||
message = _("Invalid CGSnapshot: %(reason)s")
|
||||
|
@ -178,6 +178,16 @@ class ShareDatabaseAPITestCase(test.TestCase):
|
||||
self.assertEqual(1, len(actual_result))
|
||||
self.assertEqual(share['id'], actual_result[0].id)
|
||||
|
||||
def test_share_filter_all_by_consistency_group(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
share = db_utils.create_share(consistency_group_id=cg['id'])
|
||||
|
||||
actual_result = db_api.share_get_all_by_consistency_group_id(
|
||||
self.ctxt, cg['id'])
|
||||
|
||||
self.assertEqual(1, len(actual_result))
|
||||
self.assertEqual(share['id'], actual_result[0].id)
|
||||
|
||||
def test_share_instance_delete_with_share(self):
|
||||
share = db_utils.create_share()
|
||||
|
||||
@ -193,7 +203,20 @@ class ShareDatabaseAPITestCase(test.TestCase):
|
||||
|
||||
self.assertEqual('share-%s' % instance['id'], instance['name'])
|
||||
|
||||
@ddt.data('host')
|
||||
def test_share_instance_get_all_by_consistency_group(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
db_utils.create_share(consistency_group_id=cg['id'])
|
||||
db_utils.create_share()
|
||||
|
||||
instances = db_api.share_instances_get_all_by_consistency_group_id(
|
||||
self.ctxt, cg['id'])
|
||||
|
||||
self.assertEqual(1, len(instances))
|
||||
instance = instances[0]
|
||||
|
||||
self.assertEqual('share-%s' % instance['id'], instance['name'])
|
||||
|
||||
@ddt.data('host', 'consistency_group_id')
|
||||
def test_share_get_all_sort_by_share_instance_fields(self, sort_key):
|
||||
shares = [db_utils.create_share(**{sort_key: n, 'size': 1})
|
||||
for n in ('test1', 'test2')]
|
||||
@ -205,6 +228,291 @@ class ShareDatabaseAPITestCase(test.TestCase):
|
||||
self.assertEqual(shares[0]['id'], actual_result[1]['id'])
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ConsistencyGroupDatabaseAPITestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
"""Run before each test."""
|
||||
super(ConsistencyGroupDatabaseAPITestCase, self).setUp()
|
||||
self.ctxt = context.get_admin_context()
|
||||
|
||||
def test_consistency_group_create_with_share_type(self):
|
||||
fake_share_types = ["fake_share_type"]
|
||||
cg = db_utils.create_consistency_group(share_types=fake_share_types)
|
||||
cg = db_api.consistency_group_get(self.ctxt, cg['id'])
|
||||
|
||||
self.assertEqual(1, len(cg['share_types']))
|
||||
|
||||
def test_consistency_group_get(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
|
||||
self.assertDictMatch(dict(cg),
|
||||
dict(db_api.consistency_group_get(self.ctxt,
|
||||
cg['id'])))
|
||||
|
||||
def test_count_consistency_groups_in_share_network(self):
|
||||
share_network = db_utils.create_share_network()
|
||||
db_utils.create_consistency_group()
|
||||
db_utils.create_consistency_group(share_network_id=share_network['id'])
|
||||
|
||||
count = db_api.count_consistency_groups_in_share_network(
|
||||
self.ctxt, share_network_id=share_network['id'])
|
||||
|
||||
self.assertEqual(1, count)
|
||||
|
||||
def test_consistency_group_get_all(self):
|
||||
expected_cg = db_utils.create_consistency_group()
|
||||
|
||||
cgs = db_api.consistency_group_get_all(self.ctxt, detailed=False)
|
||||
|
||||
self.assertEqual(1, len(cgs))
|
||||
cg = cgs[0]
|
||||
self.assertEqual(2, len(dict(cg).keys()))
|
||||
self.assertEqual(expected_cg['id'], cg['id'])
|
||||
self.assertEqual(expected_cg['name'], cg['name'])
|
||||
|
||||
def test_consistency_group_get_all_with_detail(self):
|
||||
expected_cg = db_utils.create_consistency_group()
|
||||
|
||||
cgs = db_api.consistency_group_get_all(self.ctxt, detailed=True)
|
||||
|
||||
self.assertEqual(1, len(cgs))
|
||||
cg = cgs[0]
|
||||
self.assertDictMatch(dict(expected_cg), dict(cg))
|
||||
|
||||
def test_consistency_group_get_all_by_host(self):
|
||||
fake_host = 'my_fake_host'
|
||||
expected_cg = db_utils.create_consistency_group(host=fake_host)
|
||||
db_utils.create_consistency_group()
|
||||
|
||||
cgs = db_api.consistency_group_get_all_by_host(self.ctxt, fake_host,
|
||||
detailed=False)
|
||||
|
||||
self.assertEqual(1, len(cgs))
|
||||
cg = cgs[0]
|
||||
self.assertEqual(2, len(dict(cg).keys()))
|
||||
self.assertEqual(expected_cg['id'], cg['id'])
|
||||
self.assertEqual(expected_cg['name'], cg['name'])
|
||||
|
||||
def test_consistency_group_get_all_by_host_with_details(self):
|
||||
fake_host = 'my_fake_host'
|
||||
expected_cg = db_utils.create_consistency_group(host=fake_host)
|
||||
db_utils.create_consistency_group()
|
||||
|
||||
cgs = db_api.consistency_group_get_all_by_host(self.ctxt,
|
||||
fake_host,
|
||||
detailed=True)
|
||||
|
||||
self.assertEqual(1, len(cgs))
|
||||
cg = cgs[0]
|
||||
self.assertDictMatch(dict(expected_cg), dict(cg))
|
||||
self.assertEqual(fake_host, cg['host'])
|
||||
|
||||
def test_consistency_group_get_all_by_project(self):
|
||||
fake_project = 'fake_project'
|
||||
expected_cg = db_utils.create_consistency_group(
|
||||
project_id=fake_project)
|
||||
db_utils.create_consistency_group()
|
||||
|
||||
cgs = db_api.consistency_group_get_all_by_project(self.ctxt,
|
||||
fake_project,
|
||||
detailed=False)
|
||||
|
||||
self.assertEqual(1, len(cgs))
|
||||
cg = cgs[0]
|
||||
self.assertEqual(2, len(dict(cg).keys()))
|
||||
self.assertEqual(expected_cg['id'], cg['id'])
|
||||
self.assertEqual(expected_cg['name'], cg['name'])
|
||||
|
||||
def test_consistency_group_get_all_by_project_with_details(self):
|
||||
fake_project = 'fake_project'
|
||||
expected_cg = db_utils.create_consistency_group(
|
||||
project_id=fake_project)
|
||||
db_utils.create_consistency_group()
|
||||
|
||||
cgs = db_api.consistency_group_get_all_by_project(self.ctxt,
|
||||
fake_project,
|
||||
detailed=True)
|
||||
|
||||
self.assertEqual(1, len(cgs))
|
||||
cg = cgs[0]
|
||||
self.assertDictMatch(dict(expected_cg), dict(cg))
|
||||
self.assertEqual(fake_project, cg['project_id'])
|
||||
|
||||
def test_consistency_group_update(self):
|
||||
fake_name = "my_fake_name"
|
||||
expected_cg = db_utils.create_consistency_group()
|
||||
expected_cg['name'] = fake_name
|
||||
|
||||
db_api.consistency_group_update(self.ctxt,
|
||||
expected_cg['id'],
|
||||
{'name': fake_name})
|
||||
|
||||
cg = db_api.consistency_group_get(self.ctxt, expected_cg['id'])
|
||||
self.assertEqual(fake_name, cg['name'])
|
||||
|
||||
def test_consistency_group_destroy(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
db_api.consistency_group_get(self.ctxt, cg['id'])
|
||||
|
||||
db_api.consistency_group_destroy(self.ctxt, cg['id'])
|
||||
|
||||
self.assertRaises(exception.NotFound, db_api.consistency_group_get,
|
||||
self.ctxt, cg['id'])
|
||||
|
||||
def test_count_shares_in_consistency_group(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
db_utils.create_share(consistency_group_id=cg['id'])
|
||||
db_utils.create_share()
|
||||
|
||||
count = db_api.count_shares_in_consistency_group(self.ctxt, cg['id'])
|
||||
|
||||
self.assertEqual(1, count)
|
||||
|
||||
def test_count_cgsnapshots_in_consistency_group(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
db_utils.create_cgsnapshot(cg['id'])
|
||||
db_utils.create_cgsnapshot(cg['id'])
|
||||
|
||||
count = db_api.count_cgsnapshots_in_consistency_group(self.ctxt,
|
||||
cg['id'])
|
||||
|
||||
self.assertEqual(2, count)
|
||||
|
||||
def test_cgsnapshot_get(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
cgsnap = db_utils.create_cgsnapshot(cg['id'])
|
||||
|
||||
self.assertDictMatch(dict(cgsnap),
|
||||
dict(db_api.cgsnapshot_get(self.ctxt,
|
||||
cgsnap['id'])))
|
||||
|
||||
def test_cgsnapshot_get_all(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
expected_cgsnap = db_utils.create_cgsnapshot(cg['id'])
|
||||
|
||||
snaps = db_api.cgsnapshot_get_all(self.ctxt, detailed=False)
|
||||
|
||||
self.assertEqual(1, len(snaps))
|
||||
snap = snaps[0]
|
||||
self.assertEqual(2, len(dict(snap).keys()))
|
||||
self.assertEqual(expected_cgsnap['id'], snap['id'])
|
||||
self.assertEqual(expected_cgsnap['name'], snap['name'])
|
||||
|
||||
def test_cgsnapshot_get_all_with_detail(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
expected_cgsnap = db_utils.create_cgsnapshot(cg['id'])
|
||||
|
||||
snaps = db_api.cgsnapshot_get_all(self.ctxt, detailed=True)
|
||||
|
||||
self.assertEqual(1, len(snaps))
|
||||
snap = snaps[0]
|
||||
self.assertDictMatch(dict(expected_cgsnap), dict(snap))
|
||||
|
||||
def test_cgsnapshot_get_all_by_project(self):
|
||||
fake_project = 'fake_project'
|
||||
cg = db_utils.create_consistency_group()
|
||||
expected_cgsnap = db_utils.create_cgsnapshot(cg['id'],
|
||||
project_id=fake_project)
|
||||
|
||||
snaps = db_api.cgsnapshot_get_all_by_project(self.ctxt,
|
||||
fake_project,
|
||||
detailed=False)
|
||||
|
||||
self.assertEqual(1, len(snaps))
|
||||
snap = snaps[0]
|
||||
self.assertEqual(2, len(dict(snap).keys()))
|
||||
self.assertEqual(expected_cgsnap['id'], snap['id'])
|
||||
self.assertEqual(expected_cgsnap['name'], snap['name'])
|
||||
|
||||
def test_cgsnapshot_get_all_by_project_with_details(self):
|
||||
fake_project = 'fake_project'
|
||||
cg = db_utils.create_consistency_group()
|
||||
expected_cgsnap = db_utils.create_cgsnapshot(cg['id'],
|
||||
project_id=fake_project)
|
||||
|
||||
snaps = db_api.cgsnapshot_get_all_by_project(self.ctxt,
|
||||
fake_project,
|
||||
detailed=True)
|
||||
|
||||
self.assertEqual(1, len(snaps))
|
||||
snap = snaps[0]
|
||||
self.assertDictMatch(dict(expected_cgsnap), dict(snap))
|
||||
self.assertEqual(fake_project, snap['project_id'])
|
||||
|
||||
def test_cgsnapshot_update(self):
|
||||
fake_name = "my_fake_name"
|
||||
cg = db_utils.create_consistency_group()
|
||||
expected_cgsnap = db_utils.create_cgsnapshot(cg['id'])
|
||||
expected_cgsnap['name'] = fake_name
|
||||
|
||||
db_api.cgsnapshot_update(self.ctxt, expected_cgsnap['id'],
|
||||
{'name': fake_name})
|
||||
|
||||
cgsnap = db_api.cgsnapshot_get(self.ctxt, expected_cgsnap['id'])
|
||||
self.assertEqual(fake_name, cgsnap['name'])
|
||||
|
||||
def test_cgsnapshot_destroy(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
cgsnap = db_utils.create_cgsnapshot(cg['id'])
|
||||
db_api.cgsnapshot_get(self.ctxt, cgsnap['id'])
|
||||
|
||||
db_api.cgsnapshot_destroy(self.ctxt, cgsnap['id'])
|
||||
|
||||
self.assertRaises(exception.NotFound, db_api.cgsnapshot_get,
|
||||
self.ctxt, cgsnap['id'])
|
||||
|
||||
def test_cgsnapshot_members_get_all(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
cgsnap = db_utils.create_cgsnapshot(cg['id'])
|
||||
expected_member = db_utils.create_cgsnapshot_member(cgsnap['id'])
|
||||
|
||||
members = db_api.cgsnapshot_members_get_all(self.ctxt, cgsnap['id'])
|
||||
|
||||
self.assertEqual(1, len(members))
|
||||
member = members[0]
|
||||
self.assertDictMatch(dict(expected_member), dict(member))
|
||||
|
||||
def test_count_cgsnapshot_members_in_share(self):
|
||||
share = db_utils.create_share()
|
||||
share2 = db_utils.create_share()
|
||||
cg = db_utils.create_consistency_group()
|
||||
cgsnap = db_utils.create_cgsnapshot(cg['id'])
|
||||
db_utils.create_cgsnapshot_member(cgsnap['id'], share_id=share['id'])
|
||||
db_utils.create_cgsnapshot_member(cgsnap['id'], share_id=share2['id'])
|
||||
|
||||
count = db_api.count_cgsnapshot_members_in_share(
|
||||
self.ctxt, share['id'])
|
||||
|
||||
self.assertEqual(1, count)
|
||||
|
||||
def test_cgsnapshot_members_get(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
cgsnap = db_utils.create_cgsnapshot(cg['id'])
|
||||
expected_member = db_utils.create_cgsnapshot_member(cgsnap['id'])
|
||||
|
||||
member = db_api.cgsnapshot_member_get(self.ctxt,
|
||||
expected_member['id'])
|
||||
|
||||
self.assertDictMatch(dict(expected_member), dict(member))
|
||||
|
||||
def test_cgsnapshot_members_get_not_found(self):
|
||||
self.assertRaises(exception.CGSnapshotMemberNotFound,
|
||||
db_api.cgsnapshot_member_get, self.ctxt, 'fake_id')
|
||||
|
||||
def test_cgsnapshot_member_update(self):
|
||||
cg = db_utils.create_consistency_group()
|
||||
cgsnap = db_utils.create_cgsnapshot(cg['id'])
|
||||
expected_member = db_utils.create_cgsnapshot_member(cgsnap['id'])
|
||||
|
||||
db_api.cgsnapshot_member_update(
|
||||
self.ctxt, expected_member['id'],
|
||||
{'status': constants.STATUS_AVAILABLE})
|
||||
|
||||
member = db_api.cgsnapshot_member_get(self.ctxt, expected_member['id'])
|
||||
self.assertEqual(constants.STATUS_AVAILABLE, member['status'])
|
||||
|
||||
|
||||
class ShareSnapshotDatabaseAPITestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -29,6 +29,45 @@ def _create_db_row(method, default_values, 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 = {
|
||||
|
Loading…
Reference in New Issue
Block a user