From 2c7595a386baa870fa557a9136fc8f132196170e Mon Sep 17 00:00:00 2001 From: Yulia Portnova Date: Fri, 16 May 2014 16:51:32 +0300 Subject: [PATCH] Share servers implementation Change-Id: I90664235237e25190191a4499e513a9fe589b855 --- .../api/share/admin/test_quotas_negative.py | 14 -- contrib/tempest/tempest/api/share/base.py | 14 +- .../share/test_share_networks_activation.py | 82 ------- manila/api/v1/share_networks.py | 127 ++++------ manila/api/v1/shares.py | 7 +- manila/compute/nova.py | 1 + manila/db/api.py | 60 +++++ manila/db/sqlalchemy/api.py | 97 +++++++- .../migrate_repo/versions/001_manila_init.py | 34 ++- manila/db/sqlalchemy/models.py | 43 +++- manila/exception.py | 16 +- manila/network/__init__.py | 6 +- .../network/neutron/neutron_network_plugin.py | 25 +- manila/scheduler/filter_scheduler.py | 2 +- manila/share/drivers/generic.py | 45 ++-- manila/share/drivers/netapp/cluster_mode.py | 10 +- manila/share/drivers/service_instance.py | 31 +-- manila/share/manager.py | 182 ++++++++------ manila/tests/api/v1/test_share_networks.py | 158 +------------ manila/tests/netapp/test_cmode_drv.py | 2 + .../network/neutron/test_neutron_plugin.py | 110 +++++---- manila/tests/network/test_share_network_db.py | 80 +------ manila/tests/test_service_instance.py | 38 +-- manila/tests/test_share.py | 222 ++++++------------ manila/tests/test_share_generic.py | 15 +- manila/volume/cinder.py | 3 +- 26 files changed, 637 insertions(+), 787 deletions(-) delete mode 100644 contrib/tempest/tempest/api/share/test_share_networks_activation.py diff --git a/contrib/tempest/tempest/api/share/admin/test_quotas_negative.py b/contrib/tempest/tempest/api/share/admin/test_quotas_negative.py index 73e6bfc77b..6b03b792ff 100644 --- a/contrib/tempest/tempest/api/share/admin/test_quotas_negative.py +++ b/contrib/tempest/tempest/api/share/admin/test_quotas_negative.py @@ -184,17 +184,3 @@ class SharesAdminQuotasNegativeTest(base.BaseSharesAdminTest): client.creds["tenant"]["id"], client.creds["user"]["id"], share_networks=bigger_value) - - @test.attr(type=["gate", "smoke", "negative"]) - def test_try_activate_share_network_with_overlimit(self): - client = self.get_client_with_isolated_creads() - - # set new quota for shares - resp, __ = client.update_quotas(client.creds["tenant"]["id"], - share_networks=0) - self.assertIn(int(resp["status"]), test.HTTP_SUCCESS) - - # Try activate share-network without enough quota - self.assertRaises(exceptions.OverLimit, - client.activate_share_network, - sn_id=client.share_network_id) diff --git a/contrib/tempest/tempest/api/share/base.py b/contrib/tempest/tempest/api/share/base.py index bc3cfacda4..9623b5bd5b 100644 --- a/contrib/tempest/tempest/api/share/base.py +++ b/contrib/tempest/tempest/api/share/base.py @@ -235,14 +235,7 @@ class BaseSharesTest(test.BaseTestCase): client = cls.shares_client if description is None: description = "Tempest's share" - if (share_network_id or client.share_network_id): - share_network_id = share_network_id or client.share_network_id - __, body = client.get_share_network(share_network_id) - if body["status"].lower() == "inactive": - resp, __ = client.activate_share_network(share_network_id) - assert (int(resp["status"]) in test.HTTP_SUCCESS) - client.wait_for_share_network_status(share_network_id, - "active") + share_network_id = share_network_id or client.share_network_id or None r, s = client.create_share(share_protocol=share_protocol, size=size, name=name, snapshot_id=snapshot_id, description=description, @@ -374,11 +367,6 @@ class BaseSharesTest(test.BaseTestCase): client.delete_snapshot(res_id) client.wait_for_resource_deletion(snapshot_id=res_id) elif res["type"] is "share_network": - __, body = client.get_share_network(res_id) - if body["status"].lower() == "active": - client.deactivate_share_network(res_id) - client.wait_for_share_network_status(res_id, - "inactive") client.delete_share_network(res_id) client.wait_for_resource_deletion(sn_id=res_id) elif res["type"] is "security_service": diff --git a/contrib/tempest/tempest/api/share/test_share_networks_activation.py b/contrib/tempest/tempest/api/share/test_share_networks_activation.py deleted file mode 100644 index eaf450ec42..0000000000 --- a/contrib/tempest/tempest/api/share/test_share_networks_activation.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2014 mirantis Inc. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.api.share import base -from tempest import clients_share as clients -from tempest import exceptions -from tempest import test - - -class SharenetworkActivationTest(base.BaseSharesTest): - """For testing activation of share-networks. - - Here all test cases were combined in one test method, - because its too expensive to activate new share-network - for each test. Activation can take about 2 minutes. - """ - - @classmethod - def setUpClass(cls): - cls.os = clients.Manager(interface=cls._interface) - - # Redefine share_network_id, because we do not need it - cls.os.shares_client.share_network_id = "fake" - super(SharenetworkActivationTest, cls).setUpClass() - - @test.attr(type=["gate", ]) - def test_share_network_activation_deactivation(self): - - # Get isolated client - client = self.get_client_with_isolated_creads(type_of_creds="admin") - - # Try create share with inactive share-network - self.assertRaises(exceptions.BadRequest, - client.create_share, - share_network_id=client.share_network_id, ) - - # Activate share-network - resp, __ = client.activate_share_network(client.share_network_id) - self.assertIn(int(resp["status"]), test.HTTP_SUCCESS) - client.wait_for_share_network_status(client.share_network_id) - - # Create share - resp, share = self.create_share_wait_for_active(client=client) - self.assertIn(int(resp["status"]), test.HTTP_SUCCESS) - - # Try deactivate - self.assertRaises(exceptions.BadRequest, - client.deactivate_share_network, - client.share_network_id) - - # Delete share - resp, __ = client.delete_share(share["id"]) - self.assertIn(int(resp["status"]), test.HTTP_SUCCESS) - client.wait_for_resource_deletion(share_id=share["id"]) - - # Deactivate - resp, __ = client.deactivate_share_network(client.share_network_id) - self.assertIn(int(resp["status"]), test.HTTP_SUCCESS) - client.wait_for_share_network_status(client.share_network_id, - "inactive") - - # Try create share with inactive share-network - self.assertRaises(exceptions.BadRequest, - client.create_share, - share_network_id=client.share_network_id, ) - - # Verify that no shares exist - resp, shares = client.list_shares() - self.assertIn(int(resp["status"]), test.HTTP_SUCCESS) - self.assertEqual(0, len(shares)) diff --git a/manila/api/v1/share_networks.py b/manila/api/v1/share_networks.py index bf405b976d..30f38a4cb6 100644 --- a/manila/api/v1/share_networks.py +++ b/manila/api/v1/share_networks.py @@ -49,7 +49,6 @@ SHARE_NETWORK_ATTRS = ( 'ip_version', 'name', 'description', - 'status', ) @@ -107,13 +106,22 @@ class ShareNetworkController(wsgi.Controller): except exception.ShareNetworkNotFound as e: msg = "%s" % e raise exc.HTTPNotFound(explanation=msg) - - if share_network['status'] == constants.STATUS_ACTIVE: - msg = "Network %s is in use" % id - raise exc.HTTPBadRequest(explanation=msg) - + if share_network['share_servers']: + msg = _("Cannot delete share network %s. " + "There are share servers using it") % id + raise exc.HTTPForbidden(explanation=msg) db_api.share_network_delete(context, id) + try: + reservations = QUOTAS.reserve( + context, project_id=share_network['project_id'], + share_networks=-1) + except Exception: + msg = _("Failed to update usages deleting share-network.") + LOG.exception(msg) + else: + QUOTAS.commit(context, reservations, + project_id=share_network['project_id']) return webob.Response(status_int=202) @wsgi.serializers(xml=ShareNetworksTemplate) @@ -163,9 +171,10 @@ class ShareNetworkController(wsgi.Controller): msg = "%s" % e raise exc.HTTPNotFound(explanation=msg) - if share_network['status'] == constants.STATUS_ACTIVE: - msg = "Network %s is in use" % id - raise exc.HTTPBadRequest(explanation=msg) + if share_network['share_servers']: + msg = _("Cannot update share network %s." + " It is used by share servers") % share_network['id'] + raise exc.HTTPForbidden(explanation=msg) update_values = body[RESOURCE_NAME] @@ -192,20 +201,39 @@ class ShareNetworkController(wsgi.Controller): values['project_id'] = context.project_id try: - share_network = db_api.share_network_create(context, values) - except exception.DBError: - msg = "Could not save supplied data due to database error" - raise exc.HTTPBadRequest(explanation=msg) + reservations = QUOTAS.reserve(context, share_networks=1) + except exception.OverQuota as e: + overs = e.kwargs['overs'] + usages = e.kwargs['usages'] + quotas = e.kwargs['quotas'] - return self._view_builder.build_share_network(share_network) + def _consumed(name): + return (usages[name]['reserved'] + usages[name]['in_use']) + + if 'share_networks' in overs: + msg = _("Quota exceeded for %(s_pid)s, tried to create" + " share-network (%(d_consumed)d of %(d_quota)d " + "already consumed)") + LOG.warn(msg % {'s_pid': context.project_id, + 'd_consumed': _consumed('share_networks'), + 'd_quota': quotas['share_networks']}) + raise exception.ShareNetworksLimitExceeded( + allowed=quotas['share_networks']) + else: + try: + share_network = db_api.share_network_create(context, values) + except exception.DBError: + msg = "Could not save supplied data due to database error" + raise exc.HTTPBadRequest(explanation=msg) + + QUOTAS.commit(context, reservations) + return self._view_builder.build_share_network(share_network) @wsgi.serializers(xml=ShareNetworkTemplate) def action(self, req, id, body): _actions = { 'add_security_service': self._add_security_service, - 'remove_security_service': self._remove_security_service, - 'activate': self._activate, - 'deactivate': self._deactivate, + 'remove_security_service': self._remove_security_service } for action, data in body.iteritems(): try: @@ -218,6 +246,10 @@ class ShareNetworkController(wsgi.Controller): """Associate share network with a given security service.""" context = req.environ['manila.context'] policy.check_policy(context, RESOURCE_NAME, 'add_security_service') + share_network = db_api.share_network_get(context, id) + if share_network['share_servers']: + msg = _("Cannot add security services. Share network is used.") + raise exc.HTTPForbidden(explanation=msg) try: share_network = db_api.share_network_add_security_service( context, @@ -256,67 +288,6 @@ class ShareNetworkController(wsgi.Controller): return self._view_builder.build_share_network(share_network) - def _activate(self, req, id, data): - """Activate share network.""" - context = req.environ['manila.context'] - policy.check_policy(context, RESOURCE_NAME, 'activate') - - try: - reservations = QUOTAS.reserve(context, share_networks=1) - except exception.OverQuota as e: - overs = e.kwargs['overs'] - usages = e.kwargs['usages'] - quotas = e.kwargs['quotas'] - - def _consumed(name): - return (usages[name]['reserved'] + usages[name]['in_use']) - - if 'share_networks' in overs: - msg = _("Quota exceeded for %(s_pid)s, tried to activate" - " share-network (%(d_consumed)d of %(d_quota)d " - "already consumed)") - LOG.warn(msg % {'s_pid': context.project_id, - 'd_consumed': _consumed('share_networks'), - 'd_quota': quotas['share_networks']}) - raise exception.ActivatedShareNetworksLimitExceeded( - allowed=quotas['share_networks']) - else: - try: - share_network = db_api.share_network_get(context, id) - except exception.ShareNetworkNotFound as e: - msg = _("Share-network was not found. %s") % e - raise exc.HTTPNotFound(explanation=msg) - - if share_network['status'] != constants.STATUS_INACTIVE: - msg = _("Share network should be 'INACTIVE'.") - raise exc.HTTPBadRequest(explanation=msg) - - self.share_rpcapi.activate_network(context, id, data) - QUOTAS.commit(context, reservations) - return self._view_builder.build_share_network(share_network) - - def _deactivate(self, req, id, data): - context = req.environ['manila.context'] - policy.check_policy(context, RESOURCE_NAME, 'deactivate') - - try: - share_network = db_api.share_network_get(context, id) - except exception.ShareNetworkNotFound as e: - msg = _("Share-network was not found. %s") % e - raise exc.HTTPNotFound(explanation=msg) - - if share_network['status'] != constants.STATUS_ACTIVE: - msg = _("Share network should be 'ACTIVE'.") - raise exc.HTTPBadRequest(explanation=msg) - - if len(share_network['shares']) > 0: - msg = _("Share network is in use.") - raise exc.HTTPBadRequest(explanation=msg) - - self.share_rpcapi.deactivate_network(context, id) - - return self._view_builder.build_share_network(share_network) - def create_resource(): return wsgi.Resource(ShareNetworkController()) diff --git a/manila/api/v1/shares.py b/manila/api/v1/shares.py index 1e71d2cfa4..87c08e7867 100644 --- a/manila/api/v1/shares.py +++ b/manila/api/v1/shares.py @@ -210,12 +210,7 @@ class ShareController(wsgi.Controller): except exception.ShareNetworkNotFound as e: msg = "%s" % e raise exc.HTTPNotFound(explanation=msg) - if share_network['status'] != constants.STATUS_ACTIVE: - msg = _("Share network '%s' is not in 'ACTIVE' state.") - msg = msg % share_network["id"] - raise exc.HTTPBadRequest(explanation=msg) - else: - kwargs['share_network_id'] = share_network_id + kwargs['share_network_id'] = share_network_id display_name = share.get('display_name') display_description = share.get('display_description') diff --git a/manila/compute/nova.py b/manila/compute/nova.py index ad1408bd9c..76cd13b2e3 100644 --- a/manila/compute/nova.py +++ b/manila/compute/nova.py @@ -30,6 +30,7 @@ from manila.db import base from manila import exception from manila.openstack.common import log as logging + nova_opts = [ cfg.StrOpt('nova_catalog_info', default='compute:nova:publicURL', diff --git a/manila/db/api.py b/manila/db/api.py index 16bdce95c1..b00bcff946 100644 --- a/manila/db/api.py +++ b/manila/db/api.py @@ -547,6 +547,66 @@ def network_allocation_update(context, id, values): return IMPL.network_allocation_update(context, id, values) +def network_allocations_get_for_share_server(context, share_server_id, + session=None): + """Get netwwork allocation for share server.""" + return IMPL.network_allocations_get_for_share_server(context, + share_server_id, + session=session) + + +################## + + +def share_server_create(context, values): + """Create share server DB record.""" + return IMPL.share_server_create(context, values) + + +def share_server_delete(context, id): + """Delete share server DB record.""" + return IMPL.share_server_delete(context, id) + + +def share_server_update(context, id, values): + """Update share server DB record.""" + return IMPL.share_server_update(context, id, values) + + +def share_server_get(context, id, session=None): + """Get share server DB record by ID.""" + return IMPL.share_server_get(context, id, session=session) + + +def share_server_get_by_host(context, host, share_net_id, session=None): + """Get share server DB records by host""" + return IMPL.share_server_get_by_host(context, host, share_net_id, + session=session) + + +def share_server_get_by_host_and_share_net(context, host, share_net_id, + session=None): + """Get share server DB records by host and share net""" + return IMPL.share_server_get_by_host_and_share_net(context, host, + share_net_id, + session=session) + + +def share_server_get_by_host_and_share_net_valid(context, host, + share_net_id, + session=None): + """Get share server DB records by host and share net not error""" + return IMPL.share_server_get_by_host_and_share_net_valid(context, + host, + share_net_id, + session=session) + + +def share_server_get_all(context): + """Get all share server DB records.""" + return IMPL.share_server_get_all(context) + + ################## diff --git a/manila/db/sqlalchemy/api.py b/manila/db/sqlalchemy/api.py index 1629e4e926..71941905ab 100644 --- a/manila/db/sqlalchemy/api.py +++ b/manila/db/sqlalchemy/api.py @@ -1511,8 +1511,8 @@ def _network_get_query(context, session=None): session = get_session() return model_query(context, models.ShareNetwork, session=session).\ options(joinedload('shares'), - joinedload('network_allocations'), - joinedload('security_services')) + joinedload('security_services'), + joinedload('share_servers')) @require_context @@ -1599,14 +1599,6 @@ def share_network_add_security_service(context, id, security_service_id): reason=msg) share_nw_ref = share_network_get(context, id, session=session) - - if share_nw_ref['status'] == constants.STATUS_ACTIVE: - msg = "Share network is active" - raise exception.ShareNetworkSecurityServiceAssociationError( - share_network_id=id, - security_service_id=security_service_id, - reason=msg) - security_service_ref = security_service_get(context, security_service_id, session=session) @@ -1646,6 +1638,81 @@ def share_network_remove_security_service(context, id, security_service_id): ################### +def _server_get_query(context, session=None): + if session is None: + session = get_session() + return model_query(context, models.ShareServer, session=session) + + +@require_context +def share_server_create(context, values): + if not values.get('id'): + values['id'] = str(uuid.uuid4()) + server_ref = models.ShareServer() + server_ref.update(values) + session = get_session() + with session.begin(): + server_ref.save(session=session) + return server_ref + + +@require_context +def share_server_delete(context, id): + session = get_session() + with session.begin(): + server_ref = share_server_get(context, id, session=session) + server_ref.delete(session=session) + + +@require_context +def share_server_update(context, id, values): + session = get_session() + with session.begin(): + server_ref = share_server_get(context, id, session=session) + server_ref.update(values) + server_ref.save(session=session) + return server_ref + + +@require_context +def share_server_get(context, server_id, session=None): + result = _server_get_query(context, session).filter_by(id=server_id)\ + .first() + if result is None: + raise exception.ShareServerNotFound(share_server_id=server_id) + return result + + +@require_context +def share_server_get_by_host_and_share_net(context, host, share_net_id, + session=None): + result = _server_get_query(context, session).filter_by(host=host)\ + .filter_by(share_network_id=share_net_id).all() + if result is None: + raise exception.ShareServerNotFound(share_server_id=id) + return result + + +@require_context +def share_server_get_by_host_and_share_net_valid(context, host, share_net_id, + session=None): + result = _server_get_query(context, session).filter_by(host=host)\ + .filter_by(share_network_id=share_net_id)\ + .filter(models.ShareServer.status.in_( + (constants.STATUS_CREATING, constants.STATUS_ACTIVE))).first() + if result is None: + raise exception.ShareServerNotFound(share_server_id=id) + return result + + +@require_context +def share_server_get_all(context): + return _server_get_query(context).all() + + +################### + + @require_context def network_allocation_create(context, values): alloc_ref = models.NetworkAllocation() @@ -1675,6 +1742,16 @@ def network_allocation_get(context, id, session=None): return result +@require_context +def network_allocations_get_for_share_server(context, share_server_id, + session=None): + if session is None: + session = get_session() + result = model_query(context, models.NetworkAllocation, session=session).\ + filter_by(share_server_id=share_server_id).all() + return result + + @require_context def network_allocation_update(context, id, values): session = get_session() diff --git a/manila/db/sqlalchemy/migrate_repo/versions/001_manila_init.py b/manila/db/sqlalchemy/migrate_repo/versions/001_manila_init.py index fb8d147cb7..68b62f63e8 100644 --- a/manila/db/sqlalchemy/migrate_repo/versions/001_manila_init.py +++ b/manila/db/sqlalchemy/migrate_repo/versions/001_manila_init.py @@ -198,6 +198,10 @@ def upgrade(migrate_engine): String(length=36), ForeignKey('share_networks.id'), nullable=True), + Column('share_server_id', + String(length=36), + ForeignKey('share_servers.id'), + nullable=True), Column('share_proto', String(255)), Column('export_location', String(255)), Column('volume_type_id', String(length=36)), @@ -297,6 +301,20 @@ def upgrade(migrate_engine): Column('ip_version', Integer, nullable=True), Column('name', String(length=255), nullable=True), Column('description', String(length=255), nullable=True), + mysql_engine='InnoDB', + mysql_charset='utf8', + ) + + share_servers = Table( + 'share_servers', meta, + 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_network_id', String(length=36), + ForeignKey('share_networks.id'), nullable=True), + Column('host', String(length=255), nullable=True), Column('status', String(length=32)), mysql_engine='InnoDB', mysql_charset='utf8', @@ -311,8 +329,8 @@ def upgrade(migrate_engine): Column('id', String(length=36), primary_key=True, nullable=False), Column('ip_address', String(length=64), nullable=True), Column('mac_address', String(length=32), nullable=True), - Column('share_network_id', String(length=36), - ForeignKey('share_networks.id'), nullable=False), + Column('share_server_id', String(length=36), + ForeignKey('share_servers.id'), nullable=False), Column('status', String(length=32)), mysql_engine='InnoDB', mysql_charset='utf8', @@ -363,9 +381,10 @@ def upgrade(migrate_engine): # Take care on create order for those with FK dependencies tables = [migrations, quotas, services, quota_classes, quota_usages, reservations, project_user_quotas, security_services, - share_networks, network_allocations, ss_nw_association, - shares, access_map, share_snapshots, share_metadata, - volume_types, volume_type_extra_specs] + share_networks, ss_nw_association, + share_servers, network_allocations, shares, access_map, + share_snapshots, + share_metadata, volume_types, volume_type_extra_specs] for table in tables: try: @@ -380,8 +399,9 @@ def upgrade(migrate_engine): "quota_classes", "quota_usages", "reservations", "project_user_quotas", "share_access_map", "share_snapshots", "share_metadata", "security_services", "share_networks", - "network_allocations", "shares", - "share_network_security_service_association"] + "network_allocations", "shares", "share_servers", + "share_network_security_service_association", "volume_types", + "volume_type_extra_specs"] sql = "SET foreign_key_checks = 0;" for table in tables: diff --git a/manila/db/sqlalchemy/models.py b/manila/db/sqlalchemy/models.py index e668d985b1..32d1f4032f 100644 --- a/manila/db/sqlalchemy/models.py +++ b/manila/db/sqlalchemy/models.py @@ -267,6 +267,8 @@ class Share(BASE, ManilaBase): nullable=True) volume_type_id = Column(String(36), ForeignKey('volume_types.id'), nullable=True) + share_server_id = Column(String(36), ForeignKey('share_servers.id'), + nullable=True) class VolumeTypes(BASE, ManilaBase): @@ -387,7 +389,7 @@ class SecurityService(BASE, ManilaBase): class ShareNetwork(BASE, ManilaBase): - "Represents network data used by share." + """Represents network data used by share.""" __tablename__ = 'share_networks' id = Column(String(36), primary_key=True, nullable=False) deleted = Column(String(36), default='False') @@ -401,9 +403,6 @@ class ShareNetwork(BASE, ManilaBase): ip_version = Column(Integer, nullable=True) name = Column(String(255), nullable=True) description = Column(String(255), nullable=True) - status = Column(Enum(constants.STATUS_INACTIVE, constants.STATUS_ACTIVE, - constants.STATUS_ERROR), - default=constants.STATUS_INACTIVE) security_services = relationship("SecurityService", secondary="share_network_security_service_association", backref="share_networks", @@ -416,15 +415,37 @@ class ShareNetwork(BASE, ManilaBase): 'SecurityService.id == ' 'ShareNetworkSecurityServiceAssociation.security_service_id,' 'SecurityService.deleted == "False")') - network_allocations = relationship("NetworkAllocation", - primaryjoin='and_(' - 'ShareNetwork.id == NetworkAllocation.share_network_id,' - 'NetworkAllocation.deleted == "False")') shares = relationship("Share", backref='share_network', primaryjoin='and_(' 'ShareNetwork.id == Share.share_network_id,' 'Share.deleted == "False")') + share_servers = relationship( + "ShareServer", backref='share_network', + primaryjoin='and_(ShareNetwork.id == ShareServer.share_network_id,' + 'ShareServer.deleted == "False")') + + +class ShareServer(BASE, ManilaBase): + """Represents share server used by share.""" + __tablename__ = 'share_servers' + id = Column(String(36), primary_key=True, nullable=False) + deleted = Column(String(36), default='False') + share_network_id = Column(String(36), ForeignKey('share_networks.id'), + nullable=True) + host = Column(String(255), nullable=False) + status = Column(Enum(constants.STATUS_INACTIVE, constants.STATUS_ACTIVE, + constants.STATUS_ERROR), + default=constants.STATUS_INACTIVE) + network_allocations = relationship("NetworkAllocation", + primaryjoin='and_(' + 'ShareServer.id == NetworkAllocation.share_server_id,' + 'NetworkAllocation.deleted == "False")') + shares = relationship("Share", + backref='share_server', + primaryjoin='and_(' + 'ShareServer.id == Share.share_server_id,' + 'Share.deleted == "False")') class ShareNetworkSecurityServiceAssociation(BASE, ManilaBase): @@ -442,14 +463,14 @@ class ShareNetworkSecurityServiceAssociation(BASE, ManilaBase): class NetworkAllocation(BASE, ManilaBase): - "Represents network allocation data." + """Represents network allocation data.""" __tablename__ = 'network_allocations' id = Column(String(36), primary_key=True, nullable=False) deleted = Column(String(36), default='False') ip_address = Column(String(64), nullable=True) mac_address = Column(String(32), nullable=True) - share_network_id = Column(String(36), ForeignKey('share_networks.id'), - nullable=False) + share_server_id = Column(String(36), ForeignKey('share_servers.id'), + nullable=False) status = Column(Enum(constants.STATUS_NEW, constants.STATUS_ACTIVE, constants.STATUS_ERROR), default=constants.STATUS_NEW) diff --git a/manila/exception.py b/manila/exception.py index afbebf0721..de3a180776 100644 --- a/manila/exception.py +++ b/manila/exception.py @@ -235,6 +235,18 @@ class ShareNetworkNotFound(NotFound): message = _("Network %(share_network_id)s could not be found.") +class ShareServerNotFound(NotFound): + message = _("Share Server %(share_server_id)s could not be found.") + + +class ShareServerInUse(InUse): + message = _("Share Server %(share_server_id)s is in use.") + + +class ShareServerNotCreated(ManilaException): + message = _("Share Server %(share_server_id)s failed on creation.") + + class InvalidImageRef(Invalid): message = _("Invalid image href %(image_href)s.") @@ -388,8 +400,8 @@ class SnapshotLimitExceeded(QuotaError): message = _("Maximum number of snapshots allowed (%(allowed)d) exceeded") -class ActivatedShareNetworksLimitExceeded(QuotaError): - message = _("Maximum number of activated share-networks " +class ShareNetworksLimitExceeded(QuotaError): + message = _("Maximum number of share-networks " "allowed (%(allowed)d) exceeded") diff --git a/manila/network/__init__.py b/manila/network/__init__.py index 021e2bab88..0dd10f3c9a 100644 --- a/manila/network/__init__.py +++ b/manila/network/__init__.py @@ -39,9 +39,13 @@ def API(): class NetworkBaseAPI(object): @abc.abstractmethod - def allocate_network(self, context, share_network, **kwargs): + def allocate_network(self, context, network_id, subnet_id, **kwargs): pass @abc.abstractmethod def deallocate_network(self, context, share_network): pass + + @abc.abstractmethod + def get_provider_info(self, context, network_id, subnet_id): + pass diff --git a/manila/network/neutron/neutron_network_plugin.py b/manila/network/neutron/neutron_network_plugin.py index 6b8b6dff3c..1108bfd404 100644 --- a/manila/network/neutron/neutron_network_plugin.py +++ b/manila/network/neutron/neutron_network_plugin.py @@ -35,7 +35,7 @@ class NeutronNetworkPlugin(manila_network.NetworkBaseAPI, db_base.Base): super(NeutronNetworkPlugin, self).__init__() self.neutron_api = neutron_api.API() - def allocate_network(self, context, share_network, **kwargs): + def allocate_network(self, context, share_server, share_network, **kwargs): """Allocate network resources using given network information: create neutron ports for a given neutron network and subnet, create manila db records for allocated neutron ports. @@ -58,12 +58,14 @@ class NeutronNetworkPlugin(manila_network.NetworkBaseAPI, db_base.Base): allocation_count = kwargs.get('count', 1) device_owner = kwargs.get('device_owner', 'share') - for _ in range(0, allocation_count): - self._create_port(context, share_network, device_owner) + ports = [] + for __ in range(0, allocation_count): + ports.append(self._create_port(context, share_server, + share_network, device_owner)) - return self.db.share_network_get(context, share_network['id']) + return ports - def deallocate_network(self, context, share_network): + def deallocate_network(self, context, share_server): """Deallocate neutron network resources for the given network info: delete previously allocated neutron ports, delete manila db records for deleted ports. @@ -72,25 +74,26 @@ class NeutronNetworkPlugin(manila_network.NetworkBaseAPI, db_base.Base): :param share_network: share network data :rtype: None """ - ports = share_network['network_allocations'] + ports = self.db.network_allocations_get_for_share_server( + context, share_server['id']) for port in ports: self._delete_port(context, port) - def _create_port(self, context, share_network, device_owner): - port = self.neutron_api.create_port(share_network['project_id'], + def _create_port(self, context, share_server, share_network, device_owner): + port = self.neutron_api.create_port( + share_network['project_id'], network_id=share_network['neutron_net_id'], subnet_id=share_network['neutron_subnet_id'], device_owner='manila:' + device_owner) port_dict = { 'id': port['id'], - 'share_network_id': share_network['id'], + 'share_server_id': share_server['id'], 'ip_address': port['fixed_ips'][0]['ip_address'], 'mac_address': port['mac_address'], 'status': constants.STATUS_ACTIVE, } - self.db.network_allocation_create(context, port_dict) - return port_dict + return self.db.network_allocation_create(context, port_dict) def _delete_port(self, context, port): try: diff --git a/manila/scheduler/filter_scheduler.py b/manila/scheduler/filter_scheduler.py index 1cb6c7ac9e..cb28fbf579 100644 --- a/manila/scheduler/filter_scheduler.py +++ b/manila/scheduler/filter_scheduler.py @@ -116,7 +116,7 @@ class FilterScheduler(driver.Scheduler): # 'volume_XX' to 'resource_XX' will make both filters happy. resource_properties = share_properties.copy() volume_type = request_spec.get("volume_type", {}) - resource_type = request_spec.get("volume_type", {}) + resource_type = request_spec.get("volume_type") or {} request_spec.update({'resource_properties': resource_properties}) config_options = self._get_configuration_options() diff --git a/manila/share/drivers/generic.py b/manila/share/drivers/generic.py index 953aa5bd8a..90537115fc 100644 --- a/manila/share/drivers/generic.py +++ b/manila/share/drivers/generic.py @@ -24,7 +24,6 @@ import time from oslo.config import cfg -from manila.common import constants from manila import compute from manila import context from manila import exception @@ -125,8 +124,9 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver): if share['share_network_id'] is None: raise exception.ManilaException( _('Share Network is not specified')) - server = self.get_service_instance(self.admin_context, - share_network_id=share['share_network_id']) + server = self.get_service_instance( + self.admin_context, share_server_id=share['share_server_id'], + share_network_id=share['share_network_id']) volume = self._allocate_container(self.admin_context, share) volume = self._attach_volume(self.admin_context, share, server, volume) self._format_device(server, volume) @@ -329,8 +329,9 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver): def create_share_from_snapshot(self, context, share, snapshot): """Is called to create share from snapshot.""" - server = self.get_service_instance(self.admin_context, - share_network_id=share['share_network_id']) + server = self.get_service_instance( + self.admin_context, share_server_id=share['share_server_id'], + share_network_id=share['share_network_id']) volume = self._allocate_container(self.admin_context, share, snapshot) volume = self._attach_volume(self.admin_context, share, server, volume) self._mount_device(context, share, server, volume) @@ -343,6 +344,7 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver): if not share['share_network_id']: return server = self.get_service_instance(self.admin_context, + share_server_id=share['share_server_id'], share_network_id=share['share_network_id'], return_inactive=True) if server: @@ -398,8 +400,9 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver): def ensure_share(self, context, share): """Ensure that storage are mounted and exported.""" - server = self.get_service_instance(context, - share_network_id=share['share_network_id'], create=True) + server = self.get_service_instance( + context, share_server_id=share['share_server_id'], + share_network_id=share['share_network_id'], create=True) volume = self._get_volume(context, share['id']) volume = self._attach_volume(context, share, server, volume) self._mount_device(context, share, server, volume) @@ -407,9 +410,9 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver): def allow_access(self, context, share, access): """Allow access to the share.""" - server = self.get_service_instance(self.admin_context, - share_network_id=share['share_network_id'], - create=False) + server = self.get_service_instance( + self.admin_context, share_server_id=share['share_server_id'], + share_network_id=share['share_network_id'], create=False) if not server: raise exception.ManilaException('Server not found. Try to ' 'restart manila share service') @@ -421,8 +424,9 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver): """Deny access to the share.""" if not share['share_network_id']: return - server = self.get_service_instance(self.admin_context, - share_network_id=share['share_network_id']) + server = self.get_service_instance( + self.admin_context, share_server_id=share['share_server_id'], + share_network_id=share['share_network_id']) if server: self._get_helper(share).deny_access(server, share['name'], access['access_type'], @@ -443,20 +447,23 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver): # use service instance provided by Nova. return 0 - def setup_network(self, share_network, metadata=None): - sn_id = share_network["id"] + def setup_network(self, network_info, metadata=None): + sn_id = network_info["share_network_id"] + srv_id = network_info["id"] msg = "Creating share infrastructure for share network '%s'." LOG.debug(msg % sn_id) self.get_service_instance(context=self.admin_context, + share_server_id=srv_id, share_network_id=sn_id, create=True) - def teardown_network(self, share_network): - sn_id = share_network["id"] - msg = "Removing share infrastructure for share network '%s'." - LOG.debug(msg % sn_id) + def teardown_network(self, network_info): + sn_id = network_info["share_network_id"] + srv_id = network_info["id"] + msg = "Removing share infrastructure for share server '%s'." + LOG.debug(msg % srv_id) try: - self.delete_service_instance(self.admin_context, sn_id) + self.delete_service_instance(self.admin_context, sn_id, srv_id) except Exception as e: LOG.debug(e) diff --git a/manila/share/drivers/netapp/cluster_mode.py b/manila/share/drivers/netapp/cluster_mode.py index 13816fd8e1..f5e485c5d3 100644 --- a/manila/share/drivers/netapp/cluster_mode.py +++ b/manila/share/drivers/netapp/cluster_mode.py @@ -449,12 +449,12 @@ class NetAppClusteredShareDriver(driver.NetAppShareDriver): def create_share(self, context, share): """Creates new share.""" - if not share.get('network_info'): + if not share.get('share_server_id'): msg = _("Cannot create share %s. " - "No share network provided") % share['id'] + "No share server provided") % share['id'] LOG.error(msg) raise exception.NetAppException(message=msg) - vserver = self._get_vserver_name(share['share_network_id']) + vserver = self._get_vserver_name(share['share_server_id']) vserver_client = driver.NetAppApiClient( self.api_version, vserver=vserver, configuration=self.configuration) @@ -464,7 +464,7 @@ class NetAppClusteredShareDriver(driver.NetAppShareDriver): def create_share_from_snapshot(self, context, share, snapshot, net_details=None): """Creates new share form snapshot.""" - vserver = self._get_vserver_name(share['share_network_id']) + vserver = self._get_vserver_name(share['share_server_id']) vserver_client = driver.NetAppApiClient( self.api_version, vserver=vserver, configuration=self.configuration) @@ -543,7 +543,7 @@ class NetAppClusteredShareDriver(driver.NetAppShareDriver): def delete_share(self, context, share): """Deletes share.""" share_name = self._get_valid_share_name(share['id']) - vserver = self._get_vserver_name(share['share_network_id']) + vserver = self._get_vserver_name(share['share_server_id']) vserver_client = driver.NetAppApiClient( self.api_version, vserver=vserver, configuration=self.configuration) diff --git a/manila/share/drivers/service_instance.py b/manila/share/drivers/service_instance.py index 79b4802b76..31dcd6ec19 100644 --- a/manila/share/drivers/service_instance.py +++ b/manila/share/drivers/service_instance.py @@ -204,14 +204,14 @@ class ServiceInstanceManager(object): else: return networks[0]['id'] - def _get_service_instance_name(self, share_network_id): + def _get_service_instance_name(self, share_server_id): """Returns service vms name.""" if self.driver_config: # Make service instance name unique for multibackend installation name = "%s_%s" % (self.driver_config.config_group, - share_network_id) + share_server_id) else: - name = share_network_id + name = share_server_id return self.get_config_option("service_instance_name_template") % name def _get_server_ip(self, server): @@ -300,23 +300,24 @@ class ServiceInstanceManager(object): self.max_time_to_build_instance) @synchronized() - def get_service_instance(self, context, share_network_id, create=False, - return_inactive=False): + def get_service_instance(self, context, share_server_id, share_network_id, + create=False, return_inactive=False): """Finds or creates and sets up service vm. :param context: defines context, that should be used :param share_network_id: it provides network data for service VM + :param share_server_id: provides server id for service VM :param create: allow create service VM or not :param return_inactive: allows to return not active VM, without raise of exception :returns: dict with data for service VM :raises: exception.ServiceInstanceException """ - server = self.share_networks_servers.get(share_network_id, {}) + server = self.share_networks_servers.get(share_server_id, {}) if self._ensure_server(context, server, update=True): return server else: - server = self._discover_service_instance(context, share_network_id) + server = self._discover_service_instance(context, share_server_id) old_server_ip = None is_active = False if server: @@ -328,10 +329,11 @@ class ServiceInstanceManager(object): self._delete_server(context, server) server = self._create_service_instance(context, share_network_id, + share_server_id, old_server_ip) is_active = True - self.share_networks_servers[share_network_id] = server + self.share_networks_servers[share_server_id] = server if is_active: server['share_network_id'] = share_network_id server['ip'] = self._get_server_ip(server) @@ -346,9 +348,9 @@ class ServiceInstanceManager(object): return server - def _discover_service_instance(self, context, share_network_id): + def _discover_service_instance(self, context, share_server_id): server = {} - instance_name = self._get_service_instance_name(share_network_id) + instance_name = self._get_service_instance_name(share_server_id) search_opts = {'name': instance_name} servers = self.compute_api.server_list(context, search_opts, True) if len(servers) == 1: @@ -413,10 +415,10 @@ class ServiceInstanceManager(object): _('Ambiguous image name.')) def _create_service_instance(self, context, share_network_id, - old_server_ip): + share_server_id, old_server_ip): """Creates service vm and sets up networking for it.""" service_image_id = self._get_service_image(context) - instance_name = self._get_service_instance_name(share_network_id) + instance_name = self._get_service_instance_name(share_server_id) with lock: key_name = self._get_key(context) @@ -648,12 +650,13 @@ class ServiceInstanceManager(object): else: raise exception.ServiceInstanceException(_('No available cidrs.')) - def delete_service_instance(self, context, share_network_id): + def delete_service_instance(self, context, share_network_id, + share_server_id): """Removes share infrastructure. Deletes service vm and subnet, associated to share network. """ - server = self._discover_service_instance(context, share_network_id) + server = self._discover_service_instance(context, share_server_id) if server: self._delete_server(context, server) subnet = self._get_service_subnet(share_network_id) diff --git a/manila/share/manager.py b/manila/share/manager.py index f2ca9aca7c..9a2b4810dd 100644 --- a/manila/share/manager.py +++ b/manila/share/manager.py @@ -1,6 +1,4 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 NetApp +# Copyright (c) 2014 NetApp Inc. # All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); you may @@ -21,6 +19,7 @@ :share_driver: Used by :class:`ShareManager`. Defaults to :class:`manila.share.drivers.lvm.LVMShareDriver`. """ +import time from manila.common import constants from manila import context @@ -29,6 +28,7 @@ from manila import manager from manila import network from manila.openstack.common import excutils from manila.openstack.common import importutils +from manila.openstack.common import lockutils from manila.openstack.common import log as logging from manila.openstack.common import timeutils from manila import quota @@ -42,6 +42,10 @@ share_manager_opts = [ cfg.StrOpt('share_driver', default='manila.share.drivers.lvm.LVMShareDriver', help='Driver to use for share creation'), + cfg.BoolOpt('delete_share_server_with_last_share', + default=False, + help='With this option is set to True share server will' + 'be deleted on deletion of last share'), ] CONF = cfg.CONF @@ -61,6 +65,7 @@ class ShareManager(manager.SchedulerDependentManager): config_group=service_name) super(ShareManager, self).__init__(service_name='share', *args, **kwargs) + if not share_driver: share_driver = self.configuration.share_driver self.driver = importutils.import_object( @@ -93,6 +98,23 @@ class ShareManager(manager.SchedulerDependentManager): self.publish_service_capabilities(ctxt) + def _share_server_get_or_create(self, context, share_network_id): + + @lockutils.synchronized(share_network_id) + def _get_or_create_server(): + try: + share_server = \ + self.db.share_server_get_by_host_and_share_net_valid( + context, self.host, share_network_id) + except exception.ShareServerNotFound: + share_network = self.db.share_network_get( + context, share_network_id) + share_server = self._setup_server(context, share_network) + LOG.info(_("Share server created successfully.")) + return share_server + + return _get_or_create_server() + def create_share(self, context, share_id, request_spec=None, filter_properties=None, snapshot_id=None): """Creates a share.""" @@ -108,13 +130,19 @@ class ShareManager(manager.SchedulerDependentManager): share_network_id = share_ref.get('share_network_id', None) if share_network_id: - share_network = self.db.share_network_get(context, - share_network_id) - else: - share_network = {} - - share_ref['network_info'] = share_network + try: + share_server = self._share_server_get_or_create( + context, share_network_id) + except Exception: + with excutils.save_and_reraise_exception(): + LOG.error(_("Failed to get share server" + " for share creation.")) + self.db.share_update(context, share_id, + {'status': 'error'}) + share_ref = self.db.share_update( + context, share_id, {'share_server_id': share_server['id']}) + LOG.debug("Using share server %s" % share_server['id']) try: if snapshot_ref: export_location = self.driver.create_share_from_snapshot( @@ -125,8 +153,10 @@ class ShareManager(manager.SchedulerDependentManager): {'export_location': export_location}) except Exception: with excutils.save_and_reraise_exception(): + LOG.error(_("Share %s failed on creation.") % share_id) self.db.share_update(context, share_id, {'status': 'error'}) else: + LOG.info(_("Share created successfully.")) self.db.share_update(context, share_id, {'status': 'available', 'launched_at': timeutils.utcnow()}) @@ -159,11 +189,17 @@ class ShareManager(manager.SchedulerDependentManager): LOG.exception(_("Failed to update usages deleting share")) self.db.share_delete(context, share_id) - LOG.info(_("share %s: deleted successfully"), share_ref['name']) + LOG.info(_("Share %s: deleted successfully."), share_ref['name']) if reservations: QUOTAS.commit(context, reservations, project_id=project_id) + share_server = self.db.share_server_get(context, + share_ref['share_server_id']) + if CONF.delete_share_server_with_last_share: + if not share_server.shares: + self._teardown_server(context, share_server) + def create_snapshot(self, context, share_id, snapshot_id): """Create snapshot for share.""" snapshot_ref = self.db.share_snapshot_get(context, snapshot_id) @@ -262,76 +298,74 @@ class ShareManager(manager.SchedulerDependentManager): self._report_driver_status(context) self._publish_service_capabilities(context) - def activate_network(self, context, share_network_id, metadata=None): - share_network = self.db.share_network_get(context, share_network_id) - if (hasattr(share_network, 'project_id') and - context.project_id != share_network['project_id']): - project_id = share_network['project_id'] - else: - project_id = context.project_id + def _form_network_info(self, context, share_server, share_network): + # Network info is used by driver for setting up share server + # and getting server info on share creation. + network_allocations = self.db.network_allocations_get_for_share_server( + context, share_server['id']) + network_info = { + 'id': share_server['id'], + 'share_network_id': share_server['share_network_id'], + 'segmentation_id': share_network['segmentation_id'], + 'cidr': share_network['cidr'], + 'security_services': share_network['security_services'], + 'network_allocations': network_allocations, + } + return network_info - reservations = None - try: - reservations = QUOTAS.reserve(context, - project_id=project_id, - share_networks=-1) - self._activate_share_network(context, share_network, metadata) - except Exception: - with excutils.save_and_reraise_exception(): - if reservations: - QUOTAS.commit(context, reservations, project_id=project_id) - - def deactivate_network(self, context, share_network_id): - share_network = self.db.share_network_get(context, share_network_id) - self._deactivate_network(context, share_network) - self.network_api.deallocate_network(context, share_network) - - if (hasattr(share_network, 'project_id') and - context.project_id != share_network['project_id']): - project_id = share_network['project_id'] - else: - project_id = context.project_id + def _setup_server(self, context, share_network, metadata=None): + share_server_val = { + 'host': self.host, + 'share_network_id': share_network['id'], + 'status': constants.STATUS_CREATING + } + share_server = self.db.share_server_create(context, + share_server_val) try: - reservations = QUOTAS.reserve(context, - project_id=project_id, - share_networks=-1) - except Exception: - msg = _("Failed to update usages deactivating share-network.") - LOG.exception(msg) - else: - QUOTAS.commit(context, reservations, project_id=project_id) + allocation_number = self.driver.get_network_allocations_number() + if allocation_number: + self.network_api.allocate_network( + context, share_server, share_network, + count=allocation_number) - def _activate_share_network(self, context, share_network, metadata=None): - allocation_number = self.driver.get_network_allocations_number() - if allocation_number: - share_network = self.network_api.allocate_network( - context, - share_network, - count=allocation_number) - try: - self.db.share_network_update(context, share_network['id'], - {'status': constants.STATUS_ACTIVATING}) - self.driver.setup_network(share_network, metadata=metadata) - self.db.share_network_update(context, share_network['id'], + share_network = self.db.share_network_get(context, + share_network['id']) + network_info = self._form_network_info(context, share_server, + share_network) + self.driver.setup_network(network_info, metadata=metadata) + return self.db.share_server_update(context, share_server['id'], {'status': constants.STATUS_ACTIVE}) - except exception.ManilaException: + except Exception: with excutils.save_and_reraise_exception(): - self.db.share_network_update(context, share_network['id'], + self.db.share_server_update(context, share_server['id'], {'status': constants.STATUS_ERROR}) self.network_api.deallocate_network(context, share_network) - else: - return share_network - def _deactivate_network(self, context, share_network): - self.db.share_network_update(context, share_network['id'], - {'status': constants.STATUS_DEACTIVATING}) - try: - self.driver.teardown_network(share_network) - except Exception as e: - with excutils.save_and_reraise_exception(): - self.db.share_network_update(context, share_network['id'], - {'status': constants.STATUS_ERROR}) - else: - self.db.share_network_update(context, share_network['id'], - {'status': constants.STATUS_INACTIVE}) + def _teardown_server(self, context, share_server): + + @lockutils.synchronized(share_server['share_network_id']) + def _teardown_server(): + share_network = self.db.share_network_get( + context, share_server['share_network_id']) + + network_info = self._form_network_info(context, share_server, + share_network) + + self.db.share_server_update(context, share_server['id'], + {'status': constants.STATUS_DELETING}) + try: + LOG.debug("Deleting share server") + self.driver.teardown_network(network_info) + except Exception as e: + with excutils.save_and_reraise_exception(): + LOG.error(_("Share server %s failed on deletion.") + % share_server['id']) + self.db.share_server_update(context, share_server['id'], + {'status': constants.STATUS_ERROR}) + else: + self.db.share_server_delete(context, share_server['id']) + + _teardown_server() + LOG.info(_("Share server deleted successfully.")) + self.network_api.deallocate_network(context, share_server) diff --git a/manila/tests/api/v1/test_share_networks.py b/manila/tests/api/v1/test_share_networks.py index 6bd21429fa..f90e41f60a 100644 --- a/manila/tests/api/v1/test_share_networks.py +++ b/manila/tests/api/v1/test_share_networks.py @@ -40,8 +40,7 @@ fake_share_network = { 'name': 'fake name', 'description': 'fake description', 'status': constants.STATUS_INACTIVE, - 'shares': [], - 'network_allocations': [], + 'share_servers': [], 'security_services': [] } fake_share_network_shortened = { @@ -122,10 +121,11 @@ class ShareNetworkAPITest(unittest.TestCase): self.req, body) - @mock.patch.object(db_api, 'share_network_get', - mock.Mock(return_value=fake_share_network)) + @mock.patch.object(db_api, 'share_network_get', mock.Mock()) def test_delete_nominal(self): - share_nw = 'fake network id' + share_nw = fake_share_network.copy() + share_nw['share_servers'] = [] + db_api.share_network_get.return_value = share_nw with mock.patch.object(db_api, 'share_network_delete'): self.controller.delete(self.req, share_nw) @@ -147,11 +147,12 @@ class ShareNetworkAPITest(unittest.TestCase): @mock.patch.object(db_api, 'share_network_get', mock.Mock()) def test_delete_in_use(self): share_nw = fake_share_network.copy() - share_nw['status'] = constants.STATUS_ACTIVE + share_servers = [{'id': 1}] + share_nw['share_servers'] = share_servers db_api.share_network_get.return_value = share_nw - self.assertRaises(webob_exc.HTTPBadRequest, + self.assertRaises(webob_exc.HTTPForbidden, self.controller.delete, self.req, share_nw['id']) @@ -252,11 +253,11 @@ class ShareNetworkAPITest(unittest.TestCase): @mock.patch.object(db_api, 'share_network_get', mock.Mock()) def test_update_in_use(self): share_nw = fake_share_network.copy() - share_nw['status'] = constants.STATUS_ACTIVE + share_nw['share_servers'] = [{'id': 1}] db_api.share_network_get.return_value = share_nw - self.assertRaises(webob_exc.HTTPBadRequest, + self.assertRaises(webob_exc.HTTPForbidden, self.controller.update, self.req, share_nw['id'], @@ -303,41 +304,6 @@ class ShareNetworkAPITest(unittest.TestCase): self.controller._remove_security_service.assert_called_once_with( self.req, share_network_id, body['remove_security_service']) - def test_action_activate(self): - share_network_id = 'fake network id' - body = {'activate': {}} - - with mock.patch.object(self.controller, '_activate', mock.Mock()): - self.controller.action(self.req, share_network_id, body) - self.controller._activate.assert_called_once_with( - self.req, share_network_id, body['activate']) - - def test_action_activate_with_overquota(self): - share_network_id = 'fake network id' - body = {'activate': {}} - - def raise_overquota(*args, **kwargs): - usages = {'share_networks': {'reserved': 0, 'in_use': 1, }} - quotas = overs = {'share_networks': 1} - raise exception.OverQuota(overs=overs, - usages=usages, - quotas=quotas) - - with mock.patch.object(QUOTAS, 'reserve', - mock.Mock(side_effect=raise_overquota)): - self.assertRaises(exception.ActivatedShareNetworksLimitExceeded, - self.controller.action, - self.req, share_network_id, body) - - def test_action_deactivate(self): - share_network_id = 'fake network id' - body = {'deactivate': {}} - - with mock.patch.object(self.controller, '_deactivate', mock.Mock()): - self.controller.action(self.req, share_network_id, body) - self.controller._deactivate.assert_called_once_with( - self.req, share_network_id, body['deactivate']) - def test_action_bad_request(self): share_network_id = 'fake network id' body = {'bad_action': {}} @@ -347,107 +313,3 @@ class ShareNetworkAPITest(unittest.TestCase): self.req, share_network_id, body) - - @mock.patch.object(db_api, 'share_network_get', - mock.Mock(return_value=fake_share_network)) - @mock.patch.object(policy, 'check_policy', mock.Mock()) - def test_activate(self): - share_network_id = 'fake network id' - - with mock.patch.object(self.controller.share_rpcapi, - 'activate_network', mock.Mock()): - self.controller._activate(self.req, share_network_id, {}) - policy.check_policy.assert_called_once_with( - self.context, - share_networks.RESOURCE_NAME, - 'activate') - db_api.share_network_get.assert_called_once_with( - self.context, - share_network_id) - self.controller.share_rpcapi.activate_network.\ - assert_called_once_with(self.context, share_network_id, {}) - - @mock.patch.object(db_api, 'share_network_get', mock.Mock()) - def test_activate_not_found(self): - share_network_id = 'fake network id' - db_api.share_network_get.side_effect = \ - exception.ShareNetworkNotFound(share_network_id=share_network_id) - - self.assertRaises(webob_exc.HTTPNotFound, - self.controller._activate, - self.req, - share_network_id, - {}) - - @mock.patch.object(db_api, 'share_network_get', mock.Mock()) - def test_activate_not_inactive(self): - share_network_id = 'fake network id' - share_network = fake_share_network.copy() - share_network['status'] = constants.STATUS_ERROR - - db_api.share_network_get.return_value = share_network - - self.assertRaises(webob_exc.HTTPBadRequest, - self.controller._activate, - self.req, - share_network_id, - {}) - - @mock.patch.object(db_api, 'share_network_get', mock.Mock()) - @mock.patch.object(policy, 'check_policy', mock.Mock()) - def test_deactivate(self): - share_network_id = 'fake network id' - share_network = fake_share_network.copy() - share_network['status'] = constants.STATUS_ACTIVE - - db_api.share_network_get.return_value = share_network - - with mock.patch.object(self.controller.share_rpcapi, - 'deactivate_network', mock.Mock()): - self.controller._deactivate(self.req, share_network_id, None) - policy.check_policy.assert_called_once_with( - self.context, - share_networks.RESOURCE_NAME, - 'deactivate') - db_api.share_network_get.assert_called_once_with( - self.context, - share_network_id) - self.controller.share_rpcapi.deactivate_network.\ - assert_called_once_with(self.context, share_network_id) - - @mock.patch.object(db_api, 'share_network_get', mock.Mock()) - def test_deactivate_not_found(self): - share_network_id = 'fake network id' - db_api.share_network_get.side_effect = \ - exception.ShareNetworkNotFound(share_network_id=share_network_id) - - self.assertRaises(webob_exc.HTTPNotFound, - self.controller._deactivate, - self.req, - share_network_id, - None) - - @mock.patch.object(db_api, 'share_network_get', - mock.Mock(return_value=fake_share_network)) - def test_deactivate_not_active(self): - share_network_id = 'fake network id' - - self.assertRaises(webob_exc.HTTPBadRequest, - self.controller._deactivate, - self.req, - share_network_id, - None) - - @mock.patch.object(db_api, 'share_network_get', mock.Mock()) - def test_deactivate_in_use(self): - share_network_id = 'fake network id' - share_network = fake_share_network.copy() - share_network['shares'].append('fake share') - - db_api.share_network_get.return_value = share_network - - self.assertRaises(webob_exc.HTTPBadRequest, - self.controller._deactivate, - self.req, - share_network_id, - None) diff --git a/manila/tests/netapp/test_cmode_drv.py b/manila/tests/netapp/test_cmode_drv.py index 0885a705ea..a25982b662 100644 --- a/manila/tests/netapp/test_cmode_drv.py +++ b/manila/tests/netapp/test_cmode_drv.py @@ -47,6 +47,7 @@ class NetAppClusteredDrvTestCase(test.TestCase): 'size': 1, 'share_proto': 'fake', 'share_network_id': 'fake_net_id', + 'share_server_id': 'fake-share-srv-id', 'network_info': { 'network_allocations': [ {'ip_address': 'ip'} @@ -406,6 +407,7 @@ class NetAppNFSHelperTestCase(test.TestCase): 'name': 'fake_name', 'size': 1, 'export_location': 'location:/path', + 'share_server_id': 'fake-share-srv-id', 'share_proto': 'fake'} self.helper = driver.NetAppClusteredNFSHelper() self.helper._client = mock.Mock() diff --git a/manila/tests/network/neutron/test_neutron_plugin.py b/manila/tests/network/neutron/test_neutron_plugin.py index cabd57b3f7..d32314e4e8 100644 --- a/manila/tests/network/neutron/test_neutron_plugin.py +++ b/manila/tests/network/neutron/test_neutron_plugin.py @@ -23,23 +23,23 @@ from manila.network.neutron import constants as neutron_constants from manila.network.neutron import neutron_network_plugin as plugin fake_neutron_port = { - "status": "test_port_status", - "allowed_address_pairs": [], - "admin_state_up": True, - "network_id": "test_net_id", - "tenant_id": "fake_tenant_id", - "extra_dhcp_opts": [], - "device_owner": "test", - "binding:capabilities": {"port_filter": True}, - "mac_address": "test_mac", - "fixed_ips": [ - {"subnet_id": "test_subnet_id", - "ip_address": "test_ip"} - ], - "id": "test_port_id", - "security_groups": ["fake_sec_group_id"], - "device_id": "fake_device_id" - } + "status": "test_port_status", + "allowed_address_pairs": [], + "admin_state_up": True, + "network_id": "test_net_id", + "tenant_id": "fake_tenant_id", + "extra_dhcp_opts": [], + "device_owner": "test", + "binding:capabilities": {"port_filter": True}, + "mac_address": "test_mac", + "fixed_ips": [ + {"subnet_id": "test_subnet_id", + "ip_address": "test_ip"} + ], + "id": "test_port_id", + "security_groups": ["fake_sec_group_id"], + "device_id": "fake_device_id" +} fake_share_network = {'id': 'fake nw info id', 'neutron_subnet_id': 'fake subnet id', @@ -48,20 +48,23 @@ fake_share_network = {'id': 'fake nw info id', 'status': 'test_subnet_status', 'name': 'fake name', 'description': 'fake description', - 'network_allocations': [], - 'security_services': [], - 'shares': []} + 'security_services': []} + +fake_share_server = {'id': 'fake nw info id', + 'status': 'test_server_status', + 'host': 'fake@host', + 'network_allocations': [], + 'shares': []} fake_network_allocation = \ {'id': fake_neutron_port['id'], - 'share_network_id': fake_share_network['id'], + 'share_server_id': fake_share_server['id'], 'ip_address': fake_neutron_port['fixed_ips'][0]['ip_address'], 'mac_address': fake_neutron_port['mac_address'], 'status': constants.STATUS_ACTIVE} class NeutronNetworkPluginTest(unittest.TestCase): - def __init__(self, *args, **kwargs): super(NeutronNetworkPluginTest, self).__init__(*args, **kwargs) @@ -75,20 +78,23 @@ class NeutronNetworkPluginTest(unittest.TestCase): mock.Mock(return_values=fake_network_allocation)) @mock.patch.object(db_api, 'share_network_get', mock.Mock(return_value=fake_share_network)) + @mock.patch.object(db_api, 'share_server_get', + mock.Mock(return_value=fake_share_server)) def test_allocate_network_one_allocation(self): - has_provider_nw_ext = mock.patch.object(self.plugin, - '_has_provider_network_extension').start() + has_provider_nw_ext = mock.patch.object( + self.plugin, '_has_provider_network_extension').start() has_provider_nw_ext.return_value = True save_nw_data = mock.patch.object(self.plugin, - '_save_neutron_network_data').start() + '_save_neutron_network_data').start() save_subnet_data = mock.patch.object( - self.plugin, - '_save_neutron_subnet_data').start() + self.plugin, + '_save_neutron_subnet_data').start() with mock.patch.object(self.plugin.neutron_api, 'create_port', mock.Mock(return_value=fake_neutron_port)): self.plugin.allocate_network( self.fake_context, + fake_share_server, fake_share_network, allocation_info={'count': 1}) @@ -114,20 +120,23 @@ class NeutronNetworkPluginTest(unittest.TestCase): mock.Mock(return_values=fake_network_allocation)) @mock.patch.object(db_api, 'share_network_get', mock.Mock(return_value=fake_share_network)) + @mock.patch.object(db_api, 'share_server_get', + mock.Mock(return_value=fake_share_server)) def test_allocate_network_two_allocation(self): - has_provider_nw_ext = mock.patch.object(self.plugin, - '_has_provider_network_extension').start() + has_provider_nw_ext = mock.patch.object( + self.plugin, '_has_provider_network_extension').start() has_provider_nw_ext.return_value = True save_nw_data = mock.patch.object(self.plugin, - '_save_neutron_network_data').start() + '_save_neutron_network_data').start() save_subnet_data = mock.patch.object( - self.plugin, - '_save_neutron_subnet_data').start() + self.plugin, + '_save_neutron_subnet_data').start() with mock.patch.object(self.plugin.neutron_api, 'create_port', mock.Mock(return_value=fake_neutron_port)): self.plugin.allocate_network( self.fake_context, + fake_share_server, fake_share_network, count=2) @@ -142,8 +151,8 @@ class NeutronNetworkPluginTest(unittest.TestCase): device_owner='manila:share'), ] db_api_calls = [ - mock.call(self.fake_context, fake_network_allocation), - mock.call(self.fake_context, fake_network_allocation) + mock.call(self.fake_context, fake_network_allocation), + mock.call(self.fake_context, fake_network_allocation) ] self.plugin.neutron_api.create_port.assert_has_calls( neutron_api_calls) @@ -155,14 +164,14 @@ class NeutronNetworkPluginTest(unittest.TestCase): @mock.patch.object(db_api, 'share_network_update', mock.Mock()) def test_allocate_network_create_port_exception(self): - has_provider_nw_ext = mock.patch.object(self.plugin, - '_has_provider_network_extension').start() + has_provider_nw_ext = mock.patch.object( + self.plugin, '_has_provider_network_extension').start() has_provider_nw_ext.return_value = True save_nw_data = mock.patch.object(self.plugin, - '_save_neutron_network_data').start() + '_save_neutron_network_data').start() save_subnet_data = mock.patch.object( - self.plugin, - '_save_neutron_subnet_data').start() + self.plugin, + '_save_neutron_subnet_data').start() create_port = mock.patch.object(self.plugin.neutron_api, 'create_port').start() create_port.side_effect = exception.NetworkException @@ -170,6 +179,7 @@ class NeutronNetworkPluginTest(unittest.TestCase): self.assertRaises(exception.NetworkException, self.plugin.allocate_network, self.fake_context, + fake_share_server, fake_share_network) has_provider_nw_ext.stop() @@ -179,13 +189,15 @@ class NeutronNetworkPluginTest(unittest.TestCase): @mock.patch.object(db_api, 'network_allocation_delete', mock.Mock()) @mock.patch.object(db_api, 'share_network_update', mock.Mock()) + @mock.patch.object(db_api, 'network_allocations_get_for_share_server', + mock.Mock(return_value=[fake_network_allocation])) def test_deallocate_network_nominal(self): - share_nw = {'id': fake_share_network['id']} - share_nw['network_allocations'] = [fake_network_allocation] + share_srv = {'id': fake_share_server['id']} + share_srv['network_allocations'] = [fake_network_allocation] with mock.patch.object(self.plugin.neutron_api, 'delete_port', mock.Mock()): - self.plugin.deallocate_network(self.fake_context, share_nw) + self.plugin.deallocate_network(self.fake_context, share_srv) self.plugin.neutron_api.delete_port.assert_called_once_with( fake_network_allocation['id']) db_api.network_allocation_delete.assert_called_once_with( @@ -195,9 +207,11 @@ class NeutronNetworkPluginTest(unittest.TestCase): @mock.patch.object(db_api, 'share_network_update', mock.Mock(return_value=fake_share_network)) @mock.patch.object(db_api, 'network_allocation_update', mock.Mock()) + @mock.patch.object(db_api, 'network_allocations_get_for_share_server', + mock.Mock(return_value=[fake_network_allocation])) def test_deallocate_network_neutron_api_exception(self): - share_nw = {'id': fake_share_network['id']} - share_nw['network_allocations'] = [fake_network_allocation] + share_srv = {'id': fake_share_server['id']} + share_srv['network_allocations'] = [fake_network_allocation] delete_port = mock.patch.object(self.plugin.neutron_api, 'delete_port').start() @@ -206,11 +220,11 @@ class NeutronNetworkPluginTest(unittest.TestCase): self.assertRaises(exception.NetworkException, self.plugin.deallocate_network, self.fake_context, - share_nw) + share_srv) db_api.network_allocation_update.assert_called_once_with( - self.fake_context, - fake_network_allocation['id'], - {'status': constants.STATUS_ERROR}) + self.fake_context, + fake_network_allocation['id'], + {'status': constants.STATUS_ERROR}) delete_port.stop() @mock.patch.object(db_api, 'share_network_update', mock.Mock()) diff --git a/manila/tests/network/test_share_network_db.py b/manila/tests/network/test_share_network_db.py index 45991c4e47..2ba694901b 100644 --- a/manila/tests/network/test_share_network_db.py +++ b/manila/tests/network/test_share_network_db.py @@ -44,13 +44,7 @@ class ShareNetworkDBTest(test.TestCase): 'cidr': '10.0.0.0/24', 'ip_version': 4, 'name': 'whatever', - 'description': 'fake description', - 'status': constants.STATUS_INACTIVE} - self.allocation_dict = {'id': 'fake port id', - 'share_network_id': self.share_nw_dict['id'], - 'ip_address': 'fake ip address', - 'mac_address': 'fake mac address', - 'status': constants.STATUS_ACTIVE} + 'description': 'fake description'} def test_create_one_network(self): result = db_api.share_network_create(self.fake_context, @@ -59,7 +53,6 @@ class ShareNetworkDBTest(test.TestCase): self._check_fields(expected=self.share_nw_dict, actual=result) self.assertEqual(len(result['shares']), 0) self.assertEqual(len(result['security_services']), 0) - self.assertEqual(len(result['network_allocations']), 0) def test_create_two_networks_in_different_tenants(self): share_nw_dict2 = self.share_nw_dict.copy() @@ -99,7 +92,6 @@ class ShareNetworkDBTest(test.TestCase): self._check_fields(expected=self.share_nw_dict, actual=result) self.assertEqual(len(result['shares']), 0) self.assertEqual(len(result['security_services']), 0) - self.assertEqual(len(result['network_allocations']), 0) def test_get_with_one_share(self): share_dict1 = {'id': 'fake share id1', @@ -169,31 +161,6 @@ class ShareNetworkDBTest(test.TestCase): self.assertEqual(len(result['security_services']), 2) - def test_get_with_one_allocation(self): - db_api.share_network_create(self.fake_context, self.share_nw_dict) - db_api.network_allocation_create(self.fake_context, - self.allocation_dict) - - result = db_api.share_network_get(self.fake_context, - self.share_nw_dict['id']) - - self.assertEqual(len(result['network_allocations']), 1) - self._check_fields(expected=self.allocation_dict, - actual=result['network_allocations'][0]) - - def test_get_with_two_allocations(self): - allocation_dict2 = dict(self.allocation_dict) - allocation_dict2['id'] = 'fake port id2' - db_api.share_network_create(self.fake_context, self.share_nw_dict) - db_api.network_allocation_create(self.fake_context, - self.allocation_dict) - db_api.network_allocation_create(self.fake_context, allocation_dict2) - - result = db_api.share_network_get(self.fake_context, - self.share_nw_dict['id']) - - self.assertEqual(len(result['network_allocations']), 2) - def test_get_not_found(self): self.assertRaises(exception.ShareNetworkNotFound, db_api.share_network_get, @@ -217,15 +184,15 @@ class ShareNetworkDBTest(test.TestCase): 'fake id') def test_update(self): - new_status = constants.STATUS_ERROR + new_name = 'fake_new_name' db_api.share_network_create(self.fake_context, self.share_nw_dict) result_update = db_api.share_network_update(self.fake_context, self.share_nw_dict['id'], - {'status': new_status}) + {'name': new_name}) result_get = db_api.share_network_get(self.fake_context, self.share_nw_dict['id']) - self.assertEqual(result_update['status'], new_status) + self.assertEqual(result_update['name'], new_name) self._check_fields(expected=dict(result_update.iteritems()), actual=dict(result_get.iteritems())) @@ -329,32 +296,6 @@ class ShareNetworkDBTest(test.TestCase): self.share_nw_dict['id'], security_dict1['id']) - def test_add_security_service_association_error_status_active(self): - security_dict1 = {'id': 'fake security service id1', - 'project_id': self.fake_context.project_id, - 'type': 'fake type'} - - db_api.share_network_create(self.fake_context, self.share_nw_dict) - db_api.share_network_update(self.fake_context, - self.share_nw_dict['id'], - {'status': constants.STATUS_ACTIVE}) - db_api.security_service_create(self.fake_context, security_dict1) - - self.assertRaises( - exception.ShareNetworkSecurityServiceAssociationError, - db_api.share_network_add_security_service, - self.fake_context, - self.share_nw_dict['id'], - security_dict1['id']) - - assoc_ref = sqlalchemy_api.model_query( - self.fake_context, - models.ShareNetworkSecurityServiceAssociation).\ - filter_by(security_service_id=security_dict1['id']).\ - filter_by(share_network_id=self.share_nw_dict['id']).first() - - self.assertTrue(assoc_ref is None) - def test_remove_security_service(self): security_dict1 = {'id': 'fake security service id1', 'project_id': self.fake_context.project_id, @@ -443,16 +384,3 @@ class ShareNetworkDBTest(test.TestCase): self.share_nw_dict['id']) self.assertEqual(len(result['shares']), 0) - - def test_network_allocations_relation(self): - db_api.share_network_create(self.fake_context, self.share_nw_dict) - - db_api.network_allocation_create(self.fake_context, - self.allocation_dict) - db_api.network_allocation_delete(self.fake_context, - self.allocation_dict['id']) - - result = db_api.share_network_get(self.fake_context, - self.share_nw_dict['id']) - - self.assertEqual(len(result['network_allocations']), 0) diff --git a/manila/tests/test_service_instance.py b/manila/tests/test_service_instance.py index 1fbf7fdca0..c9d6be4436 100644 --- a/manila/tests/test_service_instance.py +++ b/manila/tests/test_service_instance.py @@ -193,9 +193,9 @@ class ServiceInstanceManagerTestCase(test.TestCase): self.stubs.Set(self._manager, '_get_ssh_pool', mock.Mock(return_value=mock.Mock())) - result = self._manager.get_service_instance(self._context, - share_network_id='fake_share_network_id', - create=True) + result = self._manager.get_service_instance( + self._context, share_server_id='fake_share_srv_id', + share_network_id='fake_share_network_id', create=True) self._manager._ensure_server.assert_called_once() self._manager._get_ssh_pool.assert_called_once_with(fake_server) @@ -206,7 +206,7 @@ class ServiceInstanceManagerTestCase(test.TestCase): def test_get_service_instance_existed_in_memory(self): fake_server = fake_compute.FakeServer() - self._manager.share_networks_servers = {'fake_share_network_id': + self._manager.share_networks_servers = {'fake_share_srv_id': fake_server} self.stubs.Set(self._manager, '_ensure_server', mock.Mock(return_value=True)) @@ -216,8 +216,9 @@ class ServiceInstanceManagerTestCase(test.TestCase): mock.Mock(return_value=mock.Mock())) self.stubs.Set(self._manager, '_create_service_instance', mock.Mock()) - result = self._manager.get_service_instance(self._context, - share_network_id='fake_share_network_id') + result = self._manager.get_service_instance( + self._context, share_server_id='fake_share_srv_id', + share_network_id='fake_share_network_id') self._manager._ensure_server.assert_called_once() self.assertFalse(self._manager._get_ssh_pool.called) @@ -229,7 +230,7 @@ class ServiceInstanceManagerTestCase(test.TestCase): def test_get_service_instance_existed_in_memory_non_active(self): old_fake_server = fake_compute.FakeServer(status='ERROR') new_fake_server = fake_compute.FakeServer() - self._manager.share_networks_servers = {'fake_share_network_id': + self._manager.share_networks_servers = {'fake_share_srv_id': old_fake_server} self.stubs.Set(self._manager, '_ensure_server', mock.Mock(return_value=False)) @@ -243,9 +244,10 @@ class ServiceInstanceManagerTestCase(test.TestCase): self.stubs.Set(self._manager, '_get_ssh_pool', mock.Mock(return_value=mock.Mock())) - result = self._manager.get_service_instance(self._context, - share_network_id='fake_share_network_id', - create=True) + result = self._manager.get_service_instance( + self._context, share_server_id='fake_share_srv_id', + share_network_id='fake_share_network_id', + create=True) self._manager._ensure_server.assert_has_calls( [mock.call(self._context, old_fake_server, update=True)]) @@ -269,8 +271,9 @@ class ServiceInstanceManagerTestCase(test.TestCase): self.stubs.Set(self._manager, '_get_ssh_pool', mock.Mock(return_value=mock.Mock())) - result = self._manager.get_service_instance(self._context, - share_network_id='fake_share_network_id') + result = self._manager.get_service_instance( + self._context, share_server_id='fake_share_srv_id', + share_network_id='fake_share_network_id') self._manager._ensure_server.assert_called_once() self._manager._get_ssh_pool.assert_called_once_with(fake_server) @@ -418,6 +421,7 @@ class ServiceInstanceManagerTestCase(test.TestCase): fake_security_group = fake_compute.FakeSecurityGroup() fake_instance_name = 'fake_instance_name' sn_id = 'fake_sn_id' + srv_id = 'fake_srv_id' self.stubs.Set(self._manager, '_get_service_image', mock.Mock(return_value='fake_image_id')) self.stubs.Set(self._manager, '_get_key', @@ -436,8 +440,8 @@ class ServiceInstanceManagerTestCase(test.TestCase): self.stubs.Set(service_instance.socket, 'socket', mock.Mock()) self.stubs.Set(self._manager, '_get_service_instance_name', mock.Mock(return_value=fake_instance_name)) - result = self._manager._create_service_instance(self._context, - sn_id, None) + result = self._manager._create_service_instance(self._context, sn_id, + srv_id, None) self._manager._get_service_image.assert_called_once() self._manager._get_key.assert_called_once() @@ -474,7 +478,7 @@ class ServiceInstanceManagerTestCase(test.TestCase): self.assertRaises(exception.ManilaException, self._manager._create_service_instance, - self._context, self.share, None) + self._context, self.share, None, None) self._manager.compute_api.server_create.assert_called_once() self.assertFalse(self._manager.compute_api.server_get.called) @@ -504,7 +508,7 @@ class ServiceInstanceManagerTestCase(test.TestCase): self.assertRaises(exception.ManilaException, self._manager._create_service_instance, - self._context, self.share, None) + self._context, self.share, None, None) self._manager.neutron_api.delete_port.\ assert_called_once_with(fake_port['id']) @@ -519,7 +523,7 @@ class ServiceInstanceManagerTestCase(test.TestCase): mock.Mock(return_value=None)) self.assertRaises(exception.ManilaException, self._manager._create_service_instance, - self._context, self.share, None) + self._context, self.share, None, None) def test_setup_network_for_instance(self): fake_service_net = fake_network.FakeNetwork(subnets=[]) diff --git a/manila/tests/test_share.py b/manila/tests/test_share.py index 8bfb4f53a8..81099ad45f 100644 --- a/manila/tests/test_share.py +++ b/manila/tests/test_share.py @@ -93,16 +93,18 @@ class ShareTestCase(test.TestCase): super(ShareTestCase, self).setUp() self.flags(connection_type='fake', share_driver='manila.tests.test_share.FakeShareDriver') - self.share = importutils.import_object(CONF.share_manager) + self.share_manager = importutils.import_object(CONF.share_manager) self.context = context.get_admin_context() @staticmethod - def _create_share(status="creating", size=0, snapshot_id=None): + def _create_share(status="creating", size=0, snapshot_id=None, + share_network_id=None): """Create a share object.""" share = {} share['share_proto'] = "NFS" share['size'] = size share['snapshot_id'] = snapshot_id + share['share_network_id'] = share_network_id share['user_id'] = 'fake' share['project_id'] = 'fake' share['metadata'] = {'fake_key': 'fake_value'} @@ -133,6 +135,26 @@ class ShareTestCase(test.TestCase): access['state'] = state return db.share_access_create(context.get_admin_context(), access) + @staticmethod + def _create_share_server(state='new', share_network_id=None, host=None): + """Create a share server object.""" + srv = {} + srv['host'] = host + srv['share_network_id'] = share_network_id + srv['status'] = state + return db.share_server_create(context.get_admin_context(), srv) + + @staticmethod + def _create_share_network(state='new'): + """Create a share network object.""" + srv = {} + srv['user_id'] = 'fake' + srv['project_id'] = 'fake' + srv['neutron_net_id'] = 'fake-neutron-net' + srv['neutron_subnet_id'] = 'fake-neutron-subnet' + srv['status'] = state + return db.share_network_create(context.get_admin_context(), srv) + def test_init_host_ensuring_shares(self): """Test init_host for ensuring shares and access rules.""" @@ -148,8 +170,8 @@ class ShareTestCase(test.TestCase): return_value=[share, another_share]) driver = mock.Mock() driver.get_share_stats.return_value = {} - self.share.driver = driver - self.share.init_host() + self.share_manager.driver = driver + self.share_manager.init_host() driver.ensure_share.assert_called_once_with(self.context, share) driver.allow_access.assert_called_once_with( self.context, share, mock.ANY) @@ -162,7 +184,7 @@ class ShareTestCase(test.TestCase): snapshot = self._create_snapshot(share_id=share_id) snapshot_id = snapshot['id'] - self.share.create_share(self.context, share_id, + self.share_manager.create_share(self.context, share_id, snapshot_id=snapshot_id) self.assertEqual(share_id, db.share_get(context.get_admin_context(), share_id).id) @@ -185,7 +207,7 @@ class ShareTestCase(test.TestCase): snapshot = self._create_snapshot(share_id=share_id) snapshot_id = snapshot['id'] - self.share.create_snapshot(self.context, share_id, snapshot_id) + self.share_manager.create_snapshot(self.context, share_id, snapshot_id) self.assertEqual(share_id, db.share_snapshot_get(context.get_admin_context(), snapshot_id).share_id) @@ -193,7 +215,7 @@ class ShareTestCase(test.TestCase): snap = db.share_snapshot_get(self.context, snapshot_id) self.assertEqual(snap['status'], 'available') - self.share.delete_snapshot(self.context, snapshot_id) + self.share_manager.delete_snapshot(self.context, snapshot_id) self.assertRaises(exception.NotFound, db.share_snapshot_get, self.context, @@ -215,13 +237,15 @@ class ShareTestCase(test.TestCase): snapshot = self._create_snapshot(share_id=share_id) snapshot_id = snapshot['id'] - self.assertRaises(exception.NotFound, self.share.create_snapshot, + self.assertRaises(exception.NotFound, + self.share_manager.create_snapshot, self.context, share_id, snapshot_id) snap = db.share_snapshot_get(self.context, snapshot_id) self.assertEqual(snap['status'], 'error') - self.assertRaises(exception.NotFound, self.share.delete_snapshot, + self.assertRaises(exception.NotFound, + self.share_manager.delete_snapshot, self.context, snapshot_id) self.assertEqual('error_deleting', db.share_snapshot_get( @@ -239,29 +263,54 @@ class ShareTestCase(test.TestCase): snapshot = self._create_snapshot(share_id='fake_id') snapshot_id = snapshot['id'] - self.share.delete_snapshot(self.context, snapshot_id) + self.share_manager.delete_snapshot(self.context, snapshot_id) snap = db.share_snapshot_get(self.context, snapshot_id) self.assertEqual(snap['status'], 'available') - def test_create_delete_share(self): - """Test share can be created and deleted.""" - share = self._create_share() - share_id = share['id'] - self._create_access(share_id=share_id) + def test_create_share_without_server(self): + """Test share can be created without share server.""" - self.share.create_share(self.context, share_id) + share_net = self._create_share_network() + share = self._create_share(share_network_id=share_net['id']) + + share_id = share['id'] + + def fake_setup_server(context, share_network, *args, **kwargs): + return self._create_share_server( + share_network_id=share_network['id']) + + 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.assertEqual(share_id, db.share_get(context.get_admin_context(), share_id).id) shr = db.share_get(self.context, share_id) self.assertEqual(shr['status'], 'available') + self.assertTrue(shr['share_server_id']) - self.share.delete_share(self.context, share_id) - self.assertRaises(exception.NotFound, - db.share_get, - self.context, - share_id) + def test_create_share_with_server(self): + """Test share can be created with share server.""" + share_net = self._create_share_network() + share = self._create_share(share_network_id=share_net['id']) + share_srv = self._create_share_server( + share_network_id=share_net['id'], host=self.share_manager.host, + state='ACTIVE') + + share_id = share['id'] + + self.share_manager.driver = mock.Mock() + self.share_manager.driver.create_share.return_value = "fake_location" + self.share_manager.create_share(self.context, share_id) + self.assertFalse(self.share_manager.driver.setup_network.called) + self.assertEqual(share_id, db.share_get(context.get_admin_context(), + share_id).id) + + shr = db.share_get(self.context, share_id) + self.assertEquals(shr['status'], 'available') + self.assertEquals(shr['share_server_id'], share_srv['id']) def test_create_delete_share_error(self): """Test share can be created and deleted with error.""" @@ -279,14 +328,14 @@ class ShareTestCase(test.TestCase): share = self._create_share() share_id = share['id'] self.assertRaises(exception.NotFound, - self.share.create_share, + self.share_manager.create_share, self.context, share_id) shr = db.share_get(self.context, share_id) self.assertEqual(shr['status'], 'error') self.assertRaises(exception.NotFound, - self.share.delete_share, + self.share_manager.delete_share, self.context, share_id) @@ -299,11 +348,11 @@ class ShareTestCase(test.TestCase): share_id = share['id'] access = self._create_access(share_id=share_id) access_id = access['id'] - self.share.allow_access(self.context, access_id) + self.share_manager.allow_access(self.context, access_id) self.assertEqual('active', db.share_access_get(self.context, access_id).state) - self.share.deny_access(self.context, access_id) + self.share_manager.deny_access(self.context, access_id) self.assertRaises(exception.NotFound, db.share_access_get, self.context, @@ -327,7 +376,7 @@ class ShareTestCase(test.TestCase): access_id = access['id'] self.assertRaises(exception.NotFound, - self.share.allow_access, + self.share_manager.allow_access, self.context, access_id) @@ -335,128 +384,9 @@ class ShareTestCase(test.TestCase): self.assertEqual(acs['state'], 'error') self.assertRaises(exception.NotFound, - self.share.deny_access, + self.share_manager.deny_access, self.context, access_id) acs = db.share_access_get(self.context, access_id) self.assertEqual(acs['state'], 'error') - - def test_create_delete_share_with_metadata(self): - """Test share can be created with metadata and deleted.""" - test_meta = {'fake_key': 'fake_value'} - share = self._create_share() - share_id = share['id'] - self.share.create_share(self.context, share_id) - result_meta = { - share.share_metadata[0].key: share.share_metadata[0].value} - self.assertEqual(result_meta, test_meta) - - self.share.delete_share(self.context, share_id) - self.assertRaises(exception.NotFound, - db.share_get, - self.context, - share_id) - - def test_create_share_with_invalid_metadata(self): - """Test share create with too much metadata fails.""" - share_api = manila.share.api.API() - test_meta = {'fake_key': 'fake_value' * 1025} - self.assertRaises(exception.InvalidShareMetadataSize, - share_api.create, - self.context, - 'nfs', - 1, - 'name', - 'description', - metadata=test_meta) - - def test_setup_share_network(self): - share_network = {'id': 'fake_sn_id', 'share_network': 'share_network'} - allocation_number = 555 - self.share.driver.get_network_allocations_number = mock.Mock( - return_value=allocation_number) - self.share.network_api.allocate_network = mock.Mock( - return_value=share_network) - self.share.driver.setup_network = mock.Mock() - self.share._activate_share_network(context=self.context, - share_network=share_network) - self.share.network_api.allocate_network.assert_called_once_with( - self.context, share_network, count=allocation_number) - self.share.driver.setup_network.assert_called_once_with( - share_network, metadata=None) - - def test_setup_share_network_error(self): - network_info = {'fake': 'fake', 'id': 'fakeid'} - drv_allocation_cnt = mock.patch.object( - self.share.driver, - 'get_network_allocations_number').start() - drv_allocation_cnt.return_value = 555 - nw_api_allocate_nw = mock.patch.object(self.share.network_api, - 'allocate_network').start() - nw_api_allocate_nw.return_value = network_info - nw_api_deallocate_nw = mock.patch.object(self.share.network_api, - 'deallocate_network').start() - - with mock.patch.object(self.share.driver, 'setup_network', - mock.Mock(side_effect=exception.Invalid)): - self.assertRaises(exception.Invalid, - self.share._activate_share_network, - self.context, network_info) - nw_api_deallocate_nw.assert_called_once_with(self.context, - network_info) - - drv_allocation_cnt.stop() - nw_api_allocate_nw.stop() - nw_api_deallocate_nw.stop() - - def test_activate_network(self): - share_network = {'id': 'fake network id'} - db_share_nw_get = mock.patch.object(self.share.db, - 'share_network_get').start() - db_share_nw_get.return_value = share_network - drv_get_alloc_cnt = mock.patch.object( - self.share.driver, - 'get_network_allocations_number').start() - drv_get_alloc_cnt.return_value = 1 - nw_api_allocate_nw = mock.patch.object(self.share.network_api, - 'allocate_network').start() - nw_api_allocate_nw.return_value = share_network - - with mock.patch.object(self.share.driver, 'setup_network', - mock.Mock()): - self.share.activate_network(self.context, share_network['id']) - db_share_nw_get.assert_called_once_with(self.context, - share_network['id']) - drv_get_alloc_cnt.assert_any_call() - nw_api_allocate_nw.assert_called_once_with(self.context, - share_network, - count=1) - self.share.driver.setup_network.assert_called_once_with( - share_network, - metadata=None) - - db_share_nw_get.stop() - drv_get_alloc_cnt.stop() - nw_api_allocate_nw.stop() - - def test_deactivate_network(self): - share_network = {'id': 'fake network id'} - db_share_nw_get = mock.patch.object(self.share.db, - 'share_network_get').start() - db_share_nw_get.return_value = share_network - nw_api_deallocate_nw = mock.patch.object(self.share.network_api, - 'deallocate_network').start() - - with mock.patch.object(self.share.driver, 'teardown_network', - mock.Mock()): - self.share.deactivate_network(self.context, share_network['id']) - db_share_nw_get.assert_called_once_with(self.context, - share_network['id']) - nw_api_deallocate_nw.assert_called_once_with(self.context, - share_network) - self.share.driver.teardown_network.assert_called_once_with( - share_network) - - db_share_nw_get.stop() - nw_api_deallocate_nw.stop() diff --git a/manila/tests/test_share_generic.py b/manila/tests/test_share_generic.py index cbdf2d8ec3..3d8fdab0ba 100644 --- a/manila/tests/test_share_generic.py +++ b/manila/tests/test_share_generic.py @@ -44,6 +44,7 @@ def fake_share(**kwargs): 'size': 1, 'share_proto': 'NFS', 'share_network_id': 'fake share network id', + 'share_server_id': 'fake share server id', 'export_location': '127.0.0.1:/mnt/nfs/volume-00002', } share.update(kwargs) @@ -100,6 +101,10 @@ class GenericShareDriverTestCase(test.TestCase): self._driver.admin_context = self._context self.fake_sn = {"id": "fake_sn_id"} + self.fake_net_info = { + "id": "fake_srv_id", + "share_network_id": "fake_sn_id" + } fsim = fake_service_instance.FakeServiceInstanceManager() sim = mock.Mock(return_value=fsim) self._driver.instance_manager = sim @@ -531,7 +536,9 @@ class GenericShareDriverTestCase(test.TestCase): def test_setup_network(self): sim = self._driver.instance_manager - self._driver.setup_network(self.fake_sn) + net_info = self.fake_sn.copy() + net_info['share_network_id'] = net_info['id'] + self._driver.setup_network(net_info) sim.get_service_instance.assert_called_once() def test_setup_network_revert(self): @@ -539,16 +546,18 @@ class GenericShareDriverTestCase(test.TestCase): def raise_exception(*args, **kwargs): raise exception.ServiceInstanceException + net_info = self.fake_sn.copy() + net_info['share_network_id'] = net_info['id'] self.stubs.Set(self._driver, 'get_service_instance', mock.Mock(side_effect=raise_exception)) self.assertRaises(exception.ServiceInstanceException, self._driver.setup_network, - self.fake_sn) + net_info) def test_teardown_network(self): sim = self._driver.instance_manager self._driver.service_instance_manager = sim - self._driver.teardown_network(self.fake_sn) + self._driver.teardown_network(self.fake_net_info) sim.delete_service_instance.assert_called_once() diff --git a/manila/volume/cinder.py b/manila/volume/cinder.py index f6903c0feb..6bc9280d82 100644 --- a/manila/volume/cinder.py +++ b/manila/volume/cinder.py @@ -78,7 +78,8 @@ def cinderclient(context): c = cinder_client.Client(CONF.cinder_admin_username, CONF.cinder_admin_password, CONF.cinder_admin_tenant_name, - CONF.cinder_admin_auth_url) + CONF.cinder_admin_auth_url, + retries=CONF.cinder_http_retries,) c.authenticate() return c