Add methods for share instances in Share API

This commit adds a possibility to create/delete
share instances and allow/disable access to individual
share instances through Share API. It's required minimum
in Manila core to implement share migration functionality.

Also this commit updates methods in Share RPC API,
Share manager, Scheduler RPC API and Share manager
to maintain consistency.

Partially implements bp share-instances

Change-Id: I3af93071b5851944b59a3c5b1a0c2296e1267bfe
This commit is contained in:
Igor Malinovskiy 2015-08-26 11:09:39 +03:00
parent f5f36e3bfc
commit f641d8f28a
20 changed files with 1520 additions and 1070 deletions

View File

@ -287,18 +287,51 @@ def share_instance_get(context, instance_id, with_share_data=False):
with_share_data=with_share_data)
def share_instance_create(context, share_id, values):
"""Create new share instance."""
return IMPL.share_instance_create(context, share_id, values)
def share_instance_delete(context, instance_id):
"""Delete share instance."""
return IMPL.share_instance_delete(context, instance_id)
def share_instance_update(context, instance_id, values, with_share_data=False):
"""Update share instance fields."""
return IMPL.share_instance_update(context, instance_id, values,
with_share_data=with_share_data)
def share_instances_get_all_by_share_server(context, share_server_id):
"""Returns all share instances with given share_server_id."""
return IMPL.share_instances_get_all_by_share_server(context,
share_server_id)
def share_instances_get_all_by_host(context, host):
"""Returns all share instances with given host."""
return IMPL.share_instances_get_all_by_host(context, host)
def share_instances_get_all_by_share_network(context, share_network_id):
"""Returns list of shares that belong to given share network."""
return IMPL.share_instances_get_all_by_share_network(context,
share_network_id)
def share_instances_get_all_by_share(context, share_id):
"""Returns list of shares that belong to given share."""
return IMPL.share_instances_get_all_by_share_network(context, share_id)
###################
def share_create(context, values):
def share_create(context, values, create_share_instance=True):
"""Create new share."""
return IMPL.share_create(context, values)
return IMPL.share_create(context, values,
create_share_instance=create_share_instance)
def share_data_get_for_project(context, project_id, session=None):
@ -323,11 +356,6 @@ def share_get_all(context, filters=None, sort_key=None, sort_dir=None):
)
def share_instances_get_all_by_host(context, host):
"""Returns all share instances with given host."""
return IMPL.share_instances_get_all_by_host(context, host)
def share_get_all_by_project(context, project_id, filters=None,
is_public=False, sort_key=None, sort_dir=None):
"""Returns all shares with given project ID."""
@ -337,12 +365,6 @@ def share_get_all_by_project(context, project_id, filters=None,
)
def share_instances_get_all_by_share_network(context, share_network_id):
"""Returns list of shares that belong to given share network."""
return IMPL.share_instances_get_all_by_share_network(context,
share_network_id)
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."""
@ -366,12 +388,17 @@ def share_access_create(context, values):
def share_access_get(context, access_id):
"""Allow access to share."""
"""Get share access rule."""
return IMPL.share_access_get(context, access_id)
def share_instance_access_get(context, access_id, instance_id):
"""Get access rule mapping for share instance."""
return IMPL.share_instance_access_get(context, access_id, instance_id)
def share_access_get_all_for_share(context, share_id):
"""Allow access to share."""
"""Get all access rules for given share."""
return IMPL.share_access_get_all_for_share(context, share_id)
@ -387,9 +414,14 @@ def share_access_delete(context, access_id):
return IMPL.share_access_delete(context, access_id)
def share_access_update(context, access_id, values):
"""Update access record."""
return IMPL.share_access_update(context, access_id, values)
def share_instance_access_delete(context, mapping_id):
"""Deny access to share instance."""
return IMPL.share_instance_access_delete(context, mapping_id)
def share_instance_access_update_state(context, mapping_id, state):
"""Update state of access rule mapping."""
return IMPL.share_instance_access_update_state(context, mapping_id, state)
####################

View File

@ -0,0 +1,105 @@
# 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.
"""add_share_instances_access_map
Revision ID: 579c267fbb4d
Revises: 5077ffcc5f1c
Create Date: 2015-08-19 07:51:52.928542
"""
# revision identifiers, used by Alembic.
revision = '579c267fbb4d'
down_revision = '5077ffcc5f1c'
from alembic import op
from sqlalchemy import Column, DateTime, ForeignKey, String
from oslo_utils import uuidutils
from manila.db.migrations import utils
def upgrade():
"""Create 'share_instance_access_map' table and move 'state' column."""
instance_access_table = op.create_table(
'share_instance_access_map',
Column('created_at', DateTime),
Column('updated_at', DateTime),
Column('deleted_at', DateTime),
Column('deleted', String(length=36), default='False'),
Column('id', String(length=36), primary_key=True, nullable=False),
Column('share_instance_id', String(length=36),
ForeignKey('share_instances.id', name="siam_instance_fk")),
Column('access_id', String(length=36),
ForeignKey('share_access_map.id', name="siam_access_fk")),
Column('state', String(length=255)),
mysql_engine='InnoDB',
mysql_charset='utf8')
# NOTE(u_glide): Move all states from 'share_access_map'
# to 'share_instance_access_map'
instance_access_mappings = []
connection = op.get_bind()
access_table = utils.load_table('share_access_map', connection)
instances_table = utils.load_table('share_instances', connection)
for access_rule in connection.execute(access_table.select()):
instances_query = instances_table.select().where(
instances_table.c.share_id == access_rule.share_id
)
for instance in connection.execute(instances_query):
instance_access_mappings.append({
'created_at': access_rule.created_at,
'updated_at': access_rule.updated_at,
'deleted_at': access_rule.deleted_at,
'deleted': access_rule.deleted,
'id': uuidutils.generate_uuid(),
'share_instance_id': instance.id,
'access_id': access_rule.id,
'state': access_rule.state,
})
op.bulk_insert(instance_access_table, instance_access_mappings)
op.drop_column('share_access_map', 'state')
def downgrade():
"""Remove 'share_instance_access_map' table and add 'state' column back.
This method can lead to data loss because only first state is saved in
share_access_map table.
"""
op.add_column('share_access_map', Column('state', String(length=255)))
# NOTE(u_glide): Move all states from 'share_instance_access_map'
# to 'share_access_map'
connection = op.get_bind()
access_table = utils.load_table('share_access_map', connection)
instance_access_table = utils.load_table('share_instance_access_map',
connection)
for access_rule in connection.execute(access_table.select()):
access_mapping = connection.execute(
instance_access_table.select().where(
instance_access_table.c.deleted == "False").where(
instance_access_table.c.access_id == access_rule['id'])
).first()
op.execute(
access_table.update().where(
access_table.c.id == access_rule['id']
).values({'state': access_mapping['state']})
)
op.drop_table('share_instance_access_map')

View File

@ -1115,7 +1115,13 @@ def extract_snapshot_instance_values(values):
@require_context
def share_instance_create(context, share_id, values, session):
def share_instance_create(context, share_id, values):
session = get_session()
with session.begin():
return _share_instance_create(context, share_id, values, session)
def _share_instance_create(context, share_id, values, session):
if not values.get('id'):
values['id'] = uuidutils.generate_uuid()
values.update({'share_id': share_id})
@ -1171,6 +1177,26 @@ def share_instance_get(context, share_instance_id, session=None,
return result
@require_context
def share_instance_delete(context, instance_id, session=None):
if session is None:
session = get_session()
with session.begin():
instance_ref = share_instance_get(context, instance_id,
session=session)
instance_ref.soft_delete(session=session, update_status=True)
session.query(models.ShareInstanceExportLocations).filter_by(
share_instance_id=instance_id).soft_delete()
share = share_get(context, instance_ref['share_id'], session=session)
if len(share.instances) == 0:
share.soft_delete(session=session)
share_access_delete_all_by_share(context, share['id'])
@require_admin_context
def share_instances_get_all_by_host(context, host):
"""Retrieves all share instances hosted on a host."""
@ -1196,6 +1222,28 @@ def share_instances_get_all_by_share_network(context, share_network_id):
return result
@require_context
def share_instances_get_all_by_share_server(context, share_server_id):
"""Returns list of share instance with given share server."""
result = (
model_query(context, models.ShareInstance).filter(
models.ShareInstance.share_server_id == share_server_id,
).all()
)
return result
@require_context
def share_instances_get_all_by_share(context, share_id):
"""Returns list of share instances that belong to given share."""
result = (
model_query(context, models.ShareInstance).filter(
models.ShareInstance.share_id == share_id,
).all()
)
return result
################
@ -1233,8 +1281,8 @@ def share_create(context, values, create_share_instance=True):
share_ref.save(session=session)
if create_share_instance:
share_instance_create(context, share_ref['id'],
share_instance_values, session=session)
_share_instance_create(context, share_ref['id'],
share_instance_values, session=session)
# NOTE(u_glide): Do so to prevent errors with relationships
return share_get(context, share_ref['id'], session=session)
@ -1394,41 +1442,91 @@ def share_delete(context, share_id):
with session.begin():
share_ref = share_get(context, share_id, session)
if len(share_ref.instances) > 0:
msg = _("Share %(id)s has %(count)s share instances.") % {
'id': share_id, 'count': len(share_ref.instances)}
raise exception.InvalidShare(msg)
share_ref.soft_delete(session=session)
share_ref.instance.soft_delete(session=session, update_status=True)
session.query(models.ShareMetadata).\
filter_by(share_id=share_id).soft_delete()
session.query(models.ShareInstanceExportLocations).\
filter_by(share_instance_id=share_ref.instance['id']).soft_delete()
###################
def _share_access_get_query(context, session, values):
def _share_access_get_query(context, session, values, read_deleted='no'):
"""Get access record."""
query = model_query(context, models.ShareAccessMapping, session=session)
query = model_query(context, models.ShareAccessMapping, session=session,
read_deleted=read_deleted)
return query.filter_by(**values)
def _share_instance_access_query(context, session, access_id,
instance_id=None):
filters = {'access_id': access_id}
if instance_id is not None:
filters.update({'share_instance_id': instance_id})
return model_query(context, models.ShareInstanceAccessMapping,
session=session).filter_by(**filters)
@require_context
def share_access_create(context, values):
values = ensure_model_dict_has_id(values)
session = get_session()
with session.begin():
access_ref = models.ShareAccessMapping()
state = values.pop('state', None)
access_ref.update(values)
access_ref.save(session=session)
return access_ref
parent_share = share_get(context, values['share_id'], session=session)
for instance in parent_share.instances:
vals = {
'share_instance_id': instance['id'],
'access_id': access_ref['id'],
}
if state is not None:
vals.update({'state': state})
_share_instance_access_create(vals, session)
return share_access_get(context, access_ref['id'])
def _share_instance_access_create(values, session):
access_ref = models.ShareInstanceAccessMapping()
access_ref.update(ensure_model_dict_has_id(values))
access_ref.save(session=session)
return access_ref
@require_context
def share_access_get(context, access_id):
"""Get access record."""
session = get_session()
access = _share_access_get_query(context, session,
{'id': access_id}).first()
access = _share_access_get_query(
context, session, {'id': access_id}).first()
if access:
return access
else:
raise exception.NotFound()
@require_context
def share_instance_access_get(context, access_id, instance_id):
"""Get access record."""
session = get_session()
access = _share_instance_access_query(context, session, access_id,
instance_id).first()
if access:
return access
else:
@ -1442,6 +1540,10 @@ def share_access_get_all_for_share(context, share_id):
{'share_id': share_id}).all()
def _share_instance_access_get_all(context, access_id, session):
return _share_instance_access_query(context, session, access_id).all()
@require_context
def share_access_get_all_by_type_and_access(context, share_id, access_type,
access):
@ -1455,22 +1557,65 @@ def share_access_get_all_by_type_and_access(context, share_id, access_type,
@require_context
def share_access_delete(context, access_id):
session = get_session()
with session.begin():
mappings = _share_instance_access_get_all(context, access_id, session)
if len(mappings) > 0:
msg = (_("Access rule %s has mappings"
" to share instances.") % access_id)
raise exception.InvalidShareAccess(msg)
session.query(models.ShareAccessMapping).\
filter_by(id=access_id).soft_delete(update_status=True,
status_field_name='state')
@require_context
@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
def share_access_update(context, access_id, values):
def share_access_delete_all_by_share(context, share_id):
session = get_session()
with session.begin():
access = _share_access_get_query(context, session, {'id': access_id})
access = access.one()
access.update(values)
access.save(session=session)
return access
session.query(models.ShareAccessMapping). \
filter_by(share_id=share_id).soft_delete(update_status=True,
status_field_name='state')
@require_context
def share_instance_access_delete(context, mapping_id):
session = get_session()
with session.begin():
mapping = session.query(models.ShareInstanceAccessMapping).\
filter_by(id=mapping_id).first()
if not mapping:
exception.NotFound()
mapping.soft_delete(session, update_status=True,
status_field_name='state')
other_mappings = _share_instance_access_get_all(
context, mapping['access_id'], session)
# NOTE(u_glide): Remove access rule if all mappings were removed.
if len(other_mappings) == 0:
(
session.query(models.ShareAccessMapping)
.filter_by(id=mapping['access_id'])
.soft_delete(update_status=True, status_field_name='state')
)
@require_context
@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
def share_instance_access_update_state(context, mapping_id, state):
session = get_session()
with session.begin():
mapping = session.query(models.ShareInstanceAccessMapping).\
filter_by(id=mapping_id).first()
mapping.update({'state': state})
mapping.save(session=session)
return mapping
###################

View File

@ -373,24 +373,76 @@ class ShareMetadata(BASE, ManilaBase):
class ShareAccessMapping(BASE, ManilaBase):
"""Represents access to NFS."""
"""Represents access to share."""
__tablename__ = 'share_access_map'
@property
def state(self):
state = ShareInstanceAccessMapping.STATE_NEW
if len(self.instance_mappings) > 0:
state = ShareInstanceAccessMapping.STATE_ACTIVE
priorities = ShareInstanceAccessMapping.STATE_PRIORITIES
for mapping in self.instance_mappings:
priority = priorities.get(
mapping['state'], ShareInstanceAccessMapping.STATE_ERROR)
if priority > priorities.get(state):
state = mapping['state']
if state == ShareInstanceAccessMapping.STATE_ERROR:
break
return state
id = Column(String(36), primary_key=True)
deleted = Column(String(36), default='False')
share_id = Column(String(36), ForeignKey('shares.id'))
access_type = Column(String(255))
access_to = Column(String(255))
access_level = Column(Enum(*constants.ACCESS_LEVELS),
default=constants.ACCESS_LEVEL_RW)
instance_mappings = orm.relationship(
"ShareInstanceAccessMapping",
lazy='immediate',
primaryjoin=(
'and_('
'ShareAccessMapping.id == '
'ShareInstanceAccessMapping.access_id, '
'ShareInstanceAccessMapping.deleted == "False")'
)
)
class ShareInstanceAccessMapping(BASE, ManilaBase):
"""Represents access to individual share instances."""
STATE_NEW = constants.STATUS_NEW
STATE_ACTIVE = constants.STATUS_ACTIVE
STATE_DELETING = constants.STATUS_DELETING
STATE_DELETED = constants.STATUS_DELETED
STATE_ERROR = constants.STATUS_ERROR
__tablename__ = 'share_access_map'
# NOTE(u_glide): State with greatest priority becomes a state of access
# rule
STATE_PRIORITIES = {
STATE_ACTIVE: 0,
STATE_NEW: 1,
STATE_DELETED: 2,
STATE_DELETING: 3,
STATE_ERROR: 4
}
__tablename__ = 'share_instance_access_map'
id = Column(String(36), primary_key=True)
deleted = Column(String(36), default='False')
share_id = Column(String(36), ForeignKey('shares.id'))
access_type = Column(String(255))
access_to = Column(String(255))
share_instance_id = Column(String(36), ForeignKey('share_instances.id'))
access_id = Column(String(36), ForeignKey('share_access_map.id'))
state = Column(Enum(STATE_NEW, STATE_ACTIVE,
STATE_DELETING, STATE_DELETED, STATE_ERROR),
default=STATE_NEW)
access_level = Column(Enum(*constants.ACCESS_LEVELS),
default=constants.ACCESS_LEVEL_RW)
class ShareSnapshot(BASE, ManilaBase):

View File

@ -363,6 +363,10 @@ class InvalidShare(Invalid):
message = _("Invalid share: %(reason)s.")
class InvalidShareInstance(Invalid):
message = _("Invalid share instance: %(reason)s.")
class ManageInvalidShare(InvalidShare):
message = _("Manage existing share failed due to "
"invalid share: %(reason)s")

View File

@ -66,7 +66,11 @@ class ChanceScheduler(driver.Scheduler):
snapshot_id = request_spec['snapshot_id']
updated_share = driver.share_update_db(context, share_id, host)
self.share_rpcapi.create_share(context, updated_share, host,
request_spec,
filter_properties,
snapshot_id)
self.share_rpcapi.create_share_instance(
context,
updated_share.instance,
host,
request_spec,
filter_properties,
snapshot_id
)

View File

@ -102,10 +102,12 @@ class FilterScheduler(driver.Scheduler):
# context is not serializable
filter_properties.pop('context', None)
self.share_rpcapi.create_share(context, updated_share, host,
request_spec=request_spec,
filter_properties=filter_properties,
snapshot_id=snapshot_id)
self.share_rpcapi.create_share_instance(
context, updated_share.instance, host,
request_spec=request_spec,
filter_properties=filter_properties,
snapshot_id=snapshot_id
)
def _schedule_share(self, context, request_spec, filter_properties=None):
"""Returns a list of hosts that meet the required specs.

