Add share network with multiple subnets

This patch adds the possibility to create share networks with
multiple subnets in Manila. It also updates the share server api
to receive "share_network_subnet_id" instead of "share_network_id".

Each share network subnet must be associated with only one
availability zone. Each share network must have a single default
share network subnet.

DocImpact
APIImpact
Depends-On: I13bb48e7c03e16c26946ccf9d48e80592391a3d1
Partially-implements: bp share-network-multiple-subnets
Change-Id: Id8814a8b26c9b9dcb1fe71d0d7e9b79e8b8a9210
Closes-Bug: #1588144
Co-Authored-By: lseki <luciomitsuru.seki@fit-tecnologia.org.br>
Co-Authored-By: dviroel <viroel@gmail.com>
This commit is contained in:
silvacarloss authored and Douglas Viroel committed 2019-09-13 11:27:18 -03:00
1 parent 523c5aaa3a
commit 14d3e268a0
49 files changed
+3677 -647

No files matched your search

+9
View File
@@ -19,6 +19,7 @@ import re
import six
import string
from operator import xor
from oslo_config import cfg
from oslo_log import log
from oslo_utils import encodeutils
@@ -184,6 +185,14 @@ def dict_to_query_str(params):
return param_str.rstrip('&')
def check_net_id_and_subnet_id(body):
if xor('neutron_net_id' in body, 'neutron_subnet_id' in body):
msg = _("When creating a new share network subnet you need to "
"specify both neutron_net_id and neutron_subnet_id or "
"none of them.")
raise webob.exc.HTTPBadRequest(explanation=msg)
class ViewBuilder(object):
"""Model API responses as dictionaries."""
+4 -1
View File
@@ -137,13 +137,16 @@ REST_API_VERSION_HISTORY = """
* 2.50 - Added update share type API to Share Type APIs. Through this API
we can update the ``name``, ``description`` and/or
``share_type_access:is_public`` fields of the share type.
* 2.51 - Added Share Network with multiple Subnets. Updated Share Networks
to handle with one or more subnets in different availability
zones.
"""
# The minimum and maximum versions of the API supported
# The default api version request is defined to be the
# minimum version of the API supported.
_MIN_API_VERSION = "2.0"
_MAX_API_VERSION = "2.50"
_MAX_API_VERSION = "2.51"
DEFAULT_API_VERSION = _MIN_API_VERSION
@@ -281,3 +281,9 @@ user documentation.
Added update share type API to Share Type APIs. We can update the ``name``,
``description`` and/or ``share_type_access:is_public`` fields of the share
type by the update share type API.
2.51
----
Added to the service the possibility to have multiple subnets per share
network, each of them associated to a different AZ. It is also possible to
configure a default subnet that spans all availability zones.
+4 -2
View File
@@ -151,9 +151,11 @@ class SecurityServiceController(wsgi.Controller):
security_service_id):
share_networks = db.share_network_get_all_by_security_service(
context, security_service_id)
for sn in share_networks:
if sn['share_servers']:
return True
for sns in sn['share_network_subnets']:
if 'share_servers' in sns and sns['share_servers']:
return True
return False
def update(self, req, id, body):
+37 -16
View File
@@ -47,21 +47,34 @@ class ShareServerController(wsgi.Controller):
search_opts = {}
search_opts.update(req.GET)
share_servers = db_api.share_server_get_all(context)
for s in share_servers:
s.project_id = s.share_network['project_id']
if s.share_network['name']:
s.share_network_name = s.share_network['name']
else:
s.share_network_name = s.share_network_id
try:
s.share_network_id = s.share_network_subnet['share_network_id']
share_network = db_api.share_network_get(
context, s.share_network_id)
s.project_id = share_network['project_id']
if share_network['name']:
s.share_network_name = share_network['name']
else:
s.share_network_name = share_network['id']
except exception.ShareNetworkNotFound:
# NOTE(dviroel): The share-network may already be deleted while
# the share-server is in 'deleting' state. In this scenario,
# we will return some empty values.
LOG.debug("Unable to retrieve share network details for share "
"server %(server)s, the network %(network)s was "
"not found.",
{'server': s.id, 'network': s.share_network_id})
s.project_id = ''
s.share_network_name = ''
if search_opts:
for k, v in search_opts.items():
share_servers = [s for s in share_servers if
(hasattr(s, k) and
s[k] == v or k == 'share_network' and
v in [s.share_network['name'],
s.share_network['id']])]
v in [s.share_network_name,
s.share_network_id])]
return self._view_builder.build_share_servers(req, share_servers)
@wsgi.Controller.authorize
@@ -70,13 +83,21 @@ class ShareServerController(wsgi.Controller):
context = req.environ['manila.context']
try:
server = db_api.share_server_get(context, id)
server.project_id = server.share_network["project_id"]
if server.share_network['name']:
server.share_network_name = server.share_network['name']
share_network = db_api.share_network_get(
context, server.share_network_subnet['share_network_id'])
server.share_network_id = share_network['id']
server.project_id = share_network['project_id']
if share_network['name']:
server.share_network_name = share_network['name']
else:
server.share_network_name = server.share_network_id
server.share_network_name = share_network['id']
except exception.ShareServerNotFound as e:
raise exc.HTTPNotFound(explanation=e)
raise exc.HTTPNotFound(explanation=e.msg)
except exception.ShareNetworkNotFound as e:
msg = _("Share server %s could not be found. Its associated "
"share network does not "
"exist.") % server.share_network_subnet['share_network_id']
raise exc.HTTPNotFound(explanation=msg)
return self._view_builder.build_share_server(req, server)
@wsgi.Controller.authorize
@@ -86,7 +107,7 @@ class ShareServerController(wsgi.Controller):
try:
share_server = db_api.share_server_get(context, id)
except exception.ShareServerNotFound as e:
raise exc.HTTPNotFound(explanation=e)
raise exc.HTTPNotFound(explanation=e.msg)
return self._view_builder.build_share_server_details(
share_server['backend_details'])
@@ -98,7 +119,7 @@ class ShareServerController(wsgi.Controller):
try:
share_server = db_api.share_server_get(context, id)
except exception.ShareServerNotFound as e:
raise exc.HTTPNotFound(explanation=e)
raise exc.HTTPNotFound(explanation=e.msg)
allowed_statuses = [constants.STATUS_ERROR, constants.STATUS_ACTIVE]
if share_server['status'] not in allowed_statuses:
data = {
@@ -112,7 +133,7 @@ class ShareServerController(wsgi.Controller):
try:
self.share_api.delete_share_server(context, share_server)
except exception.ShareServerInUse as e:
raise exc.HTTPConflict(explanation=e)
raise exc.HTTPConflict(explanation=e.msg)
return webob.Response(status_int=http_client.ACCEPTED)
+8 -1
View File
@@ -341,8 +341,15 @@ class ShareMixin(object):
context,
share_network_id)
except exception.ShareNetworkNotFound as e:
raise exc.HTTPNotFound(explanation=six.text_type(e))
raise exc.HTTPNotFound(explanation=e.msg)
kwargs['share_network_id'] = share_network_id
if availability_zone_id:
if not db.share_network_subnet_get_by_availability_zone_id(
context, share_network_id,
availability_zone_id=availability_zone_id):
msg = _("A share network subnet was not found for the "
"requested availability zone.")
raise exc.HTTPBadRequest(explanation=msg)
display_name = share.get('display_name')
display_description = share.get('display_description')
+28
View File
@@ -43,6 +43,7 @@ from manila.api.v2 import share_group_types
from manila.api.v2 import share_groups
from manila.api.v2 import share_instance_export_locations
from manila.api.v2 import share_instances
from manila.api.v2 import share_network_subnets
from manila.api.v2 import share_networks
from manila.api.v2 import share_replica_export_locations
from manila.api.v2 import share_replicas
@@ -296,6 +297,33 @@ class APIRouter(manila.api.openstack.APIRouter):
collection={"detail": "GET"},
member={"action": "POST"})
self.resources["share_network_subnets"] = (
share_network_subnets.create_resource())
mapper.connect("share-networks",
"/{project_id}/share-networks/{share_network_id}/"
"subnets",
controller=self.resources["share_network_subnets"],
action="create",
conditions={"method": ["POST"]})
mapper.connect("share-networks",
"/{project_id}/share-networks/{share_network_id}/"
"subnets/{share_network_subnet_id}",
controller=self.resources["share_network_subnets"],
action="delete",
conditions={"method": ["DELETE"]})
mapper.connect("share-networks",
"/{project_id}/share-networks/{share_network_id}/"
"subnets/{share_network_subnet_id}",
controller=self.resources["share_network_subnets"],
action="show",
conditions={"method": ["GET"]})
mapper.connect("share-networks",
"/{project_id}/share-networks/{share_network_id}/"
"subnets",
controller=self.resources["share_network_subnets"],
action="index",
conditions={"method": ["GET"]})
self.resources["share_servers"] = share_servers.create_resource()
mapper.resource("share_server",
"share-servers",
+202
View File
@@ -0,0 +1,202 @@
# Copyright 2019 NetApp, 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 manila.api import common
from oslo_db import exception as db_exception
from oslo_log import log
from six.moves import http_client
import webob
from webob import exc
from manila.api.openstack import wsgi
from manila.api.views import share_network_subnets as subnet_views
from manila.db import api as db_api
from manila import exception
from manila.i18n import _
from manila.share import rpcapi as share_rpcapi
LOG = log.getLogger(__name__)
class ShareNetworkSubnetController(wsgi.Controller):
"""The Share Network Subnet API controller for the OpenStack API."""
resource_name = 'share_network_subnet'
_view_builder_class = subnet_views.ViewBuilder
def __init__(self):
super(ShareNetworkSubnetController, self).__init__()
self.share_rpcapi = share_rpcapi.ShareAPI()
@wsgi.Controller.api_version("2.51")
@wsgi.Controller.authorize
def index(self, req, share_network_id):
"""Returns a list of share network subnets."""
context = req.environ['manila.context']
try:
share_network = db_api.share_network_get(context, share_network_id)
except exception.ShareNetworkNotFound as e:
raise exc.HTTPNotFound(explanation=e.msg)
return self._view_builder.build_share_network_subnets(
req, share_network.get('share_network_subnets'))
def _all_share_servers_are_auto_deletable(self, share_network_subnet):
return all([ss['is_auto_deletable'] for ss
in share_network_subnet['share_servers']])
@wsgi.Controller.api_version('2.51')
@wsgi.Controller.authorize
def delete(self, req, share_network_id, share_network_subnet_id):
"""Delete specified share network subnet."""
context = req.environ['manila.context']
try:
db_api.share_network_get(context, share_network_id)
except exception.ShareNetworkNotFound as e:
raise exc.HTTPNotFound(explanation=e.msg)
try:
share_network_subnet = db_api.share_network_subnet_get(
context, share_network_subnet_id)
except exception.ShareNetworkSubnetNotFound as e:
raise exc.HTTPNotFound(explanation=e.msg)
for share_server in share_network_subnet['share_servers'] or []:
shares = db_api.share_instances_get_all_by_share_server(
context, share_server['id'])
if shares:
msg = _("Cannot delete share network subnet %(id)s, it has "
"one or more shares.") % {
'id': share_network_subnet_id}
LOG.error(msg)
raise exc.HTTPConflict(explanation=msg)
# NOTE(silvacarlose): Do not allow the deletion of any share server
# if any of them has the flag is_auto_deletable = False
if not self._all_share_servers_are_auto_deletable(
share_network_subnet):
msg = _("The service cannot determine if there are any "
"non-managed shares on the share network subnet %(id)s,"
"so it cannot be deleted. Please contact the cloud "
"administrator to rectify.") % {
'id': share_network_subnet_id}
LOG.error(msg)
raise exc.HTTPConflict(explanation=msg)
for share_server in share_network_subnet['share_servers']:
self.share_rpcapi.delete_share_server(context, share_server)
db_api.share_network_subnet_delete(context, share_network_subnet_id)
return webob.Response(status_int=http_client.ACCEPTED)
def _validate_subnet(self, context, share_network_id, az=None):
"""Validate the az for the given subnet.
If az is None, the method will search for an existent default subnet.
In case of a given AZ, validates if there's an existent subnet for it.
"""
msg = ("Another share network subnet was found in the "
"specified availability zone. Only one share network "
"subnet is allowed per availability zone for share "
"network %s." % share_network_id)
if az is None:
default_subnet = db_api.share_network_subnet_get_default_subnet(
context, share_network_id)
if default_subnet is not None:
raise exc.HTTPConflict(explanation=msg)
else:
az_subnet = (
db_api.share_network_subnet_get_by_availability_zone_id(
context, share_network_id, az['id'])
)
# If the 'availability_zone_id' is not None, we found a conflict,
# otherwise we just have found the default subnet
if az_subnet and az_subnet['availability_zone_id']:
raise exc.HTTPConflict(explanation=msg)
@wsgi.Controller.api_version("2.51")
@wsgi.Controller.authorize
def create(self, req, share_network_id, body):
"""Add a new share network subnet into the share network."""
context = req.environ['manila.context']
if not self.is_valid_body(body, 'share-network-subnet'):
msg = _("Share Network Subnet is missing from the request body.")
raise exc.HTTPBadRequest(explanation=msg)
data = body['share-network-subnet']
data['share_network_id'] = share_network_id
common.check_net_id_and_subnet_id(data)
try:
db_api.share_network_get(context, share_network_id)
except exception.ShareNetworkNotFound as e:
raise exc.HTTPNotFound(explanation=e.msg)
availability_zone = data.pop('availability_zone', None)
subnet_az = None
if availability_zone:
try:
subnet_az = db_api.availability_zone_get(context,
availability_zone)
except exception.AvailabilityZoneNotFound:
msg = _("The provided availability zone %s does not "
"exist.") % availability_zone
raise exc.HTTPBadRequest(explanation=msg)
self._validate_subnet(context, share_network_id, az=subnet_az)
try:
data['availability_zone_id'] = (
subnet_az['id'] if subnet_az is not None else None)
share_network_subnet = db_api.share_network_subnet_create(
context, data)
except db_exception.DBError as e:
msg = _('Could not create the share network subnet.')
LOG.error(e)
raise exc.HTTPInternalServerError(explanation=msg)
share_network_subnet = db_api.share_network_subnet_get(
context, share_network_subnet['id'])
return self._view_builder.build_share_network_subnet(
req, share_network_subnet)
@wsgi.Controller.api_version('2.51')
@wsgi.Controller.authorize
def show(self, req, share_network_id, share_network_subnet_id):
"""Show share network subnet."""
context = req.environ['manila.context']
try:
db_api.share_network_get(context, share_network_id)
except exception.ShareNetworkNotFound as e:
raise exc.HTTPNotFound(explanation=e.msg)
try:
share_network_subnet = db_api.share_network_subnet_get(
context, share_network_subnet_id)
except exception.ShareNetworkSubnetNotFound as e:
raise exc.HTTPNotFound(explanation=e.msg)
return self._view_builder.build_share_network_subnet(
req, share_network_subnet)
def create_resource():
return wsgi.Resource(ShareNetworkSubnetController())
+112 -27
View File
@@ -15,6 +15,7 @@
"""The shares api."""
import copy
from oslo_db import exception as db_exception
from oslo_log import log
from oslo_utils import timeutils
@@ -66,6 +67,9 @@ class ShareNetworkController(wsgi.Controller):
return all([ss['is_auto_deletable'] for ss
in share_network['share_servers']])
def _share_network_contains_subnets(self, share_network):
return len(share_network['share_network_subnets']) > 1
def delete(self, req, id):
"""Delete specified share network."""
context = req.environ['manila.context']
@@ -95,18 +99,29 @@ class ShareNetworkController(wsgi.Controller):
LOG.error(msg)
raise exc.HTTPConflict(explanation=msg)
# NOTE(silvacarlose): Do not allow the deletion of any share server
# if one of them has the flag is_auto_deletable = False
if not self._all_share_servers_are_auto_deletable(share_network):
msg = _("The service cannot determine if there are any "
"non-managed shares on the share network %(id)s, so it "
"cannot be deleted. Please contact the cloud "
"administrator to rectify.") % {'id': id}
# NOTE(silvacarlose): Do not allow the deletion of share networks
# if it still contains two or more subnets
if self._share_network_contains_subnets(share_network):
msg = _("The share network %(id)s has more than one subnet "
"attached. Please remove the subnets untill you have one "
"or no subnets remaining.") % {'id': id}
LOG.error(msg)
raise exc.HTTPConflict(explanation=msg)
for share_server in share_network['share_servers']:
self.share_rpcapi.delete_share_server(context, share_server)
for subnet in share_network['share_network_subnets']:
if not self._all_share_servers_are_auto_deletable(subnet):
msg = _("The service cannot determine if there are any "
"non-managed shares on the share network subnet "
"%(id)s, so it cannot be deleted. Please contact the "
"cloud administrator to rectify.") % {
'id': subnet['id']}
LOG.error(msg)
raise exc.HTTPConflict(explanation=msg)
for subnet in share_network['share_network_subnets']:
for share_server in subnet['share_servers']:
self.share_rpcapi.delete_share_server(context, share_server)
db_api.share_network_delete(context, id)
try:
@@ -122,6 +137,16 @@ class ShareNetworkController(wsgi.Controller):
user_id=share_network['user_id'])
return webob.Response(status_int=http_client.ACCEPTED)
def _subnet_has_search_opt(self, key, value, network, exact_value=False):
for subnet in network.get('share_network_subnets') or []:
if subnet.get(key) == value or (
not exact_value and
value in subnet.get(key.rstrip('~'))
if key.endswith('~') and
subnet.get(key.rstrip('~')) else ()):
return True
return False
def _get_share_networks(self, req, is_detail=True):
"""Returns a list of share networks."""
context = req.environ['manila.context']
@@ -179,19 +204,30 @@ class ShareNetworkController(wsgi.Controller):
value = int(value)
if (req.api_version_request >=
api_version.APIVersionRequest("2.36")):
networks = [network for network in networks
if network.get(key) == value or
(value in network.get(key.rstrip('~'))
if key.endswith('~') and
network.get(key.rstrip('~')) else ())]
networks = [
network for network in networks
if network.get(key) == value or
self._subnet_has_search_opt(key, value, network) or
(value in network.get(key.rstrip('~'))
if key.endswith('~') and
network.get(key.rstrip('~')) else ())]
else:
networks = [network for network in networks
if network.get(key) == value]
networks = [
network for network in networks
if network.get(key) == value or
self._subnet_has_search_opt(key, value, network,
exact_value=True)]
limited_list = common.limited(networks, req)
return self._view_builder.build_share_networks(
req, limited_list, is_detail)
def _share_network_subnets_contain_share_servers(self, share_network):
for subnet in share_network['share_network_subnets']:
if subnet['share_servers'] and len(subnet['share_servers']) > 0:
return True
return False
def index(self, req):
"""Returns a summary list of share networks."""
policy.check_policy(req.environ['manila.context'], RESOURCE_NAME,
@@ -223,7 +259,7 @@ class ShareNetworkController(wsgi.Controller):
msg = _("nova networking is not supported starting in Ocata.")
raise exc.HTTPBadRequest(explanation=msg)
if share_network['share_servers']:
if self._share_network_subnets_contain_share_servers(share_network):
for value in update_values:
if value not in ['name', 'description']:
msg = (_("Cannot update share network %s. It is used by "
@@ -231,8 +267,15 @@ class ShareNetworkController(wsgi.Controller):
"fields are available for update") %
share_network['id'])
raise exc.HTTPForbidden(explanation=msg)
try:
if ('neutron_net_id' in update_values or
'neutron_subnet_id' in update_values):
subnet = db_api.share_network_subnet_get_default_subnet(
context, id)
if subnet:
db_api.share_network_subnet_update(context,
subnet['id'],
update_values)
share_network = db_api.share_network_update(context,
id,
update_values)
@@ -250,14 +293,36 @@ class ShareNetworkController(wsgi.Controller):
if not body or RESOURCE_NAME not in body:
raise exc.HTTPUnprocessableEntity()
values = body[RESOURCE_NAME]
values['project_id'] = context.project_id
values['user_id'] = context.user_id
share_network_values = body[RESOURCE_NAME]
share_network_subnet_values = copy.deepcopy(share_network_values)
share_network_values['project_id'] = context.project_id
share_network_values['user_id'] = context.user_id
if 'nova_net_id' in values:
if 'nova_net_id' in share_network_values:
msg = _("nova networking is not supported starting in Ocata.")
raise exc.HTTPBadRequest(explanation=msg)
share_network_values.pop('availability_zone', None)
share_network_values.pop('neutron_net_id', None)
share_network_values.pop('neutron_subnet_id', None)
if req.api_version_request >= api_version.APIVersionRequest("2.51"):
if 'availability_zone' in share_network_subnet_values:
try:
az = db_api.availability_zone_get(
context,
share_network_subnet_values['availability_zone'])
share_network_subnet_values['availability_zone_id'] = (
az['id'])
share_network_subnet_values.pop('availability_zone')
except exception.AvailabilityZoneNotFound:
msg = (_("The provided availability zone %s does not "
"exist.")
% share_network_subnet_values['availability_zone'])
raise exc.HTTPBadRequest(explanation=msg)
common.check_net_id_and_subnet_id(share_network_subnet_values)
try:
reservations = QUOTAS.reserve(context, share_networks=1)
except exception.OverQuota as e:
@@ -279,13 +344,32 @@ class ShareNetworkController(wsgi.Controller):
raise exception.ShareNetworksLimitExceeded(
allowed=quotas['share_networks'])
else:
# Tries to create the new share network
try:
share_network = db_api.share_network_create(context, values)
share_network = db_api.share_network_create(
context, share_network_values)
except db_exception.DBError as e:
LOG.exception(e)
msg = "Could not create share network."
raise exc.HTTPInternalServerError(explanation=msg)
share_network_subnet_values['share_network_id'] = (
share_network['id'])
share_network_subnet_values.pop('id', None)
# Try to create the share network subnet. If it fails, the service
# must rollback the share network creation.
try:
db_api.share_network_subnet_create(
context, share_network_subnet_values)
except db_exception.DBError:
msg = "Could not save supplied data due to database error"
raise exc.HTTPBadRequest(explanation=msg)
db_api.share_network_delete(context, share_network['id'])
msg = _('Could not create share network.')
raise exc.HTTPInternalServerError(explanation=msg)
QUOTAS.commit(context, reservations)
share_network = db_api.share_network_get(context,
share_network['id'])
return self._view_builder.build_share_network(req, share_network)
def action(self, req, id, body):
@@ -305,7 +389,7 @@ class ShareNetworkController(wsgi.Controller):
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']:
if self._share_network_subnets_contain_share_servers(share_network):
msg = _("Cannot add security services. Share network is used.")
raise exc.HTTPForbidden(explanation=msg)
security_service = db_api.security_service_get(
@@ -338,7 +422,8 @@ class ShareNetworkController(wsgi.Controller):
context = req.environ['manila.context']
policy.check_policy(context, RESOURCE_NAME, 'remove_security_service')
share_network = db_api.share_network_get(context, id)
if share_network['share_servers']:
if self._share_network_subnets_contain_share_servers(share_network):
msg = _("Cannot remove security services. Share network is used.")
raise exc.HTTPForbidden(explanation=msg)
try:
+2 -1
View File
@@ -116,7 +116,6 @@ class ShareReplicationController(wsgi.Controller, wsgi.AdminActionsMixin):
share_id = body.get('share_replica').get('share_id')
availability_zone = body.get('share_replica').get('availability_zone')
share_network_id = body.get('share_replica').get('share_network_id')
if not share_id:
msg = _("Must provide Share ID to add replica.")
@@ -128,6 +127,8 @@ class ShareReplicationController(wsgi.Controller, wsgi.AdminActionsMixin):
msg = _("No share exists with ID %s.")
raise exc.HTTPNotFound(explanation=msg % share_id)
share_network_id = share_ref.get('share_network_id', None)
try:
new_replica = self.share_api.create_share_replica(
context, share_ref, availability_zone=availability_zone,
+46 -12
View File
@@ -31,6 +31,7 @@ LOG = log.getLogger(__name__)
class ShareServerController(share_servers.ShareServerController,
wsgi.Controller,
wsgi.AdminActionsMixin):
"""The Share Server API V2 controller for the OpenStack API."""
@@ -55,28 +56,42 @@ class ShareServerController(share_servers.ShareServerController,
def share_server_reset_status(self, req, id, body):
return self._reset_status(req, id, body)
@wsgi.Controller.api_version("2.49")
@wsgi.Controller.authorize('manage_share_server')
@wsgi.response(202)
def manage(self, req, body):
def _manage(self, req, body):
"""Manage a share server."""
LOG.debug("Manage Share Server with id: %s", id)
context = req.environ['manila.context']
identifier, host, share_network, driver_opts = (
identifier, host, share_network, driver_opts, network_subnet = (
self._validate_manage_share_server_parameters(context, body))
try:
result = self.share_api.manage_share_server(
context, identifier, host, share_network, driver_opts)
context, identifier, host, network_subnet, driver_opts)
except exception.InvalidInput as e:
raise exc.HTTPBadRequest(explanation=e)
raise exc.HTTPBadRequest(explanation=e.msg)
except exception.PolicyNotAuthorized as e:
raise exc.HTTPForbidden(explanation=e.msg)
result.project_id = share_network["project_id"]
if result.share_network['name']:
result.share_network_name = result.share_network['name']
result.share_network_id = share_network["id"]
if share_network['name']:
result.share_network_name = share_network['name']
else:
result.share_network_name = result.share_network_id
result.share_network_name = share_network['id']
return self._view_builder.build_share_server(req, result)
@wsgi.Controller.api_version('2.51')
@wsgi.response(202)
def manage(self, req, body):
return self._manage(req, body)
@wsgi.Controller.api_version('2.49') # noqa
@wsgi.response(202)
def manage(self, req, body): # pylint: disable=function-redefined
body.get('share_server', {}).pop('share_network_subnet_id', None)
return self._manage(req, body)
@wsgi.Controller.authorize('unmanage_share_server')
def _unmanage(self, req, id, body=None):
context = req.environ['manila.context']
@@ -91,7 +106,7 @@ class ShareServerController(share_servers.ShareServerController,
share_server = db_api.share_server_get(
context, id)
except exception.ShareServerNotFound as e:
raise exc.HTTPNotFound(explanation=e)
raise exc.HTTPNotFound(explanation=e.msg)
allowed_statuses = [constants.STATUS_ERROR, constants.STATUS_ACTIVE,
constants.STATUS_MANAGE_ERROR,
@@ -111,7 +126,7 @@ class ShareServerController(share_servers.ShareServerController,
context, share_server, force=force)
except (exception.ShareServerInUse,
exception.PolicyNotAuthorized) as e:
raise exc.HTTPBadRequest(explanation=e)
raise exc.HTTPBadRequest(explanation=e.msg)
return webob.Response(status_int=http_client.ACCEPTED)
@@ -141,6 +156,25 @@ class ShareServerController(share_servers.ShareServerController,
identifier = data['identifier']
host, share_network_id = data['host'], data['share_network_id']
network_subnet_id = data.get('share_network_subnet_id')
if network_subnet_id:
try:
network_subnet = db_api.share_network_subnet_get(
context, network_subnet_id)
except exception.ShareNetworkSubnetNotFound:
msg = _("The share network subnet %s does not "
"exist.") % network_subnet_id
raise exc.HTTPBadRequest(explanation=msg)
else:
network_subnet = db_api.share_network_subnet_get_default_subnet(
context, share_network_id)
if network_subnet is None:
msg = _("The share network %s does have a default subnet. Create "
"one or use a specific subnet to manage this share server "
"with API version >= 2.51.") % share_network_id
raise exc.HTTPBadRequest(explanation=msg)
if share_utils.extract_host(host, 'pool'):
msg = _("Host parameter should not contain pool.")
raise exc.HTTPBadRequest(explanation=msg)
@@ -168,7 +202,7 @@ class ShareServerController(share_servers.ShareServerController,
msg = _("Driver options must be in dictionary format.")
raise exc.HTTPBadRequest(explanation=msg)
return identifier, host, share_network, driver_opts
return identifier, host, share_network, driver_opts, network_subnet
def create_resource():
+53
View File
@@ -0,0 +1,53 @@
# Copyright 2019 NetApp, 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 manila.api import common
class ViewBuilder(common.ViewBuilder):
"""Model a server API response as a python dictionary."""
_collection_name = 'share_network_subnets'
def build_share_network_subnet(self, request, share_network_subnet):
return {
'share_network_subnet': self._build_share_network_subnet_view(
request, share_network_subnet)}
def build_share_network_subnets(self, request, share_network_subnets):
return {'share_network_subnets':
[self._build_share_network_subnet_view(
request, share_network_subnet)
for share_network_subnet in share_network_subnets]}
def _build_share_network_subnet_view(self, request, share_network_subnet):
sns = {
'id': share_network_subnet.get('id'),
'availability_zone': share_network_subnet.get('availability_zone'),
'share_network_id': share_network_subnet.get('share_network_id'),
'share_network_name': share_network_subnet.share_network['name'],
'created_at': share_network_subnet.get('created_at'),
'segmentation_id': share_network_subnet.get('segmentation_id'),
'neutron_subnet_id': share_network_subnet.get('neutron_subnet_id'),
'updated_at': share_network_subnet.get('updated_at'),
'neutron_net_id': share_network_subnet.get('neutron_net_id'),
'ip_version': share_network_subnet.get('ip_version'),
'cidr': share_network_subnet.get('cidr'),
'network_type': share_network_subnet.get('network_type'),
'mtu': share_network_subnet.get('mtu'),
'gateway': share_network_subnet.get('gateway')
}
self.update_versioned_resource_dict(request, sns, share_network_subnet)
return sns
+41 -1
View File
@@ -20,7 +20,8 @@ class ViewBuilder(common.ViewBuilder):
"""Model a server API response as a python dictionary."""
_collection_name = 'share_networks'
_detail_version_modifiers = ["add_gateway", "add_mtu", "add_nova_net_id"]
_detail_version_modifiers = ["add_gateway", "add_mtu", "add_nova_net_id",
"add_subnets"]
def build_share_network(self, request, share_network):
"""View of a share network."""
@@ -34,6 +35,20 @@ class ViewBuilder(common.ViewBuilder):
request, share_network, is_detail)
for share_network in share_networks]}
def _update_share_network_info(self, request, share_network):
for sns in share_network.get('share_network_subnets') or []:
if sns.get('is_default') and sns.get('is_default') is True:
share_network.update({
'neutron_net_id': sns.get('neutron_net_id'),
'neutron_subnet_id': sns.get('neutron_subnet_id'),
'network_type': sns.get('network_type'),
'segmentation_id': sns.get('segmentation_id'),
'cidr': sns.get('cidr'),
'ip_version': sns.get('ip_version'),
'gateway': sns.get('gateway'),
'mtu': sns.get('mtu'),
})
def _build_share_network_view(self, request, share_network,
is_detail=True):
sn = {
@@ -41,6 +56,7 @@ class ViewBuilder(common.ViewBuilder):
'name': share_network.get('name'),
}
if is_detail:
self._update_share_network_info(request, share_network)
sn.update({
'project_id': share_network.get('project_id'),
'created_at': share_network.get('created_at'),
@@ -57,6 +73,30 @@ class ViewBuilder(common.ViewBuilder):
self.update_versioned_resource_dict(request, sn, share_network)
return sn
@common.ViewBuilder.versioned_method("2.51")
def add_subnets(self, context, network_dict, network):
subnets = [{
'id': sns.get('id'),
'availability_zone': sns.get('availability_zone'),
'created_at': sns.get('created_at'),
'updated_at': sns.get('updated_at'),
'segmentation_id': sns.get('segmentation_id'),
'neutron_net_id': sns.get('neutron_net_id'),
'neutron_subnet_id': sns.get('neutron_subnet_id'),
'ip_version': sns.get('ip_version'),
'cidr': sns.get('cidr'),
'network_type': sns.get('network_type'),
'mtu': sns.get('mtu'),
'gateway': sns.get('gateway'),
} for sns in network.get('share_network_subnets')]
network_dict['share_network_subnets'] = subnets
attr_to_remove = [
'neutron_net_id', 'neutron_subnet_id', 'network_type',
'segmentation_id', 'cidr', 'ip_version', 'gateway', 'mtu']
for attr in attr_to_remove:
network_dict.pop(attr)
@common.ViewBuilder.versioned_method("2.18")
def add_gateway(self, context, network_dict, network):
network_dict['gateway'] = network.get('gateway')
+9 -2
View File
@@ -22,6 +22,7 @@ class ViewBuilder(common.ViewBuilder):
_collection_name = 'share_servers'
_detail_version_modifiers = [
"add_is_auto_deletable_and_identifier_fields",
"add_share_network_subnet_id_field"
]
def build_share_server(self, request, share_server):
@@ -56,11 +57,17 @@ class ViewBuilder(common.ViewBuilder):
share_server_dict['created_at'] = share_server.created_at
share_server_dict['backend_details'] = share_server.backend_details
self.update_versioned_resource_dict(
request, share_server_dict, share_server)
self.update_versioned_resource_dict(
request, share_server_dict, share_server)
return share_server_dict
@common.ViewBuilder.versioned_method("2.51")
def add_share_network_subnet_id_field(
self, context, share_server_dict, share_server):
share_server_dict['share_network_subnet_id'] = (
share_server['share_network_subnet_id'])
@common.ViewBuilder.versioned_method("2.49")
def add_is_auto_deletable_and_identifier_fields(
self, context, share_server_dict, share_server):
+49
View File
@@ -848,6 +848,55 @@ def count_share_networks(context, project_id, user_id=None,
##################
def share_network_subnet_create(context, values):
"""Create a share network subnet DB record."""
return IMPL.share_network_subnet_create(context, values)
def share_network_subnet_delete(context, network_subnet_id):
"""Delete a share network subnet DB record."""
return IMPL.share_network_subnet_delete(context, network_subnet_id)
def share_network_subnet_update(context, network_subnet_id, values):
"""Update a share network subnet DB record."""
return IMPL.share_network_subnet_update(context, network_subnet_id, values)
def share_network_subnet_get(context, network_subnet_id, session=None):
"""Get requested share network subnet DB record."""
return IMPL.share_network_subnet_get(context, network_subnet_id,
session=session)
def share_network_subnet_get_all(context):
"""Get all share network subnet DB record."""
return IMPL.share_network_subnet_get_all(context)
def share_network_subnet_get_by_availability_zone_id(context, share_network_id,
availability_zone_id):
"""Get a share network subnet DB record.
This method returns a subnet DB record for a given share network id and
an availability zone. If the 'availability_zone_id' is 'None', a record may
be returned and it will represent the default share network subnet.
Be aware that if there is no subnet for a specific availability zone id,
this method will return the default share network subnet, if it exists.
"""
return IMPL.share_network_subnet_get_by_availability_zone_id(
context, share_network_id, availability_zone_id)
def share_network_subnet_get_default_subnet(context, share_network_id):
"""Get the default share network subnet DB record."""
return IMPL.share_network_subnet_get_default_subnet(context,
share_network_id)
##################
def network_allocation_create(context, values):
"""Create a network allocation DB record."""
return IMPL.network_allocation_create(context, values)
@@ -0,0 +1,231 @@
# Copyright 2019 NetApp, 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.
"""add_share_network_subnets_table_and_modify_share_networks_and_servers
Revision ID: 805685098bd2
Revises: 6a3fd2984bc31
Create Date: 2019-05-09 16:28:41.919714
"""
# revision identifiers, used by Alembic.
revision = '805685098bd2'
down_revision = '6a3fd2984bc31'
from alembic import op
from manila.db.migrations import utils
from oslo_log import log
from oslo_utils import uuidutils
import sqlalchemy as sa
LOG = log.getLogger(__name__)
def upgrade():
# New table
try:
share_networks_fk_name = (
"fk_share_network_subnets_share_network_id_share_networks")
availability_zones_fk_name = (
"fk_share_network_subnets_availaility_zone_id_availability_zones")
share_network_subnets_table = op.create_table(
'share_network_subnets',
sa.Column('id', sa.String(36), primary_key=True, nullable=False),
sa.Column('neutron_net_id', sa.String(36), nullable=True),
sa.Column('neutron_subnet_id', sa.String(36), nullable=True),
sa.Column('network_type', sa.String(32), nullable=True),
sa.Column('cidr', sa.String(64), nullable=True),
sa.Column('segmentation_id', sa.Integer, nullable=True),
sa.Column('gateway', sa.String(64), nullable=True),
sa.Column('mtu', sa.Integer, nullable=True),
sa.Column('share_network_id', sa.String(36), sa.ForeignKey(
'share_networks.id', name=share_networks_fk_name)),
sa.Column('ip_version', sa.Integer, nullable=True),
sa.Column('availability_zone_id', sa.String(36),
sa.ForeignKey('availability_zones.id',
name=availability_zones_fk_name)),
sa.Column('created_at', sa.DateTime),
sa.Column('updated_at', sa.DateTime),
sa.Column('deleted_at', sa.DateTime),
sa.Column('deleted', sa.String(36), default='False'),
mysql_engine='InnoDB',
mysql_charset='utf8'
)
except Exception:
LOG.error("Table |%s| not created!", 'share_network_subnets')
raise
share_serves_fk_name = (
"fk_share_servers_share_network_subnet_id_share_network_subnets")
op.add_column(
'share_servers',
sa.Column(
'share_network_subnet_id', sa.String(36),
sa.ForeignKey('share_network_subnets.id',
name=share_serves_fk_name),
)
)
connection = op.get_bind()
share_networks_table = utils.load_table('share_networks', connection)
share_servers_table = utils.load_table('share_servers', connection)
share_network_subnets = []
# Get all share_networks and move all their data to share network subnet
for share_network in connection.execute(share_networks_table.select()):
share_network_subnet = {
'id': uuidutils.generate_uuid(),
'neutron_net_id': share_network.neutron_net_id,
'neutron_subnet_id': share_network.neutron_subnet_id,
'network_type': share_network.network_type,
'cidr': share_network.cidr,
'segmentation_id': share_network.segmentation_id,
'gateway': share_network.gateway,
'mtu': share_network.mtu,
'share_network_id': share_network.id,
'ip_version': share_network.ip_version,
'created_at': share_network.created_at,
'updated_at': share_network.updated_at,
'deleted_at': share_network.deleted_at,
'deleted': share_network.deleted,
}
share_network_subnets.append(share_network_subnet)
# Insertions for the new share network subnets
op.bulk_insert(share_network_subnets_table, share_network_subnets)
# Updates the field share server table with the share network subnet id
for sns in share_network_subnets:
share_servers = connection.execute(share_servers_table.select().where(
share_servers_table.c.share_network_id == sns['share_network_id']
))
updated_data = {'share_network_subnet_id': sns['id']}
_update_share_servers(share_servers, updated_data, share_servers_table)
if connection.engine.name == 'mysql':
# Drops necessary constraint from share servers table. Only mysql
# needs constraint handling. Postgresql/sqlite don't
op.drop_constraint("share_servers_ibfk_1", "share_servers",
type_="foreignkey")
op.drop_column('share_servers', 'share_network_id')
op.drop_column('share_networks', 'neutron_net_id')
op.drop_column('share_networks', 'neutron_subnet_id')
op.drop_column('share_networks', 'network_type')
op.drop_column('share_networks', 'segmentation_id')
op.drop_column('share_networks', 'gateway')
op.drop_column('share_networks', 'mtu')
op.drop_column('share_networks', 'cidr')
op.drop_column('share_networks', 'ip_version')
def _update_share_servers(share_servers, updated_data, share_servers_table):
for share_server in share_servers:
# pylint: disable=no-value-for-parameter
op.execute(
share_servers_table.update().where(
share_servers_table.c.id == share_server.id,
).values(updated_data)
)
def retrieve_default_subnet(subnets):
# NOTE (silvacarlose): A default subnet is that one which doesn't contain
# an availability zone. If all the share networks contain an az, we can
# retrieve whichever share network, then we pick up the first.
for subnet in subnets:
if subnet.availability_zone_id is None:
return subnet
return subnets[0] if subnets is not None else None
def downgrade():
connection = op.get_bind()
# Include again the removed fields in the share network table
op.add_column('share_networks',
sa.Column('neutron_net_id', sa.String(36), nullable=True))
op.add_column('share_networks',
sa.Column('neutron_subnet_id', sa.String(36), nullable=True))
op.add_column('share_networks',
sa.Column('network_type', sa.String(32), nullable=True))
op.add_column('share_networks',
sa.Column('cidr', sa.String(64), nullable=True))
op.add_column('share_networks',
sa.Column('gateway', sa.String(64), nullable=True))
op.add_column('share_networks',
sa.Column('mtu', sa.Integer, nullable=True))
op.add_column('share_networks',
sa.Column('segmentation_id', sa.Integer, nullable=True))
op.add_column('share_networks',
sa.Column('ip_version', sa.Integer, nullable=True))
# Include again the removed field in the share server table
op.add_column('share_servers',
sa.Column('share_network_id', sa.String(36),
sa.ForeignKey('share_networks.id',
name="share_servers_ibfk_1")))
share_networks_table = utils.load_table('share_networks', connection)
share_servers_table = utils.load_table('share_servers', connection)
subnets_table = utils.load_table('share_network_subnets', connection)
for share_network in connection.execute(share_networks_table.select()):
network_subnets = connection.execute(subnets_table.select().where(
subnets_table.c.share_network_id == share_network.id))
default_subnet = retrieve_default_subnet(network_subnets)
if default_subnet is not None:
op.execute(
# pylint: disable=no-value-for-parameter
share_networks_table.update().where(
share_networks_table.c.id == share_network.id,
).values({
'neutron_net_id': default_subnet.neutron_net_id,
'neutron_subnet_id': default_subnet.neutron_subnet_id,
'network_type': default_subnet.network_type,
'cidr': default_subnet.cidr,
'gateway': default_subnet.gateway,
'mtu': default_subnet.mtu,
'segmentation_id': default_subnet.segmentation_id,
'ip_version': default_subnet.ip_version,
})
)
for network_subnet in network_subnets:
share_servers = connection.execute(
share_servers_table.select().where(
share_servers_table.c.share_network_subnet_id ==
network_subnet.id))
updated_data = {'share_network_id': share_network.id}
_update_share_servers(share_servers, updated_data,
share_servers_table)
share_serves_fk_name = (
"fk_share_servers_share_network_subnet_id_share_network_subnets")
if connection.engine.name == 'mysql':
op.drop_constraint(share_serves_fk_name, "share_servers",
type_="foreignkey")
op.drop_column('share_servers', 'share_network_subnet_id')
try:
op.drop_table('share_network_subnets')
except Exception:
LOG.error("Failed to drop 'share_network_subnets' table!")
raise
+110 -9
View File
@@ -42,7 +42,7 @@ from oslo_utils import uuidutils
import six
from sqlalchemy import MetaData
from sqlalchemy import or_
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import joinedload, load_only
from sqlalchemy.sql.expression import literal
from sqlalchemy.sql.expression import true
from sqlalchemy.sql import func
@@ -3396,7 +3396,7 @@ def _network_get_query(context, session=None):
return (model_query(context, models.ShareNetwork, session=session).
options(joinedload('share_instances'),
joinedload('security_services'),
joinedload('share_servers')))
joinedload('share_network_subnets')))
@require_context
@@ -3454,8 +3454,8 @@ def share_network_get_all_by_security_service(context, security_service_id):
join(models.ShareNetworkSecurityServiceAssociation,
models.ShareNetwork.id ==
models.ShareNetworkSecurityServiceAssociation.share_network_id).
filter_by(security_service_id=security_service_id, deleted=0).
options(joinedload('share_servers')).all())
filter_by(security_service_id=security_service_id, deleted=0)
.all())
@require_context
@@ -3534,13 +3534,103 @@ def count_share_networks(context, project_id, user_id=None,
###################
@require_context
def _network_subnet_get_query(context, session=None):
if session is None:
session = get_session()
return (model_query(context, models.ShareNetworkSubnet, session=session).
options(joinedload('share_servers')))
@require_context
def share_network_subnet_create(context, values):
values = ensure_model_dict_has_id(values)
network_subnet_ref = models.ShareNetworkSubnet()
network_subnet_ref.update(values)
session = get_session()
with session.begin():
network_subnet_ref.save(session=session)
return share_network_subnet_get(
context, network_subnet_ref['id'], session=session)
@require_context
def share_network_subnet_delete(context, network_subnet_id):
session = get_session()
with session.begin():
network_subnet_ref = share_network_subnet_get(context,
network_subnet_id,
session=session)
network_subnet_ref.soft_delete(session=session, update_status=True)
@require_context
@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
def share_network_subnet_update(context, network_subnet_id, values):
session = get_session()
with session.begin():
network_subnet_ref = share_network_subnet_get(context,
network_subnet_id,
session=session)
network_subnet_ref.update(values)
network_subnet_ref.save(session=session)
return network_subnet_ref
@require_context
def share_network_subnet_get(context, network_subnet_id, session=None):
result = (_network_subnet_get_query(context, session)
.filter_by(id=network_subnet_id)
.first())
if result is None:
raise exception.ShareNetworkSubnetNotFound(
share_network_subnet_id=network_subnet_id)
return result
@require_context
def share_network_subnet_get_all(context):
return _network_subnet_get_query(context).all()
@require_context
def share_network_subnet_get_all_by_share_network(context, network_id):
return _network_subnet_get_query(context).filter_by(
share_network_id=network_id).all()
@require_context
def share_network_subnet_get_by_availability_zone_id(
context, share_network_id, availability_zone_id):
result = (_network_subnet_get_query(context).filter_by(
share_network_id=share_network_id,
availability_zone_id=availability_zone_id).first())
# If a specific subnet wasn't found, try get the default one
if availability_zone_id and not result:
return (_network_subnet_get_query(context).filter_by(
share_network_id=share_network_id,
availability_zone_id=None).first())
return result
@require_context
def share_network_subnet_get_default_subnet(context, share_network_id):
return share_network_subnet_get_by_availability_zone_id(
context, share_network_id, availability_zone_id=None)
###################
def _server_get_query(context, session=None):
if session is None:
session = get_session()
return (model_query(context, models.ShareServer, session=session).
options(joinedload('share_instances'),
joinedload('network_allocations'),
joinedload('share_network')))
joinedload('share_network_subnet')))
@require_context
@@ -3632,11 +3722,22 @@ def share_server_search_by_identifier(context, identifier, session=None):
def share_server_get_all_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)
# Get subnets by share_net_id
subnets = (_network_subnet_get_query(context, session)
.filter_by(share_network_id=share_net_id)
.options(load_only("id"))
.all())
subnet_ids = [s.id for s in subnets]
# Retrieve servers by the retrieved subnet ids
result = (_server_get_query(context, session)
.filter_by(host=host)
.filter(models.ShareServer.share_network_subnet_id.in_(
subnet_ids))
.filter(models.ShareServer.status.in_(
(constants.STATUS_CREATING,
constants.STATUS_ACTIVE))).all())
(constants.STATUS_CREATING,
constants.STATUS_ACTIVE))).all())
if not result:
filters_description = ('share_network_id is "%(share_net_id)s",'
' host is "%(host)s" and status in'
+53 -12
View File
@@ -916,14 +916,6 @@ class ShareNetwork(BASE, ManilaBase):
deleted = Column(String(36), default='False')
project_id = Column(String(255), nullable=False)
user_id = Column(String(255), nullable=False)
neutron_net_id = Column(String(36), nullable=True)
neutron_subnet_id = Column(String(36), nullable=True)
network_type = Column(String(32), nullable=True)
segmentation_id = Column(Integer, nullable=True)
cidr = Column(String(64), nullable=True)
gateway = Column(String(64), nullable=True)
mtu = Column(Integer, nullable=True)
ip_version = Column(Integer, nullable=True)
name = Column(String(255), nullable=True)
description = Column(String(255), nullable=True)
security_services = orm.relationship(
@@ -945,19 +937,68 @@ class ShareNetwork(BASE, ManilaBase):
primaryjoin='and_('
'ShareNetwork.id == ShareInstance.share_network_id,'
'ShareInstance.deleted == "False")')
share_network_subnets = orm.relationship(
"ShareNetworkSubnet", backref='share_network', lazy='immediate',
primaryjoin='and_'
'(ShareNetwork.id == ShareNetworkSubnet.share_network_id,'
'ShareNetworkSubnet.deleted == "False")')
class ShareNetworkSubnet(BASE, ManilaBase):
"""Represents a share network subnet used by some resources."""
_extra_keys = ['availability_zone']
__tablename__ = 'share_network_subnets'
id = Column(String(36), primary_key=True, nullable=False)
neutron_net_id = Column(String(36), nullable=True)
neutron_subnet_id = Column(String(36), nullable=True)
network_type = Column(String(32), nullable=True)
cidr = Column(String(64), nullable=True)
segmentation_id = Column(Integer, nullable=True)
gateway = Column(String(64), nullable=True)
mtu = Column(Integer, nullable=True)
deleted = Column(String(36), default='False')
share_network_id = Column(String(36), ForeignKey('share_networks.id'),
nullable=False)
ip_version = Column(Integer, nullable=True)
availability_zone_id = Column(
String(36), ForeignKey('availability_zones.id'), nullable=True)
share_servers = orm.relationship(
"ShareServer", backref='share_network',
primaryjoin='and_(ShareNetwork.id == ShareServer.share_network_id,'
"ShareServer", backref='share_network_subnet',
lazy='immediate',
primaryjoin='and_(ShareNetworkSubnet.id '
'== ShareServer.share_network_subnet_id,'
'ShareServer.deleted == "False")')
_availability_zone = orm.relationship(
"AvailabilityZone",
lazy='immediate',
foreign_keys=availability_zone_id,
primaryjoin=(
"and_("
"ShareNetworkSubnet.availability_zone_id == AvailabilityZone.id, "
"AvailabilityZone.deleted == 'False')"))
@property
def availability_zone(self):
if self._availability_zone:
return self._availability_zone['name']
@property
def is_default(self):
return self.availability_zone_id is None
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)
share_network_subnet_id = Column(
String(36), ForeignKey('share_network_subnets.id'),
nullable=True)
host = Column(String(255), nullable=False)
is_auto_deletable = Column(Boolean, default=True)
identifier = Column(String(255), nullable=True)
+5
View File
@@ -228,6 +228,11 @@ class ShareNetworkNotFound(NotFound):
message = _("Share network %(share_network_id)s could not be found.")
class ShareNetworkSubnetNotFound(NotFound):
message = _("Share network subnet %(share_network_subnet_id)s could not be"
" found.")
class ShareServerNotFound(NotFound):
message = _("Share server %(share_server_id)s could not be found.")
+12 -3
View File
@@ -85,6 +85,14 @@ class NetworkBaseAPI(db_base.Base):
"'%s'.") % share_server_id
raise exception.NetworkBadConfigurationException(reason=msg)
def _verify_share_network_subnet(self, share_server_id,
share_network_subnet):
if share_network_subnet is None:
msg = _("'Share network subnet' is not provided for setting up "
"network interfaces for 'Share server' "
"'%s'.") % share_server_id
raise exception.NetworkBadConfigurationException(reason=msg)
def update_network_allocation(self, context, share_server):
"""Update network allocation.
@@ -98,7 +106,7 @@ class NetworkBaseAPI(db_base.Base):
@abc.abstractmethod
def allocate_network(self, context, share_server, share_network=None,
**kwargs):
share_network_subnet=None, **kwargs):
pass
@abc.abstractmethod
@@ -106,8 +114,9 @@ class NetworkBaseAPI(db_base.Base):
pass
@abc.abstractmethod
def manage_network_allocations(self, context, allocations, share_server,
share_network=None):
def manage_network_allocations(
self, context, allocations, share_server, share_network=None,
share_network_subnet=None):
pass
@abc.abstractmethod
+113 -91
View File
@@ -125,19 +125,21 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
**self._neutron_api_kwargs)
return self._neutron_api
def _store_neutron_net_info(self, context, share_network):
self._save_neutron_network_data(context, share_network)
self._save_neutron_subnet_data(context, share_network)
def _store_neutron_net_info(self, context, share_network_subnet):
self._save_neutron_network_data(context, share_network_subnet)
self._save_neutron_subnet_data(context, share_network_subnet)
def allocate_network(self, context, share_server, share_network=None,
**kwargs):
share_network_subnet=None, **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.
:param context: RequestContext object
:param share_server: share server data
:param share_network: share network data
:param share_network_subnet: share network subnet data
:param kwargs: allocations parameters given by the back-end
driver. Supported params:
'count' - how many allocations should be created
@@ -149,32 +151,37 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
raise exception.NetworkBadConfigurationException(reason=msg)
self._verify_share_network(share_server['id'], share_network)
self._store_neutron_net_info(context, share_network)
self._verify_share_network_subnet(share_server['id'],
share_network_subnet)
self._store_neutron_net_info(context, share_network_subnet)
allocation_count = kwargs.get('count', 1)
device_owner = kwargs.get('device_owner', 'share')
ports = []
for __ in range(0, allocation_count):
ports.append(self._create_port(context, share_server,
share_network, device_owner))
ports.append(self._create_port(
context, share_server, share_network,
share_network_subnet, device_owner))
return ports
def manage_network_allocations(self, context, allocations, share_server,
share_network=None):
def manage_network_allocations(
self, context, allocations, share_server, share_network=None,
share_network_subnet=None):
self._verify_share_network(share_server['id'], share_network)
self._store_neutron_net_info(context, share_network)
self._verify_share_network_subnet(share_server['id'],
share_network_subnet)
self._store_neutron_net_info(context, share_network_subnet)
# We begin matching the allocations to known neutron ports and
# finally return the non-consumed allocations
remaining_allocations = list(allocations)
fixed_ip_filter = 'subnet_id=' + share_network['neutron_subnet_id']
fixed_ip_filter = ('subnet_id=' +
share_network_subnet['neutron_subnet_id'])
port_list = self.neutron_api.list_ports(
network_id=share_network['neutron_net_id'],
network_id=share_network_subnet['neutron_net_id'],
device_owner='manila:share',
fixed_ips=fixed_ip_filter)
@@ -189,15 +196,15 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
'id': selected_port['port']['id'],
'share_server_id': share_server['id'],
'ip_address': selected_port['allocation'],
'gateway': share_network['gateway'],
'gateway': share_network_subnet['gateway'],
'mac_address': selected_port['port']['mac_address'],
'status': constants.STATUS_ACTIVE,
'label': self.label,
'network_type': share_network.get('network_type'),
'segmentation_id': share_network.get('segmentation_id'),
'ip_version': share_network['ip_version'],
'cidr': share_network['cidr'],
'mtu': share_network['mtu'],
'network_type': share_network_subnet.get('network_type'),
'segmentation_id': share_network_subnet.get('segmentation_id'),
'ip_version': share_network_subnet['ip_version'],
'cidr': share_network_subnet['cidr'],
'mtu': share_network_subnet['mtu'],
}
# There should not be existing allocations with the same port_id.
@@ -296,37 +303,38 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
for port in ports:
self._delete_port(context, port)
def _get_port_create_args(self, share_server, share_network,
def _get_port_create_args(self, share_server, share_network_subnet,
device_owner):
return {
"network_id": share_network['neutron_net_id'],
"subnet_id": share_network['neutron_subnet_id'],
"network_id": share_network_subnet['neutron_net_id'],
"subnet_id": share_network_subnet['neutron_subnet_id'],
"device_owner": 'manila:' + device_owner,
"device_id": share_server.get('id'),
}
def _create_port(self, context, share_server, share_network, device_owner):
create_args = self._get_port_create_args(share_server, share_network,
device_owner)
def _create_port(self, context, share_server, share_network,
share_network_subnet, device_owner):
create_args = self._get_port_create_args(
share_server, share_network_subnet, device_owner)
port = self.neutron_api.create_port(
share_network['project_id'], **create_args)
ip_address = self._get_matched_ip_address(port['fixed_ips'],
share_network['ip_version'])
ip_address = self._get_matched_ip_address(
port['fixed_ips'], share_network_subnet['ip_version'])
port_dict = {
'id': port['id'],
'share_server_id': share_server['id'],
'ip_address': ip_address,
'gateway': share_network['gateway'],
'gateway': share_network_subnet['gateway'],
'mac_address': port['mac_address'],
'status': constants.STATUS_ACTIVE,
'label': self.label,
'network_type': share_network.get('network_type'),
'segmentation_id': share_network.get('segmentation_id'),
'ip_version': share_network['ip_version'],
'cidr': share_network['cidr'],
'mtu': share_network['mtu'],
'network_type': share_network_subnet.get('network_type'),
'segmentation_id': share_network_subnet.get('segmentation_id'),
'ip_version': share_network_subnet['ip_version'],
'cidr': share_network_subnet['cidr'],
'mtu': share_network_subnet['mtu'],
}
return self.db.network_allocation_create(context, port_dict)
@@ -344,19 +352,19 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
extensions = self.neutron_api.list_extensions()
return neutron_constants.PROVIDER_NW_EXT in extensions
def _is_neutron_multi_segment(self, share_network, net_info=None):
def _is_neutron_multi_segment(self, share_network_subnet, net_info=None):
if net_info is None:
net_info = self.neutron_api.get_network(
share_network['neutron_net_id'])
share_network_subnet['neutron_net_id'])
return 'segments' in net_info
def _save_neutron_network_data(self, context, share_network):
def _save_neutron_network_data(self, context, share_network_subnet):
net_info = self.neutron_api.get_network(
share_network['neutron_net_id'])
share_network_subnet['neutron_net_id'])
segmentation_id = None
network_type = None
if self._is_neutron_multi_segment(share_network, net_info):
if self._is_neutron_multi_segment(share_network_subnet, net_info):
# we have a multi segment network and need to identify the
# lowest segment used for binding
phy_nets = []
@@ -383,26 +391,26 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
'segmentation_id': segmentation_id,
'mtu': net_info['mtu'],
}
share_network.update(provider_nw_dict)
share_network_subnet.update(provider_nw_dict)
if self.label != 'admin':
self.db.share_network_update(
context, share_network['id'], provider_nw_dict)
self.db.share_network_subnet_update(
context, share_network_subnet['id'], provider_nw_dict)
def _save_neutron_subnet_data(self, context, share_network):
def _save_neutron_subnet_data(self, context, share_network_subnet):
subnet_info = self.neutron_api.get_subnet(
share_network['neutron_subnet_id'])
share_network_subnet['neutron_subnet_id'])
subnet_values = {
'cidr': subnet_info['cidr'],
'gateway': subnet_info['gateway_ip'],
'ip_version': subnet_info['ip_version']
}
share_network.update(subnet_values)
share_network_subnet.update(subnet_values)
if self.label != 'admin':
self.db.share_network_update(
context, share_network['id'], subnet_values)
self.db.share_network_subnet_update(
context, share_network_subnet['id'], subnet_values)
class NeutronSingleNetworkPlugin(NeutronNetworkPlugin):
@@ -416,36 +424,47 @@ class NeutronSingleNetworkPlugin(NeutronNetworkPlugin):
self.subnet = self.neutron_api.configuration.neutron_subnet_id
self._verify_net_and_subnet()
def _select_proper_share_network(self, context, share_network):
def _select_proper_share_network_subnet(self, context,
share_network_subnet):
if self.label != 'admin':
share_network = self._update_share_network_net_data(
context, share_network)
share_network_subnet = self._update_share_network_net_data(
context, share_network_subnet)
else:
share_network = {
share_network_subnet = {
'project_id': self.neutron_api.admin_project_id,
'neutron_net_id': self.net,
'neutron_subnet_id': self.subnet,
}
return share_network
return share_network_subnet
def allocate_network(self, context, share_server, share_network=None,
**kwargs):
share_network_subnet=None, **kwargs):
share_network = self._select_proper_share_network(
context, share_network)
share_network_subnet = self._select_proper_share_network_subnet(
context, share_network_subnet)
# Update share network project_id info if needed
if share_network_subnet.get('project_id', None) is not None:
share_network['project_id'] = share_network_subnet.pop(
'project_id')
return super(NeutronSingleNetworkPlugin, self).allocate_network(
context, share_server, share_network, **kwargs)
context, share_server, share_network, share_network_subnet,
**kwargs)
def manage_network_allocations(self, context, allocations, share_server,
share_network=None):
share_network = self._select_proper_share_network(
context, share_network)
def manage_network_allocations(
self, context, allocations, share_server, share_network=None,
share_network_subnet=None):
share_network_subnet = self._select_proper_share_network_subnet(
context, share_network_subnet)
# Update share network project_id info if needed
if share_network and share_network_subnet.get('project_id', None):
share_network['project_id'] = (
share_network_subnet.pop('project_id'))
return super(NeutronSingleNetworkPlugin,
self).manage_network_allocations(
context, allocations, share_server, share_network)
context, allocations, share_server, share_network,
share_network_subnet)
def _verify_net_and_subnet(self):
data = dict(net=self.net, subnet=self.subnet)
@@ -460,33 +479,33 @@ class NeutronSingleNetworkPlugin(NeutronNetworkPlugin):
"Neutron net and subnet are expected to be both set. "
"Got: net=%(net)s and subnet=%(subnet)s." % data)
def _update_share_network_net_data(self, context, share_network):
def _update_share_network_net_data(self, context, share_network_subnet):
upd = dict()
if not share_network.get('neutron_net_id') == self.net:
if share_network.get('neutron_net_id') is not None:
if not share_network_subnet.get('neutron_net_id') == self.net:
if share_network_subnet.get('neutron_net_id') is not None:
raise exception.NetworkBadConfigurationException(
"Using neutron net id different from None or value "
"specified in the config is forbidden for "
"NeutronSingleNetworkPlugin. Allowed values: (%(net)s, "
"None), received value: %(err)s" % {
"net": self.net,
"err": share_network.get('neutron_net_id')})
"err": share_network_subnet.get('neutron_net_id')})
upd['neutron_net_id'] = self.net
if not share_network.get('neutron_subnet_id') == self.subnet:
if share_network.get('neutron_subnet_id') is not None:
if not share_network_subnet.get('neutron_subnet_id') == self.subnet:
if share_network_subnet.get('neutron_subnet_id') is not None:
raise exception.NetworkBadConfigurationException(
"Using neutron subnet id different from None or value "
"specified in the config is forbidden for "
"NeutronSingleNetworkPlugin. Allowed values: (%(snet)s, "
"None), received value: %(err)s" % {
"snet": self.subnet,
"err": share_network.get('neutron_subnet_id')})
"err": share_network_subnet.get('neutron_subnet_id')})
upd['neutron_subnet_id'] = self.subnet
if upd:
share_network = self.db.share_network_update(
context, share_network['id'], upd)
return share_network
share_network_subnet = self.db.share_network_subnet_update(
context, share_network_subnet['id'], upd)
return share_network_subnet
class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
@@ -541,11 +560,11 @@ class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
"ports": inactive_ports}
raise exception.NetworkBindException(msg)
def _get_port_create_args(self, share_server, share_network,
def _get_port_create_args(self, share_server, share_network_subnet,
device_owner):
arguments = super(
NeutronBindNetworkPlugin, self)._get_port_create_args(
share_network, share_network, device_owner)
share_server, share_network_subnet, device_owner)
arguments['host_id'] = self.config.neutron_host_id
arguments['binding:vnic_type'] = self.config.neutron_vnic_type
if self.binding_profiles:
@@ -561,7 +580,7 @@ class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
"local_link_information": local_links}
return arguments
def _save_neutron_network_data(self, context, share_network):
def _save_neutron_network_data(self, context, share_network_subnet):
"""Store the Neutron network info.
In case of dynamic multi segments the segment is determined while
@@ -571,36 +590,37 @@ class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
Instead, multi segments network will wait until ports are bound and
then store network information (see allocate_network()).
"""
if self._is_neutron_multi_segment(share_network):
if self._is_neutron_multi_segment(share_network_subnet):
# In case of dynamic multi segment the segment is determined while
# binding the port, only mtu is known and already needed
self._save_neutron_network_mtu(context, share_network)
self._save_neutron_network_mtu(context, share_network_subnet)
return
super(NeutronBindNetworkPlugin, self)._save_neutron_network_data(
context, share_network)
context, share_network_subnet)
def _save_neutron_network_mtu(self, context, share_network):
def _save_neutron_network_mtu(self, context, share_network_subnet):
"""Store the Neutron network mtu.
In case of dynamic multi segments only the mtu needs storing before
binding the port.
"""
net_info = self.neutron_api.get_network(
share_network['neutron_net_id'])
share_network_subnet['neutron_net_id'])
mtu_dict = {
'mtu': net_info['mtu'],
}
share_network.update(mtu_dict)
share_network_subnet.update(mtu_dict)
if self.label != 'admin':
self.db.share_network_update(
context, share_network['id'], mtu_dict)
self.db.share_network_subnet_update(
context, share_network_subnet['id'], mtu_dict)
def allocate_network(self, context, share_server, share_network=None,
**kwargs):
share_network_subnet=None, **kwargs):
ports = super(NeutronBindNetworkPlugin, self).allocate_network(
context, share_server, share_network, **kwargs)
context, share_server, share_network, share_network_subnet,
**kwargs)
# If vnic type is 'normal' we expect a neutron agent to bind the
# ports. This action requires a vnic to be spawned by the driver.
# Therefore we do not wait for the port binding here, but
@@ -609,16 +629,18 @@ class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
# order to update the ports with the correct binding.
if self.config.neutron_vnic_type != 'normal':
self._wait_for_ports_bind(ports, share_server)
if self._is_neutron_multi_segment(share_network):
if self._is_neutron_multi_segment(share_network_subnet):
# update segment information after port bind
super(NeutronBindNetworkPlugin,
self)._save_neutron_network_data(context, share_network)
self)._save_neutron_network_data(context,
share_network_subnet)
for num, port in enumerate(ports):
port_info = {
'network_type': share_network['network_type'],
'segmentation_id': share_network['segmentation_id'],
'cidr': share_network['cidr'],
'ip_version': share_network['ip_version'],
'network_type': share_network_subnet['network_type'],
'segmentation_id':
share_network_subnet['segmentation_id'],
'cidr': share_network_subnet['cidr'],
'ip_version': share_network_subnet['ip_version'],
}
ports[num] = self.db.network_allocation_update(
context, port['id'], port_info)
+28 -24
View File
@@ -264,8 +264,8 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
'available': len(ips)}
raise exception.NetworkBadConfigurationException(reason=msg)
def _save_network_info(self, context, share_network):
"""Update share-network with plugin specific data."""
def _save_network_info(self, context, share_network_subnet):
"""Update share-network-subnet with plugin specific data."""
data = {
'network_type': self.network_type,
'segmentation_id': self.segmentation_id,
@@ -274,14 +274,15 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
'ip_version': self.ip_version,
'mtu': self.mtu,
}
share_network.update(data)
share_network_subnet.update(data)
if self.label != 'admin':
self.db.share_network_update(context, share_network['id'], data)
self.db.share_network_subnet_update(
context, share_network_subnet['id'], data)
@utils.synchronized(
"allocate_network_for_standalone_network_plugin", external=True)
def allocate_network(self, context, share_server, share_network=None,
**kwargs):
share_network_subnet=None, **kwargs):
"""Allocate network resources using one dedicated network.
This one has interprocess lock to avoid concurrency in creation of
@@ -289,10 +290,11 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
"""
allocation_count = kwargs.get('count', 1)
if self.label != 'admin':
self._verify_share_network(share_server['id'], share_network)
self._verify_share_network(share_server['id'],
share_network_subnet)
else:
share_network = share_network or {}
self._save_network_info(context, share_network)
share_network_subnet = share_network_subnet or {}
self._save_network_info(context, share_network_subnet)
allocations = []
ip_addresses = self._get_available_ips(context, allocation_count)
for ip_address in ip_addresses:
@@ -301,12 +303,12 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
'ip_address': ip_address,
'status': constants.STATUS_ACTIVE,
'label': self.label,
'network_type': share_network['network_type'],
'segmentation_id': share_network['segmentation_id'],
'cidr': share_network['cidr'],
'gateway': share_network['gateway'],
'ip_version': share_network['ip_version'],
'mtu': share_network['mtu'],
'network_type': share_network_subnet['network_type'],
'segmentation_id': share_network_subnet['segmentation_id'],
'cidr': share_network_subnet['cidr'],
'gateway': share_network_subnet['gateway'],
'ip_version': share_network_subnet['ip_version'],
'mtu': share_network_subnet['mtu'],
}
allocations.append(
self.db.network_allocation_create(context, data))
@@ -323,12 +325,14 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
self.deallocate_network(context, share_server_id)
def manage_network_allocations(self, context, allocations, share_server,
share_network=None):
share_network=None,
share_network_subnet=None):
if self.label != 'admin':
self._verify_share_network(share_server['id'], share_network)
self._verify_share_network_subnet(share_server['id'],
share_network_subnet)
else:
share_network = share_network or {}
self._save_network_info(context, share_network)
share_network_subnet = share_network_subnet or {}
self._save_network_info(context, share_network_subnet)
# We begin matching the allocations to known neutron ports and
# finally return the non-consumed allocations
@@ -350,12 +354,12 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
'ip_address': allocation,
'status': constants.STATUS_ACTIVE,
'label': self.label,
'network_type': share_network['network_type'],
'segmentation_id': share_network['segmentation_id'],
'cidr': share_network['cidr'],
'gateway': share_network['gateway'],
'ip_version': share_network['ip_version'],
'mtu': share_network['mtu'],
'network_type': share_network_subnet['network_type'],
'segmentation_id': share_network_subnet['segmentation_id'],
'cidr': share_network_subnet['cidr'],
'gateway': share_network_subnet['gateway'],
'ip_version': share_network_subnet['ip_version'],
'mtu': share_network_subnet['mtu'],
}
self.db.network_allocation_create(context, data)
remaining_allocations.remove(allocation)
+2
View File
@@ -34,6 +34,7 @@ from manila.policies import share_group_types_spec
from manila.policies import share_instance
from manila.policies import share_instance_export_location
from manila.policies import share_network
from manila.policies import share_network_subnet
from manila.policies import share_replica
from manila.policies import share_replica_export_location
from manila.policies import share_server
@@ -70,6 +71,7 @@ def list_rules():
share_replica.list_rules(),
share_replica_export_location.list_rules(),
share_network.list_rules(),
share_network_subnet.list_rules(),
security_service.list_rules(),
share_export_location.list_rules(),
share_instance.list_rules(),
+70
View File
@@ -0,0 +1,70 @@
# Copyright 2019 NetApp, 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 oslo_policy import policy
from manila.policies import base
BASE_POLICY_NAME = 'share_network_subnet:%s'
share_network_subnet_policies = [
policy.DocumentedRuleDefault(
name=BASE_POLICY_NAME % 'create',
check_str=base.RULE_DEFAULT,
description="Create a new share network subnet.",
operations=[
{
'method': 'POST',
'path': '/share-networks/{share_network_id}/subnets'
}
]),
policy.DocumentedRuleDefault(
name=BASE_POLICY_NAME % 'delete',
check_str=base.RULE_DEFAULT,
description="Delete a share network subnet.",
operations=[
{
'method': 'DELETE',
'path': '/share-networks/{share_network_id}/subnets/'
'{share_network_subnet_id}'
}
]),
policy.DocumentedRuleDefault(
name=BASE_POLICY_NAME % 'show',
check_str=base.RULE_DEFAULT,
description="Shows a share network subnet.",
operations=[
{
'method': 'GET',
'path': '/share-networks/{share_network_id}/subnets/'
'{share_network_subnet_id}'
}
]),
policy.DocumentedRuleDefault(
name=BASE_POLICY_NAME % 'index',
check_str=base.RULE_DEFAULT,
description="Get all share network subnets.",
operations=[
{
'method': 'GET',
'path': '/share-networks/{share_network_id}/subnets'
}
]),
]
def list_rules():
return share_network_subnet_policies
+69 -4
View File
@@ -66,6 +66,16 @@ class API(base.Base):
self.share_rpcapi = share_rpcapi.ShareAPI()
self.access_helper = access.ShareInstanceAccess(self.db, None)
def _get_all_availability_zones_with_subnets(self, context,
share_network_id):
compatible_azs = []
for az in self.db.availability_zone_get_all(context):
if self.db.share_network_subnet_get_by_availability_zone_id(
context, share_network_id=share_network_id,
availability_zone_id=az['id']):
compatible_azs.append(az['name'])
return compatible_azs
def create(self, context, share_proto, size, name, description,
snapshot_id=None, availability_zone=None, metadata=None,
share_network_id=None, share_type=None, is_public=False,
@@ -227,6 +237,25 @@ class API(base.Base):
options['source_share_group_snapshot_member_id'] = (
share_group_snapshot_member['id'])
# NOTE(dviroel): If a target availability zone was not provided, the
# scheduler will receive a list with all availability zones that
# contains a subnet within the selected share network.
if share_network_id and not availability_zone:
azs_with_subnet = self._get_all_availability_zones_with_subnets(
context, share_network_id)
if not availability_zones:
availability_zones = azs_with_subnet
else:
availability_zones = (
[az for az in availability_zones if az in azs_with_subnet])
if not availability_zones:
msg = _(
"The share network is not supported within any requested "
"availability zone. Check the share type's "
"'availability_zones' extra-spec and the availability "
"zones of the share network subnets")
raise exception.InvalidInput(message=msg)
try:
share = self.db.share_create(context, options,
create_share_instance=False)
@@ -484,11 +513,45 @@ class API(base.Base):
'az': availability_zone}
raise exception.InvalidShare(message=msg % payload)
if share_network_id:
if availability_zone:
try:
az = self.db.availability_zone_get(context,
availability_zone)
except exception.AvailabilityZoneNotFound:
msg = _("Share replica cannot be created because the "
"specified availability zone does not exist.")
raise exception.InvalidInput(message=msg)
if self.db.share_network_subnet_get_by_availability_zone_id(
context, share_network_id, az.get('id')) is None:
msg = _("Share replica cannot be created because the "
"share network is not available within the "
"specified availability zone.")
raise exception.InvalidShare(message=msg)
else:
# NOTE(dviroel): If a target availability zone was not
# provided, the scheduler will receive a list with all
# availability zones that contains subnets within the
# selected share network.
azs_subnet = self._get_all_availability_zones_with_subnets(
context, share_network_id)
if not type_azs:
type_azs = azs_subnet
else:
type_azs = (
[az for az in type_azs if az in azs_subnet])
if not type_azs:
msg = _(
"The share network is not supported within any "
"requested availability zone. Check the share type's "
"'availability_zones' extra-spec and the availability "
"zones of the share network subnets")
raise exception.InvalidInput(message=msg)
if share['replication_type'] == constants.REPLICATION_TYPE_READABLE:
cast_rules_to_readonly = True
else:
cast_rules_to_readonly = False
request_spec, share_replica = (
self.create_share_instance_and_get_request_spec(
context, share, availability_zone=availability_zone,
@@ -641,7 +704,9 @@ class API(base.Base):
if share_server['status'] != constants.STATUS_ACTIVE:
msg = _("Share Server specified is not active.")
raise exception.InvalidShareServer(message=msg)
share_data['share_network_id'] = share_server['share_network_id']
subnet = self.db.share_network_subnet_get(
context, share_server['share_network_subnet_id'])
share_data['share_network_id'] = subnet['share_network_id']
share_data.update({
'user_id': context.user_id,
@@ -1019,7 +1084,7 @@ class API(base.Base):
self.share_rpcapi.delete_share_server(context, server)
def manage_share_server(
self, context, identifier, host, share_network, driver_opts):
self, context, identifier, host, share_net_subnet, driver_opts):
"""Manage a share server."""
try:
@@ -1037,7 +1102,7 @@ class API(base.Base):
values = {
'host': host,
'share_network_id': share_network['id'],
'share_network_subnet_id': share_net_subnet['id'],
'status': constants.STATUS_MANAGING,
'is_auto_deletable': False,
'identifier': identifier,
+3 -2
View File
@@ -843,14 +843,15 @@ class ShareDriver(object):
share_server)
def allocate_network(self, context, share_server, share_network,
count=None, **kwargs):
share_network_subnet, count=None, **kwargs):
"""Allocate network resources using given network information."""
if count is None:
count = self.get_network_allocations_number()
if count:
kwargs.update(count=count)
self.network_api.allocate_network(
context, share_server, share_network, **kwargs)
context, share_server, share_network=share_network,
share_network_subnet=share_network_subnet, **kwargs)
def allocate_admin_network(self, context, share_server, count=None,
**kwargs):
+73 -41
View File
@@ -23,6 +23,7 @@ import copy
import datetime
import functools
import hashlib
from operator import xor
from oslo_config import cfg
from oslo_log import log
@@ -45,7 +46,7 @@ from manila.message import message_field
from manila import quota
from manila.share import access
from manila.share import api
import manila.share.configuration
from manila.share import configuration
from manila.share import drivers_private_data
from manila.share import migration
from manila.share import rpcapi as share_rpcapi
@@ -213,7 +214,7 @@ class ShareManager(manager.SchedulerDependentManager):
def __init__(self, share_driver=None, service_name=None, *args, **kwargs):
"""Load the driver from args, or from flags."""
self.configuration = manila.share.configuration.Configuration(
self.configuration = configuration.Configuration(
share_manager_opts,
config_group=service_name)
super(ShareManager, self).__init__(service_name='share',
@@ -525,13 +526,11 @@ class ShareManager(manager.SchedulerDependentManager):
" should be provided. ")
raise ValueError(msg)
parent_share_server = None
def error(msg, *args):
LOG.error(msg, *args)
self.db.share_instance_update(context, share_instance['id'],
{'status': constants.STATUS_ERROR})
parent_share_server = None
if snapshot:
parent_share_server_id = (
snapshot['share']['instance']['share_server_id'])
@@ -553,9 +552,23 @@ class ShareManager(manager.SchedulerDependentManager):
raise exception.InvalidShareServer(
share_server_id=parent_share_server
)
if parent_share_server and not share_network_id:
share_network_id = parent_share_server['share_network_id']
share_network_subnet_id = None
if share_network_id:
share_network_subnet = (
self.db.share_network_subnet_get_by_availability_zone_id(
context, share_network_id,
availability_zone_id=share_instance.get(
'availability_zone_id')))
if not share_network_subnet:
raise exception.ShareNetworkSubnetNotFound(
share_network_subnet_id=None)
share_network_subnet_id = share_network_subnet['id']
elif parent_share_server:
share_network_subnet_id = (
parent_share_server['share_network_subnet_id'])
share_network_subnet = self.db.share_network_subnet_get(
context, share_network_subnet_id)
share_network_id = share_network_subnet['share_network_id']
def get_available_share_servers():
if parent_share_server:
@@ -566,7 +579,7 @@ class ShareManager(manager.SchedulerDependentManager):
context, self.host, share_network_id)
)
@utils.synchronized("share_manager_%s" % share_network_id,
@utils.synchronized("share_manager_%s" % share_network_subnet_id,
external=True)
def _wrapped_provide_share_server_for_share():
try:
@@ -595,7 +608,7 @@ class ShareManager(manager.SchedulerDependentManager):
context,
{
'host': self.host,
'share_network_id': share_network_id,
'share_network_subnet_id': share_network_subnet_id,
'status': constants.STATUS_CREATING,
}
)
@@ -689,7 +702,9 @@ class ShareManager(manager.SchedulerDependentManager):
return share_server['id']
def _provide_share_server_for_share_group(self, context, share_network_id,
def _provide_share_server_for_share_group(self, context,
share_network_id,
share_network_subnet_id,
share_group_ref,
share_group_snapshot=None):
"""Gets or creates share_server and updates share group with its id.
@@ -707,6 +722,10 @@ class ShareManager(manager.SchedulerDependentManager):
:param context: Current context
:param share_network_id: Share network where existing share server
should be found or created.
:param share_network_subnet_id: Share network subnet where
existing share server should be found
or created. If not specified, the
default subnet will be used.
:param share_group_ref: Share Group model
:param share_group_snapshot: Optional -- ShareGroupSnapshot model. If
supplied, driver will use it to choose
@@ -757,7 +776,7 @@ class ShareManager(manager.SchedulerDependentManager):
context,
{
'host': self.host,
'share_network_id': share_network_id,
'share_network_subnet_id': share_network_subnet_id,
'status': constants.STATUS_CREATING
}
)
@@ -1831,7 +1850,6 @@ class ShareManager(manager.SchedulerDependentManager):
request_spec=None, filter_properties=None):
"""Create a share replica."""
context = context.elevated()
share_replica = self.db.share_replica_get(
context, share_replica_id, with_share_data=True,
with_share_server=True)
@@ -1847,7 +1865,6 @@ class ShareManager(manager.SchedulerDependentManager):
self.db.share_replicas_get_available_active_replica(
context, share_replica['share_id'], with_share_data=True,
with_share_server=True))
if not _active_replica:
self.db.share_replica_update(
context, share_replica['id'],
@@ -1868,9 +1885,8 @@ class ShareManager(manager.SchedulerDependentManager):
# We need the share_network_id in case of
# driver_handles_share_server=True
share_network_id = share_replica.get('share_network_id', None)
if (share_network_id and
not self.driver.driver_handles_share_servers):
if xor(bool(share_network_id),
self.driver.driver_handles_share_servers):
self.db.share_replica_update(
context, share_replica['id'],
{'status': constants.STATUS_ERROR,
@@ -1883,8 +1899,8 @@ class ShareManager(manager.SchedulerDependentManager):
resource_id=share_replica['id'],
detail=message_field.Detail.UNEXPECTED_NETWORK)
raise exception.InvalidDriverMode(
"Driver does not expect share-network to be provided "
"with current configuration.")
"The share-network value provided does not match with the "
"current driver configuration.")
if share_network_id:
try:
@@ -2608,12 +2624,14 @@ class ShareManager(manager.SchedulerDependentManager):
msg = ("Since share %(share)s has been un-managed from share "
"server %(server)s. This share server must be removed "
"manually, either by un-managing or by deleting it. The "
"share network %(network)s cannot be deleted unless this "
"share server has been removed.")
"share network subnet %(subnet)s and share network "
"%(network) cannot be deleted unless this share server has "
"been removed.")
msg_args = {
'share': share_id,
'server': share_server['id'],
'network': share_server['share_network_id']
'subnet': share_server['share_network_subnet_id'],
'network': share_instance['share_network_id']
}
LOG.warning(msg, msg_args)
@@ -2698,10 +2716,11 @@ class ShareManager(manager.SchedulerDependentManager):
server = self.db.share_server_get(context, share_server_id)
share_network = self.db.share_network_get(
context, server['share_network_id'])
try:
share_network_subnet = self.db.share_network_subnet_get(
context, server['share_network_subnet_id'])
share_network = self.db.share_network_get(
context, share_network_subnet['share_network_id'])
number_allocations = (
self.driver.get_network_allocations_number())
@@ -2733,7 +2752,7 @@ class ShareManager(manager.SchedulerDependentManager):
self.driver.network_api.
manage_network_allocations(
context, remaining_allocations, server,
share_network))
share_network, share_network_subnet))
# We require that all allocations are managed, else we
# may have problems deleting this share server
@@ -3578,7 +3597,8 @@ class ShareManager(manager.SchedulerDependentManager):
self._report_driver_status(context)
self._publish_service_capabilities(context)
def _form_server_setup_info(self, context, share_server, share_network):
def _form_server_setup_info(self, context, share_server, share_network,
share_network_subnet):
# 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(
@@ -3592,30 +3612,34 @@ class ShareManager(manager.SchedulerDependentManager):
# They should be removed right after no one uses them.
network_info = {
'server_id': share_server['id'],
'segmentation_id': share_network['segmentation_id'],
'cidr': share_network['cidr'],
'neutron_net_id': share_network['neutron_net_id'],
'neutron_subnet_id': share_network['neutron_subnet_id'],
'segmentation_id': share_network_subnet['segmentation_id'],
'cidr': share_network_subnet['cidr'],
'neutron_net_id': share_network_subnet['neutron_net_id'],
'neutron_subnet_id': share_network_subnet['neutron_subnet_id'],
'security_services': share_network['security_services'],
'network_allocations': network_allocations,
'admin_network_allocations': admin_network_allocations,
'backend_details': share_server.get('backend_details'),
'network_type': share_network['network_type'],
'network_type': share_network_subnet['network_type'],
}
return network_info
def _setup_server(self, context, share_server, metadata=None):
try:
share_network_subnet = share_server['share_network_subnet']
share_network_subnet_id = share_network_subnet['id']
share_network_id = share_network_subnet['share_network_id']
share_network = self.db.share_network_get(
context, share_server['share_network_id'])
self.driver.allocate_network(context, share_server, share_network)
context, share_network_id)
self.driver.allocate_network(context, share_server, share_network,
share_network_subnet)
self.driver.allocate_admin_network(context, share_server)
# Get share_network again in case it was updated.
share_network = self.db.share_network_get(
context, share_server['share_network_id'])
# Get share_network_subnet in case it was updated.
share_network_subnet = self.db.share_network_subnet_get(
context, share_network_subnet_id)
network_info = self._form_server_setup_info(
context, share_server, share_network)
context, share_server, share_network, share_network_subnet)
self._validate_segmentation_id(network_info)
# NOTE(vponomaryov): Save security services data to share server
@@ -3735,7 +3759,7 @@ class ShareManager(manager.SchedulerDependentManager):
def delete_share_server(self, context, share_server):
@utils.synchronized(
"share_manager_%s" % share_server['share_network_id'])
"share_manager_%s" % share_server['share_network_subnet_id'])
def _wrapped_delete_share_server():
# NOTE(vponomaryov): Verify that there are no dependent shares.
# Without this verification we can get here exception in next case:
@@ -3944,7 +3968,8 @@ class ShareManager(manager.SchedulerDependentManager):
if parent_share_server_id and self.driver.driver_handles_share_servers:
share_server = self.db.share_server_get(context,
parent_share_server_id)
share_network_id = share_server['share_network_id']
share_network_subnet = share_server['share_network_subnet']
share_network_id = share_network_subnet['share_network_id']
if share_network_id and not self.driver.driver_handles_share_servers:
self.db.share_group_update(
@@ -3954,10 +3979,17 @@ class ShareManager(manager.SchedulerDependentManager):
raise exception.InvalidInput(reason=msg)
if not share_server and share_network_id:
availability_zone_id = self._get_az_for_share_group(
context, share_group_ref)
subnet = self.db.share_network_subnet_get_by_availability_zone_id(
context, share_network_id, availability_zone_id)
try:
share_server, share_group_ref = (
self._provide_share_server_for_share_group(
context, share_network_id, share_group_ref,
context, share_network_id, subnet.get('id'),
share_group_ref,
share_group_snapshot=snap_ref,
)
)
-14
View File
@@ -270,20 +270,6 @@ fixture_valid_reset_status_body = (
({'reset_status': {'status': 'migrating_to'}}, '2.7'),
)
share_network_id = '5dfe0898-e2a1-4740-9177-81c7d26713b0'
share_network = {
'name': 'share-net-fake',
'share_network_id': '5dfe0898-e2a1-4740-9177-81c7d26713b0',
'project_id': '5dfe0898-e2a1-4740-9177-81c7d26713b0'
}
SHARE_SERVER = {
'share_network': share_network,
'share_network_id': 'c5b3a865-56d0-4d88-abe5-879965e099c9',
'host': host,
'id': 'c39bb9ae-16a5-40f2-a24f-1cf3f549d3d3',
'status': constants.STATUS_ACTIVE
}
def mock_fake_admin_check(context, resource_name, action, *args, **kwargs):
if context.is_admin:
+2 -2
View File
@@ -150,14 +150,14 @@ class RequestTest(test.TestCase):
mock.Mock(return_value=max_version))
self.mock_object(api_version, 'min_api_version',
mock.Mock(return_value=min_version))
headers = {'X-OpenStack-Manila-API-Version': '2.50'}
headers = {'X-OpenStack-Manila-API-Version': '2.51'}
request = wsgi.Request.blank(
'https://openstack.acme.com/v2/shares', method='GET',
headers=headers, script_name='/v2/shares')
self.assertRaises(exception.InvalidGlobalAPIVersion,
request.set_api_version_request)
self.assertEqual(api_version.APIVersionRequest('2.50'),
self.assertEqual(api_version.APIVersionRequest('2.51'),
request.api_version_request)
@ddt.data('', '/share', '/v1', '/v2/shares', '/v1.1/', '/share/v1',
+15
View File
@@ -328,6 +328,21 @@ class MiscFunctionsTest(test.TestCase):
policy.check_policy.assert_called_once_with(
'fake_context', 'share', 'set_public_share', do_raise=False)
@ddt.data(({}, True),
({'neutron_net_id': 'fake_nn_id'}, False),
({'neutron_subnet_id': 'fake_sn_id'}, False),
({'neutron_net_id': 'fake_nn_id',
'neutron_subnet_id': 'fake_sn_id'}, True))
@ddt.unpack
def test__check_net_id_and_subnet_id(self, body, expected):
if not expected:
self.assertRaises(webob.exc.HTTPBadRequest,
common.check_net_id_and_subnet_id,
body)
else:
result = common.check_net_id_and_subnet_id(body)
self.assertIsNone(result)
@ddt.ddt
class ViewBuilderTest(test.TestCase):
+55 -4
View File
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
import mock
from six.moves.urllib import parse
import webob
@@ -25,6 +26,7 @@ from manila import test
from manila.tests.api import fakes
@ddt.ddt
class ShareApiTest(test.TestCase):
"""Share Api Test."""
def setUp(self):
@@ -81,6 +83,21 @@ class ShareApiTest(test.TestCase):
}, ]
}
self.fake_share_network_list_with_share_servers = [{
'id': 'fake_sn_id',
'share_network_subnets': [{
'id': 'fake_sns_id',
'share_servers': [{'id': 'fake_ss_id'}]
}]
}]
self.fake_share_network_list_without_share_servers = [{
'id': 'fake_sn_id',
'share_network_subnets': [{
'id': 'fake_sns_id',
'share_servers': []
}]
}]
def _stop_started_patcher(self, patcher):
if hasattr(patcher, 'is_local'):
patcher.stop()
@@ -163,10 +180,11 @@ class ShareApiTest(test.TestCase):
self.mock_object(security_service.policy, 'check_policy')
db.security_service_get = mock.Mock(return_value=new)
db.security_service_update = mock.Mock(return_value=updated)
fake_sns = {'id': 'fake_sns_id', 'share_servers': ['fake_ss']}
db.share_network_get_all_by_security_service = mock.Mock(
return_value=[{
'id': 'fake_id',
'share_servers': 'fake_share_server'
'share_network_subnets': [fake_sns]
}])
body = {"security_service": {"name": "new"}}
req = fakes.HTTPRequest.blank('/security_service/1')
@@ -187,10 +205,11 @@ class ShareApiTest(test.TestCase):
self.mock_object(security_service.policy, 'check_policy')
db.security_service_get = mock.Mock(return_value=new)
db.security_service_update = mock.Mock(return_value=updated)
fake_sns = {'id': 'fake_sns_id', 'share_servers': ['fake_ss']}
db.share_network_get_all_by_security_service = mock.Mock(
return_value=[{
'id': 'fake_id',
'share_servers': 'fake_share_server'
'share_network_subnets': [fake_sns]
}])
body = {"security_service": {"description": "new"}}
req = fakes.HTTPRequest.blank('/security_service/1')
@@ -209,8 +228,9 @@ class ShareApiTest(test.TestCase):
mock.Mock())
def test_security_service_update_invalid_keys_sh_server_exists(self):
self.mock_object(security_service.policy, 'check_policy')
fake_sns = {'id': 'fake_sns_id', 'share_servers': ['fake_ss']}
db.share_network_get_all_by_security_service.return_value = [
{'id': 'fake_id', 'share_servers': 'fake_share_servers'},
{'id': 'fake_id', 'share_network_subnets': [fake_sns]},
]
db.security_service_get.return_value = self.ss_active_directory.copy()
body = {'security_service': {'user_id': 'new_user'}}
@@ -234,8 +254,9 @@ class ShareApiTest(test.TestCase):
mock.Mock())
def test_security_service_update_valid_keys_sh_server_exists(self):
self.mock_object(security_service.policy, 'check_policy')
fake_sns = {'id': 'fake_sns_id', 'share_servers': ['fake_ss']}
db.share_network_get_all_by_security_service.return_value = [
{'id': 'fake_id', 'share_servers': 'fake_share_servers'},
{'id': 'fake_id', 'share_network_subnets': [fake_sns]},
]
old = self.ss_active_directory.copy()
updated = self.ss_active_directory.copy()
@@ -265,6 +286,36 @@ class ShareApiTest(test.TestCase):
security_service.RESOURCE_NAME, 'update', old)
])
@mock.patch.object(db, 'security_service_get', mock.Mock())
def test_security_service_update_has_share_servers(self):
db.security_service_get = mock.Mock()
self.mock_object(
self.controller, '_share_servers_dependent_on_sn_exist',
mock.Mock(return_value=True))
body = {"security_service": {"type": "ldap"}}
req = fakes.HTTPRequest.blank('/security_services/1')
self.assertRaises(webob.exc.HTTPForbidden,
self.controller.update,
req,
1,
body)
@ddt.data(True, False)
def test_security_service_update_share_server_dependent_exists(self,
expected):
req = fakes.HTTPRequest.blank('/security_services/1')
context = req.environ['manila.context']
db.security_service_get = mock.Mock()
network = (self.fake_share_network_list_with_share_servers if expected
else self.fake_share_network_list_without_share_servers)
db.share_network_get_all_by_security_service = mock.Mock(
return_value=network)
result = self.controller._share_servers_dependent_on_sn_exist(
context, 'fake_id')
self.assertEqual(expected, result)
def test_security_service_list(self):
db.security_service_get_all_by_project = mock.Mock(
return_value=[self.ss_active_directory.copy()])
+155 -24
View File
@@ -13,9 +13,11 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
import mock
from webob import exc
from manila.api.openstack import api_version_request as api_version
from manila.api.v1 import share_servers
from manila.common import constants
from manila import context
@@ -31,23 +33,43 @@ fake_share_server_list = {
'status': constants.STATUS_ACTIVE,
'updated_at': None,
'host': 'fake_host',
'share_network_id': 'fake_sn_id',
'share_network_name': 'fake_sn_name',
'share_network_id': 'fake_sn_id',
'share_network_subnet_id': 'fake_sns_id',
'project_id': 'fake_project_id',
'id': 'fake_server_id',
'is_auto_deletable': False,
'identifier': 'fake_id'
},
{
'status': constants.STATUS_ERROR,
'updated_at': None,
'host': 'fake_host_2',
'share_network_id': 'fake_sn_id_2',
'share_network_name': 'fake_sn_id_2',
'share_network_id': 'fake_sn_id_2',
'share_network_subnet_id': 'fake_sns_id_2',
'project_id': 'fake_project_id_2',
'id': 'fake_server_id_2',
'is_auto_deletable': True,
'identifier': 'fake_id_2'
},
]
}
fake_share_network_get_list = {
'share_networks': [
{
'name': 'fake_sn_name',
'id': 'fake_sn_id',
'project_id': 'fake_project_id',
},
{
'name': None,
'id': 'fake_sn_id_2',
'project_id': 'fake_project_id_2',
}
]
}
fake_share_server_get_result = {
'share_server': {
@@ -57,12 +79,15 @@ fake_share_server_get_result = {
'host': 'fake_host',
'share_network_name': 'fake_sn_name',
'share_network_id': 'fake_sn_id',
'share_network_subnet_id': 'fake_sns_id',
'project_id': 'fake_project_id',
'id': 'fake_server_id',
'backend_details': {
'fake_key_1': 'fake_value_1',
'fake_key_2': 'fake_value_2',
}
},
'is_auto_deletable': False,
'identifier': 'fake_id'
}
}
@@ -88,13 +113,14 @@ class FakeShareServer(object):
self.created_at = kwargs.get('created_at', None)
self.updated_at = kwargs.get('updated_at', None)
self.host = kwargs.get('host', 'fake_host')
self.share_network = kwargs.get('share_network', {
'name': 'fake_sn_name', 'id': 'fake_sn_id',
'project_id': 'fake_project_id'})
self.share_network_id = kwargs.get('share_network_id',
self.share_network['id'])
self.share_network_subnet = kwargs.get('share_network_subnet', {
'id': 'fake_sns_id', 'share_network_id': 'fake_sn_id'})
self.share_network_subnet_id = kwargs.get(
'share_network_subnet_id', self.share_network_subnet['id'])
self.status = kwargs.get('status', constants.STATUS_ACTIVE)
self.project_id = self.share_network['project_id']
self.project_id = 'fake_project_id'
self.identifier = kwargs.get('identifier', 'fake_id')
self.is_auto_deletable = kwargs.get('is_auto_deletable', False)
self.backend_details = share_server_backend_details
def __getitem__(self, item):
@@ -106,10 +132,12 @@ def fake_share_server_get_all():
FakeShareServer(),
FakeShareServer(id='fake_server_id_2',
host='fake_host_2',
share_network={
'name': None,
'id': 'fake_sn_id_2',
'project_id': 'fake_project_id_2'},
share_network_subnet={
'id': 'fake_sns_id_2',
'share_network_id': 'fake_sn_id_2',
},
identifier='fake_id_2',
is_auto_deletable=True,
status=constants.STATUS_ERROR)
]
return fake_share_servers
@@ -136,15 +164,10 @@ class FakeRequestWithProjectId(FakeRequestAdmin):
GET = {'project_id': fake_share_server_get_all()[0].project_id}
class FakeRequestWithShareNetworkName(FakeRequestAdmin):
class FakeRequestWithShareNetworkSubnetId(FakeRequestAdmin):
GET = {
'share_network': fake_share_server_get_all()[0].share_network['name'],
}
class FakeRequestWithShareNetworkId(FakeRequestAdmin):
GET = {
'share_network': fake_share_server_get_all()[0].share_network['id'],
'share_network_subnet_id':
fake_share_server_get_all()[0].share_network_subnet_id,
}
@@ -152,6 +175,7 @@ class FakeRequestWithFakeFilter(FakeRequestAdmin):
GET = {'fake_key': 'fake_value'}
@ddt.ddt
class ShareServerAPITest(test.TestCase):
def setUp(self):
@@ -163,15 +187,20 @@ class ShareServerAPITest(test.TestCase):
self.mock_object(db_api, 'share_server_get_all',
mock.Mock(return_value=fake_share_server_get_all()))
def _prepare_request(self, url, use_admin_context):
def _prepare_request(self, url, use_admin_context,
version=api_version._MAX_API_VERSION):
request = fakes.HTTPRequest.blank(url,
use_admin_context=use_admin_context)
use_admin_context=use_admin_context,
version=version)
ctxt = request.environ['manila.context']
return request, ctxt
def test_index_no_filters(self):
request, ctxt = self._prepare_request(url='/v2/share-servers/',
use_admin_context=True)
self.mock_object(db_api, 'share_network_get', mock.Mock(
side_effect=[fake_share_network_get_list['share_networks'][0],
fake_share_network_get_list['share_networks'][1]]))
result = self.controller.index(request)
policy.check_policy.assert_called_once_with(
ctxt, self.resource_name, 'index')
@@ -183,6 +212,9 @@ class ShareServerAPITest(test.TestCase):
url='/index?host=%s'
% fake_share_server_list['share_servers'][0]['host'],
use_admin_context=True)
self.mock_object(db_api, 'share_network_get', mock.Mock(
side_effect=[fake_share_network_get_list['share_networks'][0],
fake_share_network_get_list['share_networks'][1]]))
result = self.controller.index(request)
policy.check_policy.assert_called_once_with(
ctxt, self.resource_name, 'index')
@@ -194,6 +226,9 @@ class ShareServerAPITest(test.TestCase):
request, ctxt = self._prepare_request(url='/index?status=%s' %
constants.STATUS_ERROR,
use_admin_context=True)
self.mock_object(db_api, 'share_network_get', mock.Mock(
side_effect=[fake_share_network_get_list['share_networks'][0],
fake_share_network_get_list['share_networks'][1]]))
result = self.controller.index(request)
policy.check_policy.assert_called_once_with(
ctxt, self.resource_name, 'index')
@@ -206,10 +241,14 @@ class ShareServerAPITest(test.TestCase):
url='/index?project_id=%s'
% fake_share_server_get_all()[0].project_id,
use_admin_context=True)
self.mock_object(db_api, 'share_network_get', mock.Mock(
side_effect=[fake_share_network_get_list['share_networks'][0],
fake_share_network_get_list['share_networks'][1]]))
result = self.controller.index(request)
policy.check_policy.assert_called_once_with(
ctxt, self.resource_name, 'index')
db_api.share_server_get_all.assert_called_once_with(ctxt)
self.assertEqual([fake_share_server_list['share_servers'][0]],
result['share_servers'])
@@ -218,6 +257,9 @@ class ShareServerAPITest(test.TestCase):
url='/index?host=%s'
% fake_share_server_list['share_servers'][0]['host'],
use_admin_context=True)
self.mock_object(db_api, 'share_network_get', mock.Mock(
side_effect=[fake_share_network_get_list['share_networks'][0],
fake_share_network_get_list['share_networks'][1]]))
result = self.controller.index(request)
policy.check_policy.assert_called_once_with(
ctxt, self.resource_name, 'index')
@@ -228,8 +270,11 @@ class ShareServerAPITest(test.TestCase):
def test_index_share_network_filter_by_id(self):
request, ctxt = self._prepare_request(
url='/index?share_network=%s'
% fake_share_server_get_all()[0].share_network['id'],
% fake_share_network_get_list['share_networks'][0]['id'],
use_admin_context=True)
self.mock_object(db_api, 'share_network_get', mock.Mock(
side_effect=[fake_share_network_get_list['share_networks'][0],
fake_share_network_get_list['share_networks'][1]]))
result = self.controller.index(request)
policy.check_policy.assert_called_once_with(
ctxt, self.resource_name, 'index')
@@ -240,16 +285,57 @@ class ShareServerAPITest(test.TestCase):
def test_index_fake_filter(self):
request, ctxt = self._prepare_request(url='/index?fake_key=fake_value',
use_admin_context=True)
self.mock_object(db_api, 'share_network_get', mock.Mock(
side_effect=[fake_share_network_get_list['share_networks'][0],
fake_share_network_get_list['share_networks'][1]]))
result = self.controller.index(request)
policy.check_policy.assert_called_once_with(
ctxt, self.resource_name, 'index')
db_api.share_server_get_all.assert_called_once_with(ctxt)
self.assertEqual(0, len(result['share_servers']))
def test_index_share_network_not_found(self):
request, ctxt = self._prepare_request(
url='/index?identifier=%s'
% fake_share_server_get_all()[0].identifier,
use_admin_context=True)
self.mock_object(
db_api, 'share_network_get',
mock.Mock(side_effect=exception.ShareNetworkNotFound(
share_network_id='fake')))
result = self.controller.index(request)
db_api.share_server_get_all.assert_called_once_with(ctxt)
policy.check_policy.assert_called_once_with(
ctxt, self.resource_name, 'index')
exp_share_server = fake_share_server_list['share_servers'][0].copy()
exp_share_server['project_id'] = ''
exp_share_server['share_network_name'] = ''
self.assertEqual([exp_share_server],
result['share_servers'])
def test_index_share_network_not_found_filter_project(self):
request, ctxt = self._prepare_request(
url='/index?project_id=%s'
% fake_share_server_get_all()[0].project_id,
use_admin_context=True)
self.mock_object(
db_api, 'share_network_get',
mock.Mock(side_effect=exception.ShareNetworkNotFound(
share_network_id='fake')))
result = self.controller.index(request)
db_api.share_server_get_all.assert_called_once_with(ctxt)
policy.check_policy.assert_called_once_with(
ctxt, self.resource_name, 'index')
self.assertEqual(0, len(result['share_servers']))
def test_show(self):
self.mock_object(db_api, 'share_server_get',
mock.Mock(return_value=fake_share_server_get()))
request, ctxt = self._prepare_request('/show', use_admin_context=True)
self.mock_object(db_api, 'share_network_get', mock.Mock(
return_value=fake_share_network_get_list['share_networks'][0]))
result = self.controller.show(
request,
fake_share_server_get_result['share_server']['id'])
@@ -260,6 +346,36 @@ class ShareServerAPITest(test.TestCase):
self.assertEqual(fake_share_server_get_result['share_server'],
result['share_server'])
@ddt.data(
{'share_server_side_effect': exception.ShareServerNotFound(
share_server_id="foo"),
'share_net_side_effect': mock.Mock()},
{'share_server_side_effect': mock.Mock(
return_value=fake_share_server_get()),
'share_net_side_effect': exception.ShareNetworkNotFound(
share_network_id="foo")})
@ddt.unpack
def test_show_server_not_found(self, share_server_side_effect,
share_net_side_effect):
self.mock_object(db_api, 'share_server_get',
mock.Mock(side_effect=share_server_side_effect))
request, ctxt = self._prepare_request('/show', use_admin_context=True)
self.mock_object(db_api, 'share_network_get', mock.Mock(
side_effect=share_net_side_effect))
self.assertRaises(
exc.HTTPNotFound, self.controller.show, request,
fake_share_server_get_result['share_server']['id'])
policy.check_policy.assert_called_once_with(
ctxt, self.resource_name, 'show')
db_api.share_server_get.assert_called_once_with(
ctxt, fake_share_server_get_result['share_server']['id'])
if isinstance(share_net_side_effect, exception.ShareNetworkNotFound):
exp_share_net_id = (fake_share_server_get()
.share_network_subnet['share_network_id'])
db_api.share_network_get.assert_called_once_with(
ctxt, exp_share_net_id)
def test_details(self):
self.mock_object(db_api, 'share_server_get',
mock.Mock(return_value=fake_share_server_get()))
@@ -274,6 +390,21 @@ class ShareServerAPITest(test.TestCase):
self.assertEqual(fake_share_server_backend_details_get_result,
result)
def test_details_share_server_not_found(self):
share_server_id = 'fake'
self.mock_object(
db_api, 'share_server_get',
mock.Mock(side_effect=exception.ShareServerNotFound(
share_server_id=share_server_id)))
self.assertRaises(exc.HTTPNotFound,
self.controller.details,
FakeRequestAdmin,
share_server_id)
policy.check_policy.assert_called_once_with(
CONTEXT, self.resource_name, 'details')
db_api.share_server_get.assert_called_once_with(
CONTEXT, share_server_id)
def test_delete_active_server(self):
share_server = FakeShareServer(status=constants.STATUS_ACTIVE)
self.mock_object(db_api, 'share_server_get',
+35
View File
@@ -239,6 +239,9 @@ class ShareAPITest(test.TestCase):
self.mock_object(share_api.API, 'create', create_mock)
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
return_value={'id': 'fakenetid'}))
self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id',
mock.Mock(return_value={'id': 'fakesubnetid'}))
body = {"share": copy.deepcopy(shr)}
req = fakes.HTTPRequest.blank('/shares')
@@ -249,6 +252,7 @@ class ShareAPITest(test.TestCase):
expected = self._get_expected_share_detailed_response(shr)
expected['share'].pop('snapshot_support')
self.assertEqual(expected, res_dict)
# pylint: disable=unsubscriptable-object
self.assertEqual("fakenetid",
create_mock.call_args[1]['share_network_id'])
@@ -312,6 +316,8 @@ class ShareAPITest(test.TestCase):
return_value=parent_share))
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
return_value={'id': parent_share_net}))
self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id')
body = {"share": copy.deepcopy(shr)}
req = fakes.HTTPRequest.blank('/shares')
@@ -323,6 +329,7 @@ class ShareAPITest(test.TestCase):
expected = self._get_expected_share_detailed_response(shr)
expected['share'].pop('snapshot_support')
self.assertEqual(expected, res_dict)
# pylint: disable=unsubscriptable-object
self.assertEqual(parent_share_net,
create_mock.call_args[1]['share_network_id'])
@@ -356,6 +363,8 @@ class ShareAPITest(test.TestCase):
return_value=parent_share))
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
return_value={'id': parent_share_net}))
self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id')
body = {"share": copy.deepcopy(shr)}
req = fakes.HTTPRequest.blank('/shares')
@@ -367,6 +376,7 @@ class ShareAPITest(test.TestCase):
expected = self._get_expected_share_detailed_response(shr)
expected['share'].pop('snapshot_support')
self.assertEqual(expected, res_dict)
# pylint: disable=unsubscriptable-object
self.assertEqual(parent_share_net,
create_mock.call_args[1]['share_network_id'])
@@ -425,6 +435,8 @@ class ShareAPITest(test.TestCase):
return_value=parent_share))
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
return_value={'id': parent_share_net}))
self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id')
body = {"share": copy.deepcopy(shr)}
req = fakes.HTTPRequest.blank('/shares', version=microversion)
@@ -436,6 +448,7 @@ class ShareAPITest(test.TestCase):
expected = self._get_expected_share_detailed_response(shr)
expected['share'].pop('snapshot_support')
self.assertDictEqual(expected, res_dict)
# pylint: disable=unsubscriptable-object
self.assertEqual(parent_share_net,
create_mock.call_args[1]['share_network_id'])
@@ -478,6 +491,28 @@ class ShareAPITest(test.TestCase):
req,
body)
@ddt.data((exception.ShareNetworkNotFound(share_network_id='fake'),
webob.exc.HTTPNotFound),
(mock.Mock(), webob.exc.HTTPBadRequest))
@ddt.unpack
def test_share_create_invalid_subnet(self, share_network_side_effect,
exception_to_raise):
fake_share_with_sn = copy.deepcopy(self.share)
fake_share_with_sn['share_network_id'] = 'fakenetid'
self.mock_object(db, 'share_network_get',
mock.Mock(side_effect=share_network_side_effect))
self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id',
mock.Mock(return_value=None))
body = {"share": fake_share_with_sn}
req = fakes.HTTPRequest.blank('/shares')
self.assertRaises(exception_to_raise,
self.controller.create,
req,
body)
def test_share_show(self):
req = fakes.HTTPRequest.blank('/shares/1')
expected = self._get_expected_share_detailed_response()
@@ -0,0 +1,481 @@
# Copyright 2019 NetApp, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
import ddt
import mock
from oslo_db import exception as db_exception
from manila.api import common
from manila.api.v2 import share_network_subnets
from manila.db import api as db_api
from manila import exception
from manila import policy
from manila import test
from manila.tests.api import fakes
from manila.tests import db_utils
from webob import exc
fake_az = {
'id': 'ae525e12-07e8-4ddc-a2fd-4a89ad4a65ff',
'name': 'fake_az_name'
}
fake_default_subnet = {
'neutron_net_id': 'fake_nn_id',
'neutron_subnet_id': 'fake_nsn_id',
'availability_zone_id': None
}
fake_subnet_with_az = {
'neutron_net_id': 'fake_nn_id',
'neutron_subnet_id': 'fake_nsn_id',
'availability_zone_id': 'fake_az_id'
}
@ddt.ddt
class ShareNetworkSubnetControllerTest(test.TestCase):
"""Share network subnet api test"""
def setUp(self):
super(ShareNetworkSubnetControllerTest, self).setUp()
self.controller = share_network_subnets.ShareNetworkSubnetController()
self.mock_policy_check = self.mock_object(
policy, 'check_policy', mock.Mock(return_value=True))
self.resource_name = self.controller.resource_name
self.mock_az_get = self.mock_object(db_api, 'availability_zone_get',
mock.Mock(return_value=fake_az))
self.share_network = db_utils.create_share_network(
name='fake_network', id='fake_sn_id')
self.share_server = db_utils.create_share_server(
share_network_subnet_id='fake_sns_id')
self.subnet = db_utils.create_share_network_subnet(
share_network_id=self.share_network['id'])
self.share = db_utils.create_share()
def test_share_network_subnet_delete(self):
req = fakes.HTTPRequest.blank('/subnets/%s' % self.subnet['id'],
version="2.51")
context = req.environ['manila.context']
mock_sns_get = self.mock_object(
db_api, 'share_network_subnet_get',
mock.Mock(return_value=self.subnet))
mock_all_get_all_shares_by_ss = self.mock_object(
db_api, 'share_instances_get_all_by_share_server',
mock.Mock(return_value=[]))
mock_all_ss_are_auto_deletable = self.mock_object(
self.controller, '_all_share_servers_are_auto_deletable',
mock.Mock(return_value=True))
mock_delete_share_server = self.mock_object(
self.controller.share_rpcapi, 'delete_share_server')
mock_subnet_delete = self.mock_object(db_api,
'share_network_subnet_delete')
result = self.controller.delete(req, self.share_network['id'],
self.subnet['id'])
self.assertEqual(202, result.status_int)
mock_sns_get.assert_called_once_with(
context, self.subnet['id'])
mock_all_get_all_shares_by_ss.assert_called_once_with(
context, self.subnet['share_servers'][0].id
)
mock_all_ss_are_auto_deletable.assert_called_once_with(
self.subnet)
mock_delete_share_server.assert_called_once_with(
context, self.subnet['share_servers'][0])
mock_subnet_delete.assert_called_once_with(
context, self.subnet['id'])
policy.check_policy.assert_called_once_with(
context, self.resource_name, 'delete')
def test_share_network_subnet_delete_network_not_found(self):
req = fakes.HTTPRequest.blank('/subnets/%s' % self.subnet['id'],
version="2.51")
context = req.environ['manila.context']
mock_sn_get = self.mock_object(
db_api, 'share_network_get',
mock.Mock(side_effect=exception.ShareNetworkNotFound(
share_network_id=self.share_network['id']
)))
self.assertRaises(exc.HTTPNotFound,
self.controller.delete,
req,
self.share_network['id'],
self.subnet['id'])
mock_sn_get.assert_called_once_with(
context, self.share_network['id'])
self.mock_policy_check.assert_called_once_with(
context, self.resource_name, 'delete')
def test_share_network_subnet_delete_subnet_not_found(self):
req = fakes.HTTPRequest.blank('/subnets/%s' % self.subnet['id'],
version="2.51")
context = req.environ['manila.context']
mock_sns_get = self.mock_object(
db_api, 'share_network_subnet_get',
mock.Mock(side_effect=exception.ShareNetworkSubnetNotFound(
share_network_subnet_id=self.subnet['id']
)))
self.assertRaises(exc.HTTPNotFound,
self.controller.delete,
req,
self.share_network['id'],
self.subnet['id'])
mock_sns_get.assert_called_once_with(
context, self.subnet['id'])
self.mock_policy_check.assert_called_once_with(
context, self.resource_name, 'delete')
def test_delete_subnet_with_share_servers_fail(self):
req = fakes.HTTPRequest.blank('/subnets/%s' % self.subnet['id'],
version="2.51")
context = req.environ['manila.context']
mock_sns_get = self.mock_object(
db_api, 'share_network_subnet_get',
mock.Mock(return_value=self.subnet))
mock_all_get_all_shares_by_ss = self.mock_object(
db_api, 'share_instances_get_all_by_share_server',
mock.Mock(return_value=[]))
mock_all_ss_are_auto_deletable = self.mock_object(
self.controller, '_all_share_servers_are_auto_deletable',
mock.Mock(return_value=False))
self.assertRaises(exc.HTTPConflict,
self.controller.delete,
req,
self.share_network['id'],
self.subnet['id'])
mock_sns_get.assert_called_once_with(
context, self.subnet['id'])
mock_all_get_all_shares_by_ss.assert_called_once_with(
context, self.subnet['share_servers'][0].id
)
mock_all_ss_are_auto_deletable.assert_called_once_with(
self.subnet
)
self.mock_policy_check.assert_called_once_with(
context, self.resource_name, 'delete')
def test_delete_subnet_with_shares_fail(self):
req = fakes.HTTPRequest.blank('/subnets/%s' % self.subnet['id'],
version="2.51")
context = req.environ['manila.context']
mock_sns_get = self.mock_object(
db_api, 'share_network_subnet_get',
mock.Mock(return_value=self.subnet))
mock_all_get_all_shares_by_ss = self.mock_object(
db_api, 'share_instances_get_all_by_share_server',
mock.Mock(return_value=[self.share]))
self.assertRaises(exc.HTTPConflict,
self.controller.delete,
req,
self.share_network['id'],
self.subnet['id'])
mock_sns_get.assert_called_once_with(
context, self.subnet['id'])
mock_all_get_all_shares_by_ss.assert_called_once_with(
context, self.subnet['share_servers'][0].id
)
self.mock_policy_check.assert_called_once_with(
context, self.resource_name, 'delete')
@ddt.data((None, fake_default_subnet, None),
(fake_az, None, fake_subnet_with_az))
@ddt.unpack
def test__validate_subnet(self, az, default_subnet, subnet_az):
req = fakes.HTTPRequest.blank('/subnets', version='2.51')
context = req.environ['manila.context']
mock_get_default_sns = self.mock_object(
db_api, 'share_network_subnet_get_default_subnet',
mock.Mock(return_value=default_subnet))
mock_get_subnet_by_az = self.mock_object(
db_api, 'share_network_subnet_get_by_availability_zone_id',
mock.Mock(return_value=subnet_az))
self.assertRaises(exc.HTTPConflict,
self.controller._validate_subnet,
context,
self.share_network['id'],
az)
if az:
mock_get_subnet_by_az.assert_called_once_with(
context, self.share_network['id'], az['id'])
mock_get_default_sns.assert_not_called()
else:
mock_get_default_sns.assert_called_once_with(
context, self.share_network['id'])
mock_get_subnet_by_az.assert_not_called()
def _setup_create_test_request_body(self):
body = {
'share_network_id': self.share_network['id'],
'availability_zone': fake_az['name'],
'neutron_net_id': 'fake_nn_id',
'neutron_subnet_id': 'fake_nsn_id'
}
return body
def test_subnet_create(self):
req = fakes.HTTPRequest.blank('/subnets', version="2.51")
context = req.environ['manila.context']
body = {
'share-network-subnet': self._setup_create_test_request_body()
}
sn_id = body['share-network-subnet']['share_network_id']
expected_result = copy.deepcopy(body)
expected_result['share-network-subnet']['id'] = self.subnet['id']
mock_check_net_and_subnet_id = self.mock_object(
common, 'check_net_id_and_subnet_id')
mock_validate_subnet = self.mock_object(
self.controller, '_validate_subnet')
mock_subnet_create = self.mock_object(
db_api, 'share_network_subnet_create',
mock.Mock(return_value=self.subnet))
self.controller.create(
req, body['share-network-subnet']['share_network_id'], body)
mock_check_net_and_subnet_id.assert_called_once_with(
body['share-network-subnet'])
mock_validate_subnet.assert_called_once_with(
context, sn_id, az=fake_az)
mock_subnet_create.assert_called_once_with(
context, body['share-network-subnet'])
def test_subnet_create_share_network_not_found(self):
fake_sn_id = 'fake_id'
req = fakes.HTTPRequest.blank('/subnets', version="2.51")
context = req.environ['manila.context']
body = {
'share-network-subnet': self._setup_create_test_request_body()
}
mock_sn_get = self.mock_object(
db_api, 'share_network_get',
mock.Mock(side_effect=exception.ShareNetworkNotFound(
share_network_id=fake_sn_id)))
self.assertRaises(exc.HTTPNotFound,
self.controller.create,
req,
fake_sn_id,
body)
mock_sn_get.assert_called_once_with(context, fake_sn_id)
def test_subnet_create_az_not_found(self):
fake_sn_id = 'fake_id'
req = fakes.HTTPRequest.blank('/subnets', version="2.51")
context = req.environ['manila.context']
body = {
'share-network-subnet': self._setup_create_test_request_body()
}
mock_sn_get = self.mock_object(db_api, 'share_network_get')
mock_az_get = self.mock_object(
db_api, 'availability_zone_get',
mock.Mock(side_effect=exception.AvailabilityZoneNotFound(id='')))
expected_az = body['share-network-subnet']['availability_zone']
self.assertRaises(exc.HTTPBadRequest,
self.controller.create,
req,
fake_sn_id,
body)
mock_sn_get.assert_called_once_with(context, fake_sn_id)
mock_az_get.assert_called_once_with(
context, expected_az)
def test_subnet_create_subnet_default_or_same_az_exists(self):
fake_sn_id = 'fake_id'
req = fakes.HTTPRequest.blank('/subnets', version="2.51")
context = req.environ['manila.context']
body = {
'share-network-subnet': self._setup_create_test_request_body()
}
mock_sn_get = self.mock_object(db_api, 'share_network_get')
mock__validate_subnet = self.mock_object(
self.controller, '_validate_subnet',
mock.Mock(side_effect=exc.HTTPConflict(''))
)
expected_az = body['share-network-subnet']['availability_zone']
self.assertRaises(exc.HTTPConflict,
self.controller.create,
req,
fake_sn_id,
body)
mock_sn_get.assert_called_once_with(context, fake_sn_id)
self.mock_az_get.assert_called_once_with(context, expected_az)
mock__validate_subnet.assert_called_once_with(
context, fake_sn_id, az=fake_az)
def test_subnet_create_subnet_db_error(self):
fake_sn_id = 'fake_sn_id'
req = fakes.HTTPRequest.blank('/subnets', version="2.51")
context = req.environ['manila.context']
body = {
'share-network-subnet': self._setup_create_test_request_body()
}
mock_sn_get = self.mock_object(db_api, 'share_network_get')
mock__validate_subnet = self.mock_object(
self.controller, '_validate_subnet')
mock_db_subnet_create = self.mock_object(
db_api, 'share_network_subnet_create',
mock.Mock(side_effect=db_exception.DBError()))
expected_data = copy.deepcopy(body['share-network-subnet'])
expected_data['availability_zone_id'] = fake_az['id']
expected_data.pop('availability_zone')
self.assertRaises(exc.HTTPInternalServerError,
self.controller.create,
req,
fake_sn_id,
body)
mock_sn_get.assert_called_once_with(context, fake_sn_id)
self.mock_az_get.assert_called_once_with(context, fake_az['name'])
mock__validate_subnet.assert_called_once_with(
context, fake_sn_id, az=fake_az)
mock_db_subnet_create.assert_called_once_with(
context, expected_data
)
def test_show_subnet(self):
subnet = db_utils.create_share_network_subnet(
id='fake_sns_2', share_network_id=self.share_network['id'])
expected_result = {
'share_network_subnet': {
"created_at": subnet['created_at'],
"id": subnet['id'],
"share_network_id": subnet['share_network_id'],
"share_network_name": self.share_network['name'],
"availability_zone": subnet['availability_zone'],
"segmentation_id": subnet['segmentation_id'],
"neutron_subnet_id": subnet['neutron_subnet_id'],
"updated_at": subnet['updated_at'],
"neutron_net_id": subnet['neutron_net_id'],
"ip_version": subnet['ip_version'],
"cidr": subnet['cidr'],
"network_type": subnet['network_type'],
"gateway": subnet['gateway'],
"mtu": subnet['mtu'],
}
}
req = fakes.HTTPRequest.blank('/subnets/%s' % subnet['id'],
version="2.51")
context = req.environ['manila.context']
mock_sn_get = self.mock_object(
db_api, 'share_network_get', mock.Mock(
return_value=self.share_network))
mock_sns_get = self.mock_object(
db_api, 'share_network_subnet_get', mock.Mock(
return_value=subnet))
result = self.controller.show(req, self.share_network['id'],
subnet['id'])
self.assertEqual(expected_result, result)
mock_sn_get.assert_called_once_with(context, self.share_network['id'])
mock_sns_get.assert_called_once_with(context, subnet['id'])
@ddt.data(
(mock.Mock(side_effect=exception.ShareNetworkNotFound(
share_network_id='fake_net_id')), None),
(mock.Mock(), mock.Mock(
side_effect=exception.ShareNetworkSubnetNotFound(
share_network_subnet_id='fake_subnet_id'))))
@ddt.unpack
def test_show_subnet_not_found(self, sn_get_side_effect,
sns_get_side_effect):
req = fakes.HTTPRequest.blank('/subnets/%s' % self.subnet['id'],
version="2.51")
context = req.environ['manila.context']
mock_sn_get = self.mock_object(
db_api, 'share_network_get', sn_get_side_effect)
mock_sns_get = self.mock_object(
db_api, 'share_network_subnet_get', sns_get_side_effect)
self.assertRaises(exc.HTTPNotFound,
self.controller.show,
req,
self.share_network['id'],
self.subnet['id'])
mock_sn_get.assert_called_once_with(context, self.share_network['id'])
if sns_get_side_effect:
mock_sns_get.assert_called_once_with(context, self.subnet['id'])
def test_list_subnet(self):
share_network_id = 'fake_id'
subnet = db_utils.create_share_network_subnet(
share_network_id=share_network_id, id='fake_id')
fake_sn = db_utils.create_share_network(id=share_network_id)
expected_result = {
'share_network_subnets': [{
"created_at": subnet['created_at'],
"id": subnet['id'],
"share_network_id": subnet['id'],
"share_network_name": fake_sn["name"],
"availability_zone": subnet['availability_zone'],
"segmentation_id": subnet['segmentation_id'],
"neutron_subnet_id": subnet['neutron_subnet_id'],
"updated_at": subnet['updated_at'],
"neutron_net_id": subnet['neutron_net_id'],
"ip_version": subnet['ip_version'],
"cidr": subnet['cidr'],
"network_type": subnet['network_type'],
"gateway": subnet['gateway'],
"mtu": subnet['mtu'],
}]
}
req = fakes.HTTPRequest.blank('/subnets/', version="2.51")
context = req.environ['manila.context']
mock_sn_get = self.mock_object(
db_api, 'share_network_get', mock.Mock(
return_value=fake_sn))
result = self.controller.index(req, self.share_network['id'])
self.assertEqual(expected_result, result)
mock_sn_get.assert_called_once_with(context, self.share_network['id'])
def test_list_subnet_share_network_not_found(self):
req = fakes.HTTPRequest.blank('/subnets/', version="2.51")
context = req.environ['manila.context']
mock_sn_get = self.mock_object(
db_api, 'share_network_get', mock.Mock(
side_effect=exception.ShareNetworkNotFound(
share_network_id=self.share_network['id'])))
self.assertRaises(exc.HTTPNotFound,
self.controller.index,
req,
self.share_network['id'])
mock_sn_get.assert_called_once_with(context, self.share_network['id'])
+246 -47
View File
@@ -13,7 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import ddt
from manila.api import common
import mock
from oslo_db import exception as db_exception
from oslo_utils import timeutils
@@ -29,23 +31,32 @@ from manila import test
from manila.tests.api import fakes
fake_share_network = {
'id': 'fake network id',
'project_id': 'fake project',
'created_at': timeutils.parse_strtime('2002-02-02', fmt="%Y-%m-%d"),
'updated_at': None,
fake_share_network_subnet = {
'id': 'fake subnet id',
'neutron_net_id': 'fake net id',
'neutron_subnet_id': 'fake subnet id',
'network_type': 'vlan',
'segmentation_id': 1000,
'cidr': '10.0.0.0/24',
'ip_version': 4,
'share_network_id': 'fake network id',
'availability_zone_id': None,
'share_servers': [],
'availability_zone': []
}
fake_share_network = {
'id': 'fake network id',
'project_id': 'fake project',
'created_at': timeutils.parse_strtime('2002-02-02', fmt="%Y-%m-%d"),
'updated_at': None,
'name': 'fake name',
'description': 'fake description',
'share_servers': [],
'security_services': []
'security_services': [],
'share_network_subnets': []
}
fake_share_network_shortened = {
'id': 'fake network id',
'name': 'fake name',
@@ -56,15 +67,9 @@ fake_share_network_with_ss = {
'project_id': 'fake',
'created_at': timeutils.parse_strtime('2001-01-01', fmt="%Y-%m-%d"),
'updated_at': None,
'neutron_net_id': '1111',
'neutron_subnet_id': '2222',
'network_type': 'local',
'segmentation_id': 2000,
'cidr': '8.0.0.0/12',
'ip_version': 6,
'name': 'test-sn',
'description': 'fake description',
'share_servers': [],
'share_network_subnets': [],
'security_services': [{'id': 'fake-ss-id'}]
}
@@ -95,42 +100,63 @@ class ShareNetworkAPITest(test.TestCase):
self.assertEqual(share_nw['project_id'], view['project_id'])
self.assertEqual(share_nw['created_at'], view['created_at'])
self.assertEqual(share_nw['updated_at'], view['updated_at'])
self.assertEqual(share_nw['neutron_net_id'],
view['neutron_net_id'])
self.assertEqual(share_nw['neutron_subnet_id'],
view['neutron_subnet_id'])
self.assertEqual(share_nw['network_type'], view['network_type'])
self.assertEqual(share_nw['segmentation_id'],
view['segmentation_id'])
self.assertEqual(share_nw['cidr'], view['cidr'])
self.assertEqual(share_nw['ip_version'], view['ip_version'])
self.assertEqual(share_nw['name'], view['name'])
self.assertEqual(share_nw['description'], view['description'])
self.assertEqual(share_nw['created_at'], view['created_at'])
self.assertEqual(share_nw['updated_at'], view['updated_at'])
self.assertNotIn('shares', view)
self.assertNotIn('network_allocations', view)
self.assertNotIn('security_services', view)
@ddt.data(
{'neutron_net_id': 'fake_neutron_net_id'},
{'neutron_subnet_id': 'fake_neutron_subnet_id'},
{'neutron_net_id': 'fake', 'neutron_subnet_id': 'fake'})
def test_create_valid_cases(self, data):
def _setup_body_for_create_test(self, data):
data.update({'user_id': 'fake_user_id'})
body = {share_networks.RESOURCE_NAME: data}
return body
@ddt.data(
{'neutron_net_id': 'fake', 'neutron_subnet_id': 'fake'})
def test_create_valid_cases(self, data):
body = self._setup_body_for_create_test(data)
result = self.controller.create(self.req, body)
data.pop('user_id', None)
for k, v in data.items():
self.assertIn(data[k], result['share_network'][k])
@ddt.data(
{'neutron_net_id': 'fake', 'neutron_subnet_id': 'fake',
'availability_zone': 'fake'})
def test_create_valid_cases_upper_2_50(self, data):
req = fakes.HTTPRequest.blank('/share-networks', version="2.51")
context = req.environ['manila.context']
body = self._setup_body_for_create_test(data)
fake_az = {
'name': 'fake',
'id': 'fake_id'
}
self.mock_object(db_api, 'availability_zone_get',
mock.Mock(return_value=fake_az))
result = self.controller.create(req, body)
result_subnet = result['share_network']['share_network_subnets'][0]
data.pop('user_id', None)
data.pop('project_id', None)
data.pop('availability_zone_id', None)
data.pop('id', None)
data['availability_zone'] = result_subnet['availability_zone']
for k, v in data.items():
self.assertIn(k, result_subnet.keys())
db_api.availability_zone_get.assert_called_once_with(
context, fake_az['name']
)
@ddt.data(
{'nova_net_id': 'foo', 'neutron_net_id': 'bar'},
{'nova_net_id': 'foo', 'neutron_subnet_id': 'quuz'},
{'nova_net_id': 'foo', 'neutron_net_id': 'bar',
'neutron_subnet_id': 'quuz'},
{'nova_net_id': 'fake_nova_net_id'})
{'nova_net_id': 'fake_nova_net_id'},
{'neutron_net_id': 'bar'},
{'neutron_subnet_id': 'quuz'})
def test_create_invalid_cases(self, data):
data.update({'user_id': 'fake_user_id'})
body = {share_networks.RESOURCE_NAME: data}
@@ -138,9 +164,9 @@ class ShareNetworkAPITest(test.TestCase):
webob_exc.HTTPBadRequest, self.controller.create, self.req, body)
@ddt.data(
{'neutron_net_id': 'fake_neutron_net_id'},
{'neutron_subnet_id': 'fake_neutron_subnet_id'},
{'neutron_net_id': 'fake', 'neutron_subnet_id': 'fake'})
{'name': 'new fake name'},
{'description': 'new fake description'},
{'name': 'new fake name', 'description': 'new fake description'})
def test_update_valid_cases(self, data):
body = {share_networks.RESOURCE_NAME: {'user_id': 'fake_user'}}
created = self.controller.create(self.req, body)
@@ -172,7 +198,29 @@ class ShareNetworkAPITest(test.TestCase):
self.controller.update,
self.req, created['share_network']['id'], body)
@ddt.data(
({'share_network_subnets': [
{'share_network_id': fake_share_network['id']}]}, True),
({'share_network_subnets': []}, False))
@ddt.unpack
def test__subnet_has_search_opt(self, network, has_search_opt):
search_opts = {
'share_network_id': fake_share_network['id']
}
result = None
for key, value in search_opts.items():
result = self.controller._subnet_has_search_opt(
key, value, network)
self.assertEqual(has_search_opt, result)
def test_create_nominal(self):
self.mock_object(db_api, 'share_network_subnet_create')
self.mock_object(db_api, 'share_network_get',
mock.Mock(return_value=fake_share_network))
self.mock_object(common, 'check_net_id_and_subnet_id')
with mock.patch.object(db_api,
'share_network_create',
mock.Mock(return_value=fake_share_network)):
@@ -191,7 +239,7 @@ class ShareNetworkAPITest(test.TestCase):
with mock.patch.object(db_api,
'share_network_create',
mock.Mock(side_effect=db_exception.DBError)):
self.assertRaises(webob_exc.HTTPBadRequest,
self.assertRaises(webob_exc.HTTPInternalServerError,
self.controller.create,
self.req,
self.body)
@@ -203,9 +251,55 @@ class ShareNetworkAPITest(test.TestCase):
self.req,
body)
@ddt.data(
{'availability_zone': 'fake-zone'})
def test_create_az_not_found(self, data):
req = fakes.HTTPRequest.blank('/share-networks', version="2.51")
self.mock_object(
db_api, 'availability_zone_get',
mock.Mock(
side_effect=exception.AvailabilityZoneNotFound(id='fake')))
body = {share_networks.RESOURCE_NAME: data}
self.assertRaises(webob_exc.HTTPBadRequest,
self.controller.create,
req,
body)
def test_create_error_on_subnet_creation(self):
data = {
'neutron_net_id': 'fake',
'neutron_subnet_id': 'fake',
'id': fake_share_network['id']
}
subnet_data = copy.deepcopy(data)
self.mock_object(db_api, 'share_network_create',
mock.Mock(return_value=fake_share_network))
self.mock_object(db_api, 'share_network_subnet_create',
mock.Mock(side_effect=db_exception.DBError()))
self.mock_object(db_api, 'share_network_delete')
body = {share_networks.RESOURCE_NAME: data}
self.assertRaises(webob_exc.HTTPInternalServerError,
self.controller.create,
self.req,
body)
db_api.share_network_create.assert_called_once_with(self.context, data)
subnet_data['share_network_id'] = data['id']
subnet_data.pop('id')
db_api.share_network_subnet_create.assert_called_once_with(
self.context, subnet_data)
db_api.share_network_delete.assert_called_once_with(
self.context, fake_share_network['id'])
def test_delete_nominal(self):
share_nw = fake_share_network.copy()
share_nw['share_servers'] = ['foo', 'bar']
subnet = fake_share_network_subnet.copy()
subnet['share_servers'] = ['foo', 'bar']
share_nw['share_network_subnets'] = [subnet]
self.mock_object(db_api, 'share_network_get',
mock.Mock(return_value=share_nw))
self.mock_object(db_api, 'share_instances_get_all_by_share_network',
@@ -242,7 +336,9 @@ class ShareNetworkAPITest(test.TestCase):
def test_quota_delete_reservation_failed(self):
share_nw = fake_share_network.copy()
share_nw['share_servers'] = ['foo', 'bar']
subnet = fake_share_network_subnet.copy()
subnet['share_servers'] = ['foo', 'bar']
share_nw['share_network_subnets'] = [subnet]
share_nw['user_id'] = 'fake_user_id'
self.mock_object(db_api, 'share_network_get',
@@ -330,6 +426,53 @@ class ShareNetworkAPITest(test.TestCase):
db_api.share_network_get.assert_called_once_with(
self.req.environ['manila.context'], share_nw['id'])
def test_delete_contains_more_than_one_subnet(self):
share_nw = fake_share_network.copy()
self.mock_object(db_api, 'share_network_get',
mock.Mock(return_value=share_nw))
self.mock_object(db_api, 'share_instances_get_all_by_share_network',
mock.Mock(return_value=None))
self.mock_object(db_api, 'count_share_groups_in_share_network',
mock.Mock(return_value=None))
self.mock_object(self.controller, '_share_network_contains_subnets',
mock.Mock(return_value=True))
self.assertRaises(webob_exc.HTTPConflict,
self.controller.delete,
self.req,
share_nw['id'])
db_api.share_network_get.assert_called_once_with(
self.context, share_nw['id'])
(db_api.share_instances_get_all_by_share_network
.assert_called_once_with(self.context, share_nw['id']))
db_api.count_share_groups_in_share_network.assert_called_once_with(
self.context, share_nw['id']
)
(self.controller._share_network_contains_subnets
.assert_called_once_with(share_nw))
def test_delete_subnet_contains_share_server(self):
share_nw = fake_share_network.copy()
share_nw['share_network_subnets'].append({
'id': 'fake_sns_id',
'share_servers': [{'id': 'fake_share_server_id'}]
})
self.mock_object(db_api, 'share_network_get',
mock.Mock(return_value=share_nw))
self.mock_object(db_api, 'count_share_groups_in_share_network',
mock.Mock(return_value=0))
self.mock_object(self.controller, '_share_network_contains_subnets',
mock.Mock(return_value=False))
self.mock_object(
self.controller, '_all_share_servers_are_auto_deletable',
mock.Mock(return_value=False))
self.assertRaises(webob_exc.HTTPConflict,
self.controller.delete,
self.req,
share_nw['id'])
@ddt.data(
({'share_servers': [{'is_auto_deletable': True},
{'is_auto_deletable': True}]}, True),
@@ -344,6 +487,18 @@ class ShareNetworkAPITest(test.TestCase):
self.controller._all_share_servers_are_auto_deletable(
fake_share_network))
@ddt.data(
({'share_network_subnets': [{'share_servers': [{}, {}]}]}, True),
({'share_network_subnets': [{'share_servers': []}]}, False),
)
@ddt.unpack
def test__share_network_subnets_contain_share_servers(self, share_network,
expected_result):
self.assertEqual(
expected_result,
self.controller._share_network_subnets_contain_share_servers(
share_network))
def test_show_nominal(self):
share_nw = 'fake network id'
with mock.patch.object(db_api,
@@ -552,12 +707,6 @@ class ShareNetworkAPITest(test.TestCase):
valid_filter_opts = {
'created_before': '2001-02-02',
'created_since': '1999-01-01',
'neutron_net_id': '1111',
'neutron_subnet_id': '2222',
'network_type': 'local',
'segmentation_id': 2000,
'cidr': '8.0.0.0/12',
'ip_version': 6,
'name': 'test-sn'
}
db_api.share_network_get_all_by_project.return_value = [
@@ -614,7 +763,9 @@ class ShareNetworkAPITest(test.TestCase):
@mock.patch.object(db_api, 'share_network_get', mock.Mock())
def test_update_invalid_key_in_use(self):
share_nw = fake_share_network.copy()
share_nw['share_servers'] = [{'id': 1}]
subnet = fake_share_network_subnet.copy()
subnet['share_servers'] = [{'id': 1}]
share_nw['share_network_subnets'] = [subnet]
db_api.share_network_get.return_value = share_nw
body = {
@@ -633,12 +784,15 @@ class ShareNetworkAPITest(test.TestCase):
@mock.patch.object(db_api, 'share_network_update', mock.Mock())
def test_update_valid_keys_in_use(self):
share_nw = fake_share_network.copy()
share_nw['share_servers'] = [{'id': 1}]
subnet = fake_share_network_subnet.copy()
subnet['share_servers'] = [{'id': 1}]
share_nw['share_network_subnets'] = [subnet]
updated_share_nw = share_nw.copy()
updated_share_nw['name'] = 'new name'
updated_share_nw['description'] = 'new description'
db_api.share_network_get.return_value = share_nw
db_api.share_network_update.return_value = updated_share_nw
body = {
share_networks.RESOURCE_NAME: {
'name': updated_share_nw['name'],
@@ -656,6 +810,10 @@ class ShareNetworkAPITest(test.TestCase):
share_nw = 'fake network id'
db_api.share_network_get.return_value = fake_share_network
self.mock_object(
self.controller, '_share_network_subnets_contain_share_servers',
mock.Mock(return_value=False))
body = {share_networks.RESOURCE_NAME: {'neutron_subnet_id':
'new subnet'}}
@@ -672,6 +830,9 @@ class ShareNetworkAPITest(test.TestCase):
def test_action_add_security_service(self, microversion):
share_network_id = 'fake network id'
security_service_id = 'fake ss id'
self.mock_object(
self.controller, '_share_network_subnets_contain_share_servers')
body = {'add_security_service': {'security_service_id':
security_service_id}}
@@ -692,6 +853,9 @@ class ShareNetworkAPITest(test.TestCase):
'type': 'ldap'}
body = {'add_security_service': {'security_service_id':
security_service['id']}}
self.mock_object(
self.controller, '_share_network_subnets_contain_share_servers',
mock.Mock(return_value=False))
db_api.security_service_get.return_value = security_service
db_api.share_network_get.return_value = share_network
@@ -716,6 +880,8 @@ class ShareNetworkAPITest(test.TestCase):
def test_action_remove_security_service(self, microversion):
share_network_id = 'fake network id'
security_service_id = 'fake ss id'
self.mock_object(
self.controller, '_share_network_subnets_contain_share_servers')
body = {'remove_security_service': {'security_service_id':
security_service_id}}
@@ -730,8 +896,13 @@ class ShareNetworkAPITest(test.TestCase):
@mock.patch.object(share_networks.policy, 'check_policy', mock.Mock())
def test_action_remove_security_service_forbidden(self):
share_network = fake_share_network.copy()
share_network['share_servers'] = 'fake share server'
subnet = fake_share_network_subnet.copy()
subnet['share_servers'] = ['foo']
share_network['share_network_subnets'] = [subnet]
db_api.share_network_get.return_value = share_network
self.mock_object(
self.controller, '_share_network_subnets_contain_share_servers',
mock.Mock(return_value=True))
body = {
'remove_security_service': {
'security_service_id': 'fake id',
@@ -758,3 +929,31 @@ class ShareNetworkAPITest(test.TestCase):
self.req,
share_network_id,
body)
@ddt.data('add_security_service', 'remove_security_service')
def test_action_security_service_contains_share_servers(self, action):
share_network = fake_share_network.copy()
security_service = {'id': ' security_service_2',
'type': 'ldap'}
body = {
action: {
'security_service_id': security_service['id']
}
}
self.mock_object(share_networks.policy, 'check_policy')
self.mock_object(db_api, 'share_network_get',
mock.Mock(return_value=share_network))
self.mock_object(
self.controller, '_share_network_subnets_contain_share_servers',
mock.Mock(return_value=True))
self.assertRaises(webob_exc.HTTPForbidden,
self.controller.action,
self.req,
share_network['id'],
body)
db_api.share_network_get.assert_called_once_with(
self.req.environ['manila.context'], share_network['id'])
share_networks.policy.check_policy.assert_called_once_with(
self.req.environ['manila.context'],
share_networks.RESOURCE_NAME, action)
+89 -22
View File
@@ -46,7 +46,8 @@ class ShareServerControllerTest(test.TestCase):
constants.STATUS_UNMANAGE_ERROR, constants.STATUS_MANAGE_ERROR)
def test_share_server_reset_status(self, status):
req = fakes.HTTPRequest.blank('/v2/share-servers/fake-share-server/',
use_admin_context=True)
use_admin_context=True,
version="2.49")
body = {'reset_status': {'status': status}}
context = req.environ['manila.context']
@@ -62,7 +63,8 @@ class ShareServerControllerTest(test.TestCase):
context, 'fake_server_id', {'status': status})
def test_share_reset_server_status_invalid(self):
req = fakes.HTTPRequest.blank('/reset_status', use_admin_context=True)
req = fakes.HTTPRequest.blank('/reset_status', use_admin_context=True,
version="2.49")
body = {'reset_status': {'status': constants.STATUS_EXTENDING}}
context = req.environ['manila.context']
@@ -74,7 +76,8 @@ class ShareServerControllerTest(test.TestCase):
context, self.resource_name, 'reset_status')
def test_share_server_reset_status_no_body(self):
req = fakes.HTTPRequest.blank('/reset_status', use_admin_context=True)
req = fakes.HTTPRequest.blank('/reset_status', use_admin_context=True,
version="2.49")
context = req.environ['manila.context']
self.assertRaises(
@@ -85,7 +88,8 @@ class ShareServerControllerTest(test.TestCase):
context, self.resource_name, 'reset_status')
def test_share_server_reset_status_no_status(self):
req = fakes.HTTPRequest.blank('/reset_status', use_admin_context=True)
req = fakes.HTTPRequest.blank('/reset_status', use_admin_context=True,
version="2.49")
context = req.environ['manila.context']
self.assertRaises(
@@ -98,6 +102,7 @@ class ShareServerControllerTest(test.TestCase):
def _setup_manage_test_request_body(self):
body = {
'share_network_id': 'fake_net_id',
'share_network_subnet_id': 'fake_subnet_id',
'host': 'fake_host',
'identifier': 'fake_identifier',
'driver_options': {'opt1': 'fake_opt1', 'opt2': 'fake_opt2'},
@@ -112,14 +117,18 @@ class ShareServerControllerTest(test.TestCase):
version="2.49")
context = req.environ['manila.context']
share_network = db_utils.create_share_network(name=share_net_name)
share_net_subnet = db_utils.create_share_network_subnet(
share_network_id=share_network['id'])
share_server = db_utils.create_share_server(
share_network_id=share_network['id'],
share_network_subnet_id=share_net_subnet['id'],
host='fake_host',
identifier='fake_identifier',
is_auto_deletable=False)
self.mock_object(db_api, 'share_network_get', mock.Mock(
return_value=share_network))
self.mock_object(db_api, 'share_network_subnet_get_default_subnet',
mock.Mock(return_value=share_net_subnet))
self.mock_object(utils, 'validate_service_host')
body = {
@@ -138,7 +147,8 @@ class ShareServerControllerTest(test.TestCase):
'updated_at': None,
'status': constants.STATUS_ACTIVE,
'host': 'fake_host',
'share_network_id': share_server['share_network_id'],
'share_network_id':
share_server['share_network_subnet']['share_network_id'],
'created_at': share_server['created_at'],
'backend_details': {},
'identifier': share_server['identifier'],
@@ -150,12 +160,12 @@ class ShareServerControllerTest(test.TestCase):
'fake_net_name')
else:
expected_result['share_server']['share_network_name'] = (
share_server['share_network_id'])
share_net_subnet['share_network_id'])
req_params = body['share_server']
manage_share_server_mock.assert_called_once_with(
context, req_params['identifier'], req_params['host'],
share_network, req_params['driver_options'])
share_net_subnet, req_params['driver_options'])
self.assertEqual(expected_result, result)
@@ -164,9 +174,11 @@ class ShareServerControllerTest(test.TestCase):
def test_manage_invalid(self):
req = fakes.HTTPRequest.blank('/manage_share_server',
use_admin_context=True)
use_admin_context=True, version="2.49")
context = req.environ['manila.context']
share_network = db_utils.create_share_network()
share_net_subnet = db_utils.create_share_network_subnet(
share_network_id=share_network['id'])
body = {
'share_server': self._setup_manage_test_request_body()
@@ -174,6 +186,8 @@ class ShareServerControllerTest(test.TestCase):
self.mock_object(utils, 'validate_service_host')
self.mock_object(db_api, 'share_network_get',
mock.Mock(return_value=share_network))
self.mock_object(db_api, 'share_network_subnet_get_default_subnet',
mock.Mock(return_value=share_net_subnet))
manage_share_server_mock = self.mock_object(
share_api.API, 'manage_share_server',
@@ -185,15 +199,24 @@ class ShareServerControllerTest(test.TestCase):
req_params = body['share_server']
manage_share_server_mock.assert_called_once_with(
context, req_params['identifier'], req_params['host'],
share_network, req_params['driver_options'])
share_net_subnet, req_params['driver_options'])
def test_manage_forbidden(self):
"""Tests share server manage without admin privileges"""
req = fakes.HTTPRequest.blank('/manage_share_server')
self.mock_object(share_api.API, 'manage_share_server', mock.Mock())
req = fakes.HTTPRequest.blank('/manage_share_server', version="2.49")
error = mock.Mock(side_effect=exception.PolicyNotAuthorized(action=''))
self.mock_object(share_api.API, 'manage_share_server', error)
share_network = db_utils.create_share_network()
share_net_subnet = db_utils.create_share_network_subnet(
share_network_id=share_network['id'])
self.mock_object(db_api, 'share_network_get', mock.Mock(
return_value=share_network))
self.mock_object(db_api, 'share_network_subnet_get_default_subnet',
mock.Mock(return_value=share_net_subnet))
self.mock_object(utils, 'validate_service_host')
body = {
'share_server': self._setup_manage_test_request_body()
}
@@ -205,7 +228,7 @@ class ShareServerControllerTest(test.TestCase):
def test__validate_manage_share_server_validate_no_body(self):
"""Tests share server manage"""
req = fakes.HTTPRequest.blank('/manage')
req = fakes.HTTPRequest.blank('/manage', version="2.49")
body = {}
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
@@ -223,7 +246,7 @@ class ShareServerControllerTest(test.TestCase):
def test__validate_manage_share_server_validate_without_parameters(
self, empty, key):
"""Tests share server manage without some parameters"""
req = fakes.HTTPRequest.blank('/manage_share_server')
req = fakes.HTTPRequest.blank('/manage_share_server', version="2.49")
self.mock_object(share_api.API, 'manage_share_server', mock.Mock())
body = {
@@ -249,11 +272,20 @@ class ShareServerControllerTest(test.TestCase):
@ddt.unpack
def test__validate_manage_share_server_validate_service_host(
self, exception_to_raise, side_effect_exception):
req = fakes.HTTPRequest.blank('/manage')
req = fakes.HTTPRequest.blank('/manage', version="2.49")
context = req.environ['manila.context']
error = mock.Mock(side_effect=side_effect_exception)
self.mock_object(utils, 'validate_service_host', error)
share_network = db_utils.create_share_network()
share_net_subnet = db_utils.create_share_network_subnet(
share_network_id=share_network['id'])
self.mock_object(db_api, 'share_network_get', mock.Mock(
return_value=share_network))
self.mock_object(db_api, 'share_network_subnet_get_default_subnet',
mock.Mock(return_value=share_net_subnet))
self.assertRaises(
exception_to_raise, self.controller.manage, req,
{'share_server': self._setup_manage_test_request_body()})
@@ -262,7 +294,7 @@ class ShareServerControllerTest(test.TestCase):
context, self.resource_name, 'manage_share_server')
def test__validate_manage_share_server_share_network_not_found(self):
req = fakes.HTTPRequest.blank('/manage')
req = fakes.HTTPRequest.blank('/manage', version="2.49")
context = req.environ['manila.context']
self.mock_object(utils, 'validate_service_host')
error = mock.Mock(
@@ -279,7 +311,7 @@ class ShareServerControllerTest(test.TestCase):
context, self.resource_name, 'manage_share_server')
def test__validate_manage_share_server_driver_opts_not_instance_dict(self):
req = fakes.HTTPRequest.blank('/manage')
req = fakes.HTTPRequest.blank('/manage', version="2.49")
context = req.environ['manila.context']
self.mock_object(utils, 'validate_service_host')
self.mock_object(db_api, 'share_network_get')
@@ -294,7 +326,7 @@ class ShareServerControllerTest(test.TestCase):
context, self.resource_name, 'manage_share_server')
def test__validate_manage_share_server_error_extract_host(self):
req = fakes.HTTPRequest.blank('/manage')
req = fakes.HTTPRequest.blank('/manage', version="2.49")
context = req.environ['manila.context']
body = self._setup_manage_test_request_body()
body['host'] = 'fake@backend#pool'
@@ -306,10 +338,44 @@ class ShareServerControllerTest(test.TestCase):
policy.check_policy.assert_called_once_with(
context, self.resource_name, 'manage_share_server')
@ddt.data(True, False)
def test__validate_manage_share_server_error_subnet_not_found(
self, body_contains_subnet):
req = fakes.HTTPRequest.blank('/manage', version="2.51")
context = req.environ['manila.context']
share_network = db_utils.create_share_network()
body = {'share_server': self._setup_manage_test_request_body()}
share_net_subnet = db_utils.create_share_network_subnet(
share_network_id=share_network['id'])
body['share_server']['share_network_subnet_id'] = (
share_net_subnet['id'] if body_contains_subnet else None)
self.mock_object(
db_api, 'share_network_subnet_get',
mock.Mock(side_effect=exception.ShareNetworkSubnetNotFound(
share_network_subnet_id='fake')))
self.mock_object(db_api, 'share_network_subnet_get_default_subnet',
mock.Mock(return_value=None))
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.manage,
req,
body)
policy.check_policy.assert_called_once_with(
context, self.resource_name, 'manage_share_server')
if body_contains_subnet:
db_api.share_network_subnet_get.assert_called_once_with(
context, share_net_subnet['id'])
else:
(db_api.share_network_subnet_get_default_subnet
.assert_called_once_with(
context, body['share_server']['share_network_id']))
@ddt.data(True, False)
def test_unmanage(self, force):
server = self._setup_unmanage_tests()
req = fakes.HTTPRequest.blank('/unmanage')
req = fakes.HTTPRequest.blank('/unmanage', version="2.49")
context = req.environ['manila.context']
mock_get = self.mock_object(
db_api, 'share_server_get', mock.Mock(return_value=server))
@@ -326,7 +392,8 @@ class ShareServerControllerTest(test.TestCase):
def test_unmanage_share_server_not_found(self):
"""Tests unmanaging share servers"""
req = fakes.HTTPRequest.blank('/v2/share-servers/fake_server_id/')
req = fakes.HTTPRequest.blank('/v2/share-servers/fake_server_id/',
version="2.49")
context = req.environ['manila.context']
share_server_error = mock.Mock(
side_effect=exception.ShareServerNotFound(
@@ -350,7 +417,7 @@ class ShareServerControllerTest(test.TestCase):
server = self._setup_unmanage_tests(status=status)
get_mock = self.mock_object(db_api, 'share_server_get',
mock.Mock(return_value=server))
req = fakes.HTTPRequest.blank('/unmanage_share_server')
req = fakes.HTTPRequest.blank('/unmanage_share_server', version="2.49")
context = req.environ['manila.context']
body = {'unmanage': {'force': True}}
@@ -371,7 +438,7 @@ class ShareServerControllerTest(test.TestCase):
@ddt.data(exception.ShareServerInUse, exception.PolicyNotAuthorized)
def test_unmanage_share_server_badrequest(self, exc):
req = fakes.HTTPRequest.blank('/unmanage')
req = fakes.HTTPRequest.blank('/unmanage', version="2.49")
server = self._setup_unmanage_tests()
context = req.environ['manila.context']
error = mock.Mock(side_effect=exc('foobar'))
+9
View File
@@ -666,6 +666,8 @@ class ShareAPITest(test.TestCase):
self.mock_object(share_api.API, 'create', create_mock)
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
return_value={'id': 'fakenetid'}))
self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id')
body = {"share": copy.deepcopy(shr)}
req = fakes.HTTPRequest.blank('/shares', version='2.7')
@@ -674,6 +676,7 @@ class ShareAPITest(test.TestCase):
expected = self._get_expected_share_detailed_response(
shr, version='2.7')
self.assertDictMatch(expected, res_dict)
# pylint: disable=unsubscriptable-object
self.assertEqual("fakenetid",
create_mock.call_args[1]['share_network_id'])
@@ -1244,6 +1247,8 @@ class ShareAPITest(test.TestCase):
return_value=parent_share))
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
return_value={'id': parent_share_net}))
self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id')
body = {"share": copy.deepcopy(shr)}
req = fakes.HTTPRequest.blank('/shares', version='2.7')
@@ -1253,6 +1258,7 @@ class ShareAPITest(test.TestCase):
expected = self._get_expected_share_detailed_response(
shr, version='2.7')
self.assertEqual(expected, res_dict)
# pylint: disable=unsubscriptable-object
self.assertEqual(parent_share_net,
create_mock.call_args[1]['share_network_id'])
@@ -1286,6 +1292,8 @@ class ShareAPITest(test.TestCase):
return_value=parent_share))
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
return_value={'id': parent_share_net}))
self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id')
body = {"share": copy.deepcopy(shr)}
req = fakes.HTTPRequest.blank('/shares', version='2.7')
@@ -1293,6 +1301,7 @@ class ShareAPITest(test.TestCase):
expected = self._get_expected_share_detailed_response(
shr, version='2.7')
self.assertDictMatch(expected, res_dict)
# pylint: disable=unsubscriptable-object
self.assertEqual(parent_share_net,
create_mock.call_args[1]['share_network_id'])
@@ -0,0 +1,75 @@
# Copyright 2019 NetApp, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ddt
from manila.api.views import share_network_subnets
from manila import test
from manila.tests.api import fakes
from manila.tests import db_utils
@ddt.ddt
class ViewBuilderTestCase(test.TestCase):
def setUp(self):
super(ViewBuilderTestCase, self).setUp()
self.builder = share_network_subnets.ViewBuilder()
self.share_network = db_utils.create_share_network(
name='fake_network', id='fake_sn_id')
def _validate_is_detail_return(self, result):
expected_keys = ['id', 'created_at', 'updated_at', 'neutron_net_id',
'neutron_subnet_id', 'network_type', 'cidr',
'segmentation_id', 'ip_version', 'share_network_id',
'availability_zone', 'gateway', 'mtu']
for key in expected_keys:
self.assertIn(key, result)
def test_build_share_network_subnet(self):
req = fakes.HTTPRequest.blank('/subnets', version='2.51')
subnet = db_utils.create_share_network_subnet(
share_network_id=self.share_network['id'])
result = self.builder.build_share_network_subnet(req, subnet)
self.assertEqual(1, len(result))
self.assertIn('share_network_subnet', result)
self.assertEqual(subnet['id'],
result['share_network_subnet']['id'])
self.assertEqual(subnet['share_network_id'],
result['share_network_subnet']['share_network_id'])
self.assertIsNone(
result['share_network_subnet']['availability_zone'])
self._validate_is_detail_return(result['share_network_subnet'])
def test_build_share_network_subnets(self):
req = fakes.HTTPRequest.blank('/subnets', version='2.51')
share_network = db_utils.create_share_network(
name='fake_network', id='fake_sn_id_1')
subnet = db_utils.create_share_network_subnet(
share_network_id=share_network['id'])
result = self.builder.build_share_network_subnets(req, [subnet])
self.assertIn('share_network_subnets', result)
self.assertEqual(1, len(result['share_network_subnets']))
subnet_list = result['share_network_subnets']
for subnet in subnet_list:
self._validate_is_detail_return(subnet)
+62 -27
View File
@@ -34,12 +34,21 @@ class ViewBuilderTestCase(test.TestCase):
@ddt.data(*itertools.product(
[
{'id': 'fake_sn_id', 'name': 'fake_sn_name'},
{'id': 'fake_sn_id', 'name': 'fake_sn_name',
'share_network_subnets': []},
{'id': 'fake_sn_id', 'name': 'fake_sn_name',
'share_network_subnets': [], 'fake_extra_key': 'foo'},
{'id': 'fake_sn_id', 'name': 'fake_sn_name',
'share_network_subnets': [
{'availability_zone_id': None,
'id': 'fake',
'availability_zone': None,
'is_default': False
}],
'fake_extra_key': 'foo'},
],
["1.0", "2.0", "2.18", "2.20", "2.25", "2.26",
api_version._MAX_API_VERSION])
"2.49", api_version._MAX_API_VERSION])
)
@ddt.unpack
def test_build_share_network(self, share_network_data, microversion):
@@ -49,17 +58,28 @@ class ViewBuilderTestCase(test.TestCase):
api_version.APIVersionRequest('2.20'))
nova_net_support = (api_version.APIVersionRequest(microversion) <
api_version.APIVersionRequest('2.26'))
default_net_info_support = (api_version.APIVersionRequest(microversion)
<= api_version.APIVersionRequest('2.49'))
subnets_support = (api_version.APIVersionRequest(microversion) >
api_version.APIVersionRequest('2.49'))
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
expected_keys = {
'id', 'name', 'project_id', 'created_at', 'updated_at',
'neutron_net_id', 'neutron_subnet_id', 'network_type',
'segmentation_id', 'cidr', 'ip_version', 'description'}
if gateway_support:
expected_keys.add('gateway')
if mtu_support:
expected_keys.add('mtu')
if nova_net_support:
expected_keys.add('nova_net_id')
'description'}
if subnets_support:
expected_keys.add('share_network_subnets')
else:
if default_net_info_support:
network_info = {
'neutron_net_id', 'neutron_subnet_id', 'network_type',
'segmentation_id', 'cidr', 'ip_version'}
expected_keys.update(network_info)
if gateway_support:
expected_keys.add('gateway')
if mtu_support:
expected_keys.add('mtu')
if nova_net_support:
expected_keys.add('nova_net_id')
result = self.builder.build_share_network(req, share_network_data)
self.assertEqual(1, len(result))
@@ -93,7 +113,7 @@ class ViewBuilderTestCase(test.TestCase):
{'id': 'fake_id2',
'name': 'fake_name2'}],
],
set(["1.0", "2.0", "2.18", "2.20", "2.25", "2.26",
set(["1.0", "2.0", "2.18", "2.20", "2.25", "2.26", "2.49",
api_version._MAX_API_VERSION]))
)
@ddt.unpack
@@ -105,6 +125,10 @@ class ViewBuilderTestCase(test.TestCase):
api_version.APIVersionRequest('2.20'))
nova_net_support = (api_version.APIVersionRequest(microversion) <
api_version.APIVersionRequest('2.26'))
default_net_info_support = (api_version.APIVersionRequest(microversion)
<= api_version.APIVersionRequest('2.49'))
subnets_support = (api_version.APIVersionRequest(microversion) >
api_version.APIVersionRequest('2.49'))
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
expected_networks_list = []
for share_network in share_networks:
@@ -114,23 +138,34 @@ class ViewBuilderTestCase(test.TestCase):
'project_id': share_network.get('project_id'),
'created_at': share_network.get('created_at'),
'updated_at': share_network.get('updated_at'),
'neutron_net_id': share_network.get('neutron_net_id'),
'neutron_subnet_id': share_network.get('neutron_subnet_id'),
'network_type': share_network.get('network_type'),
'segmentation_id': share_network.get('segmentation_id'),
'cidr': share_network.get('cidr'),
'ip_version': share_network.get('ip_version'),
'description': share_network.get('description'),
}
if gateway_support:
share_network.update({'gateway': 'fake_gateway'})
expected_data.update({'gateway': share_network.get('gateway')})
if mtu_support:
share_network.update({'mtu': 1509})
expected_data.update({'mtu': share_network.get('mtu')})
if nova_net_support:
share_network.update({'nova_net_id': 'fake_nova_net_id'})
expected_data.update({'nova_net_id': None})
if subnets_support:
share_network.update({'share_network_subnets': []})
expected_data.update({'share_network_subnets': []})
else:
if default_net_info_support:
network_data = {
'neutron_net_id': share_network.get('neutron_net_id'),
'neutron_subnet_id': share_network.get(
'neutron_subnet_id'),
'network_type': share_network.get('network_type'),
'segmentation_id': share_network.get(
'segmentation_id'),
'cidr': share_network.get('cidr'),
'ip_version': share_network.get('ip_version'),
}
expected_data.update(network_data)
if gateway_support:
share_network.update({'gateway': 'fake_gateway'})
expected_data.update({'gateway':
share_network.get('gateway')})
if mtu_support:
share_network.update({'mtu': 1509})
expected_data.update({'mtu': share_network.get('mtu')})
if nova_net_support:
share_network.update({'nova_net_id': 'fake_nova_net_id'})
expected_data.update({'nova_net_id': None})
expected_networks_list.append(expected_data)
expected = {'share_networks': expected_networks_list}
@@ -148,7 +183,7 @@ class ViewBuilderTestCase(test.TestCase):
{'id': 'id2', 'name': 'name2',
'fake': 'I should not be returned'}]
],
set(["1.0", "2.0", "2.18", "2.20", "2.25", "2.26",
set(["1.0", "2.0", "2.18", "2.20", "2.25", "2.26", "2.49",
api_version._MAX_API_VERSION]))
)
@ddt.unpack
@@ -34,6 +34,7 @@ See BaseMigrationChecks class for more information.
"""
import abc
import copy
import datetime
from oslo_db import exception as oslo_db_exc
@@ -2803,3 +2804,116 @@ class ShareServerIsAutoDeletableAndIdentifierChecks(BaseMigrationChecks):
for ss in engine.execute(ss_table.select()):
self.test_case.assertFalse(hasattr(ss, 'is_auto_deletable'))
self.test_case.assertFalse(hasattr(ss, 'identifier'))
@map_to_migration('805685098bd2')
class ShareNetworkSubnetMigrationChecks(BaseMigrationChecks):
user_id = '6VFQ87wnV24lg1c2q1q0lJkTbQBPFZ1m4968'
project_id = '19HAW8w58yeUPBy8zGex4EGulWZHd8zZGtHk'
share_network = {
'id': uuidutils.generate_uuid(),
'user_id': user_id,
'project_id': project_id,
'neutron_net_id': uuidutils.generate_uuid(),
'neutron_subnet_id': uuidutils.generate_uuid(),
'cidr': '203.0.113.0/24',
'ip_version': 4,
'network_type': 'vxlan',
'segmentation_id': 100,
'gateway': 'fake_gateway',
'mtu': 1500,
}
share_networks = [share_network]
sns_table_name = 'share_network_subnets'
sn_table_name = 'share_networks'
ss_table_name = 'share_servers'
expected_keys = ['neutron_net_id', 'neutron_subnet_id', 'cidr',
'ip_version', 'network_type', 'segmentation_id',
'gateway', 'mtu']
def _setup_data_for_empty_neutron_net_and_subnet_id_test(self, network):
network['id'] = uuidutils.generate_uuid()
for key in self.expected_keys:
network[key] = None
return network
def setup_upgrade_data(self, engine):
share_network_data_without_net_info = (
self._setup_data_for_empty_neutron_net_and_subnet_id_test(
copy.deepcopy(self.share_network)))
self.share_networks.append(share_network_data_without_net_info)
# Load the table to be used below
sn_table = utils.load_table(self.sn_table_name, engine)
ss_table = utils.load_table(self.ss_table_name, engine)
# Share server data
share_server_data = {
'host': 'acme@controller-ostk-0',
'status': 'active',
}
# Create share share networks and one share server for each of them
for network in self.share_networks:
share_server_data['share_network_id'] = network['id']
share_server_data['id'] = uuidutils.generate_uuid()
engine.execute(sn_table.insert(network))
engine.execute(ss_table.insert(share_server_data))
def check_upgrade(self, engine, data):
# Load the necessary tables
sn_table = utils.load_table(self.sn_table_name, engine)
sns_table = utils.load_table(self.sns_table_name, engine)
ss_table = utils.load_table(self.ss_table_name, engine)
for network in self.share_networks:
sn_record = engine.execute(sn_table.select().where(
sn_table.c.id == network['id'])).first()
for key in self.expected_keys:
self.test_case.assertFalse(hasattr(sn_record, key))
sns_record = engine.execute(sns_table.select().where(
sns_table.c.share_network_id == network['id'])).first()
for key in self.expected_keys:
self.test_case.assertTrue(hasattr(sns_record, key))
self.test_case.assertEqual(network[key], sns_record[key])
ss_record = (
engine.execute(
ss_table.select().where(
ss_table.c.share_network_subnet_id == sns_record['id'])
).first())
self.test_case.assertIs(
True, hasattr(ss_record, 'share_network_subnet_id'))
self.test_case.assertEqual(
ss_record['share_network_subnet_id'], sns_record['id'])
self.test_case.assertIs(
False, hasattr(ss_record, 'share_network_id'))
def check_downgrade(self, engine):
sn_table = utils.load_table(self.sn_table_name, engine)
# Check if the share network table contains the expected keys
for sn in engine.execute(sn_table.select()):
for key in self.expected_keys:
self.test_case.assertTrue(hasattr(sn, key))
ss_table = utils.load_table(self.ss_table_name, engine)
for network in self.share_networks:
for ss in engine.execute(ss_table.select().where(
ss_table.c.share_network_id == network['id'])):
self.test_case.assertFalse(hasattr(ss,
'share_network_subnet_id'))
self.test_case.assertTrue(hasattr(ss, 'share_network_id'))
self.test_case.assertEqual(network['id'], ss['id'])
# Check if the created table doesn't exists anymore
self.test_case.assertRaises(
sa_exc.NoSuchTableError,
utils.load_table, self.sns_table_name, engine)
+194 -19
View File
@@ -577,7 +577,7 @@ class ShareDatabaseAPITestCase(test.TestCase):
db_utils.create_share_replica(share_id=share_2['id'])
expected_ss_keys = {
'backend_details', 'host', 'id',
'share_network_id', 'status',
'share_network_subnet_id', 'status',
}
expected_share_keys = {
'project_id', 'share_type_id', 'display_name',
@@ -625,7 +625,7 @@ class ShareDatabaseAPITestCase(test.TestCase):
share_server_id=share_server['id'])
expected_ss_keys = {
'backend_details', 'host', 'id',
'share_network_id', 'status',
'share_network_subnet_id', 'status',
}
expected_share_keys = {
'project_id', 'share_type_id', 'display_name',
@@ -690,7 +690,7 @@ class ShareDatabaseAPITestCase(test.TestCase):
session = db_api.get_session()
expected_ss_keys = {
'backend_details', 'host', 'id',
'share_network_id', 'status',
'share_network_subnet_id', 'status',
}
expected_share_keys = {
'project_id', 'share_type_id', 'display_name',
@@ -778,7 +778,7 @@ class ShareDatabaseAPITestCase(test.TestCase):
)
expected_extra_keys = {
'backend_details', 'host', 'id',
'share_network_id', 'status',
'share_network_subnet_id', 'status',
}
with session.begin():
share_replica = db_api.share_replica_get(
@@ -1941,14 +1941,8 @@ class ShareNetworkDatabaseAPITestCase(BaseDatabaseAPITestCase):
def setUp(self):
super(ShareNetworkDatabaseAPITestCase, self).setUp()
self.share_nw_dict = {'id': 'fake network id',
'neutron_net_id': 'fake net id',
'neutron_subnet_id': 'fake subnet id',
'project_id': self.fake_context.project_id,
'user_id': 'fake_user_id',
'network_type': 'vlan',
'segmentation_id': 1000,
'cidr': '10.0.0.0/24',
'ip_version': 4,
'name': 'whatever',
'description': 'fake description'}
@@ -2042,6 +2036,26 @@ class ShareNetworkDatabaseAPITestCase(BaseDatabaseAPITestCase):
self._check_fields(expected=service,
actual=result['security_services'][index])
@ddt.data([{'id': 'fake_id_1', 'availability_zone_id': 'None'}],
[{'id': 'fake_id_2', 'availability_zone_id': 'None'},
{'id': 'fake_id_3', 'availability_zone_id': 'fake_az_id'}])
def test_get_with_subnets(self, subnets):
db_api.share_network_create(self.fake_context, self.share_nw_dict)
for subnet in subnets:
subnet['share_network_id'] = self.share_nw_dict['id']
db_api.share_network_subnet_create(self.fake_context, subnet)
result = db_api.share_network_get(self.fake_context,
self.share_nw_dict['id'])
self.assertEqual(len(subnets),
len(result['share_network_subnets']))
for index, subnet in enumerate(subnets):
self._check_fields(expected=subnet,
actual=result['share_network_subnets'][index])
def test_get_not_found(self):
self.assertRaises(exception.ShareNetworkNotFound,
db_api.share_network_get,
@@ -2092,7 +2106,7 @@ class ShareNetworkDatabaseAPITestCase(BaseDatabaseAPITestCase):
share_network_dict = dict(self.share_nw_dict)
fake_id = 'fake_id%s' % index
share_network_dict.update({'id': fake_id,
'neutron_subnet_id': fake_id})
'project_id': fake_id})
share_networks.append(share_network_dict)
db_api.share_network_create(self.fake_context, share_network_dict)
index += 1
@@ -2107,7 +2121,6 @@ class ShareNetworkDatabaseAPITestCase(BaseDatabaseAPITestCase):
share_nw_dict2 = dict(self.share_nw_dict)
share_nw_dict2['id'] = 'fake share nw id2'
share_nw_dict2['project_id'] = 'fake project 2'
share_nw_dict2['neutron_subnet_id'] = 'fake subnet id2'
db_api.share_network_create(self.fake_context, self.share_nw_dict)
db_api.share_network_create(self.fake_context, share_nw_dict2)
@@ -2269,6 +2282,155 @@ class ShareNetworkDatabaseAPITestCase(BaseDatabaseAPITestCase):
self.assertEqual(0, len(result['share_instances']))
@ddt.ddt
class ShareNetworkSubnetDatabaseAPITestCase(BaseDatabaseAPITestCase):
def __init__(self, *args, **kwargs):
super(ShareNetworkSubnetDatabaseAPITestCase, self).__init__(
*args, **kwargs)
self.fake_context = context.RequestContext(user_id='fake user',
project_id='fake project',
is_admin=False)
def setUp(self):
super(ShareNetworkSubnetDatabaseAPITestCase, self).setUp()
self.subnet_dict = {'id': 'fake network id',
'neutron_net_id': 'fake net id',
'neutron_subnet_id': 'fake subnet id',
'network_type': 'vlan',
'segmentation_id': 1000,
'share_network_id': 'fake_id',
'cidr': '10.0.0.0/24',
'ip_version': 4,
'availability_zone_id': None}
def test_create(self):
result = db_api.share_network_subnet_create(
self.fake_context, self.subnet_dict)
self._check_fields(expected=self.subnet_dict, actual=result)
def test_create_duplicated_id(self):
db_api.share_network_subnet_create(self.fake_context, self.subnet_dict)
self.assertRaises(db_exception.DBDuplicateEntry,
db_api.share_network_subnet_create,
self.fake_context,
self.subnet_dict)
def test_get(self):
db_api.share_network_subnet_create(self.fake_context, self.subnet_dict)
result = db_api.share_network_subnet_get(self.fake_context,
self.subnet_dict['id'])
self._check_fields(expected=self.subnet_dict, actual=result)
@ddt.data([{'id': 'fake_id_1', 'identifier': 'fake_identifier',
'host': 'fake_host'}],
[{'id': 'fake_id_2', 'identifier': 'fake_identifier',
'host': 'fake_host'},
{'id': 'fake_id_3', 'identifier': 'fake_identifier',
'host': 'fake_host'}])
def test_get_with_share_servers(self, share_servers):
db_api.share_network_subnet_create(self.fake_context,
self.subnet_dict)
for share_server in share_servers:
share_server['share_network_subnet_id'] = self.subnet_dict['id']
db_api.share_server_create(self.fake_context, share_server)
result = db_api.share_network_subnet_get(self.fake_context,
self.subnet_dict['id'])
self.assertEqual(len(share_servers),
len(result['share_servers']))
for index, share_server in enumerate(share_servers):
self._check_fields(expected=share_server,
actual=result['share_servers'][index])
def test_get_not_found(self):
db_api.share_network_subnet_create(self.fake_context, self.subnet_dict)
self.assertRaises(exception.ShareNetworkSubnetNotFound,
db_api.share_network_subnet_get,
self.fake_context,
'fake_id')
def test_delete(self):
db_api.share_network_subnet_create(self.fake_context, self.subnet_dict)
db_api.share_network_subnet_delete(self.fake_context,
self.subnet_dict['id'])
self.assertRaises(exception.ShareNetworkSubnetNotFound,
db_api.share_network_subnet_delete,
self.fake_context,
self.subnet_dict['id'])
def test_delete_not_found(self):
self.assertRaises(exception.ShareNetworkSubnetNotFound,
db_api.share_network_subnet_delete,
self.fake_context,
'fake_id')
def test_update(self):
update_dict = {
'gateway': 'fake_gateway',
'ip_version': 6,
'mtu': ''
}
db_api.share_network_subnet_create(self.fake_context, self.subnet_dict)
db_api.share_network_subnet_update(
self.fake_context, self.subnet_dict['id'], update_dict)
result = db_api.share_network_subnet_get(self.fake_context,
self.subnet_dict['id'])
self._check_fields(expected=update_dict, actual=result)
def test_update_not_found(self):
self.assertRaises(exception.ShareNetworkSubnetNotFound,
db_api.share_network_subnet_update,
self.fake_context,
self.subnet_dict['id'],
{})
@ddt.data([{'id': 'sn_id1', 'project_id': 'fake', 'user_id': 'fake'}],
[{'id': 'fake_id', 'project_id': 'fake', 'user_id': 'fake'},
{'id': 'sn_id2', 'project_id': 'fake', 'user_id': 'fake'}])
def test_get_all_by_share_network(self, share_networks):
for idx, share_network in enumerate(share_networks):
self.subnet_dict['share_network_id'] = share_network['id']
self.subnet_dict['id'] = 'fake_id%s' % idx
db_api.share_network_create(self.fake_context, share_network)
db_api.share_network_subnet_create(self.fake_context,
self.subnet_dict)
for share_network in share_networks:
subnets = db_api.share_network_subnet_get_all_by_share_network(
self.fake_context, share_network['id'])
self.assertEqual(1, len(subnets))
def test_get_by_availability_zone_id(self):
az = db_api.availability_zone_create_if_not_exist(self.fake_context,
'fake_zone_id')
self.subnet_dict['availability_zone_id'] = az['id']
db_api.share_network_subnet_create(self.fake_context, self.subnet_dict)
result = db_api.share_network_subnet_get_by_availability_zone_id(
self.fake_context, self.subnet_dict['share_network_id'], az['id'])
self._check_fields(expected=self.subnet_dict, actual=result)
def test_get_default_subnet(self):
db_api.share_network_subnet_create(self.fake_context, self.subnet_dict)
result = db_api.share_network_subnet_get_default_subnet(
self.fake_context, self.subnet_dict['share_network_id'])
self._check_fields(expected=self.subnet_dict, actual=result)
@ddt.ddt
class SecurityServiceDatabaseAPITestCase(BaseDatabaseAPITestCase):
@@ -2437,7 +2599,8 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
expected = db_utils.create_share_server()
server = db_api.share_server_get(self.ctxt, expected['id'])
self.assertEqual(expected['id'], server['id'])
self.assertEqual(expected.share_network_id, server.share_network_id)
self.assertEqual(expected.share_network_subnet_id,
server.share_network_subnet_id)
self.assertEqual(expected.host, server.host)
self.assertEqual(expected.status, server.status)
@@ -2449,7 +2612,8 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
def test_create(self):
server = db_utils.create_share_server()
self.assertTrue(server['id'])
self.assertEqual(server.share_network_id, server['share_network_id'])
self.assertEqual(server.share_network_subnet_id,
server['share_network_subnet_id'])
self.assertEqual(server.host, server['host'])
self.assertEqual(server.status, server['status'])
@@ -2488,21 +2652,31 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
self.ctxt, fake_id, {})
def test_get_all_by_host_and_share_net_valid(self):
valid = {
subnet_1 = {
'id': '1',
'share_network_id': '1',
}
subnet_2 = {
'id': '2',
'share_network_id': '2',
}
valid = {
'share_network_subnet_id': '1',
'host': 'host1',
'status': constants.STATUS_ACTIVE,
}
invalid = {
'share_network_id': '1',
'share_network_subnet_id': '2',
'host': 'host1',
'status': constants.STATUS_ERROR,
}
other = {
'share_network_id': '2',
'share_network_subnet_id': '1',
'host': 'host2',
'status': constants.STATUS_ACTIVE,
}
db_utils.create_share_network_subnet(**subnet_1)
db_utils.create_share_network_subnet(**subnet_2)
valid = db_utils.create_share_server(**valid)
db_utils.create_share_server(**invalid)
db_utils.create_share_server(**other)
@@ -2572,7 +2746,7 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
def test_get_with_details(self):
values = {
'share_network_id': 'fake-share-net-id',
'share_network_subnet_id': 'fake-share-net-id',
'host': 'hostname',
'status': constants.STATUS_ACTIVE,
}
@@ -2584,7 +2758,8 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
db_api.share_server_backend_details_set(self.ctxt, srv_id, details)
server = db_api.share_server_get(self.ctxt, srv_id)
self.assertEqual(srv_id, server['id'])
self.assertEqual(values['share_network_id'], server.share_network_id)
self.assertEqual(values['share_network_subnet_id'],
server.share_network_subnet_id)
self.assertEqual(values['host'], server.host)
self.assertEqual(values['status'], server.status)
self.assertDictMatch(server['backend_details'], details)
+19 -7
View File
@@ -212,7 +212,7 @@ def create_share_server(**kwargs):
backend_details = kwargs.pop('backend_details', {})
srv = {
'host': 'host1',
'share_network_id': 'fake_srv_id',
'share_network_subnet_id': 'fake_srv_id',
'status': constants.STATUS_ACTIVE
}
share_srv = _create_db_row(db.share_server_create, srv, kwargs)
@@ -251,19 +251,31 @@ def create_share_network(**kwargs):
net = {
'user_id': 'fake',
'project_id': 'fake',
'neutron_net_id': 'fake-neutron-net',
'neutron_subnet_id': 'fake-neutron-subnet',
'status': 'new',
'network_type': 'vlan',
'segmentation_id': 1000,
'cidr': '10.0.0.0/24',
'ip_version': 4,
'name': 'whatever',
'description': 'fake description',
}
return _create_db_row(db.share_network_create, net, kwargs)
def create_share_network_subnet(**kwargs):
"""Create a share network subnet object."""
subnet = {
'id': 'fake_sns_id',
'neutron_net_id': 'fake-neutron-net',
'neutron_subnet_id': 'fake-neutron-subnet',
'network_type': 'vlan',
'segmentation_id': 1000,
'cidr': '10.0.0.0/24',
'ip_version': 4,
'availability_zone_id': 'fake_zone_id',
'share_network_id': 'fake_sn_id',
'gateway': None,
'mtu': None
}
return _create_db_row(db.share_network_subnet_create, subnet, kwargs)
def create_security_service(**kwargs):
share_network_id = kwargs.pop('share_network_id', None)
service = {
+1 -1
View File
@@ -302,7 +302,7 @@ def fake_share_server_get():
'status': constants.STATUS_ACTIVE,
'updated_at': None,
'host': 'fake_host',
'share_network_id': 'fake_sn_id',
'share_network_subnet_id': 'fake_sn_id',
'share_network_name': 'fake_sn_name',
'project_id': 'fake_project_id',
'id': 'fake_share_server_id',
@@ -79,15 +79,10 @@ fake_neutron_subnet = {
'gateway_ip': '10.0.0.1',
}
fake_share_network = {
'id': 'fake nw info id',
fake_share_network_subnet = {
'id': 'fake nw subnet id',
'neutron_subnet_id': fake_neutron_network['subnets'][0],
'neutron_net_id': fake_neutron_network['id'],
'project_id': 'fake project id',
'status': 'test_subnet_status',
'name': 'fake name',
'description': 'fake description',
'security_services': [],
'network_type': 'fake_network_type',
'segmentation_id': 1234,
'ip_version': 4,
@@ -96,6 +91,16 @@ fake_share_network = {
'mtu': 1509,
}
fake_share_network = {
'id': 'fake nw info id',
'project_id': 'fake project id',
'status': 'test_subnet_status',
'name': 'fake name',
'description': 'fake description',
'security_services': [],
'subnets': [fake_share_network_subnet],
}
fake_share_server = {
'id': 'fake nw info id',
'status': 'test_server_status',
@@ -111,11 +116,11 @@ fake_network_allocation = {
'mac_address': fake_neutron_port['mac_address'],
'status': constants.STATUS_ACTIVE,
'label': 'user',
'network_type': fake_share_network['network_type'],
'segmentation_id': fake_share_network['segmentation_id'],
'ip_version': fake_share_network['ip_version'],
'cidr': fake_share_network['cidr'],
'gateway': fake_share_network['gateway'],
'network_type': fake_share_network_subnet['network_type'],
'segmentation_id': fake_share_network_subnet['segmentation_id'],
'ip_version': fake_share_network_subnet['ip_version'],
'cidr': fake_share_network_subnet['cidr'],
'gateway': fake_share_network_subnet['gateway'],
'mtu': 1509,
}
@@ -230,17 +235,18 @@ class NeutronNetworkPluginTest(test.TestCase):
self.fake_context,
fake_share_server,
fake_share_network,
fake_share_network_subnet,
allocation_info={'count': 1})
has_provider_nw_ext.assert_any_call()
save_nw_data.assert_called_once_with(self.fake_context,
fake_share_network)
fake_share_network_subnet)
save_subnet_data.assert_called_once_with(self.fake_context,
fake_share_network)
fake_share_network_subnet)
self.plugin.neutron_api.create_port.assert_called_once_with(
fake_share_network['project_id'],
network_id=fake_share_network['neutron_net_id'],
subnet_id=fake_share_network['neutron_subnet_id'],
network_id=fake_share_network_subnet['neutron_net_id'],
subnet_id=fake_share_network_subnet['neutron_subnet_id'],
device_owner='manila:share',
device_id=fake_share_network['id'])
db_api.network_allocation_create.assert_called_once_with(
@@ -270,22 +276,22 @@ class NeutronNetworkPluginTest(test.TestCase):
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)
self.fake_context, fake_share_server, fake_share_network,
fake_share_network_subnet, count=2)
neutron_api_calls = [
mock.call(fake_share_network['project_id'],
network_id=fake_share_network['neutron_net_id'],
subnet_id=fake_share_network['neutron_subnet_id'],
device_owner='manila:share',
device_id=fake_share_network['id']),
mock.call(fake_share_network['project_id'],
network_id=fake_share_network['neutron_net_id'],
subnet_id=fake_share_network['neutron_subnet_id'],
device_owner='manila:share',
device_id=fake_share_network['id']),
mock.call(
fake_share_network['project_id'],
network_id=fake_share_network_subnet['neutron_net_id'],
subnet_id=fake_share_network_subnet['neutron_subnet_id'],
device_owner='manila:share',
device_id=fake_share_network['id']),
mock.call(
fake_share_network['project_id'],
network_id=fake_share_network_subnet['neutron_net_id'],
subnet_id=fake_share_network_subnet['neutron_subnet_id'],
device_owner='manila:share',
device_id=fake_share_network['id']),
]
db_api_calls = [
mock.call(self.fake_context, fake_network_allocation),
@@ -342,7 +348,7 @@ class NeutronNetworkPluginTest(test.TestCase):
neutron_ports[3]['fixed_ips'][0]['ip_address'] = '192.168.0.13'
neutron_ports[3]['id'] = 'fake_port_id_3'
self.mock_object(self.plugin, '_verify_share_network')
self.mock_object(self.plugin, '_verify_share_network_subnet')
self.mock_object(self.plugin, '_store_neutron_net_info')
self.mock_object(self.plugin.neutron_api, 'list_ports',
@@ -366,14 +372,15 @@ class NeutronNetworkPluginTest(test.TestCase):
result = self.plugin.manage_network_allocations(
self.fake_context, allocations, fake_share_server,
fake_share_network)
share_network_subnet=fake_share_network_subnet)
self.assertEqual(['fd12::2000'], result)
self.plugin.neutron_api.list_ports.assert_called_once_with(
network_id=fake_share_network['neutron_net_id'],
network_id=fake_share_network_subnet['neutron_net_id'],
device_owner='manila:share',
fixed_ips='subnet_id=' + fake_share_network['neutron_subnet_id'])
fixed_ips='subnet_id=' +
fake_share_network_subnet['neutron_subnet_id'])
db_api.network_allocation_get.assert_has_calls([
mock.call(self.fake_context, 'fake_port_id_1', read_deleted=False),
@@ -385,15 +392,15 @@ class NeutronNetworkPluginTest(test.TestCase):
port_dict_list = [{
'share_server_id': fake_share_server['id'],
'ip_address': x,
'gateway': fake_share_network['gateway'],
'gateway': fake_share_network_subnet['gateway'],
'mac_address': fake_neutron_port['mac_address'],
'status': constants.STATUS_ACTIVE,
'label': 'user',
'network_type': fake_share_network['network_type'],
'segmentation_id': fake_share_network['segmentation_id'],
'ip_version': fake_share_network['ip_version'],
'cidr': fake_share_network['cidr'],
'mtu': fake_share_network['mtu'],
'network_type': fake_share_network_subnet['network_type'],
'segmentation_id': fake_share_network_subnet['segmentation_id'],
'ip_version': fake_share_network_subnet['ip_version'],
'cidr': fake_share_network_subnet['cidr'],
'mtu': fake_share_network_subnet['mtu'],
} for x in ['192.168.0.11', '192.168.0.12']]
if side_effect:
@@ -415,11 +422,11 @@ class NeutronNetworkPluginTest(test.TestCase):
port_dict_list[1], read_deleted=True)
])
self.plugin._verify_share_network.assert_called_once_with(
fake_share_server['id'], fake_share_network)
self.plugin._verify_share_network_subnet.assert_called_once_with(
fake_share_server['id'], fake_share_network_subnet)
self.plugin._store_neutron_net_info(
self.fake_context, fake_share_network)
self.fake_context, fake_share_network_subnet)
def test__get_ports_respective_to_ips_multiple_fixed_ips(self):
self.mock_object(plugin.LOG, 'warning')
@@ -462,7 +469,8 @@ class NeutronNetworkPluginTest(test.TestCase):
self.assertRaises(
exception.ManageShareServerError,
self.plugin.manage_network_allocations, self.fake_context,
allocations, fake_share_server, fake_share_network)
allocations, fake_share_server, fake_share_network,
fake_share_network_subnet)
db_api.network_allocation_get.assert_called_once_with(
self.fake_context, 'fake_port_id_1', read_deleted=False)
@@ -533,7 +541,7 @@ class NeutronNetworkPluginTest(test.TestCase):
{'status': constants.STATUS_ERROR})
delete_port.stop()
@mock.patch.object(db_api, 'share_network_update', mock.Mock())
@mock.patch.object(db_api, 'share_network_subnet_update', mock.Mock())
def test_save_neutron_network_data(self):
neutron_nw_info = {
'provider:network_type': 'vlan',
@@ -550,16 +558,16 @@ class NeutronNetworkPluginTest(test.TestCase):
'get_network',
mock.Mock(return_value=neutron_nw_info)):
self.plugin._save_neutron_network_data(self.fake_context,
fake_share_network)
fake_share_network_subnet)
self.plugin.neutron_api.get_network.assert_called_once_with(
fake_share_network['neutron_net_id'])
self.plugin.db.share_network_update.assert_called_once_with(
fake_share_network_subnet['neutron_net_id'])
self.plugin.db.share_network_subnet_update.assert_called_once_with(
self.fake_context,
fake_share_network['id'],
fake_share_network_subnet['id'],
share_nw_update_dict)
@mock.patch.object(db_api, 'share_network_update', mock.Mock())
@mock.patch.object(db_api, 'share_network_subnet_update', mock.Mock())
def test_save_neutron_network_data_multi_segment(self):
share_nw_update_dict = {
'network_type': 'vlan',
@@ -577,13 +585,13 @@ class NeutronNetworkPluginTest(test.TestCase):
with test_utils.create_temp_config_with_opts(config_data):
self.plugin._save_neutron_network_data(self.fake_context,
fake_share_network)
fake_share_network_subnet)
self.plugin.neutron_api.get_network.assert_called_once_with(
fake_share_network['neutron_net_id'])
self.plugin.db.share_network_update.assert_called_once_with(
fake_share_network_subnet['neutron_net_id'])
self.plugin.db.share_network_subnet_update.assert_called_once_with(
self.fake_context,
fake_share_network['id'],
fake_share_network_subnet['id'],
share_nw_update_dict)
@mock.patch.object(db_api, 'share_network_update', mock.Mock())
@@ -600,7 +608,7 @@ class NeutronNetworkPluginTest(test.TestCase):
with test_utils.create_temp_config_with_opts(config_data):
self.assertRaises(exception.NetworkBadConfigurationException,
self.plugin._save_neutron_network_data,
self.fake_context, fake_share_network)
self.fake_context, fake_share_network_subnet)
@mock.patch.object(db_api, 'share_network_update', mock.Mock())
def test_save_neutron_network_data_multi_segment_without_cfg(self):
@@ -609,9 +617,9 @@ class NeutronNetworkPluginTest(test.TestCase):
self.assertRaises(exception.NetworkBadConfigurationException,
self.plugin._save_neutron_network_data,
self.fake_context, fake_share_network)
self.fake_context, fake_share_network_subnet)
@mock.patch.object(db_api, 'share_network_update', mock.Mock())
@mock.patch.object(db_api, 'share_network_subnet_update', mock.Mock())
def test_save_neutron_subnet_data(self):
neutron_subnet_info = fake_neutron_subnet
subnet_value = {
@@ -624,13 +632,13 @@ class NeutronNetworkPluginTest(test.TestCase):
'get_subnet',
mock.Mock(return_value=neutron_subnet_info)):
self.plugin._save_neutron_subnet_data(self.fake_context,
fake_share_network)
fake_share_network_subnet)
self.plugin.neutron_api.get_subnet.assert_called_once_with(
fake_share_network['neutron_subnet_id'])
self.plugin.db.share_network_update.assert_called_once_with(
fake_share_network_subnet['neutron_subnet_id'])
self.plugin.db.share_network_subnet_update.assert_called_once_with(
self.fake_context,
fake_share_network['id'],
fake_share_network_subnet['id'],
subnet_value)
def test_has_network_provider_extension_true(self):
@@ -757,13 +765,13 @@ class NeutronSingleNetworkPluginTest(test.TestCase):
'neutron_subnet_id': instance.subnet,
}
self.mock_object(
instance.db, 'share_network_update',
instance.db, 'share_network_subnet_update',
mock.Mock(return_value='foo'))
instance._update_share_network_net_data(
self.context, share_network_input)
instance.db.share_network_update.assert_called_once_with(
instance.db.share_network_subnet_update.assert_called_once_with(
self.context, share_network_input['id'], share_network_result)
@ddt.data(
@@ -793,23 +801,24 @@ class NeutronSingleNetworkPluginTest(test.TestCase):
fake_neutron_port, fake_neutron_port]
instance = self._get_neutron_network_plugin_instance()
share_server = 'fake_share_server'
share_network = 'fake_share_network'
share_network_upd = 'updated_fake_share_network'
share_network = {'id': 'fake_share_network'}
share_network_subnet = {'id': 'fake_share_network_subnet'}
share_network_subnet_upd = {'id': 'updated_fake_share_network_subnet'}
count = 2
device_owner = 'fake_device_owner'
self.mock_object(
instance, '_update_share_network_net_data',
mock.Mock(return_value=share_network_upd))
mock.Mock(return_value=share_network_subnet_upd))
instance.allocate_network(
self.context, share_server, share_network, count=count,
device_owner=device_owner)
self.context, share_server, share_network, share_network_subnet,
count=count, device_owner=device_owner)
instance._update_share_network_net_data.assert_called_once_with(
self.context, share_network)
self.context, share_network_subnet)
plugin.NeutronNetworkPlugin.allocate_network.assert_called_once_with(
self.context, share_server, share_network_upd, count=count,
device_owner=device_owner)
self.context, share_server, share_network,
share_network_subnet_upd, count=count, device_owner=device_owner)
def test_manage_network_allocations(self):
allocations = ['192.168.10.10', 'fd12::2000']
@@ -819,18 +828,20 @@ class NeutronSingleNetworkPluginTest(test.TestCase):
mock.Mock(return_value=['fd12::2000']))
self.mock_object(
instance, '_update_share_network_net_data',
mock.Mock(return_value=fake_share_network))
mock.Mock(return_value=fake_share_network_subnet))
result = instance.manage_network_allocations(
self.context, allocations, fake_share_server, fake_share_network)
self.context, allocations, fake_share_server, fake_share_network,
fake_share_network_subnet)
self.assertEqual(['fd12::2000'], result)
instance._update_share_network_net_data.assert_called_once_with(
self.context, fake_share_network)
self.context, fake_share_network_subnet)
parent.assert_called_once_with(
self.context, allocations, fake_share_server, fake_share_network)
self.context, allocations, fake_share_server, fake_share_network,
fake_share_network_subnet)
def test_manage_network_allocations_admin(self):
allocations = ['192.168.10.10', 'fd12::2000']
@@ -846,12 +857,14 @@ class NeutronSingleNetworkPluginTest(test.TestCase):
}
result = instance.manage_network_allocations(
self.context, allocations, fake_share_server, None)
self.context, allocations, fake_share_server,
share_network_subnet=share_network_dict)
self.assertEqual(['fd12::2000'], result)
parent.assert_called_once_with(
self.context, allocations, fake_share_server, share_network_dict)
self.context, allocations, fake_share_server, None,
share_network_dict)
@ddt.ddt
@@ -943,18 +956,19 @@ class NeutronBindNetworkPluginTest(test.TestCase):
self.fake_context,
fake_share_server,
fake_share_network,
fake_share_network_subnet,
allocation_info={'count': 1})
self.bind_plugin._has_provider_network_extension.assert_any_call()
save_nw_data.assert_called_once_with(self.fake_context,
fake_share_network)
fake_share_network_subnet)
save_subnet_data.assert_called_once_with(self.fake_context,
fake_share_network)
fake_share_network_subnet)
expected_kwargs = {
'binding:vnic_type': 'baremetal',
'host_id': 'foohost1',
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'network_id': fake_share_network_subnet['neutron_net_id'],
'subnet_id': fake_share_network_subnet['neutron_subnet_id'],
'device_owner': 'manila:share',
'device_id': fake_share_network['id'],
}
@@ -1020,13 +1034,14 @@ class NeutronBindNetworkPluginTest(test.TestCase):
self.mock_object(self.bind_plugin.neutron_api, 'get_subnet')
self.bind_plugin.neutron_api.get_subnet.return_value = (
fake_neutron_subnet)
self.mock_object(db_api, 'share_network_update')
self.mock_object(db_api, 'share_network_subnet_update')
with mock.patch.object(self.bind_plugin.neutron_api, 'create_port',
mock.Mock(return_value=fake_neutron_port)):
self.bind_plugin.allocate_network(
self.fake_context,
fake_share_server,
fake_share_network,
self.fake_share_network_multi,
allocation_info={'count': 1})
@@ -1044,7 +1059,7 @@ class NeutronBindNetworkPluginTest(test.TestCase):
db_api.network_allocation_create.assert_called_once_with(
self.fake_context,
fake_network_allocation_multi)
db_api.share_network_update.assert_called_with(
db_api.share_network_subnet_update.assert_called_with(
self.fake_context,
fake_share_network_multi['id'],
network_update_data)
@@ -1143,14 +1158,14 @@ class NeutronBindNetworkPluginTest(test.TestCase):
instance = self._get_neutron_network_plugin_instance(config_data)
create_args = instance._get_port_create_args(fake_share_server,
fake_share_network,
fake_share_network_subnet,
fake_device_owner)
expected_create_args = {
'binding:vnic_type': 'baremetal',
'host_id': fake_host_id,
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'network_id': fake_share_network_subnet['neutron_net_id'],
'subnet_id': fake_share_network_subnet['neutron_subnet_id'],
'device_owner': 'manila:' + fake_device_owner,
'device_id': fake_share_server['id']
}
@@ -1197,14 +1212,14 @@ class NeutronBindNetworkPluginTest(test.TestCase):
instance = self._get_neutron_network_plugin_instance(config_data)
create_args = instance._get_port_create_args(fake_share_server,
fake_share_network,
fake_share_network_subnet,
fake_device_owner)
expected_create_args = {
'binding:vnic_type': 'baremetal',
'host_id': fake_host_id,
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'network_id': fake_share_network_subnet['neutron_net_id'],
'subnet_id': fake_share_network_subnet['neutron_subnet_id'],
'device_owner': 'manila:' + fake_device_owner,
'device_id': fake_share_server['id']
}
@@ -1253,7 +1268,8 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
'port1', 'port2']
instance = self._get_neutron_network_plugin_instance()
share_server = 'fake_share_server'
share_network = {'neutron_net_id': {}}
share_network = {}
share_network_subnet = {'neutron_net_id': {}}
share_network_upd = {'neutron_net_id': {'upd': True}}
count = 2
device_owner = 'fake_device_owner'
@@ -1263,14 +1279,14 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
self.mock_object(instance, '_wait_for_ports_bind', mock.Mock())
instance.allocate_network(
self.context, share_server, share_network, count=count,
device_owner=device_owner)
self.context, share_server, share_network, share_network_subnet,
count=count, device_owner=device_owner)
instance._update_share_network_net_data.assert_called_once_with(
self.context, share_network)
self.context, share_network_subnet)
plugin.NeutronNetworkPlugin.allocate_network.assert_called_once_with(
self.context, share_server, share_network_upd, count=count,
device_owner=device_owner)
self.context, share_server, share_network, share_network_upd,
count=count, device_owner=device_owner)
instance._wait_for_ports_bind.assert_called_once_with(
['port1', 'port2'], share_server)
@@ -1360,7 +1376,7 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
def test___update_share_network_net_data_different_values_empty(self):
instance = self._get_neutron_single_network_plugin_instance()
share_network_input = {
share_network_subnet_input = {
'id': 'fake_share_network_id',
}
share_network_result = {
@@ -1368,14 +1384,15 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
'neutron_subnet_id': instance.subnet,
}
self.mock_object(
instance.db, 'share_network_update',
instance.db, 'share_network_subnet_update',
mock.Mock(return_value='foo'))
instance._update_share_network_net_data(
self.context, share_network_input)
self.context, share_network_subnet_input)
instance.db.share_network_update.assert_called_once_with(
self.context, share_network_input['id'], share_network_result)
instance.db.share_network_subnet_update.assert_called_once_with(
self.context, share_network_subnet_input['id'],
share_network_result)
@ddt.data(
{'n': 'fake_net_id', 's': 'bar'},
@@ -1464,18 +1481,19 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
self.fake_context,
fake_share_server,
fake_share_network,
fake_share_network_subnet,
allocation_info={'count': 1})
self.bind_plugin._has_provider_network_extension.assert_any_call()
save_nw_data.assert_called_once_with(self.fake_context,
fake_share_network)
fake_share_network_subnet)
save_subnet_data.assert_called_once_with(self.fake_context,
fake_share_network)
fake_share_network_subnet)
expected_kwargs = {
'binding:vnic_type': 'baremetal',
'host_id': 'foohost1',
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'network_id': fake_share_network_subnet['neutron_net_id'],
'subnet_id': fake_share_network_subnet['neutron_subnet_id'],
'device_owner': 'manila:share',
'device_id': fake_share_network['id'],
}
@@ -1575,14 +1593,14 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
instance = self._get_neutron_network_plugin_instance(config_data)
create_args = instance._get_port_create_args(fake_share_server,
fake_share_network,
fake_share_network_subnet,
fake_device_owner)
expected_create_args = {
'binding:vnic_type': 'baremetal',
'host_id': fake_host_id,
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'network_id': fake_share_network_subnet['neutron_net_id'],
'subnet_id': fake_share_network_subnet['neutron_subnet_id'],
'device_owner': 'manila:' + fake_device_owner,
'device_id': fake_share_server['id']
}
@@ -1629,14 +1647,14 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
instance = self._get_neutron_network_plugin_instance(config_data)
create_args = instance._get_port_create_args(fake_share_server,
fake_share_network,
fake_share_network_subnet,
fake_device_owner)
expected_create_args = {
'binding:vnic_type': 'baremetal',
'host_id': fake_host_id,
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'network_id': fake_share_network_subnet['neutron_net_id'],
'subnet_id': fake_share_network_subnet['neutron_subnet_id'],
'device_owner': 'manila:' + fake_device_owner,
'device_id': fake_share_server['id']
}
@@ -1690,20 +1708,21 @@ class NeutronBindNetworkPluginWithNormalTypeTest(test.TestCase):
self.fake_context,
fake_share_server,
fake_share_network,
fake_share_network_subnet,
allocation_info={'count': 1})
self.bind_plugin._has_provider_network_extension.assert_any_call()
save_nw_data.assert_called_once_with(self.fake_context,
fake_share_network)
fake_share_network_subnet)
save_subnet_data.assert_called_once_with(self.fake_context,
fake_share_network)
fake_share_network_subnet)
expected_kwargs = {
'binding:vnic_type': 'normal',
'host_id': 'foohost1',
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'network_id': fake_share_network_subnet['neutron_net_id'],
'subnet_id': fake_share_network_subnet['neutron_subnet_id'],
'device_owner': 'manila:share',
'device_id': fake_share_network['id'],
'device_id': fake_share_server['id'],
}
self.bind_plugin.neutron_api.create_port.assert_called_once_with(
fake_share_network['project_id'], **expected_kwargs)
@@ -1776,18 +1795,19 @@ class NeutronBindSingleNetworkPluginWithNormalTypeTest(test.TestCase):
self.fake_context,
fake_share_server,
fake_share_network,
fake_share_network_subnet,
allocation_info={'count': 1})
self.bind_plugin._has_provider_network_extension.assert_any_call()
save_nw_data.assert_called_once_with(self.fake_context,
fake_share_network)
fake_share_network_subnet)
save_subnet_data.assert_called_once_with(self.fake_context,
fake_share_network)
fake_share_network_subnet)
expected_kwargs = {
'binding:vnic_type': 'normal',
'host_id': 'foohost1',
'network_id': fake_share_network['neutron_net_id'],
'subnet_id': fake_share_network['neutron_subnet_id'],
'network_id': fake_share_network_subnet['neutron_net_id'],
'subnet_id': fake_share_network_subnet['neutron_subnet_id'],
'device_owner': 'manila:share',
'device_id': fake_share_network['id'],
}
@@ -32,6 +32,7 @@ fake_context = context.RequestContext(
user_id='fake user', project_id='fake project', is_admin=False)
fake_share_server = dict(id='fake_share_server_id')
fake_share_network = dict(id='fake_share_network_id')
fake_share_network_subnet = dict(id='fake_share_network_subnet_id')
@ddt.ddt
@@ -305,14 +306,15 @@ class StandaloneNetworkPluginTest(test.TestCase):
}
with test_utils.create_temp_config_with_opts(data):
instance = plugin.StandaloneNetworkPlugin()
self.mock_object(instance.db, 'share_network_update')
self.mock_object(instance.db, 'share_network_subnet_update')
allocations = instance.allocate_network(
fake_context, fake_share_server, fake_share_network, count=0)
fake_context, fake_share_server, fake_share_network,
fake_share_network_subnet, count=0)
self.assertEqual([], allocations)
instance.db.share_network_update.assert_called_once_with(
fake_context, fake_share_network['id'],
instance.db.share_network_subnet_update.assert_called_once_with(
fake_context, fake_share_network_subnet['id'],
dict(network_type=None, segmentation_id=None,
cidr=six.text_type(instance.net.cidr),
gateway=six.text_type(instance.gateway),
@@ -329,14 +331,15 @@ class StandaloneNetworkPluginTest(test.TestCase):
}
with test_utils.create_temp_config_with_opts(data):
instance = plugin.StandaloneNetworkPlugin()
self.mock_object(instance.db, 'share_network_update')
self.mock_object(instance.db, 'share_network_subnet_update')
allocations = instance.allocate_network(
fake_context, fake_share_server, fake_share_network, count=0)
fake_context, fake_share_server, fake_share_network,
fake_share_network_subnet, count=0)
self.assertEqual([], allocations)
instance.db.share_network_update.assert_called_once_with(
fake_context, fake_share_network['id'],
instance.db.share_network_subnet_update.assert_called_once_with(
fake_context, fake_share_network_subnet['id'],
dict(network_type=None, segmentation_id=None,
cidr=six.text_type(instance.net.cidr),
gateway=six.text_type(instance.gateway),
@@ -354,14 +357,15 @@ class StandaloneNetworkPluginTest(test.TestCase):
}
with test_utils.create_temp_config_with_opts(data):
instance = plugin.StandaloneNetworkPlugin()
self.mock_object(instance.db, 'share_network_update')
self.mock_object(instance.db, 'share_network_subnet_update')
self.mock_object(instance.db, 'network_allocation_create')
self.mock_object(
instance.db, 'network_allocations_get_by_ip_address',
mock.Mock(return_value=[]))
allocations = instance.allocate_network(
fake_context, fake_share_server, fake_share_network)
fake_context, fake_share_server, fake_share_network,
fake_share_network_subnet)
self.assertEqual(1, len(allocations))
na_data = {
@@ -372,8 +376,8 @@ class StandaloneNetworkPluginTest(test.TestCase):
'ip_version': 4,
'mtu': 1500,
}
instance.db.share_network_update.assert_called_once_with(
fake_context, fake_share_network['id'], na_data)
instance.db.share_network_subnet_update.assert_called_once_with(
fake_context, fake_share_network_subnet['id'], na_data)
instance.db.network_allocations_get_by_ip_address.assert_has_calls(
[mock.call(fake_context, '10.0.0.2')])
instance.db.network_allocation_create.assert_called_once_with(
@@ -400,14 +404,15 @@ class StandaloneNetworkPluginTest(test.TestCase):
}
with test_utils.create_temp_config_with_opts(data):
instance = plugin.StandaloneNetworkPlugin()
self.mock_object(instance.db, 'share_network_update')
self.mock_object(instance.db, 'share_network_subnet_update')
self.mock_object(instance.db, 'network_allocation_create')
self.mock_object(
instance.db, 'network_allocations_get_by_ip_address',
mock.Mock(side_effect=fake_get_allocations_by_ip_address))
allocations = instance.allocate_network(
ctxt, fake_share_server, fake_share_network, count=2)
ctxt, fake_share_server, fake_share_network,
fake_share_network_subnet, count=2)
self.assertEqual(2, len(allocations))
na_data = {
@@ -418,8 +423,8 @@ class StandaloneNetworkPluginTest(test.TestCase):
'ip_version': 4,
'mtu': 1500,
}
instance.db.share_network_update.assert_called_once_with(
ctxt, fake_share_network['id'], dict(**na_data))
instance.db.share_network_subnet_update.assert_called_once_with(
ctxt, fake_share_network_subnet['id'], dict(**na_data))
instance.db.network_allocations_get_by_ip_address.assert_has_calls(
[mock.call(ctxt, '10.0.0.2'), mock.call(ctxt, '10.0.0.3'),
mock.call(ctxt, '10.0.0.4'), mock.call(ctxt, '10.0.0.5')])
@@ -445,7 +450,7 @@ class StandaloneNetworkPluginTest(test.TestCase):
}
with test_utils.create_temp_config_with_opts(data):
instance = plugin.StandaloneNetworkPlugin()
self.mock_object(instance.db, 'share_network_update')
self.mock_object(instance.db, 'share_network_subnet_update')
self.mock_object(instance.db, 'network_allocation_create')
self.mock_object(
instance.db, 'network_allocations_get_by_ip_address',
@@ -454,10 +459,11 @@ class StandaloneNetworkPluginTest(test.TestCase):
self.assertRaises(
exception.NetworkBadConfigurationException,
instance.allocate_network,
fake_context, fake_share_server, fake_share_network)
fake_context, fake_share_server, fake_share_network,
fake_share_network_subnet)
instance.db.share_network_update.assert_called_once_with(
fake_context, fake_share_network['id'],
instance.db.share_network_subnet_update.assert_called_once_with(
fake_context, fake_share_network_subnet['id'],
dict(network_type=None, segmentation_id=None,
cidr=six.text_type(instance.net.cidr),
gateway=six.text_type(instance.gateway),
@@ -484,12 +490,13 @@ class StandaloneNetworkPluginTest(test.TestCase):
instance = self._setup_manage_network_allocations(label=label)
if not label:
self.mock_object(instance, '_verify_share_network')
self.mock_object(instance.db, 'share_network_update')
self.mock_object(instance, '_verify_share_network_subnet')
self.mock_object(instance.db, 'share_network_subnet_update')
self.mock_object(instance.db, 'network_allocation_create')
result = instance.manage_network_allocations(
fake_context, allocations, fake_share_server, fake_share_network)
fake_context, allocations, fake_share_server,
fake_share_network, fake_share_network_subnet)
self.assertEqual(['fd12::2000'], result)
@@ -513,10 +520,10 @@ class StandaloneNetworkPluginTest(test.TestCase):
data_list[1].update(network_data)
if not label:
instance.db.share_network_update.assert_called_once_with(
fake_context, fake_share_network['id'], network_data)
instance._verify_share_network.assert_called_once_with(
fake_share_server['id'], fake_share_network)
instance.db.share_network_subnet_update.assert_called_once_with(
fake_context, fake_share_network_subnet['id'], network_data)
instance._verify_share_network_subnet.assert_called_once_with(
fake_share_server['id'], fake_share_network_subnet)
instance.db.network_allocation_create.assert_has_calls([
mock.call(fake_context, data_list[0]),
+355 -14
View File
@@ -683,6 +683,128 @@ class ShareAPITestCase(test.TestCase):
self.assertSubDictMatch(share_data,
db_api.share_create.call_args[0][1])
@ddt.data(
{'get_all_azs_return': [], 'subnet_by_az_side_effect': []},
{'get_all_azs_return': [{'name': 'az1', 'id': 'az_id_1'}],
'subnet_by_az_side_effect': [None]},
{'get_all_azs_return': [{'name': 'az1', 'id': 'az_id_1'}],
'subnet_by_az_side_effect': ['fake_sns_1']},
{'get_all_azs_return': [{'name': 'az1', 'id': 'az_id_1'},
{'name': 'az2', 'id': 'az_id_2'}],
'subnet_by_az_side_effect': [None, 'fake_sns_2']}
)
@ddt.unpack
def test__get_all_availability_zones_with_subnets(
self, get_all_azs_return, subnet_by_az_side_effect):
fake_share_network_id = 'fake_sn_id'
self.mock_object(db_api, 'availability_zone_get_all',
mock.Mock(return_value=get_all_azs_return))
self.mock_object(db_api,
'share_network_subnet_get_by_availability_zone_id',
mock.Mock(side_effect=subnet_by_az_side_effect))
expected_az_names = []
expected_get_az_calls = []
for index, value in enumerate(get_all_azs_return):
expected_get_az_calls.append(mock.call(
self.context, share_network_id=fake_share_network_id,
availability_zone_id=value['id']))
if subnet_by_az_side_effect[index] is not None:
expected_az_names.append(value['name'])
get_all_subnets = self.api._get_all_availability_zones_with_subnets
compatible_azs = get_all_subnets(self.context, fake_share_network_id)
db_api.availability_zone_get_all.assert_called_once_with(
self.context)
db_get_azs_with_subnet = (
db_api.share_network_subnet_get_by_availability_zone_id)
db_get_azs_with_subnet.assert_has_calls(expected_get_az_calls)
self.assertEqual(expected_az_names, compatible_azs)
@ddt.data(
{'availability_zones': None, 'azs_with_subnet': ['fake_az_1']},
{'availability_zones': ['fake_az_2'],
'azs_with_subnet': ['fake_az_2']},
{'availability_zones': ['fake_az_1', 'faze_az_2', 'fake_az_3'],
'azs_with_subnet': ['fake_az_3']}
)
@ddt.unpack
def test_create_share_with_subnets(self, availability_zones,
azs_with_subnet):
share, share_data = self._setup_create_mocks()
reservation = 'fake'
self.mock_object(quota.QUOTAS, 'reserve',
mock.Mock(return_value=reservation))
self.mock_object(self.api, '_get_all_availability_zones_with_subnets',
mock.Mock(return_value=azs_with_subnet))
self.mock_object(quota.QUOTAS, 'commit')
self.mock_object(self.api, 'create_instance')
self.mock_object(db_api, 'share_get')
fake_share_network_id = 'fake_sn_id'
if availability_zones:
expected_azs = (
[az for az in availability_zones if az in azs_with_subnet])
else:
expected_azs = azs_with_subnet
self.api.create(
self.context,
share_data['share_proto'],
share_data['size'],
share_data['display_name'],
share_data['display_description'],
share_network_id=fake_share_network_id,
availability_zones=availability_zones)
share['status'] = constants.STATUS_CREATING
share['host'] = None
quota.QUOTAS.reserve.assert_called_once()
get_all_azs_sns = self.api._get_all_availability_zones_with_subnets
get_all_azs_sns.assert_called_once_with(
self.context, fake_share_network_id)
quota.QUOTAS.commit.assert_called_once()
self.api.create_instance.assert_called_once_with(
self.context, share, share_network_id=fake_share_network_id,
host=None, availability_zone=None, share_group=None,
share_group_snapshot_member=None, share_type_id=None,
availability_zones=expected_azs
)
db_api.share_get.assert_called_once()
@ddt.data(
{'availability_zones': None, 'azs_with_subnet': []},
{'availability_zones': ['fake_az_1'],
'azs_with_subnet': ['fake_az_2']}
)
@ddt.unpack
def test_create_share_with_subnets_invalid_azs(self, availability_zones,
azs_with_subnet):
share, share_data = self._setup_create_mocks()
reservation = 'fake'
self.mock_object(quota.QUOTAS, 'reserve',
mock.Mock(return_value=reservation))
self.mock_object(self.api, '_get_all_availability_zones_with_subnets',
mock.Mock(return_value=azs_with_subnet))
self.mock_object(quota.QUOTAS, 'commit')
self.mock_object(self.api, 'create_instance')
self.mock_object(db_api, 'share_get')
fake_share_network_id = 'fake_sn_id'
self.assertRaises(
exception.InvalidInput,
self.api.create,
self.context, share_data['share_proto'], share_data['size'],
share_data['display_name'], share_data['display_description'],
share_network_id=fake_share_network_id,
availability_zones=availability_zones)
quota.QUOTAS.reserve.assert_called_once()
get_all_azs_sns = self.api._get_all_availability_zones_with_subnets
get_all_azs_sns.assert_called_once_with(
self.context, fake_share_network_id)
@ddt.data(
None, '', 'fake', 'nfsfake', 'cifsfake', 'glusterfsfake', 'hdfsfake')
def test_create_share_invalid_protocol(self, proto):
@@ -868,17 +990,31 @@ class ShareAPITestCase(test.TestCase):
self.api.get_share_attributes_from_share_type,
share_type)
@ddt.data('dr', 'readable', None)
def test_manage_new(self, replication_type):
@ddt.data(
{'replication_type': 'dr', 'dhss': False, 'share_server_id': None},
{'replication_type': 'readable', 'dhss': False,
'share_server_id': None},
{'replication_type': None, 'dhss': False, 'share_server_id': None},
{'replication_type': None, 'dhss': True, 'share_server_id': 'fake'}
)
@ddt.unpack
def test_manage_new(self, replication_type, dhss, share_server_id):
share_data = {
'host': 'fake',
'export_location': 'fake',
'share_proto': 'fake',
'share_type_id': 'fake',
}
if dhss:
share_data['share_server_id'] = share_server_id