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 2019-05-08 14:49:51 -03:00 committed by Douglas Viroel
parent 523c5aaa3a
commit 14d3e268a0
49 changed files with 3677 additions and 647 deletions

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."""

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

View File

@ -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.

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):

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)

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')

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",

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())

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:

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,

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():

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

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')

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):

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)

View File

@ -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

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'

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)

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.")

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

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)

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)

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(),

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

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,

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):

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,
)
)

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:

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',

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):

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()])

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',

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()

View File

@ -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'])

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)

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'))

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'])

View File

@ -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)

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

View File

@ -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)

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)

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 = {

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',

View File

@ -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'],
}

View File

@ -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]),

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
driver_options = {}
date = datetime.datetime(1, 1, 1, 1, 1, 1)
timeutils.utcnow.return_value = date
fake_subnet = db_utils.create_share_network_subnet(
share_network_id='fake')
share_server = db_utils.create_share_server(
status=constants.STATUS_ACTIVE, id=share_server_id,
share_network_subnet_id=fake_subnet['id'])
fake_share_data = {
'id': 'fakeid',
'status': constants.STATUS_CREATING,
@ -891,7 +1027,7 @@ class ShareAPITestCase(test.TestCase):
'create_share_from_snapshot_support': False,
'revert_to_snapshot_support': False,
'mount_snapshot_support': False,
'driver_handles_share_servers': False,
'driver_handles_share_servers': dhss,
},
}
@ -905,6 +1041,10 @@ class ShareAPITestCase(test.TestCase):
mock.Mock(return_value=share))
self.mock_object(share_types, 'get_share_type',
mock.Mock(return_value=fake_type))
self.mock_object(db_api, 'share_server_get',
mock.Mock(return_value=share_server))
self.mock_object(db_api, 'share_network_subnet_get',
mock.Mock(return_value=fake_subnet))
self.mock_object(self.api, 'get_all', mock.Mock(return_value=[]))
self.api.manage(self.context, copy.deepcopy(share_data),
@ -929,6 +1069,9 @@ class ShareAPITestCase(test.TestCase):
share, fake_type, size=0, share_proto=share_data['share_proto'],
host=share_data['host'])
if dhss:
share_data.update({
'share_network_id': fake_subnet['share_network_id']})
export_location = share_data.pop('export_location')
self.api.get_all.assert_called_once_with(self.context, mock.ANY)
db_api.share_create.assert_called_once_with(self.context, share_data)
@ -938,6 +1081,11 @@ class ShareAPITestCase(test.TestCase):
)
self.scheduler_rpcapi.manage_share.assert_called_once_with(
self.context, share['id'], driver_options, expected_request_spec)
if dhss:
db_api.share_server_get.assert_called_once_with(
self.context, share_data['share_server_id'])
db_api.share_network_subnet_get.assert_called_once_with(
self.context, share_server['share_network_subnet_id'])
@ddt.data((True, exception.InvalidInput, True),
(True, exception.InvalidInput, False),
@ -1387,10 +1535,14 @@ class ShareAPITestCase(test.TestCase):
fake_share_network = {
'id': 'fake_net_id'
}
fake_share_net_subnet = {
'id': 'fake_subnet_id',
'share_network_id': fake_share_network['id']
}
identifier = 'fake_identifier'
values = {
'host': host,
'share_network_id': fake_share_network['id'],
'share_network_subnet_id': fake_share_net_subnet['id'],
'status': constants.STATUS_MANAGING,
'is_auto_deletable': False,
'identifier': identifier,
@ -1400,7 +1552,7 @@ class ShareAPITestCase(test.TestCase):
'id': 'fake_server_id',
'status': constants.STATUS_MANAGING,
'host': host,
'share_network_id': fake_share_network['id'],
'share_network_subnet_id': fake_share_net_subnet['id'],
'is_auto_deletable': False,
'identifier': identifier,
}
@ -1419,7 +1571,7 @@ class ShareAPITestCase(test.TestCase):
mock.Mock(return_value=server_managing)
)
result = self.api.manage_share_server(
self.context, 'fake_identifier', host, fake_share_network,
self.context, 'fake_identifier', host, fake_share_net_subnet,
{'opt1': 'val1', 'opt2': 'val2'}
)
@ -1434,7 +1586,7 @@ class ShareAPITestCase(test.TestCase):
result_dict = {
'host': result['host'],
'share_network_id': result['share_network_id'],
'share_network_subnet_id': result['share_network_subnet_id'],
'status': result['status'],
'is_auto_deletable': result['is_auto_deletable'],
'identifier': result['identifier'],
@ -3273,26 +3425,211 @@ class ShareAPITestCase(test.TestCase):
self.assertFalse(mock_db_update_call.called)
self.assertFalse(mock_scheduler_rpcapi_call.called)
def test_create_share_replica_subnet_not_found(self):
request_spec = fakes.fake_replica_request_spec()
replica = request_spec['share_instance_properties']
extra_specs = {
'availability_zones': 'FAKE_AZ,FAKE_AZ2',
'replication_type': constants.REPLICATION_TYPE_DR
}
share_type = db_utils.create_share_type(extra_specs=extra_specs)
share_type = db_api.share_type_get(self.context, share_type['id'])
az_name = 'FAKE_AZ'
share = db_utils.create_share(
id=replica['share_id'], replication_type='dr')
self.mock_object(db_api, 'share_replicas_get_available_active_replica',
mock.Mock(return_value=mock.Mock(
return_value={'host': 'fake_ar_host'})))
self.mock_object(share_types, 'get_share_type',
mock.Mock(return_value=share_type))
self.mock_object(db_api, 'availability_zone_get')
self.mock_object(db_api,
'share_network_subnet_get_by_availability_zone_id',
mock.Mock(return_value=None))
self.assertRaises(exception.InvalidShare,
self.api.create_share_replica,
self.context,
share,
availability_zone=az_name,
share_network_id='fake_id')
(db_api.share_replicas_get_available_active_replica
.assert_called_once_with(self.context, share['id']))
self.assertTrue(share_types.get_share_type.called)
db_api.availability_zone_get.assert_called_once_with(
self.context, az_name)
self.assertTrue(
db_api.share_network_subnet_get_by_availability_zone_id.called)
def test_create_share_replica_az_not_found(self):
request_spec = fakes.fake_replica_request_spec()
replica = request_spec['share_instance_properties']
extra_specs = {
'availability_zones': 'FAKE_AZ,FAKE_AZ2',
'replication_type': constants.REPLICATION_TYPE_DR
}
share_type = db_utils.create_share_type(extra_specs=extra_specs)
share_type = db_api.share_type_get(self.context, share_type['id'])
az_name = 'FAKE_AZ'
share = db_utils.create_share(
id=replica['share_id'], replication_type='dr')
self.mock_object(db_api, 'share_replicas_get_available_active_replica',
mock.Mock(return_value=mock.Mock(
return_value={'host': 'fake_ar_host'})))
self.mock_object(share_types, 'get_share_type',
mock.Mock(return_value=share_type))
side_effect = exception.AvailabilityZoneNotFound(id=az_name)
self.mock_object(db_api, 'availability_zone_get',
mock.Mock(side_effect=side_effect))
self.assertRaises(exception.InvalidInput,
self.api.create_share_replica,
self.context,
share,
availability_zone=az_name,
share_network_id='fake_id')
(db_api.share_replicas_get_available_active_replica
.assert_called_once_with(self.context, share['id']))
self.assertTrue(share_types.get_share_type.called)
db_api.availability_zone_get.assert_called_once_with(
self.context, az_name)
@ddt.data(
{'availability_zones': '', 'azs_with_subnet': ['fake_az_1']},
{'availability_zones': 'fake_az_1,fake_az_2',
'azs_with_subnet': ['fake_az_2']}
)
@ddt.unpack
def test_create_share_replica_azs_with_subnets(self, availability_zones,
azs_with_subnet):
request_spec = fakes.fake_replica_request_spec()
replica = request_spec['share_instance_properties']
share_network_id = 'fake_share_network_id'
extra_specs = {
'availability_zones': availability_zones,
'replication_type': constants.REPLICATION_TYPE_DR
}
share_type = db_utils.create_share_type(extra_specs=extra_specs)
share_type = db_api.share_type_get(self.context, share_type['id'])
share = db_utils.create_share(
id=replica['share_id'], replication_type='dr',
share_type_id=share_type['id'])
cast_rules_to_readonly = (
share['replication_type'] == constants.REPLICATION_TYPE_READABLE)
fake_replica = fakes.fake_replica(id=replica['id'])
fake_request_spec = fakes.fake_replica_request_spec()
self.mock_object(db_api, 'share_replicas_get_available_active_replica',
mock.Mock(return_value={'host': 'fake_ar_host'}))
self.mock_object(share_types, 'get_share_type',
mock.Mock(return_value=share_type))
mock_get_all_az_subnet = self.mock_object(
self.api, '_get_all_availability_zones_with_subnets',
mock.Mock(return_value=azs_with_subnet))
if availability_zones == '':
expected_azs = azs_with_subnet
else:
availability_zones = [
t for t in availability_zones.split(',') if availability_zones]
expected_azs = (
[az for az in availability_zones if az in azs_with_subnet])
self.mock_object(
self.api, 'create_share_instance_and_get_request_spec',
mock.Mock(return_value=(fake_request_spec, fake_replica)))
self.mock_object(db_api, 'share_replica_update')
mock_snapshot_get_all_call = self.mock_object(
db_api, 'share_snapshot_get_all_for_share',
mock.Mock(return_value=[]))
mock_sched_rpcapi_call = self.mock_object(
self.api.scheduler_rpcapi, 'create_share_replica')
self.api.create_share_replica(
self.context, share, share_network_id=share_network_id)
(db_api.share_replicas_get_available_active_replica
.assert_called_once_with(self.context, share['id']))
self.assertTrue(share_types.get_share_type.called)
mock_get_all_az_subnet.assert_called_once_with(
self.context, share_network_id
)
(self.api.create_share_instance_and_get_request_spec.
assert_called_once_with(
self.context, share, availability_zone=None,
share_network_id=share_network_id, share_type_id=share_type['id'],
availability_zones=expected_azs,
cast_rules_to_readonly=cast_rules_to_readonly))
db_api.share_replica_update.assert_called_once()
mock_snapshot_get_all_call.assert_called_once()
mock_sched_rpcapi_call.assert_called_once()
@ddt.data(
{'availability_zones': '', 'azs_with_subnet': []},
{'availability_zones': 'fake_az_1,fake_az_2',
'azs_with_subnet': ['fake_az_3']}
)
@ddt.unpack
def test_create_share_replica_azs_with_subnets_invalid_input(
self, availability_zones, azs_with_subnet):
request_spec = fakes.fake_replica_request_spec()
replica = request_spec['share_instance_properties']
share_network_id = 'fake_share_network_id'
extra_specs = {
'availability_zones': availability_zones,
'replication_type': constants.REPLICATION_TYPE_DR
}
share_type = db_utils.create_share_type(extra_specs=extra_specs)
share_type = db_api.share_type_get(self.context, share_type['id'])
share = db_utils.create_share(
id=replica['share_id'], replication_type='dr',
share_type_id=share_type['id'])
self.mock_object(db_api, 'share_replicas_get_available_active_replica',
mock.Mock(return_value={'host': 'fake_ar_host'}))
self.mock_object(share_types, 'get_share_type',
mock.Mock(return_value=share_type))
mock_get_all_az_subnet = self.mock_object(
self.api, '_get_all_availability_zones_with_subnets',
mock.Mock(return_value=azs_with_subnet))
self.assertRaises(
exception.InvalidInput,
self.api.create_share_replica,
self.context, share, share_network_id=share_network_id)
(db_api.share_replicas_get_available_active_replica
.assert_called_once_with(self.context, share['id']))
self.assertTrue(share_types.get_share_type.called)
mock_get_all_az_subnet.assert_called_once_with(
self.context, share_network_id
)
@ddt.data({'has_snapshots': True,
'extra_specs': {
'replication_type': constants.REPLICATION_TYPE_DR,
}},
},
'share_network_id': None},
{'has_snapshots': False,
'extra_specs': {
'availability_zones': 'FAKE_AZ,FAKE_AZ2',
'replication_type': constants.REPLICATION_TYPE_DR,
}},
},
'share_network_id': None},
{'has_snapshots': True,
'extra_specs': {
'availability_zones': 'FAKE_AZ,FAKE_AZ2',
'replication_type': constants.REPLICATION_TYPE_READABLE,
}},
},
'share_network_id': None},
{'has_snapshots': False,
'extra_specs': {
'replication_type': constants.REPLICATION_TYPE_READABLE,
}})
},
'share_network_id': 'fake_sn_id'})
@ddt.unpack
def test_create_share_replica(self, has_snapshots, extra_specs):
def test_create_share_replica(self, has_snapshots, extra_specs,
share_network_id):
request_spec = fakes.fake_replica_request_spec()
replication_type = extra_specs['replication_type']
replica = request_spec['share_instance_properties']
@ -3314,6 +3651,9 @@ class ShareAPITestCase(test.TestCase):
mock.Mock(return_value={'host': 'fake_ar_host'}))
self.mock_object(share_types, 'get_share_type',
mock.Mock(return_value=share_type))
self.mock_object(db_api, 'availability_zone_get')
self.mock_object(db_api,
'share_network_subnet_get_by_availability_zone_id')
self.mock_object(
share_api.API, 'create_share_instance_and_get_request_spec',
mock.Mock(return_value=(fake_request_spec, fake_replica)))
@ -3328,7 +3668,8 @@ class ShareAPITestCase(test.TestCase):
expected_snap_instance_create_call_count = 2 if has_snapshots else 0
result = self.api.create_share_replica(
self.context, share, availability_zone='FAKE_AZ')
self.context, share, availability_zone='FAKE_AZ',
share_network_id=share_network_id)
self.assertTrue(mock_sched_rpcapi_call.called)
self.assertEqual(replica, result)
@ -3343,7 +3684,7 @@ class ShareAPITestCase(test.TestCase):
(share_api.API.create_share_instance_and_get_request_spec.
assert_called_once_with(
self.context, share, availability_zone='FAKE_AZ',
share_network_id=None, share_type_id=share_type['id'],
share_network_id=share_network_id, share_type_id=share_type['id'],
availability_zones=expected_azs,
cast_rules_to_readonly=cast_rules_to_readonly))

View File

@ -713,8 +713,10 @@ class ShareManagerTestCase(test.TestCase):
def test_create_share_instance_from_snapshot_with_server(self):
"""Test share can be created from snapshot if server exists."""
network = db_utils.create_share_network()
subnet = db_utils.create_share_network_subnet(
share_network_id=network['id'])
server = db_utils.create_share_server(
share_network_id=network['id'], host='fake_host',
share_network_subnet_id=subnet['id'], host='fake_host',
backend_details=dict(fake='fake'))
parent_share = db_utils.create_share(share_network_id='net-id',
share_server_id=server['id'])
@ -843,6 +845,9 @@ class ShareManagerTestCase(test.TestCase):
def test_create_share_replica_with_share_server_exception(self):
replica = fake_replica()
share_network_subnet = db_utils.create_share_network_subnet(
share_network_id=replica['share_network_id'],
availability_zone_id=replica['availability_zone_id'])
manager.CONF.set_default('driver_handles_share_servers', True)
self.mock_object(db, 'share_instance_access_copy',
mock.Mock(return_value=[]))
@ -850,6 +855,9 @@ class ShareManagerTestCase(test.TestCase):
mock.Mock(return_value=fake_replica(id='fake2')))
self.mock_object(db, 'share_replica_get',
mock.Mock(return_value=replica))
self.mock_object(db,
'share_network_subnet_get_by_availability_zone_id',
mock.Mock(return_value=share_network_subnet))
mock_replica_update_call = self.mock_object(db, 'share_replica_update')
mock_driver_replica_call = self.mock_object(
self.share_manager.driver, 'create_replica')
@ -871,7 +879,7 @@ class ShareManagerTestCase(test.TestCase):
def test_create_share_replica_driver_error_on_creation(self):
fake_access_rules = [{'id': '1'}, {'id': '2'}, {'id': '3'}]
replica = fake_replica(share_network_id='')
replica = fake_replica()
replica_2 = fake_replica(id='fake2')
self.mock_object(db, 'share_replica_get',
mock.Mock(return_value=replica))
@ -2038,13 +2046,16 @@ class ShareManagerTestCase(test.TestCase):
"""Test share can be created without share server."""
share_net = db_utils.create_share_network()
share_net_subnet = db_utils.create_share_network_subnet(
share_network_id=share_net['id'],
availability_zone_id=None,
)
share = db_utils.create_share(share_network_id=share_net['id'])
share_id = share['id']
def fake_setup_server(context, share_network, *args, **kwargs):
return db_utils.create_share_server(
share_network_id=share_network['id'],
share_network_subnet_id=share_net_subnet['id'],
host='fake_host')
self.mock_object(manager.LOG, 'info')
@ -2058,18 +2069,23 @@ class ShareManagerTestCase(test.TestCase):
manager.LOG.info.assert_called_with(mock.ANY, share.instance['id'])
def test_create_share_instance_with_share_network_server_fail(self):
fake_share = db_utils.create_share(share_network_id='fake_sn_id',
size=1)
fake_server = {
'id': 'fake_srv_id',
'status': constants.STATUS_CREATING,
}
share_network = db_utils.create_share_network(id='fake_sn_id')
share_net_subnet = db_utils.create_share_network_subnet(
id='fake_sns_id', share_network_id=share_network['id']
)
fake_share = db_utils.create_share(
share_network_id=share_network['id'], size=1)
fake_server = db_utils.create_share_server(
id='fake_srv_id', status=constants.STATUS_CREATING)
self.mock_object(db, 'share_server_create',
mock.Mock(return_value=fake_server))
self.mock_object(db, 'share_instance_update',
mock.Mock(return_value=fake_share.instance))
self.mock_object(db, 'share_instance_get',
mock.Mock(return_value=fake_share.instance))
self.mock_object(db,
'share_network_subnet_get_by_availability_zone_id',
mock.Mock(return_value=share_net_subnet))
self.mock_object(manager.LOG, 'error')
def raise_share_server_not_found(*args, **kwargs):
@ -2119,7 +2135,7 @@ class ShareManagerTestCase(test.TestCase):
resource_id=fake_share['id'],
detail=message_field.Detail.NO_SHARE_SERVER)
def test_create_share_instance_with_share_network_not_found(self):
def test_create_share_instance_with_share_network_subnet_not_found(self):
"""Test creation fails if share network not found."""
self.mock_object(manager.LOG, 'error')
@ -2127,7 +2143,7 @@ class ShareManagerTestCase(test.TestCase):
share = db_utils.create_share(share_network_id='fake-net-id')
share_id = share['id']
self.assertRaises(
exception.ShareNetworkNotFound,
exception.ShareNetworkSubnetNotFound,
self.share_manager.create_share_instance,
self.context,
share.instance['id']
@ -2146,9 +2162,14 @@ class ShareManagerTestCase(test.TestCase):
def test_create_share_instance_with_share_network_server_exists(self):
"""Test share can be created with existing share server."""
share_net = db_utils.create_share_network()
share_net_subnet = db_utils.create_share_network_subnet(
share_network_id=share_net['id'],
availability_zone_id=None,
)
share = db_utils.create_share(share_network_id=share_net['id'])
share_srv = db_utils.create_share_server(
share_network_id=share_net['id'], host=self.share_manager.host)
share_network_subnet_id=share_net_subnet['id'],
host=self.share_manager.host)
share_id = share['id']
@ -2201,9 +2222,14 @@ class ShareManagerTestCase(test.TestCase):
def test_create_share_instance_with_server_created(self):
"""Test share can be created and share server is created."""
share_net = db_utils.create_share_network()
share = db_utils.create_share(share_network_id=share_net['id'])
share_net_subnet = db_utils.create_share_network_subnet(
share_network_id=share_net['id'],
availability_zone_id=None)
share = db_utils.create_share(share_network_id=share_net['id'],
availability_zone=None)
db_utils.create_share_server(
share_network_id=share_net['id'], host=self.share_manager.host,
share_network_subnet_id=share_net_subnet['id'],
host=self.share_manager.host,
status=constants.STATUS_ERROR)
share_id = share['id']
fake_server = {
@ -2231,11 +2257,16 @@ class ShareManagerTestCase(test.TestCase):
def test_create_share_instance_update_replica_state(self):
share_net = db_utils.create_share_network()
share_net_subnet = db_utils.create_share_network_subnet(
share_network_id=share_net['id'],
availability_zone_id=None
)
share = db_utils.create_share(share_network_id=share_net['id'],
replication_type='dr')
replication_type='dr',
availability_zone=None)
db_utils.create_share_server(
share_network_id=share_net['id'], host=self.share_manager.host,
status=constants.STATUS_ERROR)
share_network_subnet_id=share_net_subnet['id'],
host=self.share_manager.host, status=constants.STATUS_ERROR)
share_id = share['id']
fake_server = {
'id': 'fake_srv_id',
@ -2344,9 +2375,16 @@ class ShareManagerTestCase(test.TestCase):
def test_provide_share_server_for_share_incompatible_servers(self):
fake_exception = exception.ManilaException("fake")
fake_share_server = {'id': 'fake'}
fake_share_network = db_utils.create_share_network(id='fake_sn_id')
fake_share_net_subnet = db_utils.create_share_network_subnet(
id='fake_sns_id', share_network_id=fake_share_network['id']
)
fake_share_server = db_utils.create_share_server(id='fake')
share = db_utils.create_share()
db_method_mock = self.mock_object(
db, 'share_network_subnet_get_by_availability_zone_id',
mock.Mock(return_value=fake_share_net_subnet))
self.mock_object(db,
'share_server_get_all_by_host_and_share_net_valid',
mock.Mock(return_value=[fake_share_server]))
@ -2358,7 +2396,13 @@ class ShareManagerTestCase(test.TestCase):
self.assertRaises(exception.ManilaException,
self.share_manager._provide_share_server_for_share,
self.context, "fake_id", share.instance)
self.context, fake_share_network['id'],
share.instance)
db_method_mock.assert_called_once_with(
self.context, fake_share_network['id'],
availability_zone_id=share.instance.get('availability_zone_id')
)
driver_mock = self.share_manager.driver
driver_method_mock = (
driver_mock.choose_share_server_compatible_with_share
@ -2374,6 +2418,7 @@ class ShareManagerTestCase(test.TestCase):
def test_provide_share_server_for_share_parent_ss_not_found(self):
fake_parent_id = "fake_server_id"
fake_share_network = db_utils.create_share_network(id='fake_sn_id')
fake_exception = exception.ShareServerNotFound("fake")
share = db_utils.create_share()
fake_snapshot = {
@ -2388,14 +2433,15 @@ class ShareManagerTestCase(test.TestCase):
self.assertRaises(exception.ShareServerNotFound,
self.share_manager._provide_share_server_for_share,
self.context, "fake_id", share.instance,
snapshot=fake_snapshot)
self.context, fake_share_network['id'],
share.instance, snapshot=fake_snapshot)
db.share_server_get.assert_called_once_with(
self.context, fake_parent_id)
def test_provide_share_server_for_share_parent_ss_invalid(self):
fake_parent_id = "fake_server_id"
fake_share_network = db_utils.create_share_network(id='fake_sn_id')
share = db_utils.create_share()
fake_snapshot = {
'share': {
@ -2410,8 +2456,8 @@ class ShareManagerTestCase(test.TestCase):
self.assertRaises(exception.InvalidShareServer,
self.share_manager._provide_share_server_for_share,
self.context, "fake_id", share.instance,
snapshot=fake_snapshot)
self.context, fake_share_network['id'],
share.instance, snapshot=fake_snapshot)
db.share_server_get.assert_called_once_with(
self.context, fake_parent_id)
@ -2433,7 +2479,7 @@ class ShareManagerTestCase(test.TestCase):
self.assertRaises(
exception.ManilaException,
self.share_manager._provide_share_server_for_share_group,
self.context, "fake_id", sg)
self.context, "fake_sn_id", "fake_sns_id", sg)
driver_mock = self.share_manager.driver
driver_method_mock = (
@ -2445,7 +2491,7 @@ class ShareManagerTestCase(test.TestCase):
self.assertRaises(
exception.InvalidInput,
self.share_manager._provide_share_server_for_share_group,
self.context, None, None)
self.context, None, None, None)
def test_manage_share_driver_exception(self):
self.mock_object(self.share_manager, 'driver')
@ -2951,12 +2997,13 @@ class ShareManagerTestCase(test.TestCase):
def test_setup_server(self):
# Setup required test data
share_server = {
'id': 'fake_id',
'share_network_id': 'fake_sn_id',
}
metadata = {'fake_metadata_key': 'fake_metadata_value'}
share_network = {'id': 'fake_sn_id'}
share_network = db_utils.create_share_network(id='fake_sn_id')
share_net_subnet = db_utils.create_share_network_subnet(
id='fake_sns_id', share_network_id=share_network['id']
)
share_server = db_utils.create_share_server(
id='fake_id', share_network_subnet_id=share_net_subnet['id'])
network_info = {'security_services': []}
for ss_type in constants.SECURITY_SERVICES_ALLOWED_TYPES:
network_info['security_services'].append({
@ -2974,6 +3021,8 @@ class ShareManagerTestCase(test.TestCase):
network_info['network_type'] = 'fake_network_type'
# mock required stuff
self.mock_object(self.share_manager.db, 'share_network_subnet_get',
mock.Mock(return_value=share_net_subnet))
self.mock_object(self.share_manager.db, 'share_network_get',
mock.Mock(return_value=share_network))
self.mock_object(self.share_manager.driver, 'allocate_network')
@ -2993,14 +3042,15 @@ class ShareManagerTestCase(test.TestCase):
# verify results
self.assertEqual(share_server, result)
self.share_manager.db.share_network_get.assert_has_calls([
mock.call(self.context, share_server['share_network_id']),
mock.call(self.context, share_server['share_network_id']),
])
self.share_manager.db.share_network_get.assert_called_once_with(
self.context, share_net_subnet['share_network_id'])
self.share_manager.db.share_network_subnet_get.assert_called_once_with(
self.context, share_server['share_network_subnet']['id'])
self.share_manager.driver.allocate_network.assert_called_once_with(
self.context, share_server, share_network)
self.context, share_server, share_network,
share_server['share_network_subnet'])
self.share_manager._form_server_setup_info.assert_called_once_with(
self.context, share_server, share_network)
self.context, share_server, share_network, share_net_subnet)
self.share_manager._validate_segmentation_id.assert_called_once_with(
network_info)
self.share_manager.driver.setup_server.assert_called_once_with(
@ -3025,12 +3075,14 @@ class ShareManagerTestCase(test.TestCase):
def test_setup_server_server_info_not_present(self):
# Setup required test data
share_server = {
'id': 'fake_id',
'share_network_id': 'fake_sn_id',
}
metadata = {'fake_metadata_key': 'fake_metadata_value'}
share_network = {'id': 'fake_sn_id'}
share_net_subnet = {'id': 'fake_sns_id',
'share_network_id': share_network['id']}
share_server = {
'id': 'fake_id',
'share_network_subnet': share_net_subnet,
}
network_info = {
'fake_network_info_key': 'fake_network_info_value',
'security_services': [],
@ -3039,6 +3091,8 @@ class ShareManagerTestCase(test.TestCase):
server_info = {}
# mock required stuff
self.mock_object(self.share_manager.db, 'share_network_subnet_get',
mock.Mock(return_value=share_net_subnet))
self.mock_object(self.share_manager.db, 'share_network_get',
mock.Mock(return_value=share_network))
self.mock_object(self.share_manager, '_form_server_setup_info',
@ -3055,11 +3109,12 @@ class ShareManagerTestCase(test.TestCase):
# verify results
self.assertEqual(share_server, result)
self.share_manager.db.share_network_get.assert_has_calls([
mock.call(self.context, share_server['share_network_id']),
mock.call(self.context, share_server['share_network_id'])])
self.share_manager.db.share_network_get.assert_called_once_with(
self.context, share_net_subnet['share_network_id'])
self.share_manager.db.share_network_subnet_get.assert_called_once_with(
self.context, share_server['share_network_subnet']['id'])
self.share_manager._form_server_setup_info.assert_called_once_with(
self.context, share_server, share_network)
self.context, share_server, share_network, share_net_subnet)
self.share_manager.driver.setup_server.assert_called_once_with(
network_info, metadata=metadata)
self.share_manager.db.share_server_update.assert_called_once_with(
@ -3067,16 +3122,18 @@ class ShareManagerTestCase(test.TestCase):
{'status': constants.STATUS_ACTIVE,
'identifier': share_server['id']})
self.share_manager.driver.allocate_network.assert_called_once_with(
self.context, share_server, share_network)
self.context, share_server, share_network, share_net_subnet)
def setup_server_raise_exception(self, detail_data_proper):
# Setup required test data
share_server = {
'id': 'fake_id',
'share_network_id': 'fake_sn_id',
}
server_info = {'details_key': 'value'}
share_network = {'id': 'fake_sn_id'}
share_net_subnet = {'id': 'fake_sns_id',
'share_network_id': share_network['id']}
share_server = {
'id': 'fake_id',
'share_network_subnet': share_net_subnet
}
network_info = {
'fake_network_info_key': 'fake_network_info_value',
'security_services': [],
@ -3092,6 +3149,8 @@ class ShareManagerTestCase(test.TestCase):
# Mock required parameters
self.mock_object(self.share_manager.db, 'share_network_get',
mock.Mock(return_value=share_network))
self.mock_object(self.share_manager.db, 'share_network_subnet_get',
mock.Mock(return_value=share_net_subnet))
self.mock_object(self.share_manager.db, 'share_server_update')
for m in ['deallocate_network', 'allocate_network']:
self.mock_object(self.share_manager.driver, m)
@ -3117,15 +3176,17 @@ class ShareManagerTestCase(test.TestCase):
assert_called_once_with(
self.context, share_server['id'], server_info))
self.share_manager._form_server_setup_info.assert_called_once_with(
self.context, share_server, share_network)
self.context, share_server, share_network, share_net_subnet)
self.share_manager.db.share_server_update.assert_called_once_with(
self.context, share_server['id'],
{'status': constants.STATUS_ERROR})
self.share_manager.db.share_network_get.assert_has_calls([
mock.call(self.context, share_server['share_network_id']),
mock.call(self.context, share_server['share_network_id'])])
self.share_manager.db.share_network_get.assert_called_once_with(
self.context, share_net_subnet['share_network_id'])
self.share_manager.db.share_network_subnet_get.assert_called_once_with(
self.context, share_server['share_network_subnet']['id'])
self.share_manager.driver.allocate_network.assert_has_calls([
mock.call(self.context, share_server, share_network)])
mock.call(self.context, share_server, share_network,
share_net_subnet)])
self.share_manager.driver.deallocate_network.assert_has_calls([
mock.call(self.context, share_server['id'])])
@ -3151,13 +3212,17 @@ class ShareManagerTestCase(test.TestCase):
if not isinstance(d, dict):
return {}
return d
share_server = {'id': 'fake', 'share_network_id': 'fake'}
share_net_subnet = db_utils.create_share_network_subnet(
id='fake_subnet_id', share_network_id='fake_share_net_id'
)
share_server = db_utils.create_share_server(
id='fake', share_network_subnet_id=share_net_subnet['id'])
details = get_server_details_from_data(data)
exc_mock = mock.Mock(side_effect=exception.ManilaException(**data))
details_mock = mock.Mock(side_effect=exception.ManilaException())
self.mock_object(self.share_manager.db, 'share_network_get', exc_mock)
self.mock_object(self.share_manager.db, 'share_network_get',
exc_mock)
self.mock_object(self.share_manager.db,
'share_server_backend_details_set', details_mock)
self.mock_object(self.share_manager.db, 'share_server_update')
@ -3242,28 +3307,31 @@ class ShareManagerTestCase(test.TestCase):
fake_share_server = dict(
id='fake_share_server_id', backend_details=dict(foo='bar'))
fake_share_network = dict(
security_services='fake_security_services'
)
fake_share_network_subnet = dict(
segmentation_id='fake_segmentation_id',
cidr='fake_cidr',
neutron_net_id='fake_neutron_net_id',
neutron_subnet_id='fake_neutron_subnet_id',
security_services='fake_security_services',
network_type='fake_network_type')
expected = dict(
server_id=fake_share_server['id'],
segmentation_id=fake_share_network['segmentation_id'],
cidr=fake_share_network['cidr'],
neutron_net_id=fake_share_network['neutron_net_id'],
neutron_subnet_id=fake_share_network['neutron_subnet_id'],
segmentation_id=fake_share_network_subnet['segmentation_id'],
cidr=fake_share_network_subnet['cidr'],
neutron_net_id=fake_share_network_subnet['neutron_net_id'],
neutron_subnet_id=fake_share_network_subnet['neutron_subnet_id'],
security_services=fake_share_network['security_services'],
network_allocations=(
fake_network_allocations_get_for_share_server()),
admin_network_allocations=(
fake_network_allocations_get_for_share_server(label='admin')),
backend_details=fake_share_server['backend_details'],
network_type=fake_share_network['network_type'])
network_type=fake_share_network_subnet['network_type'])
network_info = self.share_manager._form_server_setup_info(
self.context, fake_share_server, fake_share_network)
self.context, fake_share_server, fake_share_network,
fake_share_network_subnet)
self.assertEqual(expected, network_info)
(self.share_manager.db.network_allocations_get_for_share_server.
@ -3674,12 +3742,20 @@ class ShareManagerTestCase(test.TestCase):
'host': "fake_host",
'availability_zone_id': 'fake_az',
}
fake_subnet = {
'id': 'fake_subnet_id'
}
self.mock_object(
self.share_manager.db, 'share_group_get',
mock.Mock(return_value=fake_group))
self.mock_object(
self.share_manager.db, 'share_group_update',
mock.Mock(return_value=fake_group))
self.mock_object(
self.share_manager.db,
'share_network_subnet_get_by_availability_zone_id',
mock.Mock(return_value=fake_subnet)
)
self.mock_object(
self.share_manager, '_provide_share_server_for_share_group',
mock.Mock(return_value=({}, fake_group)))
@ -3757,7 +3833,9 @@ class ShareManagerTestCase(test.TestCase):
'share_server_id': 'fake_ss_id',
'availability_zone_id': 'fake_az',
}
fake_ss = {'id': 'fake_ss_id', 'share_network_id': 'fake_sn'}
fake_sn = {'id': 'fake_sn_id'}
fake_sns = {'id': 'fake_sns_id', 'share_network_id': fake_sn['id']}
fake_ss = {'id': 'fake_ss_id', 'share_network_subnet': fake_sns}
fake_snap = {'id': 'fake_snap_id', 'share_group_snapshot_members': [],
'share_group': {'share_server_id': fake_ss['id']}}
self.mock_object(self.share_manager.db, 'share_group_get',
@ -3823,6 +3901,9 @@ class ShareManagerTestCase(test.TestCase):
self.mock_object(self.share_manager.driver.configuration, 'safe_get',
mock.Mock(return_value=True))
share_network_id = 'fake_sn'
share_network_subnet = {
'id': 'fake_subnet_id'
}
fake_group = {
'id': 'fake_id',
'source_share_group_snapshot_id': 'fake_snap_id',
@ -3837,6 +3918,9 @@ class ShareManagerTestCase(test.TestCase):
mock.Mock(return_value=fake_snap))
self.mock_object(self.share_manager.db, 'share_group_update',
mock.Mock(return_value=fake_group))
self.mock_object(self.share_manager.db,
'share_network_subnet_get_by_availability_zone_id',
mock.Mock(return_value=share_network_subnet))
self.mock_object(
self.share_manager, '_provide_share_server_for_share_group',
mock.Mock(return_value=({}, fake_group)))
@ -5564,6 +5648,8 @@ class ShareManagerTestCase(test.TestCase):
share_server = db_utils.create_share_server(**fake_share_server)
security_service = db_utils.create_security_service(**ss_data)
share_network = db_utils.create_share_network()
share_net_subnet = db_utils.create_share_network_subnet(
share_network_id=share_network['id'])
db.share_network_add_security_service(context.get_admin_context(),
share_network['id'],
security_service['id'])
@ -5577,6 +5663,10 @@ class ShareManagerTestCase(test.TestCase):
db, 'share_server_get', mock.Mock(return_value=share_server))
mock_share_network_get = self.mock_object(
db, 'share_network_get', mock.Mock(return_value=share_network))
mock_share_net_subnet_get = self.mock_object(
db, 'share_network_subnet_get', mock.Mock(
return_value=share_net_subnet)
)
mock_network_allocations_get = self.mock_object(
self.share_manager.driver, 'get_network_allocations_number',
mock.Mock(return_value=1))
@ -5627,7 +5717,11 @@ class ShareManagerTestCase(test.TestCase):
)
mock_share_network_get.assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
fake_share_server['share_network_id']
share_net_subnet['share_network_id']
)
mock_share_net_subnet_get.assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
fake_share_server['share_network_subnet_id']
)
mock_network_allocations_get.assert_called_once_with()
mock_share_server_net_info.assert_called_once_with(
@ -5636,7 +5730,8 @@ class ShareManagerTestCase(test.TestCase):
)
mock_manage_network_allocations.assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
fake_list_network_info, share_server, share_network
fake_list_network_info, share_server, share_network,
share_net_subnet
)
mock_manage_server.assert_called_once_with(
utils.IsAMatcher(context.RequestContext), share_server, identifier,
@ -5673,12 +5768,19 @@ class ShareManagerTestCase(test.TestCase):
identifier = 'fake_id'
share_server = db_utils.create_share_server(**fake_share_server)
share_network = db_utils.create_share_network()
share_network_subnet = db_utils.create_share_network_subnet(
share_network_id=share_network['id']
)
share_server['share_network_subnet_id'] = share_network_subnet['id']
self.share_manager.driver._admin_network_api = mock.Mock()
mock_share_server_get = self.mock_object(
db, 'share_server_get', mock.Mock(return_value=share_server))
mock_share_network_get = self.mock_object(
db, 'share_network_get', mock.Mock(return_value=share_network))
mock_share_net_subnet_get = self.mock_object(
db, 'share_network_subnet_get', mock.Mock(
return_value=share_network_subnet))
mock_network_allocations_get = self.mock_object(
self.share_manager.driver, 'get_network_allocations_number',
mock.Mock(return_value=1))
@ -5697,7 +5799,11 @@ class ShareManagerTestCase(test.TestCase):
)
mock_share_network_get.assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
fake_share_server['share_network_id']
share_network_subnet['share_network_id']
)
mock_share_net_subnet_get.assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
share_server['share_network_subnet_id']
)
mock_network_allocations_get.assert_called_once_with()
mock_get_share_network_info.assert_called_once_with(
@ -5712,12 +5818,19 @@ class ShareManagerTestCase(test.TestCase):
identifier = 'fake_id'
share_server = db_utils.create_share_server(**fake_share_server)
share_network = db_utils.create_share_network()
share_network_subnet = db_utils.create_share_network_subnet(
share_network_id=share_network['id']
)
share_server['share_network_subnet_id'] = share_network_subnet['id']
self.share_manager.driver._admin_network_api = mock.Mock()
mock_share_server_get = self.mock_object(
db, 'share_server_get', mock.Mock(return_value=share_server))
mock_share_network_get = self.mock_object(
db, 'share_network_get', mock.Mock(return_value=share_network))
mock_share_net_subnet_get = self.mock_object(
db, 'share_network_subnet_get', mock.Mock(
return_value=share_network_subnet))
mock_network_allocations_get = self.mock_object(
self.share_manager.driver, 'get_network_allocations_number',
mock.Mock(return_value=1))
@ -5744,7 +5857,11 @@ class ShareManagerTestCase(test.TestCase):
)
mock_share_network_get.assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
fake_share_server['share_network_id']
share_network_subnet['share_network_id']
)
mock_share_net_subnet_get.assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
share_server['share_network_subnet_id']
)
mock_network_allocations_get.assert_called_once_with()
mock_get_share_network_info.assert_called_once_with(
@ -5757,7 +5874,8 @@ class ShareManagerTestCase(test.TestCase):
)
mock_manage_network_allocations.assert_called_once_with(
utils.IsAMatcher(context.RequestContext),
fake_list_network_info, share_server, share_network
fake_list_network_info, share_server, share_network,
share_network_subnet
)
def test_manage_snapshot_driver_exception(self):

View File

@ -303,6 +303,14 @@ class ManilaExceptionResponseCode404(test.TestCase):
self.assertEqual(404, e.code)
self.assertIn(share_network_id, e.msg)
def test_share_network_subnet_not_found(self):
# Verify response code for exception.ShareNetworkSubnetNotFound
share_network_subnet_id = "fake_share_network_subnet_id"
e = exception.ShareNetworkSubnetNotFound(
share_network_subnet_id=share_network_subnet_id)
self.assertEqual(404, e.code)
self.assertIn(share_network_subnet_id, e.msg)
def test_share_server_not_found(self):
# Verify response code for exception.ShareServerNotFound
share_server_id = "fake_share_server_id"

View File

@ -0,0 +1,21 @@
---
features:
- Added APIs with default policy set to 'rule:default' that allow the
creation of share networks with multiple subnets. This gives the users
the ability to create multiple subnets in a share network for different
availability zones. Also, users will be able to delete and show
existing subnets.
- Updated the share server API to make possible to manage share servers
in a specific subnet when the driver is operating in
``driver_handles_share_servers`` enabled mode.
- Share servers are now associated with a single share network subnet, which
pertain to a share network.
upgrade:
- On upgrading to this release, all existing share networks will be updated
to accommodate an availability zone assignment. Existing share networks
will have their availability zone set to "empty" indicating that they are
available across all storage availability zones known to manila.
fixes:
- A share network cannot be provided while creating a share replica. Replicas
will inherit the share's share network if one exists.