View File

@ -46,7 +46,7 @@ CONF.register_opt(scheduler_driver_opt)
class SchedulerManager(manager.Manager):
"""Chooses a host to create shares."""
RPC_API_VERSION = '1.1'
RPC_API_VERSION = '1.2'
def __init__(self, scheduler_driver=None, service_name=None,
*args, **kwargs):
@ -76,8 +76,8 @@ class SchedulerManager(manager.Manager):
host,
capabilities)
def create_share(self, context, topic, share_id, snapshot_id=None,
request_spec=None, filter_properties=None):
def create_share_instance(self, context, request_spec=None,
filter_properties=None):
try:
self.driver.schedule_create_share(context, request_spec,
filter_properties)

View File

@ -32,26 +32,25 @@ class SchedulerAPI(object):
1.0 - Initial version.
1.1 - Add get_pools method
1.2 - Introduce Share Instances:
Replace create_share() - > create_share_instance()
'''
RPC_API_VERSION = '1.1'
RPC_API_VERSION = '1.2'
def __init__(self):
super(SchedulerAPI, self).__init__()
target = messaging.Target(topic=CONF.scheduler_topic,
version=self.RPC_API_VERSION)
self.client = rpc.get_client(target, version_cap='1.1')
self.client = rpc.get_client(target, version_cap='1.2')
def create_share(self, ctxt, topic, share_id, snapshot_id=None,
request_spec=None, filter_properties=None):
def create_share_instance(self, ctxt, request_spec=None,
filter_properties=None):
request_spec_p = jsonutils.to_primitive(request_spec)
cctxt = self.client.prepare(version='1.0')
cctxt = self.client.prepare(version='1.2')
return cctxt.cast(
ctxt,
'create_share',
topic=topic,
share_id=share_id,
snapshot_id=snapshot_id,
'create_share_instance',
request_spec=request_spec_p,
filter_properties=filter_properties,
)

View File

@ -59,13 +59,14 @@ class SimpleScheduler(chance.ChanceScheduler):
if not utils.service_is_up(service):
raise exception.WillNotSchedule(host=host)
updated_share = driver.share_update_db(context, share_id, host)
self.share_rpcapi.create_share(context,
updated_share,
host,
request_spec,
None,
snapshot_id=snapshot_id
)
self.share_rpcapi.create_share_instance(
context,
updated_share.instance,
host,
request_spec,
None,
snapshot_id=snapshot_id
)
return None
results = db.service_get_all_share_sorted(elevated)
@ -80,12 +81,13 @@ class SimpleScheduler(chance.ChanceScheduler):
if utils.service_is_up(service) and not service['disabled']:
updated_share = driver.share_update_db(context, share_id,
service['host'])
self.share_rpcapi.create_share(context,
updated_share,
service['host'],
request_spec,
None,
snapshot_id=snapshot_id)
self.share_rpcapi.create_share_instance(
context,
updated_share.instance,
service['host'],
request_spec,
None,
snapshot_id=snapshot_id)
return None
msg = _("Is the appropriate service running?")
raise exception.NoValidHost(reason=msg)

View File

@ -2,6 +2,7 @@
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
# Copyright (c) 2015 Tom Barron. All rights reserved.
# Copyright (c) 2015 Mirantis Inc.
#
# 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
@ -38,7 +39,6 @@ from manila import policy
from manila import quota
from manila.scheduler import rpcapi as scheduler_rpcapi
from manila.share import rpcapi as share_rpcapi
from manila.share import share_types
share_api_opts = [
cfg.BoolOpt('use_scheduler_creating_share_from_snapshot',
@ -108,9 +108,6 @@ class API(base.Base):
source_share = self.db.share_get(context, snapshot['share_id'])
if share_type is None:
share_type_id = source_share['share_type_id']
if share_type_id is not None:
share_type = share_types.get_share_type(context,
share_type_id)
else:
share_type_id = share_type['id']
if share_type_id != source_share['share_type_id']:
@ -172,11 +169,8 @@ class API(base.Base):
'user_id': context.user_id,
'project_id': context.project_id,
'snapshot_id': snapshot_id,
'share_network_id': share_network_id,
'availability_zone': availability_zone,
'metadata': metadata,
'status': constants.STATUS_CREATING,
'scheduled_at': timeutils.utcnow(),
'display_name': name,
'display_description': description,
'share_proto': share_proto,
@ -185,7 +179,8 @@ class API(base.Base):
}
try:
share = self.db.share_create(context, options)
share = self.db.share_create(context, options,
create_share_instance=False)
QUOTAS.commit(context, reservations)
except Exception:
with excutils.save_and_reraise_exception():
@ -194,43 +189,64 @@ class API(base.Base):
finally:
QUOTAS.rollback(context, reservations)
request_spec = {
'share_properties': options,
'share_proto': share_proto,
'share_id': share['id'],
'snapshot_id': snapshot_id,
'share_type': share_type,
}
filter_properties = {}
if (snapshot and not CONF.use_scheduler_creating_share_from_snapshot):
host = None
if snapshot and not CONF.use_scheduler_creating_share_from_snapshot:
# Shares from snapshots with restriction - source host only.
# It is common situation for different types of backends.
host = snapshot['share']['host']
share = self.db.share_update(context, share['id'], {'host': host})
self.share_rpcapi.create_share(
context,
share,
host,
request_spec=request_spec,
filter_properties=filter_properties,
snapshot_id=snapshot_id,
)
else:
# Shares from scratch and from snapshots when source host is not
# the only allowed, it is possible, for example, in multibackend
# installation with Generic drivers only.
self.scheduler_rpcapi.create_share(
context,
CONF.share_topic,
share['id'],
snapshot_id,
request_spec=request_spec,
filter_properties=filter_properties,
)
self.create_instance(context, share, share_network_id=share_network_id,
host=host)
return share
def create_instance(self, context, share, share_network_id=None,
host=None):
policy.check_policy(context, 'share', 'create')
share_instance = self.db.share_instance_create(
context, share['id'],
{
'share_network_id': share_network_id,
'status': constants.STATUS_CREATING,
'scheduled_at': timeutils.utcnow(),
'host': host or ''
}
)
share_dict = share.to_dict()
share_dict.update(
{'metadata': self.db.share_metadata_get(context, share['id'])}
)
share_type = None
if share['share_type_id']:
share_type = self.db.share_type_get(
context, share['share_type_id'])
request_spec = {
'share_properties': share_dict,
'share_proto': share['share_proto'],
'share_id': share['id'],
'snapshot_id': share['snapshot_id'],
'share_type': share_type,
}
if host:
self.share_rpcapi.create_share_instance(
context,
share_instance,
host,
request_spec=request_spec,
filter_properties={},
snapshot_id=share['snapshot_id'],
)
else:
# Create share instance from scratch or from snapshot could happen
# on hosts other than the source host.
self.scheduler_rpcapi.create_share_instance(
context, request_spec=request_spec, filter_properties={})
def manage(self, context, share_data, driver_options):
policy.check_policy(context, 'share', 'manage')
@ -285,26 +301,13 @@ class API(base.Base):
@policy.wrap_check_policy('share')
def delete(self, context, share, force=False):
"""Delete share."""
share = self.db.share_get(context, share['id'])
if context.is_admin and context.project_id != share['project_id']:
project_id = share['project_id']
else:
project_id = context.project_id
share_id = share['id']
if not share['host']:
try:
reservations = QUOTAS.reserve(context,
project_id=project_id,
shares=-1,
gigabytes=-share['size'])
except Exception:
reservations = None
LOG.exception(_LE("Failed to update quota for deleting share"))
self.db.share_delete(context.elevated(), share_id)
if reservations:
QUOTAS.commit(context, reservations, project_id=project_id)
return
statuses = (constants.STATUS_AVAILABLE, constants.STATUS_ERROR)
if not (force or share['status'] in statuses):
@ -317,12 +320,43 @@ class API(base.Base):
msg = _("Share still has %d dependent snapshots") % len(snapshots)
raise exception.InvalidShare(reason=msg)
now = timeutils.utcnow()
share = self.db.share_update(
context, share_id, {'status': constants.STATUS_DELETING,
'terminated_at': now})
try:
reservations = QUOTAS.reserve(context,
project_id=project_id,
shares=-1,
gigabytes=-share['size'])
except Exception as e:
reservations = None
LOG.exception(
_LE("Failed to update quota for deleting share: %s"),
six.text_type(e)
)
self.share_rpcapi.delete_share(context, share)
for share_instance in share.instances:
if share_instance['host']:
self.delete_instance(context, share_instance, force=force)
else:
self.db.share_instance_delete(context, share_instance['id'])
if reservations:
QUOTAS.commit(context, reservations, project_id=project_id)
def delete_instance(self, context, share_instance, force=False):
policy.check_policy(context, 'share', 'delete')
statuses = (constants.STATUS_AVAILABLE, constants.STATUS_ERROR)
if not (force or share_instance['status'] in statuses):
msg = _("Share instance status must be one of %(statuses)s") % {
"statuses": statuses}
raise exception.InvalidShareInstance(reason=msg)
share_instance = self.db.share_instance_update(
context, share_instance['id'],
{'status': constants.STATUS_DELETING,
'terminated_at': timeutils.utcnow()}
)
self.share_rpcapi.delete_share_instance(context, share_instance)
# NOTE(u_glide): 'updated_at' timestamp is used to track last usage of
# share server. This is required for automatic share servers cleanup
@ -330,16 +364,17 @@ class API(base.Base):
# doesn't have shares (unused). We do this update only on share
# deletion because share server with shares cannot be deleted, so no
# need to do this update on share creation or any other share operation
if share['share_server_id']:
if share_instance['share_server_id']:
self.db.share_server_update(
context,
share['share_server_id'],
share_instance['share_server_id'],
{'updated_at': timeutils.utcnow()})
def delete_share_server(self, context, server):
"""Delete share server."""
policy.check_policy(context, 'share_server', 'delete', server)
shares = self.db.share_get_all_by_share_server(context, server['id'])
shares = self.db.share_instances_get_all_by_share_server(context,
server['id'])
if shares:
raise exception.ShareServerInUse(share_server_id=server['id'])
# NOTE(vponomaryov): There is no share_server status update here,
@ -560,13 +595,11 @@ class API(base.Base):
def allow_access(self, ctx, share, access_type, access_to,
access_level=None):
"""Allow access to share."""
if not share['host']:
msg = _("Share host is None")
raise exception.InvalidShare(reason=msg)
policy.check_policy(ctx, 'share', 'allow_access')
share = self.db.share_get(ctx, share['id'])
if share['status'] != constants.STATUS_AVAILABLE:
msg = _("Share status must be %s") % constants.STATUS_AVAILABLE
raise exception.InvalidShare(reason=msg)
policy.check_policy(ctx, 'share', 'allow_access')
values = {
'share_id': share['id'],
'access_type': access_type,
@ -582,27 +615,39 @@ class API(base.Base):
msg = _("Invalid share access level: %s.") % access_level
raise exception.InvalidShareAccess(reason=msg)
access = self.db.share_access_create(ctx, values)
self.share_rpcapi.allow_access(ctx, share, access)
for share_instance in share.instances:
self.allow_access_to_instance(ctx, share_instance, access)
return access
def allow_access_to_instance(self, context, share_instance, access):
policy.check_policy(context, 'share', 'allow_access')
if not share_instance['host']:
msg = _("Invalid share instance host: %s") % share_instance['host']
raise exception.InvalidShareInstance(reason=msg)
self.share_rpcapi.allow_access(context, share_instance, access)
def deny_access(self, ctx, share, access):
"""Deny access to share."""
policy.check_policy(ctx, 'share', 'deny_access')
# First check state of the target share
if not share['host']:
msg = _("Share host is None")
share = self.db.share_get(ctx, share['id'])
if not (share.instances and share.instance['host']):
msg = _("Share doesn't have any instances")
raise exception.InvalidShare(reason=msg)
if share['status'] != constants.STATUS_AVAILABLE:
msg = _("Share status must be %s") % constants.STATUS_AVAILABLE
raise exception.InvalidShare(reason=msg)
# Then check state of the access rule
if access['state'] == access.STATE_ERROR:
if access['state'] == constants.STATUS_ERROR:
self.db.share_access_delete(ctx, access["id"])
elif access['state'] == access.STATE_ACTIVE:
self.db.share_access_update(ctx, access["id"],
{'state': access.STATE_DELETING})
self.share_rpcapi.deny_access(ctx, share, access)
elif access['state'] == constants.STATUS_ACTIVE:
for share_instance in share.instances:
self.deny_access_to_instance(ctx, share_instance, access)
else:
msg = _("Access policy should be %(active)s or in %(error)s "
"state") % {"active": constants.STATUS_ACTIVE,
@ -610,6 +655,21 @@ class API(base.Base):
raise exception.InvalidShareAccess(reason=msg)
# update share state and send message to manager
def deny_access_to_instance(self, context, share_instance, access):
policy.check_policy(context, 'share', 'deny_access')
if not share_instance['host']:
msg = _("Invalid share instance host: %s") % share_instance['host']
raise exception.InvalidShareInstance(reason=msg)
access_mapping = self.db.share_instance_access_get(
context, access['id'], share_instance['id'])
self.db.share_instance_access_update_state(
context, access_mapping['id'],
access_mapping.STATE_DELETING)
self.share_rpcapi.deny_access(context, share_instance, access)
def access_get_all(self, context, share):
"""Returns all access rules for share."""
policy.check_policy(context, 'share', 'access_get_all')

View File

@ -94,7 +94,7 @@ QUOTAS = quota.QUOTAS
class ShareManager(manager.SchedulerDependentManager):
"""Manages NAS storages."""
RPC_API_VERSION = '1.3'
RPC_API_VERSION = '1.4'
def __init__(self, share_driver=None, service_name=None, *args, **kwargs):
"""Load the driver from args, or from flags."""
@ -188,9 +188,9 @@ class ShareManager(manager.SchedulerDependentManager):
ctxt, share_instance['id'], export_locations)
rules = self.db.share_access_get_all_for_share(
ctxt, share_instance['id'])
ctxt, share_instance['share_id'])
for access_ref in rules:
if access_ref['state'] != access_ref.STATE_ACTIVE:
if access_ref['state'] != constants.STATUS_ACTIVE:
continue
try:
@ -343,31 +343,32 @@ class ShareManager(manager.SchedulerDependentManager):
return _provide_share_server_for_share()
def _get_share_server(self, context, share):
if share['share_server_id']:
def _get_share_server(self, context, share_instance):
if share_instance['share_server_id']:
return self.db.share_server_get(
context, share['share_server_id'])
context, share_instance['share_server_id'])
else:
return None
def _get_share_instance(self, context, share):
return self.db.share_instance_get(
context, share.instance['id'], with_share_data=True)
if isinstance(share, six.string_types):
id = share
else:
id = share.instance['id']
return self.db.share_instance_get(context, id, with_share_data=True)
def create_share(self, context, share_id, request_spec=None,
filter_properties=None, snapshot_id=None):
"""Creates a share."""
def create_share_instance(self, context, share_instance_id,
request_spec=None, filter_properties=None,
snapshot_id=None):
"""Creates a share instance."""
context = context.elevated()
if filter_properties is None:
filter_properties = {}
share_ref = self.db.share_get(context, share_id)
share_instance = self._get_share_instance(context, share_ref)
share_instance = self._get_share_instance(context, share_instance_id)
share_network_id = share_instance.get('share_network_id', None)
if share_network_id and not self.driver.driver_handles_share_servers:
self.db.share_update(
context, share_id, {'status': constants.STATUS_ERROR})
self.db.share_instance_update(
context, share_instance_id, {'status': constants.STATUS_ERROR})
raise exception.ManilaException(
"Driver does not expect share-network to be provided "
"with current configuration.")
@ -390,9 +391,11 @@ class ShareManager(manager.SchedulerDependentManager):
except Exception:
with excutils.save_and_reraise_exception():
LOG.error(_LE("Failed to get share server"
" for share creation."))
self.db.share_update(context, share_id,
{'status': constants.STATUS_ERROR})
" for share instance creation."))
self.db.share_instance_update(
context, share_instance_id,
{'status': constants.STATUS_ERROR}
)
else:
share_server = None
@ -410,7 +413,8 @@ class ShareManager(manager.SchedulerDependentManager):
except Exception as e:
with excutils.save_and_reraise_exception():
LOG.error(_LE("Share %s failed on creation."), share_id)
LOG.error(_LE("Share instance %s failed on creation."),
share_instance_id)
detail_data = getattr(e, 'detail_data', {})
def get_export_location(details):
@ -425,17 +429,21 @@ class ShareManager(manager.SchedulerDependentManager):
self.db.share_export_locations_update(
context, share_instance['id'], export_locations)
else:
LOG.warning(_LW('Share information in exception '
LOG.warning(_LW('Share instance information in exception '
'can not be written to db because it '
'contains %s and it is not a dictionary.'),
detail_data)
self.db.share_update(
context, share_id, {'status': constants.STATUS_ERROR})
self.db.share_instance_update(
context, share_instance_id,
{'status': constants.STATUS_ERROR}
)
else:
LOG.info(_LI("Share created successfully."))
self.db.share_update(context, share_id,
{'status': constants.STATUS_AVAILABLE,
'launched_at': timeutils.utcnow()})
LOG.info(_LI("Share instance created successfully."))
self.db.share_instance_update(
context, share_instance_id,
{'status': constants.STATUS_AVAILABLE,
'launched_at': timeutils.utcnow()}
)
def manage_share(self, context, share_id, driver_options):
context = context.elevated()
@ -547,7 +555,7 @@ class ShareManager(manager.SchedulerDependentManager):
if self.configuration.safe_get('unmanage_remove_access_rules'):
try:
self._remove_share_access_rules(context, share_ref,
share_server)
share_instance, share_server)
except Exception as e:
share_manage_set_error_status(
_LE("Can not remove access rules of share: %s."), e)
@ -557,46 +565,32 @@ class ShareManager(manager.SchedulerDependentManager):
{'status': constants.STATUS_UNMANAGED,
'deleted': True})
def delete_share(self, context, share_id):
"""Delete a share."""
def delete_share_instance(self, context, share_instance_id):
"""Delete a share instance."""
context = context.elevated()
share_ref = self.db.share_get(context, share_id)
share_instance = self._get_share_instance(context, share_ref)
share_server = self._get_share_server(context, share_ref)
if context.project_id != share_ref['project_id']:
project_id = share_ref['project_id']
else:
project_id = context.project_id
share_instance = self._get_share_instance(context, share_instance_id)
share = self.db.share_get(context, share_instance['share_id'])
share_server = self._get_share_server(context, share_instance)
try:
self._remove_share_access_rules(context, share_ref, share_server)
self._remove_share_access_rules(context, share, share_instance,
share_server)
self.driver.delete_share(context, share_instance,
share_server=share_server)
except Exception:
with excutils.save_and_reraise_exception():
self.db.share_update(
self.db.share_instance_update(
context,
share_id,
share_instance_id,
{'status': constants.STATUS_ERROR_DELETING})
try:
reservations = QUOTAS.reserve(context,
project_id=project_id,
shares=-1,
gigabytes=-share_ref['size'])
except Exception:
reservations = None
LOG.exception(_LE("Failed to update usages deleting share"))
self.db.share_delete(context, share_id)
LOG.info(_LI("Share %s: deleted successfully."), share_ref['name'])
if reservations:
QUOTAS.commit(context, reservations, project_id=project_id)
self.db.share_instance_delete(context, share_instance_id)
LOG.info(_LI("Share instance %s: deleted successfully."),
share_instance_id)
if CONF.delete_share_server_with_last_share:
share_server = self._get_share_server(context, share_ref)
if share_server and not share_server.share_instances:
share_server = self._get_share_server(context, share_instance)
if share_server and len(share_server.share_instances) == 0:
LOG.debug("Scheduled deletion of share-server "
"with id '%s' automatically by "
"deletion of last share.", share_server['id'])
@ -616,12 +610,14 @@ class ShareManager(manager.SchedulerDependentManager):
for server in servers:
self.delete_share_server(ctxt, server)
def _remove_share_access_rules(self, context, share_ref, share_server):
def _remove_share_access_rules(self, context, share_ref, share_instance,
share_server):
rules = self.db.share_access_get_all_for_share(
context, share_ref['id'])
for access_ref in rules:
self._deny_access(context, access_ref, share_ref, share_server)
self._deny_access(context, access_ref,
share_instance, share_server)
def create_snapshot(self, context, share_id, snapshot_id):
"""Create snapshot for share."""
@ -701,44 +697,47 @@ class ShareManager(manager.SchedulerDependentManager):
if reservations:
QUOTAS.commit(context, reservations, project_id=project_id)
def allow_access(self, context, access_id):
"""Allow access to some share."""
def allow_access(self, context, share_instance_id, access_id):
"""Allow access to some share instance."""
access_mapping = self.db.share_instance_access_get(context, access_id,
share_instance_id)
if access_mapping['state'] != access_mapping.STATE_NEW:
return
try:
access_ref = self.db.share_access_get(context, access_id)
share_ref = self.db.share_get(context, access_ref['share_id'])
share_server = self._get_share_server(context,
share_ref)
if access_ref['state'] == access_ref.STATE_NEW:
share_instance = self._get_share_instance(context, share_ref)
self.driver.allow_access(context, share_instance,
access_ref,
share_server=share_server)
self.db.share_access_update(
context, access_id, {'state': access_ref.STATE_ACTIVE})
share_instance = self.db.share_instance_get(
context, share_instance_id, with_share_data=True)
share_server = self._get_share_server(context, share_instance)
self.driver.allow_access(context, share_instance, access_ref,
share_server=share_server)
self.db.share_instance_access_update_state(
context, access_mapping['id'], access_mapping.STATE_ACTIVE)
except Exception:
with excutils.save_and_reraise_exception():
self.db.share_access_update(
context, access_id, {'state': access_ref.STATE_ERROR})
self.db.share_instance_access_update_state(
context, access_mapping['id'], access_mapping.STATE_ERROR)
def deny_access(self, context, access_id):
def deny_access(self, context, share_instance_id, access_id):
"""Deny access to some share."""
access_ref = self.db.share_access_get(context, access_id)
share_ref = self.db.share_get(context, access_ref['share_id'])
share_server = self._get_share_server(context,
share_ref)
self._deny_access(context, access_ref, share_ref, share_server)
share_instance = self.db.share_instance_get(
context, share_instance_id, with_share_data=True)
share_server = self._get_share_server(context, share_instance)
self._deny_access(context, access_ref, share_instance, share_server)
def _deny_access(self, context, access_ref, share_ref, share_server):
access_id = access_ref['id']
share_instance = self._get_share_instance(context, share_ref)
def _deny_access(self, context, access_ref, share_instance, share_server):
access_mapping = self.db.share_instance_access_get(
context, access_ref['id'], share_instance['id'])
try:
self.driver.deny_access(context, share_instance, access_ref,
share_server=share_server)
self.db.share_instance_access_delete(context, access_mapping['id'])
except Exception:
with excutils.save_and_reraise_exception():
self.db.share_access_update(
context, access_id, {'state': access_ref.STATE_ERROR})
self.db.share_access_delete(context, access_id)
self.db.share_instance_access_update_state(
context, access_mapping['id'], access_mapping.STATE_ERROR)
@periodic_task.periodic_task(spacing=CONF.periodic_interval)
def _report_driver_status(self, context):
@ -920,7 +919,8 @@ class ShareManager(manager.SchedulerDependentManager):
# this method starts executing when amount of dependent shares
# has been changed.
server_id = share_server['id']
shares = self.db.share_get_all_by_share_server(context, server_id)
shares = self.db.share_instances_get_all_by_share_server(
context, server_id)
if shares:
raise exception.ShareServerInUse(share_server_id=server_id)

View File

@ -27,7 +27,7 @@ CONF = cfg.CONF
class ShareAPI(object):
'''Client side of the share rpc API.
"""Client side of the share rpc API.
API version history:
@ -35,7 +35,11 @@ class ShareAPI(object):
1.1 - Add manage_share() and unmanage_share() methods
1.2 - Add extend_share() method
1.3 - Add shrink_share() method
'''
1.4 - Introduce Share Instances:
create_share() -> create_share_instance()
delete_share() -> delete_share_instance()
Add share_instance argument to allow_access() & deny_access()
"""
BASE_RPC_API_VERSION = '1.0'
@ -43,18 +47,18 @@ class ShareAPI(object):
super(ShareAPI, self).__init__()
target = messaging.Target(topic=CONF.share_topic,
version=self.BASE_RPC_API_VERSION)
self.client = rpc.get_client(target, version_cap='1.3')
self.client = rpc.get_client(target, version_cap='1.4')
def create_share(self, ctxt, share, host,
request_spec, filter_properties,
snapshot_id=None):
def create_share_instance(self, ctxt, share_instance, host,
request_spec, filter_properties,
snapshot_id=None):
new_host = utils.extract_host(host)
cctxt = self.client.prepare(server=new_host, version='1.0')
cctxt = self.client.prepare(server=new_host, version='1.4')
request_spec_p = jsonutils.to_primitive(request_spec)
cctxt.cast(
ctxt,
'create_share',
share_id=share['id'],
'create_share_instance',
share_instance_id=share_instance['id'],
request_spec=request_spec_p,
filter_properties=filter_properties,
snapshot_id=snapshot_id,
@ -73,10 +77,11 @@ class ShareAPI(object):
cctxt = self.client.prepare(server=host, version='1.1')
cctxt.cast(ctxt, 'unmanage_share', share_id=share['id'])
def delete_share(self, ctxt, share):
host = utils.extract_host(share['host'])
cctxt = self.client.prepare(server=host, version='1.0')
cctxt.cast(ctxt, 'delete_share', share_id=share['id'])
def delete_share_instance(self, ctxt, share_instance):
host = utils.extract_host(share_instance['host'])
cctxt = self.client.prepare(server=host, version='1.4')
cctxt.cast(ctxt, 'delete_share_instance',
share_instance_id=share_instance['id'])
def delete_share_server(self, ctxt, share_server):
host = utils.extract_host(share_server['host'])
@ -98,15 +103,19 @@ class ShareAPI(object):
cctxt = self.client.prepare(server=new_host)
cctxt.cast(ctxt, 'delete_snapshot', snapshot_id=snapshot['id'])
def allow_access(self, ctxt, share, access):
host = utils.extract_host(share['host'])
cctxt = self.client.prepare(server=host, version='1.0')
cctxt.cast(ctxt, 'allow_access', access_id=access['id'])
def allow_access(self, ctxt, share_instance, access):
host = utils.extract_host(share_instance['host'])
cctxt = self.client.prepare(server=host, version='1.4')
cctxt.cast(ctxt, 'allow_access',
share_instance_id=share_instance['id'],
access_id=access['id'])
def deny_access(self, ctxt, share, access):
host = utils.extract_host(share['host'])
cctxt = self.client.prepare(server=host, version='1.0')
cctxt.cast(ctxt, 'deny_access', access_id=access['id'])
def deny_access(self, ctxt, share_instance, access):
host = utils.extract_host(share_instance['host'])
cctxt = self.client.prepare(server=host, version='1.4')
cctxt.cast(ctxt, 'deny_access',
share_instance_id=share_instance['id'],
access_id=access['id'])
def publish_service_capabilities(self, ctxt):
cctxt = self.client.prepare(fanout=True, version='1.0')

View File

@ -77,11 +77,60 @@ class GenericDatabaseAPITestCase(test.TestCase):
share = db_utils.create_share()
share_access = db_utils.create_access(share_id=share['id'])
db_api.share_instance_access_delete(
self.ctxt, share_access.instance_mappings[0].id)
db_api.share_access_delete(self.ctxt, share_access.id)
self.assertRaises(exception.NotFound, db_api.share_access_get,
self.ctxt, share_access.id)
@ddt.ddt
class ShareAccessDatabaseAPITestCase(test.TestCase):
def setUp(self):
"""Run before each test."""
super(ShareAccessDatabaseAPITestCase, self).setUp()
self.ctxt = context.get_admin_context()
@ddt.data(
{'statuses': (constants.STATUS_ACTIVE, constants.STATUS_ACTIVE,
constants.STATUS_ACTIVE),
'valid': constants.STATUS_ACTIVE},
{'statuses': (constants.STATUS_ACTIVE, constants.STATUS_ACTIVE,
constants.STATUS_NEW),
'valid': constants.STATUS_NEW},
{'statuses': (constants.STATUS_ACTIVE, constants.STATUS_ACTIVE,
constants.STATUS_ERROR),
'valid': constants.STATUS_ERROR},
{'statuses': (constants.STATUS_DELETING, constants.STATUS_DELETED,
constants.STATUS_ERROR),
'valid': constants.STATUS_ERROR},
{'statuses': (constants.STATUS_DELETING, constants.STATUS_DELETED,
constants.STATUS_ACTIVE),
'valid': constants.STATUS_DELETING},
{'statuses': (constants.STATUS_DELETED, constants.STATUS_DELETED,
constants.STATUS_DELETED),
'valid': constants.STATUS_DELETED},
)
@ddt.unpack
def test_share_access_state(self, statuses, valid):
share = db_utils.create_share()
db_utils.create_share_instance(share_id=share['id'])
db_utils.create_share_instance(share_id=share['id'])
share = db_api.share_get(self.ctxt, share['id'])
access = db_utils.create_access(state=constants.STATUS_ACTIVE,
share_id=share['id'])
for index, mapping in enumerate(access.instance_mappings):
db_api.share_instance_access_update_state(
self.ctxt, mapping['id'], statuses[index])
access = db_api.share_access_get(self.ctxt, access['id'])
self.assertEqual(valid, access.state)
@ddt.ddt
class ShareDatabaseAPITestCase(test.TestCase):
@ -129,6 +178,14 @@ class ShareDatabaseAPITestCase(test.TestCase):
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()
db_api.share_instance_delete(self.ctxt, share.instance['id'])
self.assertRaises(exception.NotFound, db_api.share_get,
self.ctxt, share['id'])
@ddt.data('host', 'availability_zone')
def test_share_get_all_sort_by_share_instance_fields(self, sort_key):
shares = [db_utils.create_share(**{sort_key: n, 'size': 1})

View File

@ -41,18 +41,37 @@ def create_share(**kwargs):
'project_id': 'fake',
'metadata': {'fake_key': 'fake_value'},
'availability_zone': 'fake_availability_zone',
'status': "creating",
'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_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': None,
'share_id': share['id'] if with_share else None,
'user_id': 'fake',
'project_id': 'fake',
'status': 'creating'
@ -66,7 +85,6 @@ def create_access(**kwargs):
'access_type': 'fake_type',
'access_to': 'fake_IP',
'share_id': None,
'state': 'new',
}
return _create_db_row(db.share_access_create, access, kwargs)

View File

@ -80,15 +80,12 @@ class SchedulerRpcAPITestCase(test.TestCase):
capabilities='fake_capabilities',
fanout=True)
def test_create_share(self):
self._test_scheduler_api('create_share',
def test_create_share_instance(self):
self._test_scheduler_api('create_share_instance',
rpc_method='cast',
topic='topic',
share_id='share_id',
snapshot_id='snapshot_id',
request_spec='fake_request_spec',
filter_properties='filter_properties',
version='1.0')
version='1.2')
def test_get_pools(self):
self._test_scheduler_api('get_pools',

View File

@ -29,6 +29,7 @@ from manila.scheduler import manager
from manila.scheduler import simple
from manila.share import rpcapi as share_rpcapi
from manila import test
from manila.tests import db_utils
from manila import utils
CONF = cfg.CONF
@ -83,16 +84,14 @@ class SchedulerManagerTestCase(test.TestCase):
raise exception.NoValidHost(reason="")
fake_share_id = 1
topic = 'fake_topic'
share_id = fake_share_id
request_spec = {'share_id': fake_share_id}
with mock.patch.object(self.manager.driver,
'schedule_create_share',
mock.Mock(side_effect=raise_no_valid_host)):
self.mock_object(manager.LOG, 'error')
self.manager.create_share(self.context, topic, share_id,
request_spec=request_spec,
filter_properties={})
self.manager.create_share_instance(
self.context, request_spec=request_spec, filter_properties={})
db.share_update.assert_called_once_with(
self.context, fake_share_id, {'status': 'error'})
self.manager.driver.schedule_create_share.assert_called_once_with(
@ -209,19 +208,18 @@ class SimpleSchedulerSharesTestCase(test.TestCase):
'share_id': share_id,
'share_properties': fake_share,
}
with mock.patch.object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result)):
with mock.patch.object(driver, 'share_update_db',
mock.Mock(return_value=fake_share)):
self.driver.schedule_create_share(self.context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with(
utils.IsAMatcher(dict))
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
driver.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
share_id, 'fake_host1')
self.mock_object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result))
self.mock_object(driver, 'share_update_db',
mock.Mock(return_value=db_utils.create_share()))
self.driver.schedule_create_share(self.context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with(utils.IsAMatcher(dict))
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
driver.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id, 'fake_host1')
def test_create_share_if_services_not_available(self):
share_id = 'fake'
@ -278,18 +276,19 @@ class SimpleSchedulerSharesTestCase(test.TestCase):
'share_id': share_id,
'share_properties': fake_share,
}
with mock.patch.object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result)):
with mock.patch.object(driver, 'share_update_db',
mock.Mock(return_value=fake_share)):
self.driver.schedule_create_share(self.context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with(fake_service_1)
driver.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id,
fake_service_1['host'])
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
self.mock_object(db, 'service_get_all_share_sorted',
mock.Mock(return_value=fake_result))
self.mock_object(driver, 'share_update_db',
mock.Mock(return_value=db_utils.create_share()))
self.driver.schedule_create_share(self.context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with(fake_service_1)
driver.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id,
fake_service_1['host'])
db.service_get_all_share_sorted.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
@mock.patch.object(utils, 'service_is_up', mock.Mock(return_value=True))
def test_create_share_availability_zone_on_host(self):
@ -303,18 +302,18 @@ class SimpleSchedulerSharesTestCase(test.TestCase):
'share_id': share_id,
'share_properties': fake_share,
}
with mock.patch.object(db, 'service_get_by_args',
mock.Mock(return_value='fake_service')):
with mock.patch.object(driver, 'share_update_db',
mock.Mock(return_value=fake_share)):
self.driver.schedule_create_share(self.admin_context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with('fake_service')
db.service_get_by_args.assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
'fake', 'manila-share')
driver.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id, 'fake')
self.mock_object(db, 'service_get_by_args',
mock.Mock(return_value='fake_service'))
self.mock_object(driver, 'share_update_db',
mock.Mock(return_value=db_utils.create_share()))
self.driver.schedule_create_share(self.admin_context,
fake_request_spec, {})
utils.service_is_up.assert_called_once_with('fake_service')
db.service_get_by_args.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), 'fake', 'manila-share')
driver.share_update_db.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id, 'fake')
@mock.patch.object(utils, 'service_is_up', mock.Mock(return_value=False))
def test_create_share_availability_zone_if_service_down(self):

File diff suppressed because it is too large Load Diff

View File

@ -37,21 +37,6 @@ from manila.tests import utils as test_utils
from manila import utils
class FakeAccessRule(object):
def __init__(self, **kwargs):
self.STATE_ACTIVE = constants.STATUS_ACTIVE
self.STATE_NEW = constants.STATUS_NEW
self.STATE_ERROR = constants.STATUS_ERROR
self.access_type = 'fake_type'
self.id = 'fake_id'
for k, v in kwargs.items():
setattr(self, k, v)
def __getitem__(self, item):
return getattr(self, item)
@ddt.ddt
class ShareManagerTestCase(test.TestCase):
@ -98,6 +83,30 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.driver.check_for_setup_error.\
assert_called_once_with()
def _setup_init_mocks(self, setup_access_rules=True):
instances = [
db_utils.create_share(id='fake_id_1',
status=constants.STATUS_AVAILABLE,
display_name='fake_name_1').instance,
db_utils.create_share(id='fake_id_2',
status=constants.STATUS_ERROR,
display_name='fake_name_2').instance,
db_utils.create_share(id='fake_id_3',
status=constants.STATUS_AVAILABLE,
display_name='fake_name_3').instance,
]
if not setup_access_rules:
return instances
rules = [
db_utils.create_access(state=constants.STATUS_ACTIVE,
share_id='fake_id_1'),
db_utils.create_access(state=constants.STATUS_ERROR,
share_id='fake_id_3'),
]
return instances, rules
def test_init_host_with_shares_and_rules(self):
# initialisation of test data
@ -105,24 +114,14 @@ class ShareManagerTestCase(test.TestCase):
raise exception.ShareAccessExists(
access_type='fake_access_type', access='fake_access')
shares = [
{'id': 'fake_id_1', 'status': constants.STATUS_AVAILABLE},
{'id': 'fake_id_2',
'status': constants.STATUS_ERROR,
'name': 'fake_name_2'},
{'id': 'fake_id_3', 'status': 'fake', 'name': 'fake_name_3'},
]
rules = [
FakeAccessRule(state=constants.STATUS_ACTIVE),
FakeAccessRule(state=constants.STATUS_ERROR),
]
instances, rules = self._setup_init_mocks()
fake_export_locations = ['fake/path/1', 'fake/path']
share_server = 'fake_share_server_type_does_not_matter'
self.mock_object(self.share_manager.db,
'share_instances_get_all_by_host',
mock.Mock(return_value=shares))
mock.Mock(return_value=instances))
self.mock_object(self.share_manager.db, 'share_instance_get',
mock.Mock(side_effect=shares))
mock.Mock(side_effect=[instances[0], instances[2]]))
self.mock_object(self.share_manager.db,
'share_export_locations_update')
self.mock_object(self.share_manager.driver, 'ensure_share',
@ -146,51 +145,55 @@ class ShareManagerTestCase(test.TestCase):
assert_called_once_with(utils.IsAMatcher(context.RequestContext),
self.share_manager.host)
exports_update = self.share_manager.db.share_export_locations_update
exports_update.assert_called_once_with(
mock.ANY, 'fake_id_1', fake_export_locations)
exports_update.assert_has_calls([
mock.call(mock.ANY, instances[0]['id'], fake_export_locations),
mock.call(mock.ANY, instances[2]['id'], fake_export_locations)
])
self.share_manager.driver.do_setup.assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
self.share_manager.driver.check_for_setup_error.\
assert_called_once_with()
self.share_manager._ensure_share_instance_has_pool.\
assert_called_once_with(utils.IsAMatcher(context.RequestContext),
shares[0])
self.share_manager._get_share_server.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), shares[0])
self.share_manager.driver.ensure_share.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), shares[0],
share_server=share_server)
self.share_manager.db.share_access_get_all_for_share.\
assert_called_once_with(
utils.IsAMatcher(context.RequestContext), shares[0]['id'])
self.share_manager._ensure_share_instance_has_pool.assert_has_calls([
mock.call(utils.IsAMatcher(context.RequestContext), instances[0]),
mock.call(utils.IsAMatcher(context.RequestContext), instances[2]),
])
self.share_manager._get_share_server.assert_has_calls([
mock.call(utils.IsAMatcher(context.RequestContext), instances[0]),
mock.call(utils.IsAMatcher(context.RequestContext), instances[2]),
])
self.share_manager.driver.ensure_share.assert_has_calls([
mock.call(utils.IsAMatcher(context.RequestContext), instances[0],
share_server=share_server),
mock.call(utils.IsAMatcher(context.RequestContext), instances[2],
share_server=share_server),
])
self.share_manager.db.share_access_get_all_for_share.assert_has_calls([
mock.call(utils.IsAMatcher(context.RequestContext),
instances[0]['share_id']),
mock.call(utils.IsAMatcher(context.RequestContext),
instances[2]['share_id']),
])
self.share_manager.publish_service_capabilities.\
assert_called_once_with(
utils.IsAMatcher(context.RequestContext))
self.share_manager.driver.allow_access.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), shares[0], rules[0],
share_server=share_server)
self.share_manager.driver.allow_access.assert_has_calls([
mock.call(mock.ANY, instances[0], rules[0],
share_server=share_server),
mock.call(mock.ANY, instances[2], rules[0],
share_server=share_server),
])
def test_init_host_with_exception_on_ensure_share(self):
def raise_exception(*args, **kwargs):
raise exception.ManilaException(message="Fake raise")
shares = [
{'id': 'fake_id_1',
'status': constants.STATUS_AVAILABLE,
'name': 'fake_name_1'},
{'id': 'fake_id_2',
'status': constants.STATUS_ERROR,
'name': 'fake_name_2'},
{'id': 'fake_id_3',
'status': constants.STATUS_AVAILABLE,
'name': 'fake_name_3'},
]
instances = self._setup_init_mocks(setup_access_rules=False)
share_server = 'fake_share_server_type_does_not_matter'
self.mock_object(self.share_manager.db,
'share_instances_get_all_by_host',
mock.Mock(return_value=shares))
mock.Mock(return_value=instances))
self.mock_object(self.share_manager.db, 'share_instance_get',
mock.Mock(side_effect=[shares[0], shares[2]]))
mock.Mock(side_effect=[instances[0], instances[2]]))
self.mock_object(self.share_manager.driver, 'ensure_share',
mock.Mock(side_effect=raise_exception))
self.mock_object(self.share_manager, '_ensure_share_instance_has_pool')
@ -211,17 +214,17 @@ class ShareManagerTestCase(test.TestCase):
utils.IsAMatcher(context.RequestContext))
self.share_manager.driver.check_for_setup_error.assert_called_with()
self.share_manager._ensure_share_instance_has_pool.assert_has_calls([
mock.call(utils.IsAMatcher(context.RequestContext), shares[0]),
mock.call(utils.IsAMatcher(context.RequestContext), shares[2]),
mock.call(utils.IsAMatcher(context.RequestContext), instances[0]),
mock.call(utils.IsAMatcher(context.RequestContext), instances[2]),
])
self.share_manager._get_share_server.assert_has_calls([
mock.call(utils.IsAMatcher(context.RequestContext), shares[0]),
mock.call(utils.IsAMatcher(context.RequestContext), shares[2]),
mock.call(utils.IsAMatcher(context.RequestContext), instances[0]),
mock.call(utils.IsAMatcher(context.RequestContext), instances[2]),
])
self.share_manager.driver.ensure_share.assert_has_calls([
mock.call(utils.IsAMatcher(context.RequestContext), shares[0],
mock.call(utils.IsAMatcher(context.RequestContext), instances[0],
share_server=share_server),
mock.call(utils.IsAMatcher(context.RequestContext), shares[2],
mock.call(utils.IsAMatcher(context.RequestContext), instances[2],
share_server=share_server),
])
self.share_manager.publish_service_capabilities.\
@ -229,34 +232,20 @@ class ShareManagerTestCase(test.TestCase):
utils.IsAMatcher(context.RequestContext))
manager.LOG.info.assert_called_once_with(
mock.ANY,
{'id': shares[1]['id'], 'status': shares[1]['status']},
{'id': instances[1]['id'], 'status': instances[1]['status']},
)
def test_init_host_with_exception_on_rule_access_allow(self):
def raise_exception(*args, **kwargs):
raise exception.ManilaException(message="Fake raise")
shares = [
{'id': 'fake_id_1',
'status': constants.STATUS_AVAILABLE,
'name': 'fake_name_1'},
{'id': 'fake_id_2',
'status': constants.STATUS_ERROR,
'name': 'fake_name_2'},
{'id': 'fake_id_3',
'status': constants.STATUS_AVAILABLE,
'name': 'fake_name_3'},
]
rules = [
FakeAccessRule(state=constants.STATUS_ACTIVE),
FakeAccessRule(state=constants.STATUS_ERROR),
]
instances, rules = self._setup_init_mocks()
share_server = 'fake_share_server_type_does_not_matter'
self.mock_object(self.share_manager.db,
'share_instances_get_all_by_host',
mock.Mock(return_value=shares))
mock.Mock(return_value=instances))
self.mock_object(self.share_manager.db, 'share_instance_get',
mock.Mock(side_effect=[shares[0], shares[2]]))
mock.Mock(side_effect=[instances[0], instances[2]]))
self.mock_object(self.share_manager.driver, 'ensure_share',
mock.Mock(return_value=None))
self.mock_object(self.share_manager, '_ensure_share_instance_has_pool')
@ -282,17 +271,17 @@ class ShareManagerTestCase(test.TestCase):
utils.IsAMatcher(context.RequestContext))
self.share_manager.driver.check_for_setup_error.assert_called_with()
self.share_manager._ensure_share_instance_has_pool.assert_has_calls([
mock.call(utils.IsAMatcher(context.RequestContext), shares[0]),
mock.call(utils.IsAMatcher(context.RequestContext), shares[2]),
mock.call(utils.IsAMatcher(context.RequestContext), instances[0]),
mock.call(utils.IsAMatcher(context.RequestContext), instances[2]),
])
self.share_manager._get_share_server.assert_has_calls([
mock.call(utils.IsAMatcher(context.RequestContext), shares[0]),
mock.call(utils.IsAMatcher(context.RequestContext), shares[2]),
mock.call(utils.IsAMatcher(context.RequestContext), instances[0]),
mock.call(utils.IsAMatcher(context.RequestContext), instances[2]),
])
self.share_manager.driver.ensure_share.assert_has_calls([
mock.call(utils.IsAMatcher(context.RequestContext), shares[0],
mock.call(utils.IsAMatcher(context.RequestContext), instances[0],
share_server=share_server),
mock.call(utils.IsAMatcher(context.RequestContext), shares[2],
mock.call(utils.IsAMatcher(context.RequestContext), instances[2],
share_server=share_server),
])
self.share_manager.publish_service_capabilities.\
@ -300,12 +289,12 @@ class ShareManagerTestCase(test.TestCase):
utils.IsAMatcher(context.RequestContext))
manager.LOG.info.assert_called_once_with(
mock.ANY,
{'id': shares[1]['id'], 'status': shares[1]['status']},
{'id': instances[1]['id'], 'status': instances[1]['status']},
)
self.share_manager.driver.allow_access.assert_has_calls([
mock.call(utils.IsAMatcher(context.RequestContext), shares[0],
mock.call(utils.IsAMatcher(context.RequestContext), instances[0],
rules[0], share_server=share_server),
mock.call(utils.IsAMatcher(context.RequestContext), shares[2],
mock.call(utils.IsAMatcher(context.RequestContext), instances[2],
rules[0], share_server=share_server),
])
manager.LOG.error.assert_has_calls([
@ -313,7 +302,7 @@ class ShareManagerTestCase(test.TestCase):
mock.call(mock.ANY, mock.ANY),
])
def test_create_share_from_snapshot_with_server(self):
def test_create_share_instance_from_snapshot_with_server(self):
"""Test share can be created from snapshot if server exists."""
network = db_utils.create_share_network()
server = db_utils.create_share_server(
@ -326,8 +315,8 @@ class ShareManagerTestCase(test.TestCase):
snapshot = db_utils.create_snapshot(share_id=parent_share['id'])
snapshot_id = snapshot['id']
self.share_manager.create_share(self.context, share_id,
snapshot_id=snapshot_id)
self.share_manager.create_share_instance(
self.context, share.instance['id'], snapshot_id=snapshot_id)
self.assertEqual(share_id, db.share_get(context.get_admin_context(),
share_id).id)
@ -335,7 +324,7 @@ class ShareManagerTestCase(test.TestCase):
self.assertEqual(shr['status'], constants.STATUS_AVAILABLE)
self.assertEqual(shr['share_server_id'], server['id'])
def test_create_share_from_snapshot_with_server_not_found(self):
def test_create_share_instance_from_snapshot_with_server_not_found(self):
"""Test creation from snapshot fails if server not found."""
parent_share = db_utils.create_share(share_network_id='net-id',
share_server_id='fake-id')
@ -345,24 +334,24 @@ class ShareManagerTestCase(test.TestCase):
snapshot_id = snapshot['id']
self.assertRaises(exception.ShareServerNotFound,
self.share_manager.create_share,
self.share_manager.create_share_instance,
self.context,
share_id,
share.instance['id'],
snapshot_id=snapshot_id
)
shr = db.share_get(self.context, share_id)
self.assertEqual(shr['status'], constants.STATUS_ERROR)
def test_create_share_from_snapshot(self):
def test_create_share_instance_from_snapshot(self):
"""Test share can be created from snapshot."""
share = db_utils.create_share()
share_id = share['id']
snapshot = db_utils.create_snapshot(share_id=share_id)
snapshot_id = snapshot['id']
self.share_manager.create_share(self.context, share_id,
snapshot_id=snapshot_id)
self.share_manager.create_share_instance(
self.context, share.instance['id'], snapshot_id=snapshot_id)
self.assertEqual(share_id, db.share_get(context.get_admin_context(),
share_id).id)
@ -439,7 +428,7 @@ class ShareManagerTestCase(test.TestCase):
utils.IsAMatcher(models.ShareSnapshotInstance),
share_server=None)
def test_delete_share_if_busy(self):
def test_delete_share_instance_if_busy(self):
"""Test snapshot could not be deleted if busy."""
def _raise_share_snapshot_is_busy(self, *args, **kwargs):
@ -460,30 +449,34 @@ class ShareManagerTestCase(test.TestCase):
utils.IsAMatcher(models.ShareSnapshotInstance),
share_server=None)
def test_create_share_with_share_network_driver_not_handles_servers(self):
def test_create_share_instance_with_share_network_dhss_false(self):
manager.CONF.set_default('driver_handles_share_servers', False)
self.mock_object(
self.share_manager.driver.configuration, 'safe_get',
mock.Mock(return_value=False))
share_id = 'fake_share_id'
share_network_id = 'fake_sn'
share_instance = db_utils.create_share(
share_network_id=share_network_id).instance
self.mock_object(
self.share_manager.db, 'share_get',
mock.Mock(return_value=db_utils.create_share(
share_network_id=share_network_id)))
self.mock_object(self.share_manager.db, 'share_update')
self.share_manager.db, 'share_instance_get',
mock.Mock(return_value=share_instance))
self.mock_object(self.share_manager.db, 'share_instance_update')
self.assertRaises(
exception.ManilaException,
self.share_manager.create_share, self.context, share_id)
self.share_manager.create_share_instance, self.context,
share_instance['id'])
self.share_manager.db.share_get.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id)
self.share_manager.db.share_update.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_id,
self.share_manager.db.share_instance_get.assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
share_instance['id'],
with_share_data=True
)
self.share_manager.db.share_instance_update.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_instance['id'],
{'status': constants.STATUS_ERROR})
def test_create_share_with_share_network_server_not_exists(self):
def test_create_share_instance_with_share_network_server_not_exists(self):
"""Test share can be created without share server."""
share_net = db_utils.create_share_network()
@ -499,11 +492,12 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.driver.create_share = mock.Mock(
return_value='fake_location')
self.share_manager._setup_server = fake_setup_server
self.share_manager.create_share(self.context, share_id)
self.share_manager.create_share_instance(self.context,
share.instance['id'])
self.assertEqual(share_id, db.share_get(context.get_admin_context(),
share_id).id)
def test_create_share_with_share_network_server_creation_failed(self):
def test_create_share_instance_with_share_network_server_fail(self):
fake_share = db_utils.create_share(share_network_id='fake_sn_id',
size=1)
fake_server = {
@ -512,10 +506,10 @@ class ShareManagerTestCase(test.TestCase):
}
self.mock_object(db, 'share_server_create',
mock.Mock(return_value=fake_server))
self.mock_object(db, 'share_update',
mock.Mock(return_value=fake_share))
self.mock_object(db, 'share_get',
mock.Mock(return_value=fake_share))
self.mock_object(db, 'share_instance_update',
mock.Mock(return_value=fake_share.instance))
self.mock_object(db, 'share_instance_get',
mock.Mock(return_value=fake_share.instance))
def raise_share_server_not_found(*args, **kwargs):
raise exception.ShareServerNotFound(
@ -532,9 +526,9 @@ class ShareManagerTestCase(test.TestCase):
self.assertRaises(
exception.ManilaException,
self.share_manager.create_share,
self.share_manager.create_share_instance,
self.context,
fake_share['id'],
fake_share.instance['id'],
)
db.share_server_get_all_by_host_and_share_net_valid.\
assert_called_once_with(
@ -544,31 +538,31 @@ class ShareManagerTestCase(test.TestCase):
)
db.share_server_create.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), mock.ANY)
db.share_update.assert_has_calls([
db.share_instance_update.assert_has_calls([
mock.call(
utils.IsAMatcher(context.RequestContext),
fake_share['id'],
fake_share.instance['id'],
{'status': constants.STATUS_ERROR},
)
])
self.share_manager._setup_server.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), fake_server)
def test_create_share_with_share_network_not_found(self):
def test_create_share_instance_with_share_network_not_found(self):
"""Test creation fails if share network not found."""
share = db_utils.create_share(share_network_id='fake-net-id')
share_id = share['id']
self.assertRaises(
exception.ShareNetworkNotFound,
self.share_manager.create_share,
self.share_manager.create_share_instance,
self.context,
share_id
share.instance['id']
)
shr = db.share_get(self.context, share_id)
self.assertEqual(shr['status'], constants.STATUS_ERROR)
def test_create_share_with_share_network_server_exists(self):
def test_create_share_instance_with_share_network_server_exists(self):
"""Test share can be created with existing share server."""
share_net = db_utils.create_share_network()
share = db_utils.create_share(share_network_id=share_net['id'])
@ -583,7 +577,8 @@ class ShareManagerTestCase(test.TestCase):
share_srv
)
self.share_manager.driver = driver_mock
self.share_manager.create_share(self.context, share_id)
self.share_manager.create_share_instance(self.context,
share.instance['id'])
self.assertFalse(self.share_manager.driver.setup_network.called)
self.assertEqual(share_id, db.share_get(context.get_admin_context(),
share_id).id)
@ -595,7 +590,7 @@ class ShareManagerTestCase(test.TestCase):
self.assertEqual(1, len(shr['export_locations']))
@ddt.data('export_location', 'export_locations')
def test_create_share_with_error_in_driver(self, details_key):
def test_create_share_instance_with_error_in_driver(self, details_key):
"""Test db updates if share creation fails in driver."""
share = db_utils.create_share()
share_id = share['id']
@ -605,15 +600,15 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.driver.create_share.side_effect = e
self.assertRaises(
exception.ManilaException,
self.share_manager.create_share,
self.share_manager.create_share_instance,
self.context,
share_id
share.instance['id']
)
self.assertTrue(self.share_manager.driver.create_share.called)
shr = db.share_get(self.context, share_id)
self.assertEqual(some_data, shr['export_location'])
def test_create_share_with_server_created(self):
def test_create_share_instance_with_server_created(self):
"""Test share can be created and share server is created."""
share_net = db_utils.create_share_network()
share = db_utils.create_share(share_network_id=share_net['id'])
@ -630,7 +625,8 @@ class ShareManagerTestCase(test.TestCase):
self.mock_object(self.share_manager, '_setup_server',
mock.Mock(return_value=fake_server))
self.share_manager.create_share(self.context, share_id)
self.share_manager.create_share_instance(self.context,
share.instance['id'])
self.assertEqual(share_id, db.share_get(context.get_admin_context(),
share_id).id)
@ -642,7 +638,7 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager._setup_server.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), fake_server)
def test_create_delete_share_error(self):
def test_create_delete_share_instance_error(self):
"""Test share can be created and deleted with error."""
def _raise_not_found(self, *args, **kwargs):
@ -656,16 +652,16 @@ class ShareManagerTestCase(test.TestCase):
share = db_utils.create_share()
share_id = share['id']
self.assertRaises(exception.NotFound,
self.share_manager.create_share,
self.share_manager.create_share_instance,
self.context,
share_id)
share.instance['id'])
shr = db.share_get(self.context, share_id)
self.assertEqual(shr['status'], constants.STATUS_ERROR)
self.assertRaises(exception.NotFound,
self.share_manager.delete_share,
self.share_manager.delete_share_instance,
self.context,
share_id)
share.instance['id'])
shr = db.share_get(self.context, share_id)
self.assertEqual(shr['status'], constants.STATUS_ERROR_DELETING)
@ -1002,7 +998,7 @@ class ShareManagerTestCase(test.TestCase):
self.share_manager.driver.unmanage.\
assert_called_once_with(mock.ANY)
self.share_manager._remove_share_access_rules.assert_called_once_with(
mock.ANY, mock.ANY, mock.ANY
mock.ANY, mock.ANY, mock.ANY, mock.ANY
)
self.share_manager.db.share_update.assert_called_once_with(
mock.ANY, share_id,
@ -1013,31 +1009,31 @@ class ShareManagerTestCase(test.TestCase):
'share_access_get_all_for_share',
mock.Mock(return_value=['fake_ref', 'fake_ref2']))
self.mock_object(self.share_manager, '_deny_access')
share_ref = {'id': 'fake_id'}
share_ref = db_utils.create_share()
share_server = 'fake'
self.share_manager._remove_share_access_rules(self.context,
share_ref, share_server)
self.share_manager._remove_share_access_rules(
self.context, share_ref, share_ref.instance, share_server)
self.share_manager.db.share_access_get_all_for_share.\
assert_called_once_with(mock.ANY, share_ref['id'])
self.assertEqual(2, self.share_manager._deny_access.call_count)
def test_delete_share_share_server_not_found(self):
def test_delete_share_instance_share_server_not_found(self):
share_net = db_utils.create_share_network()
share = db_utils.create_share(share_network_id=share_net['id'],
share_server_id='fake-id')
share_id = share['id']
self.assertRaises(
exception.ShareServerNotFound,
self.share_manager.delete_share,
self.share_manager.delete_share_instance,
self.context,
share_id
share.instance['id']
)
@ddt.data(True, False)
def test_delete_share_last_on_server_with_sec_services(self, with_details):
def test_delete_share_instance_last_on_srv_with_sec_service(
self, with_details):
share_net = db_utils.create_share_network()
sec_service = db_utils.create_security_service(
share_network_id=share_net['id'])
@ -1056,18 +1052,18 @@ class ShareManagerTestCase(test.TestCase):
context.get_admin_context(), share_srv['id'], backend_details)
share = db_utils.create_share(share_network_id=share_net['id'],
share_server_id=share_srv['id'])
share_id = share['id']
self.share_manager.driver = mock.Mock()
manager.CONF.delete_share_server_with_last_share = True
self.share_manager.delete_share(self.context, share_id)
self.share_manager.delete_share_instance(self.context,
share.instance['id'])
self.share_manager.driver.teardown_server.assert_called_once_with(
server_details=backend_details,
security_services=[jsonutils.loads(
backend_details['security_service_ldap'])])
def test_delete_share_last_on_server(self):
def test_delete_share_instance_last_on_server(self):
share_net = db_utils.create_share_network()
share_srv = db_utils.create_share_server(
share_network_id=share_net['id'],
@ -1076,16 +1072,15 @@ class ShareManagerTestCase(test.TestCase):
share = db_utils.create_share(share_network_id=share_net['id'],
share_server_id=share_srv['id'])
share_id = share['id']
self.share_manager.driver = mock.Mock()
manager.CONF.delete_share_server_with_last_share = True
self.share_manager.delete_share(self.context, share_id)
self.share_manager.delete_share_instance(self.context,
share.instance['id'])
self.share_manager.driver.teardown_server.assert_called_once_with(
server_details=share_srv.get('backend_details'),
security_services=[])
def test_delete_share_last_on_server_deletion_disabled(self):
def test_delete_share_instance_last_on_server_deletion_disabled(self):
share_net = db_utils.create_share_network()
share_srv = db_utils.create_share_server(
share_network_id=share_net['id'],
@ -1094,13 +1089,13 @@ class ShareManagerTestCase(test.TestCase):
share = db_utils.create_share(share_network_id=share_net['id'],
share_server_id=share_srv['id'])
share_id = share['id']
manager.CONF.delete_share_server_with_last_share = False
self.share_manager.driver = mock.Mock()
self.share_manager.delete_share(self.context, share_id)
self.share_manager.delete_share_instance(self.context,
share.instance['id'])
self.assertFalse(self.share_manager.driver.teardown_network.called)
def test_delete_share_not_last_on_server(self):
def test_delete_share_instance_not_last_on_server(self):
share_net = db_utils.create_share_network()
share_srv = db_utils.create_share_server(
share_network_id=share_net['id'],
@ -1110,11 +1105,11 @@ class ShareManagerTestCase(test.TestCase):
share_server_id=share_srv['id'])
db_utils.create_share(share_network_id=share_net['id'],
share_server_id=share_srv['id'])
share_id = share['id']
manager.CONF.delete_share_server_with_last_share = True
self.share_manager.driver = mock.Mock()
self.share_manager.delete_share(self.context, share_id)
self.share_manager.delete_share_instance(self.context,
share.instance['id'])
self.assertFalse(self.share_manager.driver.teardown_network.called)
def test_allow_deny_access(self):
@ -1123,15 +1118,13 @@ class ShareManagerTestCase(test.TestCase):
share_id = share['id']
access = db_utils.create_access(share_id=share_id)
access_id = access['id']
self.share_manager.allow_access(self.context, access_id)
self.share_manager.allow_access(self.context, share.instance['id'],
access_id)
self.assertEqual('active', db.share_access_get(self.context,
access_id).state)
self.share_manager.deny_access(self.context, access_id)
self.assertRaises(exception.NotFound,
db.share_access_get,
self.context,
access_id)
self.share_manager.deny_access(self.context, share.instance['id'],
access_id)
def test_allow_deny_access_error(self):
"""Test access rules to share can be created and deleted with error."""
@ -1155,6 +1148,7 @@ class ShareManagerTestCase(test.TestCase):
self.assertRaises(exception.NotFound,
self.share_manager.allow_access,
self.context,
share.instance['id'],
access_id)
acs = db.share_access_get(self.context, access_id)
@ -1163,6 +1157,7 @@ class ShareManagerTestCase(test.TestCase):
self.assertRaises(exception.NotFound,
self.share_manager.deny_access,
self.context,
share.instance['id'],
access_id)
acs = db.share_access_get(self.context, access_id)
@ -1400,14 +1395,14 @@ class ShareManagerTestCase(test.TestCase):
self.context, share_server['id']
)
def test_ensure_share_has_pool_with_only_host(self):
def test_ensure_share_instance_has_pool_with_only_host(self):
fake_share = {
'status': constants.STATUS_AVAILABLE, 'host': 'host1', 'id': 1}
host = self.share_manager._ensure_share_instance_has_pool(
context.get_admin_context(), fake_share)
self.assertIsNone(host)
def test_ensure_share_has_pool_with_full_pool_name(self):
def test_ensure_share_instance_has_pool_with_full_pool_name(self):
fake_share = {'host': 'host1#pool0', 'id': 1,
'status': constants.STATUS_AVAILABLE}
fake_share_expected_value = 'pool0'
@ -1415,7 +1410,7 @@ class ShareManagerTestCase(test.TestCase):
context.get_admin_context(), fake_share)
self.assertEqual(fake_share_expected_value, host)
def test_ensure_share_has_pool_unable_to_fetch_share(self):
def test_ensure_share_instance_has_pool_unable_to_fetch_share(self):
fake_share = {'host': 'host@backend', 'id': 1,
'status': constants.STATUS_AVAILABLE}
with mock.patch.object(self.share_manager.driver, 'get_pool',

View File

@ -65,11 +65,13 @@ class ShareRpcAPITestCase(test.TestCase):
share = expected_msg['share']
del expected_msg['share']
expected_msg['share_id'] = share['id']
if 'share_instance' in expected_msg:
share_instance = expected_msg.pop('share_instance', None)
expected_msg['share_instance_id'] = share_instance['id']
if 'access' in expected_msg:
access = expected_msg['access']
del expected_msg['access']
expected_msg['access_id'] = access['id']
del expected_msg['share_id']
if 'host' in expected_msg:
del expected_msg['host']
if 'snapshot' in expected_msg:
@ -81,6 +83,8 @@ class ShareRpcAPITestCase(test.TestCase):
host = kwargs['host']
elif 'share_server' in kwargs:
host = kwargs['share_server']['host']
elif 'share_instance' in kwargs:
host = kwargs['share_instance']['host']
else:
host = kwargs['share']['host']
target['server'] = host
@ -113,30 +117,34 @@ class ShareRpcAPITestCase(test.TestCase):
for kwarg, value in six.iteritems(self.fake_kwargs):
self.assertEqual(value, expected_msg[kwarg])
def test_create_share(self):
self._test_share_api('create_share',
def test_create_share_instance(self):
self._test_share_api('create_share_instance',
rpc_method='cast',
share=self.fake_share,
version='1.4',
share_instance=self.fake_share,
host='fake_host1',
snapshot_id='fake_snapshot_id',
filter_properties=None,
request_spec=None)
def test_delete_share(self):
self._test_share_api('delete_share',
def test_delete_share_instance(self):
self._test_share_api('delete_share_instance',
rpc_method='cast',
share=self.fake_share)
version='1.4',
share_instance=self.fake_share)
def test_allow_access(self):
self._test_share_api('allow_access',
rpc_method='cast',
share=self.fake_share,
version='1.4',
share_instance=self.fake_share,
access=self.fake_access)
def test_deny_access(self):
self._test_share_api('deny_access',
rpc_method='cast',
share=self.fake_share,
version='1.4',
share_instance=self.fake_share,
access=self.fake_access)
def test_create_snapshot(self):