Add multiple subnets per AZ support
Manila can now configure a share network with multiple subnets in an availability zone. Also, it can add a new subnet for an availability that has share servers, which will triger an update share server allocations. Changes: - API: - Bump version to 2.70. - setup share network with multiple subents per az. - Block manage server with multiple subnets. - Allow add subnet for in-use share servers. - `share_network_subnet_id` is dropped from ShareServer view - `share_network_subnet_ids` is added in ShareServer view - `network_allocation_update_support` is added to ShareServer and ShareNetwork views. - Add a check operation for share network subnet create. - DB: - Remove `share_network_subnet_id` from share_servers. - Create mapping table `share_server_share_network_subnet_mappings`. - Fix queries with new db design. - Add migration downgrade and upgrade alembic. - Add `share_network_subnet_id` to the NetworkAllocations. - Scheduler: - Change `AvailabilityZoneFilter` to take in account if the host supports the allocation required by the setup request. - Manager: - Bump RPC API version. - `_setup_server` allocating multiple subnets. - Modify signature of driver `_setup_server` interface, passing a list of `network_info` for each subnet. - Share server DB creation to inform a list of subnets and create with `network_allocation_update_support`. - Implement `check_update_share_server_network_allocations` and `update_share_server_network_allocations`. - Drivers: - For legacy compatibility, all drivers implementing `_setup_server` consume the first element of the `network_ino`. - Dummy Driver: - Implement `_setup_server` with new signature as multiple subnet. - Modify the `backend_details` to save allocations for all subnets. - Report update allocation and share server multiple subnet support. - Implement `check_update_share_server_network_allocations` and `update_share_server_network_allocations` interfaces. Signed-off-by: Felipe Rodrigues <felipefuty01@gmail.com> Co-Authored-By: Andre Beltrami <debeltrami@gmail.com> Co-Authored-By: Fábio Oliveira <fabioaurelio1269@gmail.com> Co-Authored-By: Nahim Alves de Souza <nahimsouza@outlook.com> Co-Authored-By: Caique Mello <caique_mellosbo@hotmail.com> DocImpact APIImpact Partially-Implements: blueprint multiple-share-network-subnets Change-Id: I7de9de4ae509182e9494bba604979cce03acceec
This commit is contained in:
parent
3ce3854ae9
commit
2b57d15c64
@ -25,10 +25,12 @@ from oslo_log import log
|
||||
from oslo_utils import encodeutils
|
||||
from oslo_utils import strutils
|
||||
import webob
|
||||
from webob import exc
|
||||
|
||||
from manila.api.openstack import api_version_request as api_version
|
||||
from manila.api.openstack import versioned_method
|
||||
from manila.common import constants
|
||||
from manila.db import api as db_api
|
||||
from manila import exception
|
||||
from manila.i18n import _
|
||||
from manila import policy
|
||||
@ -560,3 +562,53 @@ def validate_public_share_policy(context, api_params, api='create'):
|
||||
raise exception.NotAuthorized(message=message)
|
||||
|
||||
return api_params
|
||||
|
||||
|
||||
def _get_existing_subnets(context, share_network_id, az):
|
||||
"""Return any existing subnets in the requested AZ.
|
||||
|
||||
If az is None, the method will search for an existent default subnet.
|
||||
"""
|
||||
if az is None:
|
||||
return db_api.share_network_subnet_get_default_subnets(
|
||||
context, share_network_id)
|
||||
|
||||
return (
|
||||
db_api.share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id, az,
|
||||
fallback_to_default=False)
|
||||
)
|
||||
|
||||
|
||||
def validate_subnet_create(context, share_network_id, data,
|
||||
multiple_subnet_support):
|
||||
|
||||
check_net_id_and_subnet_id(data)
|
||||
try:
|
||||
share_network = 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 = {}
|
||||
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)
|
||||
data['availability_zone_id'] = subnet_az.get('id')
|
||||
|
||||
existing_subnets = _get_existing_subnets(
|
||||
context, share_network_id, data['availability_zone_id'])
|
||||
if existing_subnets and not multiple_subnet_support:
|
||||
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)
|
||||
raise exc.HTTPConflict(explanation=msg)
|
||||
|
||||
return share_network, existing_subnets
|
||||
|
@ -182,13 +182,17 @@ REST_API_VERSION_HISTORY = """
|
||||
restore share from recycle bin. Also, a new parameter called
|
||||
`is_soft_deleted` was added so users can filter out
|
||||
shares in the recycle bin while listing shares.
|
||||
* 2.70 - Added support for multiple share network subnets in the same
|
||||
availability zone. Also, users can add subnets for an in-use share
|
||||
network.
|
||||
|
||||
"""
|
||||
|
||||
# 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.69"
|
||||
_MAX_API_VERSION = "2.70"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
|
||||
|
@ -384,3 +384,11 @@ ____
|
||||
/v2/shares/{share_id}/action {"soft_delete": null}``. List shares in
|
||||
Recycle Bin: `` GET /v2/shares?is_soft_deleted=true``. Restore share from
|
||||
Recycle Bin: `` POST /v2/shares/{share_id}/action {'restore': null}``.
|
||||
|
||||
2.70
|
||||
----
|
||||
Added support to configure multiple subnets for a given share network in the
|
||||
same availability zone (or the default one). Users can also add new subnets
|
||||
for an in-use share network. To distinguish this update support a new
|
||||
property called 'network_allocation_update_support' was added in the share
|
||||
network and share server.
|
||||
|
@ -51,7 +51,6 @@ class ShareServerController(wsgi.Controller):
|
||||
share_servers = db_api.share_server_get_all(context)
|
||||
for s in share_servers:
|
||||
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']
|
||||
@ -75,7 +74,9 @@ class ShareServerController(wsgi.Controller):
|
||||
(hasattr(s, k) and
|
||||
s[k] == v or k == 'share_network' and
|
||||
v in [s.share_network_name,
|
||||
s.share_network_id])]
|
||||
s.share_network_id] or
|
||||
k == 'share_network_subnet_id' and
|
||||
v in s.share_network_subnet_ids)]
|
||||
return self._view_builder.build_share_servers(req, share_servers)
|
||||
|
||||
@wsgi.Controller.authorize
|
||||
@ -85,8 +86,7 @@ class ShareServerController(wsgi.Controller):
|
||||
try:
|
||||
server = db_api.share_server_get(context, id)
|
||||
share_network = db_api.share_network_get(
|
||||
context, server.share_network_subnet['share_network_id'])
|
||||
server.share_network_id = share_network['id']
|
||||
context, server['share_network_id'])
|
||||
server.project_id = share_network['project_id']
|
||||
if share_network['name']:
|
||||
server.share_network_name = share_network['name']
|
||||
@ -97,7 +97,7 @@ class ShareServerController(wsgi.Controller):
|
||||
except exception.ShareNetworkNotFound:
|
||||
msg = _("Share server %s could not be found. Its associated "
|
||||
"share network does not "
|
||||
"exist.") % server.share_network_subnet['share_network_id']
|
||||
"exist.") % server['share_network_id']
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
return self._view_builder.build_share_server(req, server)
|
||||
|
||||
|
@ -355,12 +355,17 @@ class ShareMixin(object):
|
||||
common.check_share_network_is_active(share_network)
|
||||
|
||||
if availability_zone_id:
|
||||
if not db.share_network_subnet_get_by_availability_zone_id(
|
||||
subnets = (
|
||||
db.share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id,
|
||||
availability_zone_id=availability_zone_id):
|
||||
availability_zone_id=availability_zone_id))
|
||||
if not subnets:
|
||||
msg = _("A share network subnet was not found for the "
|
||||
"requested availability zone.")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
kwargs['az_request_multiple_subnet_support_map'] = {
|
||||
availability_zone_id: len(subnets) > 1,
|
||||
}
|
||||
|
||||
display_name = share.get('display_name')
|
||||
display_description = share.get('display_description')
|
||||
|
@ -21,11 +21,13 @@ from oslo_log import log
|
||||
import webob
|
||||
from webob import exc
|
||||
|
||||
from manila.api.openstack import api_version_request as api_version
|
||||
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 import share
|
||||
from manila.share import rpcapi as share_rpcapi
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
@ -40,6 +42,7 @@ class ShareNetworkSubnetController(wsgi.Controller):
|
||||
def __init__(self):
|
||||
super(ShareNetworkSubnetController, self).__init__()
|
||||
self.share_rpcapi = share_rpcapi.ShareAPI()
|
||||
self.share_api = share.API()
|
||||
|
||||
@wsgi.Controller.api_version("2.51")
|
||||
@wsgi.Controller.authorize
|
||||
@ -104,74 +107,55 @@ class ShareNetworkSubnetController(wsgi.Controller):
|
||||
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
|
||||
multiple_subnet_support = (req.api_version_request >=
|
||||
api_version.APIVersionRequest("2.70"))
|
||||
share_network, existing_subnets = common.validate_subnet_create(
|
||||
context, share_network_id, data, multiple_subnet_support)
|
||||
|
||||
common.check_net_id_and_subnet_id(data)
|
||||
# create subnet operation on subnets with share servers means that an
|
||||
# allocation update is requested.
|
||||
if existing_subnets and existing_subnets[0]['share_servers']:
|
||||
|
||||
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:
|
||||
# NOTE(felipe_rodrigues): all subnets have the same set of share
|
||||
# servers, so we can just get the servers from one of them. Not
|
||||
# necessarily all share servers from the specified AZ will be
|
||||
# updated, only the ones created with subnets in the AZ. Others
|
||||
# created with default AZ will only have its allocations updated
|
||||
# when default subnet set is updated.
|
||||
data['share_servers'] = existing_subnets[0]['share_servers']
|
||||
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)
|
||||
share_network_subnet = (
|
||||
self.share_api.update_share_server_network_allocations(
|
||||
context, share_network, data))
|
||||
except exception.ServiceIsDown as e:
|
||||
msg = _('Could not add the share network subnet.')
|
||||
LOG.error(e)
|
||||
raise exc.HTTPInternalServerError(explanation=msg)
|
||||
except exception.InvalidShareNetwork as e:
|
||||
raise exc.HTTPBadRequest(explanation=e.msg)
|
||||
except db_exception.DBError as e:
|
||||
msg = _('Could not add the share network subnet.')
|
||||
LOG.error(e)
|
||||
raise exc.HTTPInternalServerError(explanation=msg)
|
||||
else:
|
||||
try:
|
||||
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)
|
||||
|
||||
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(
|
||||
|
@ -279,15 +279,23 @@ class ShareNetworkController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
try:
|
||||
if ('neutron_net_id' in update_values or
|
||||
'neutron_subnet_id' in update_values):
|
||||
subnet = db_api.share_network_subnet_get_default_subnet(
|
||||
subnets = db_api.share_network_subnet_get_default_subnets(
|
||||
context, id)
|
||||
if not subnet:
|
||||
if not subnets:
|
||||
msg = _("The share network %(id)s does not have a "
|
||||
"'default' subnet that serves all availability "
|
||||
"zones, so subnet details "
|
||||
"('neutron_net_id', 'neutron_subnet_id') cannot "
|
||||
"be updated.") % {'id': id}
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
if len(subnets) > 1:
|
||||
msg = _("The share network %(id)s does not have an unique "
|
||||
"'default' subnet that serves all availability "
|
||||
"zones, so subnet details "
|
||||
"('neutron_net_id', 'neutron_subnet_id') cannot "
|
||||
"be updated.") % {'id': id}
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
subnet = subnets[0]
|
||||
|
||||
# NOTE(silvacarlose): If the default share network subnet have
|
||||
# the fields neutron_net_id and neutron_subnet_id set as None,
|
||||
@ -616,6 +624,54 @@ class ShareNetworkController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
return self._view_builder.build_security_service_update_check(
|
||||
req, data, result)
|
||||
|
||||
@wsgi.Controller.api_version('2.70')
|
||||
@wsgi.action('share_network_subnet_create_check')
|
||||
@wsgi.response(202)
|
||||
def share_network_subnet_create_check(self, req, id, body):
|
||||
"""Check the feasibility of creating a share network subnet."""
|
||||
context = req.environ['manila.context']
|
||||
if not self.is_valid_body(body, 'share_network_subnet_create_check'):
|
||||
msg = _("Share Network Subnet Create Check is missing from "
|
||||
"the request body.")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
data = body['share_network_subnet_create_check']
|
||||
share_network, existing_subnets = common.validate_subnet_create(
|
||||
context, id, data, True)
|
||||
|
||||
reset_check = utils.get_bool_from_api_params('reset_operation', data)
|
||||
|
||||
# create subnet operation alongside subnets with share servers means
|
||||
# that an allocation update is requested.
|
||||
if existing_subnets and existing_subnets[0]['share_servers']:
|
||||
|
||||
# NOTE(felipe_rodrigues): all subnets within the same az have the
|
||||
# same set of share servers, so we can just get the servers from
|
||||
# one of them. Not necessarily all share servers from the specified
|
||||
# AZ will be updated, only the ones created with subnets in the AZ.
|
||||
# Others created with default AZ will only have its allocations
|
||||
# updated when default subnet set is updated.
|
||||
data['share_servers'] = existing_subnets[0]['share_servers']
|
||||
try:
|
||||
check_result = (
|
||||
self.share_api.
|
||||
check_update_share_server_network_allocations(
|
||||
context, share_network, data, reset_check))
|
||||
except exception.ServiceIsDown as e:
|
||||
msg = _("A share network subnet update check cannot be "
|
||||
"performed at this time.")
|
||||
LOG.error(e)
|
||||
raise exc.HTTPInternalServerError(explanation=msg)
|
||||
except exception.InvalidShareNetwork as e:
|
||||
raise exc.HTTPBadRequest(explanation=e.msg)
|
||||
else:
|
||||
check_result = {
|
||||
'compatible': True,
|
||||
'hosts_check_result': {}
|
||||
}
|
||||
|
||||
return self._view_builder.build_share_network_subnet_create_check(
|
||||
req, check_result)
|
||||
|
||||
@wsgi.Controller.api_version('2.63')
|
||||
@wsgi.action('reset_status')
|
||||
def reset_status(self, req, id, body):
|
||||
|
@ -73,7 +73,6 @@ class ShareServerController(share_servers.ShareServerController,
|
||||
raise exc.HTTPForbidden(explanation=e.msg)
|
||||
|
||||
result.project_id = share_network["project_id"]
|
||||
result.share_network_id = share_network["id"]
|
||||
if share_network['name']:
|
||||
result.share_network_name = share_network['name']
|
||||
else:
|
||||
@ -107,14 +106,12 @@ class ShareServerController(share_servers.ShareServerController,
|
||||
except exception.ShareServerNotFound as e:
|
||||
raise exc.HTTPNotFound(explanation=e.msg)
|
||||
|
||||
network_subnet_id = share_server.get('share_network_subnet_id', None)
|
||||
if network_subnet_id:
|
||||
subnet = db_api.share_network_subnet_get(context,
|
||||
network_subnet_id)
|
||||
share_network_id = subnet['share_network_id']
|
||||
else:
|
||||
share_network_id = share_server.get('share_network_id')
|
||||
if len(share_server['share_network_subnets']) > 1:
|
||||
msg = _("Cannot unmanage the share server containing multiple "
|
||||
"subnets.")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
share_network_id = share_server['share_network_id']
|
||||
share_network = db_api.share_network_get(context, share_network_id)
|
||||
common.check_share_network_is_active(share_network)
|
||||
|
||||
@ -169,22 +166,30 @@ class ShareServerController(share_servers.ShareServerController,
|
||||
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)
|
||||
network_subnets = (
|
||||
db_api.share_network_subnet_get_all_with_same_az(
|
||||
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(
|
||||
network_subnets = db_api.share_network_subnet_get_default_subnets(
|
||||
context, share_network_id)
|
||||
|
||||
if network_subnet is None:
|
||||
if not network_subnets:
|
||||
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 len(network_subnets) > 1:
|
||||
msg = _("Cannot manage the share server, since the share network "
|
||||
"subnet %s has more subnets in its availability "
|
||||
"zone and share network.") % network_subnet_id
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
network_subnet = network_subnets[0]
|
||||
common.check_share_network_is_active(network_subnet['share_network'])
|
||||
|
||||
if share_utils.extract_host(host, 'pool'):
|
||||
@ -260,7 +265,7 @@ class ShareServerController(share_servers.ShareServerController,
|
||||
common.check_share_network_is_active(new_share_network)
|
||||
else:
|
||||
share_network_id = (
|
||||
share_server['share_network_subnet']['share_network_id'])
|
||||
share_server['share_network_id'])
|
||||
current_share_network = db_api.share_network_get(
|
||||
context, share_network_id)
|
||||
common.check_share_network_is_active(current_share_network)
|
||||
@ -387,7 +392,7 @@ class ShareServerController(share_servers.ShareServerController,
|
||||
common.check_share_network_is_active(new_share_network)
|
||||
else:
|
||||
share_network_id = (
|
||||
share_server['share_network_subnet']['share_network_id'])
|
||||
share_server['share_network_id'])
|
||||
current_share_network = db_api.share_network_get(
|
||||
context, share_network_id)
|
||||
common.check_share_network_is_active(current_share_network)
|
||||
|
@ -22,7 +22,8 @@ class ViewBuilder(common.ViewBuilder):
|
||||
_collection_name = 'share_networks'
|
||||
_detail_version_modifiers = ["add_gateway", "add_mtu", "add_nova_net_id",
|
||||
"add_subnets",
|
||||
"add_status_and_sec_service_update_fields"]
|
||||
"add_status_and_sec_service_update_fields",
|
||||
"add_network_allocation_update_support_field"]
|
||||
|
||||
def build_share_network(self, request, share_network):
|
||||
"""View of a share network."""
|
||||
@ -55,6 +56,16 @@ class ViewBuilder(common.ViewBuilder):
|
||||
view['hosts_check_result'] = result['hosts_check_result']
|
||||
return view
|
||||
|
||||
def build_share_network_subnet_create_check(self, request, result):
|
||||
"""View of share network subnet create check."""
|
||||
context = request.environ['manila.context']
|
||||
view = {
|
||||
'compatible': result['compatible'],
|
||||
}
|
||||
if context.is_admin:
|
||||
view['hosts_check_result'] = result['hosts_check_result']
|
||||
return view
|
||||
|
||||
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:
|
||||
@ -135,3 +146,9 @@ class ViewBuilder(common.ViewBuilder):
|
||||
network_dict['status'] = network.get('status')
|
||||
network_dict['security_service_update_support'] = network.get(
|
||||
'security_service_update_support')
|
||||
|
||||
@common.ViewBuilder.versioned_method("2.70")
|
||||
def add_network_allocation_update_support_field(
|
||||
self, context, network_dict, network):
|
||||
network_dict['network_allocation_update_support'] = network.get(
|
||||
'network_allocation_update_support')
|
||||
|
@ -24,7 +24,8 @@ class ViewBuilder(common.ViewBuilder):
|
||||
"add_is_auto_deletable_and_identifier_fields",
|
||||
"add_share_network_subnet_id_field",
|
||||
"add_task_state_and_source_server_fields",
|
||||
"add_sec_service_update_fields"
|
||||
"add_sec_service_update_fields",
|
||||
"add_share_network_subnet_ids_and_network_allocation_update_support"
|
||||
]
|
||||
|
||||
def build_share_server(self, request, share_server):
|
||||
@ -64,11 +65,13 @@ class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
return share_server_dict
|
||||
|
||||
@common.ViewBuilder.versioned_method("2.51")
|
||||
@common.ViewBuilder.versioned_method("2.51", "2.69")
|
||||
def add_share_network_subnet_id_field(
|
||||
self, context, share_server_dict, share_server):
|
||||
"""In 2.70, share_network_subnet_id is dropped, it becomes a list."""
|
||||
share_server_dict['share_network_subnet_id'] = (
|
||||
share_server['share_network_subnet_id'])
|
||||
share_server['share_network_subnet_ids'][0]
|
||||
if share_server['share_network_subnet_ids'] else None)
|
||||
|
||||
@common.ViewBuilder.versioned_method("2.49")
|
||||
def add_is_auto_deletable_and_identifier_fields(
|
||||
@ -89,3 +92,11 @@ class ViewBuilder(common.ViewBuilder):
|
||||
self, context, share_server_dict, share_server):
|
||||
share_server_dict['security_service_update_support'] = share_server[
|
||||
'security_service_update_support']
|
||||
|
||||
@common.ViewBuilder.versioned_method("2.70")
|
||||
def add_share_network_subnet_ids_and_network_allocation_update_support(
|
||||
self, context, share_server_dict, share_server):
|
||||
share_server_dict['share_network_subnet_ids'] = sorted(
|
||||
share_server['share_network_subnet_ids'])
|
||||
share_server_dict['network_allocation_update_support'] = (
|
||||
share_server['network_allocation_update_support'])
|
||||
|
@ -421,7 +421,8 @@ class ShareServerCommands(object):
|
||||
"""
|
||||
share_servers = [server.strip() for server in share_servers.split(",")]
|
||||
capabilities = [cap.strip() for cap in capabilities.split(",")]
|
||||
supported_capabilities = ['security_service_update_support']
|
||||
supported_capabilities = ['security_service_update_support',
|
||||
'network_allocation_update_support']
|
||||
|
||||
values = dict()
|
||||
for capability in capabilities:
|
||||
|
@ -984,29 +984,45 @@ def share_network_subnet_get(context, network_subnet_id, session=None):
|
||||
session=session)
|
||||
|
||||
|
||||
def share_network_subnet_get_all_with_same_az(context, network_subnet_id,
|
||||
session=None):
|
||||
"""Get requested az share network subnets DB record."""
|
||||
return IMPL.share_network_subnet_get_all_with_same_az(
|
||||
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.
|
||||
def share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id, availability_zone_id,
|
||||
fallback_to_default=True):
|
||||
"""Get the share network subnets DB record in a given AZ.
|
||||
|
||||
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.
|
||||
This method returns list of subnets 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
|
||||
subnets. If there is no subnet for a specific availability zone id and
|
||||
"fallback_to_default" is True, this method will return the default share
|
||||
network subnets, if it exists.
|
||||
"""
|
||||
return IMPL.share_network_subnet_get_by_availability_zone_id(
|
||||
context, share_network_id, availability_zone_id)
|
||||
return IMPL.share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id, availability_zone_id,
|
||||
fallback_to_default=fallback_to_default)
|
||||
|
||||
|
||||
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 share_network_subnet_get_default_subnets(context, share_network_id):
|
||||
"""Get the default share network subnets DB records."""
|
||||
return IMPL.share_network_subnet_get_default_subnets(context,
|
||||
share_network_id)
|
||||
|
||||
|
||||
def share_network_subnet_get_all_by_share_server_id(context, share_server_id):
|
||||
"""Get the subnets that are being used by the share server."""
|
||||
return IMPL.share_network_subnet_get_all_by_share_server_id(
|
||||
context, share_server_id)
|
||||
|
||||
|
||||
##################
|
||||
@ -1035,10 +1051,12 @@ def network_allocation_get(context, id, session=None, read_deleted=None):
|
||||
|
||||
|
||||
def network_allocations_get_for_share_server(context, share_server_id,
|
||||
session=None, label=None):
|
||||
session=None, label=None,
|
||||
subnet_id=None):
|
||||
"""Get network allocations for share server."""
|
||||
return IMPL.network_allocations_get_for_share_server(
|
||||
context, share_server_id, label=label, session=session)
|
||||
context, share_server_id, label=label, session=session,
|
||||
subnet_id=subnet_id)
|
||||
|
||||
|
||||
def network_allocations_get_by_ip_address(context, ip_address):
|
||||
@ -1077,6 +1095,7 @@ def share_server_search_by_identifier(context, identifier, session=None):
|
||||
|
||||
def share_server_get_all_by_host_and_share_subnet_valid(context, host,
|
||||
share_subnet_id,
|
||||
server_status=None,
|
||||
session=None):
|
||||
"""Get share server DB records by host and share net not error."""
|
||||
return IMPL.share_server_get_all_by_host_and_share_subnet_valid(
|
||||
|
@ -0,0 +1,229 @@
|
||||
# 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.
|
||||
|
||||
"""multiple share server subnets
|
||||
|
||||
Revision ID: a87e0fb17dee
|
||||
Revises: 1946cb97bb8d
|
||||
Create Date: 2022-01-14 06:12:27.596130
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'a87e0fb17dee'
|
||||
down_revision = '1946cb97bb8d'
|
||||
|
||||
|
||||
from alembic import op
|
||||
from oslo_log import log
|
||||
import sqlalchemy as sa
|
||||
|
||||
from manila.db.migrations import utils
|
||||
|
||||
|
||||
SHARE_SERVERS_TABLE = 'share_servers'
|
||||
SHARE_SERVER_SUBNET_MAP_TABLE = 'share_server_share_network_subnet_mappings'
|
||||
NETWORK_ALLOCATIONS_TABLE = 'network_allocations'
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
def upgrade():
|
||||
|
||||
# Create mappings table.
|
||||
context = op.get_context()
|
||||
mysql_dl = context.bind.dialect.name == 'mysql'
|
||||
datetime_type = (sa.dialects.mysql.DATETIME(fsp=6)
|
||||
if mysql_dl else sa.DateTime)
|
||||
try:
|
||||
share_server_fk_name = "fk_ss_sns_m_share_server_id_share_servers"
|
||||
share_network_subnet_fk_name = (
|
||||
"fk_ss_sns_m_share_network_subnet_id_share_network_subnets")
|
||||
server_subnet_mappings_table = op.create_table(
|
||||
SHARE_SERVER_SUBNET_MAP_TABLE,
|
||||
sa.Column('id', sa.Integer, primary_key=True, nullable=False),
|
||||
sa.Column('created_at', datetime_type),
|
||||
sa.Column('updated_at', datetime_type),
|
||||
sa.Column('deleted_at', datetime_type),
|
||||
sa.Column('deleted', sa.Integer, default=0),
|
||||
sa.Column(
|
||||
'share_server_id', sa.String(length=36),
|
||||
sa.ForeignKey('share_servers.id', name=share_server_fk_name),
|
||||
nullable=False),
|
||||
sa.Column(
|
||||
'share_network_subnet_id', sa.String(length=36),
|
||||
sa.ForeignKey('share_network_subnets.id',
|
||||
name=share_network_subnet_fk_name),
|
||||
nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8')
|
||||
except Exception:
|
||||
LOG.error('Table %s could not be created.',
|
||||
SHARE_SERVER_SUBNET_MAP_TABLE)
|
||||
raise
|
||||
|
||||
# Populate the mappings table from the share servers table.
|
||||
try:
|
||||
connection = op.get_bind()
|
||||
share_servers_table = utils.load_table(SHARE_SERVERS_TABLE, connection)
|
||||
server_subnet_mappings = []
|
||||
for server in connection.execute(share_servers_table.select()):
|
||||
if server.share_network_subnet_id:
|
||||
server_subnet_mappings.append({
|
||||
'created_at': server.created_at,
|
||||
'updated_at': server.updated_at,
|
||||
'deleted_at': server.deleted_at,
|
||||
'deleted': 0 if server.deleted == 'False' else 1,
|
||||
'share_server_id': server.id,
|
||||
'share_network_subnet_id': server.share_network_subnet_id,
|
||||
})
|
||||
op.bulk_insert(server_subnet_mappings_table, server_subnet_mappings)
|
||||
except Exception:
|
||||
LOG.error('Table %s could not be populated from the %s table.',
|
||||
SHARE_SERVER_SUBNET_MAP_TABLE, SHARE_SERVERS_TABLE)
|
||||
raise
|
||||
|
||||
# add subnet id column to the allocations table.
|
||||
try:
|
||||
network_allocation_fk_name = (
|
||||
"fk_network_allocation_subnet_id_share_network_subnets")
|
||||
op.add_column(
|
||||
NETWORK_ALLOCATIONS_TABLE,
|
||||
sa.Column('share_network_subnet_id', sa.String(length=36),
|
||||
sa.ForeignKey('share_network_subnets.id',
|
||||
name=network_allocation_fk_name))
|
||||
)
|
||||
except Exception:
|
||||
LOG.error("Could not add ForeignKey column 'share_network_subnet_id'"
|
||||
"to table %s.", NETWORK_ALLOCATIONS_TABLE)
|
||||
raise
|
||||
|
||||
# populate the allocation with its subnet id using the share server.
|
||||
network_allocation_table = utils.load_table(NETWORK_ALLOCATIONS_TABLE,
|
||||
connection)
|
||||
for alloc in connection.execute(network_allocation_table.select()):
|
||||
# admin allocations should not contain subnet id.
|
||||
if alloc['label'] == 'admin':
|
||||
continue
|
||||
|
||||
server = connection.execute(
|
||||
share_servers_table.select().where(
|
||||
alloc['share_server_id'] == (
|
||||
share_servers_table.c.id))).first()
|
||||
|
||||
# pylint: disable=no-value-for-parameter
|
||||
op.execute(network_allocation_table.update().where(
|
||||
alloc['id'] == network_allocation_table.c.id).values(
|
||||
{'share_network_subnet_id': server['share_network_subnet_id']}))
|
||||
|
||||
# add a new column to share_servers.
|
||||
try:
|
||||
op.add_column(
|
||||
SHARE_SERVERS_TABLE,
|
||||
sa.Column('network_allocation_update_support', sa.Boolean,
|
||||
nullable=False, server_default=sa.sql.false()))
|
||||
except Exception:
|
||||
LOG.error("Table %s could not add column "
|
||||
"'network_allocation_update_support'.",
|
||||
SHARE_SERVERS_TABLE)
|
||||
raise
|
||||
|
||||
# drop subnet id foreign key from share servers.
|
||||
try:
|
||||
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_TABLE,
|
||||
type_="foreignkey")
|
||||
op.drop_column(SHARE_SERVERS_TABLE, 'share_network_subnet_id')
|
||||
except Exception:
|
||||
LOG.error("Table %s could not drop column 'share_network_subnet_id'.",
|
||||
SHARE_SERVERS_TABLE)
|
||||
raise
|
||||
|
||||
|
||||
def downgrade():
|
||||
"""Remove share_server_share_network_subnet_mapping table and new columns.
|
||||
|
||||
This method can lead to data loss because the share server can have
|
||||
more than one subnet.
|
||||
"""
|
||||
try:
|
||||
share_serves_fk_name = (
|
||||
"fk_share_servers_share_network_subnet_id_share_network_subnets")
|
||||
op.add_column(
|
||||
SHARE_SERVERS_TABLE,
|
||||
sa.Column(
|
||||
'share_network_subnet_id', sa.String(36),
|
||||
sa.ForeignKey('share_network_subnets.id',
|
||||
name=share_serves_fk_name),
|
||||
)
|
||||
)
|
||||
|
||||
connection = op.get_bind()
|
||||
server_subnet_mappings_table = utils.load_table(
|
||||
SHARE_SERVER_SUBNET_MAP_TABLE, connection)
|
||||
share_servers_table = utils.load_table(SHARE_SERVERS_TABLE,
|
||||
connection)
|
||||
session = sa.orm.Session(bind=connection.connect())
|
||||
for server in connection.execute(share_servers_table.select()):
|
||||
subnets = session.query(
|
||||
server_subnet_mappings_table).filter(
|
||||
server['id'] == (
|
||||
server_subnet_mappings_table.c.share_server_id)).all()
|
||||
|
||||
if server['deleted'] != 'False' and len(subnets) > 1:
|
||||
LOG.warning('Share server %s is not deleted and it '
|
||||
'has more than one subnet (%s subnets), '
|
||||
'the downgrade may cause an inconsistent '
|
||||
'environment.', server['id'], len(subnets))
|
||||
|
||||
subnet_id = subnets[0].share_network_subnet_id if subnets else None
|
||||
|
||||
# pylint: disable=no-value-for-parameter
|
||||
op.execute(share_servers_table.update().where(
|
||||
server['id'] == share_servers_table.c.id).values(
|
||||
{'share_network_subnet_id': subnet_id}))
|
||||
|
||||
session.close_all()
|
||||
|
||||
except Exception:
|
||||
LOG.error("'share_network_subnet_id' field in the %s table could not "
|
||||
"be created and populated from %s table.",
|
||||
SHARE_SERVERS_TABLE, SHARE_SERVER_SUBNET_MAP_TABLE)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_table(SHARE_SERVER_SUBNET_MAP_TABLE)
|
||||
except Exception:
|
||||
LOG.error("Failed to drop table %s.", SHARE_SERVER_SUBNET_MAP_TABLE)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_column(SHARE_SERVERS_TABLE,
|
||||
'network_allocation_update_support')
|
||||
except Exception:
|
||||
LOG.error("Table %s failed to drop the column "
|
||||
"'network_allocation_update_support'.", SHARE_SERVERS_TABLE)
|
||||
raise
|
||||
|
||||
try:
|
||||
network_allocation_fk_name = (
|
||||
"fk_network_allocation_subnet_id_share_network_subnets")
|
||||
if connection.engine.name == 'mysql':
|
||||
op.drop_constraint(network_allocation_fk_name,
|
||||
NETWORK_ALLOCATIONS_TABLE,
|
||||
type_="foreignkey")
|
||||
op.drop_column(NETWORK_ALLOCATIONS_TABLE, 'share_network_subnet_id')
|
||||
except Exception:
|
||||
LOG.error("Column 'network_allocations.share_network_subnet_id' from "
|
||||
"table %s failed to drop.", NETWORK_ALLOCATIONS_TABLE)
|
||||
raise
|
@ -4253,6 +4253,24 @@ def share_network_subnet_get(context, network_subnet_id, session=None):
|
||||
return result
|
||||
|
||||
|
||||
@require_context
|
||||
def share_network_subnet_get_all_with_same_az(context, network_subnet_id,
|
||||
session=None):
|
||||
subnet = (_network_subnet_get_query(context, session)
|
||||
.filter_by(id=network_subnet_id).subquery())
|
||||
result = (_network_subnet_get_query(context, session)
|
||||
.join(subnet, subnet.c.share_network_id ==
|
||||
models.ShareNetworkSubnet.share_network_id)
|
||||
.filter(func.coalesce(subnet.c.availability_zone_id, '0') ==
|
||||
func.coalesce(
|
||||
models.ShareNetworkSubnet.availability_zone_id, '0'))
|
||||
.all())
|
||||
if not result:
|
||||
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()
|
||||
@ -4265,25 +4283,55 @@ def share_network_subnet_get_all_by_share_network(context, network_id):
|
||||
|
||||
|
||||
@require_context
|
||||
def share_network_subnet_get_by_availability_zone_id(
|
||||
context, share_network_id, availability_zone_id):
|
||||
def share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id, availability_zone_id,
|
||||
fallback_to_default=True):
|
||||
"""Get the share network subnets DB records in a given AZ.
|
||||
|
||||
This method returns list of subnets 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
|
||||
subnets. If there is no subnet for a specific availability zone id and
|
||||
"fallback_to_default" is True, this method will return the default share
|
||||
network subnets, if it exists.
|
||||
|
||||
:param context: operation context.
|
||||
:param share_network_id: the share network id to be the subnets.
|
||||
:param availability_zone_id: the availability zone id to be the subnets.
|
||||
:param fallback_to_default: determines in case no subnets found in the
|
||||
given AZ, it will return the "default" subnets.
|
||||
:return: the list of share network subnets in the AZ and share network.
|
||||
"""
|
||||
result = (_network_subnet_get_query(context).filter_by(
|
||||
share_network_id=share_network_id,
|
||||
availability_zone_id=availability_zone_id).first())
|
||||
availability_zone_id=availability_zone_id).all())
|
||||
# If a specific subnet wasn't found, try get the default one
|
||||
if availability_zone_id and not result:
|
||||
if availability_zone_id and not result and fallback_to_default:
|
||||
return (_network_subnet_get_query(context).filter_by(
|
||||
share_network_id=share_network_id,
|
||||
availability_zone_id=None).first())
|
||||
availability_zone_id=None).all())
|
||||
return result
|
||||
|
||||
|
||||
@require_context
|
||||
def share_network_subnet_get_default_subnet(context, share_network_id):
|
||||
return share_network_subnet_get_by_availability_zone_id(
|
||||
def share_network_subnet_get_default_subnets(context, share_network_id):
|
||||
return share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id, availability_zone_id=None)
|
||||
|
||||
|
||||
@require_context
|
||||
def share_network_subnet_get_all_by_share_server_id(context, share_server_id):
|
||||
result = (_network_subnet_get_query(context)
|
||||
.filter(models.ShareNetworkSubnet.share_servers.any(
|
||||
id=share_server_id))
|
||||
.all())
|
||||
if not result:
|
||||
raise exception.ShareNetworkSubnetNotFoundByShareServer(
|
||||
share_server_id=share_server_id)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
###################
|
||||
|
||||
|
||||
@ -4293,7 +4341,7 @@ def _server_get_query(context, session=None):
|
||||
return (model_query(context, models.ShareServer, session=session).
|
||||
options(joinedload('share_instances'),
|
||||
joinedload('network_allocations'),
|
||||
joinedload('share_network_subnet')))
|
||||
joinedload('share_network_subnets')))
|
||||
|
||||
|
||||
@require_context
|
||||
@ -4314,6 +4362,12 @@ def share_server_delete(context, id):
|
||||
session = get_session()
|
||||
with session.begin():
|
||||
server_ref = share_server_get(context, id, session=session)
|
||||
model_query(
|
||||
context, models.ShareServerShareNetworkSubnetMapping,
|
||||
session=session
|
||||
).filter_by(
|
||||
share_server_id=id,
|
||||
).soft_delete()
|
||||
share_server_backend_details_delete(context, id, session=session)
|
||||
server_ref.soft_delete(session=session, update_status=True)
|
||||
|
||||
@ -4384,12 +4438,19 @@ def share_server_search_by_identifier(context, identifier, session=None):
|
||||
@require_context
|
||||
def share_server_get_all_by_host_and_share_subnet_valid(context, host,
|
||||
share_subnet_id,
|
||||
server_status=None,
|
||||
session=None):
|
||||
result = (_server_get_query(context, session).filter_by(host=host)
|
||||
.filter_by(share_network_subnet_id=share_subnet_id)
|
||||
.filter(models.ShareServer.status.in_(
|
||||
(constants.STATUS_CREATING,
|
||||
constants.STATUS_ACTIVE))).all())
|
||||
query = (_server_get_query(context, session)
|
||||
.filter_by(host=host)
|
||||
.filter(models.ShareServer.share_network_subnets.any(
|
||||
id=share_subnet_id)))
|
||||
if server_status:
|
||||
query.filter_by(status=server_status)
|
||||
else:
|
||||
query.filter(models.ShareServer.status.in_(
|
||||
(constants.STATUS_CREATING, constants.STATUS_ACTIVE)))
|
||||
|
||||
result = query.all()
|
||||
if not result:
|
||||
filters_description = ('share_network_subnet_id is "%(share_net_id)s",'
|
||||
' host is "%(host)s" and status in'
|
||||
@ -4423,9 +4484,13 @@ def share_server_get_all_with_filters(context, filters):
|
||||
source_share_server_id=filters.get('source_share_server_id'))
|
||||
if filters.get('share_network_id'):
|
||||
query = query.join(
|
||||
models.ShareServerShareNetworkSubnetMapping,
|
||||
models.ShareServerShareNetworkSubnetMapping.share_server_id ==
|
||||
models.ShareServer.id
|
||||
).join(
|
||||
models.ShareNetworkSubnet,
|
||||
models.ShareNetworkSubnet.id ==
|
||||
models.ShareServer.share_network_subnet_id
|
||||
models.ShareServerShareNetworkSubnetMapping.share_network_subnet_id
|
||||
).filter(
|
||||
models.ShareNetworkSubnet.share_network_id ==
|
||||
filters.get('share_network_id'))
|
||||
@ -4637,7 +4702,8 @@ def network_allocations_get_by_ip_address(context, ip_address):
|
||||
|
||||
@require_context
|
||||
def network_allocations_get_for_share_server(context, share_server_id,
|
||||
session=None, label=None):
|
||||
session=None, label=None,
|
||||
subnet_id=None):
|
||||
if session is None:
|
||||
session = get_session()
|
||||
|
||||
@ -4655,6 +4721,9 @@ def network_allocations_get_for_share_server(context, share_server_id,
|
||||
))
|
||||
else:
|
||||
query = query.filter(models.NetworkAllocation.label == label)
|
||||
if subnet_id:
|
||||
query = query.filter(
|
||||
models.NetworkAllocation.share_network_subnet_id == subnet_id)
|
||||
|
||||
result = query.all()
|
||||
return result
|
||||
|
@ -967,6 +967,17 @@ class ShareNetwork(BASE, ManilaBase):
|
||||
# set to True.
|
||||
return all(share_servers_support_updating)
|
||||
|
||||
@property
|
||||
def network_allocation_update_support(self):
|
||||
share_servers_support_updating = []
|
||||
for network_subnet in self.share_network_subnets:
|
||||
for server in network_subnet['share_servers']:
|
||||
share_servers_support_updating.append(
|
||||
server['network_allocation_update_support'])
|
||||
# NOTE(felipe_rodrigues): all share servers within this share network
|
||||
# must support updating in order to have this property set to True.
|
||||
return all(share_servers_support_updating)
|
||||
|
||||
|
||||
class ShareNetworkSubnet(BASE, ManilaBase):
|
||||
"""Represents a share network subnet used by some resources."""
|
||||
@ -990,11 +1001,19 @@ class ShareNetworkSubnet(BASE, ManilaBase):
|
||||
String(36), ForeignKey('availability_zones.id'), nullable=True)
|
||||
|
||||
share_servers = orm.relationship(
|
||||
"ShareServer", backref='share_network_subnet',
|
||||
"ShareServer",
|
||||
secondary="share_server_share_network_subnet_mappings",
|
||||
backref="share_network_subnets",
|
||||
lazy='immediate',
|
||||
primaryjoin='and_(ShareNetworkSubnet.id '
|
||||
'== ShareServer.share_network_subnet_id,'
|
||||
'ShareServer.deleted == "False")')
|
||||
primaryjoin="and_(ShareNetworkSubnet.id == "
|
||||
"%(cls_name)s.share_network_subnet_id, "
|
||||
"%(cls_name)s.deleted == 0)" % {
|
||||
"cls_name": "ShareServerShareNetworkSubnetMapping"},
|
||||
secondaryjoin='and_('
|
||||
'ShareServer.id == '
|
||||
'ShareServerShareNetworkSubnetMapping.share_server_id,'
|
||||
'ShareServerShareNetworkSubnetMapping.deleted == 0)'
|
||||
)
|
||||
|
||||
_availability_zone = orm.relationship(
|
||||
"AvailabilityZone",
|
||||
@ -1024,9 +1043,6 @@ class ShareServer(BASE, ManilaBase):
|
||||
__tablename__ = 'share_servers'
|
||||
id = Column(String(36), primary_key=True, nullable=False)
|
||||
deleted = Column(String(36), default='False')
|
||||
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)
|
||||
@ -1035,6 +1051,8 @@ class ShareServer(BASE, ManilaBase):
|
||||
nullable=True)
|
||||
security_service_update_support = Column(
|
||||
Boolean, nullable=False, default=False)
|
||||
network_allocation_update_support = Column(
|
||||
Boolean, nullable=False, default=False)
|
||||
status = Column(Enum(
|
||||
constants.STATUS_INACTIVE, constants.STATUS_ACTIVE,
|
||||
constants.STATUS_ERROR, constants.STATUS_DELETING,
|
||||
@ -1071,12 +1089,31 @@ class ShareServer(BASE, ManilaBase):
|
||||
'ShareServerBackendDetails.share_server_id, '
|
||||
'ShareServerBackendDetails.deleted == "False")')
|
||||
|
||||
_share_network_subnet_ids = orm.relationship(
|
||||
"ShareServerShareNetworkSubnetMapping",
|
||||
lazy='immediate',
|
||||
viewonly=True,
|
||||
primaryjoin='and_('
|
||||
'ShareServer.id == '
|
||||
'ShareServerShareNetworkSubnetMapping.share_server_id,'
|
||||
'ShareServerShareNetworkSubnetMapping.deleted == 0)')
|
||||
|
||||
@property
|
||||
def backend_details(self):
|
||||
return {model['key']: model['value']
|
||||
for model in self._backend_details}
|
||||
|
||||
_extra_keys = ['backend_details']
|
||||
@property
|
||||
def share_network_subnet_ids(self):
|
||||
return [model['share_network_subnet_id']
|
||||
for model in self._share_network_subnet_ids]
|
||||
|
||||
@property
|
||||
def share_network_id(self):
|
||||
return (self.share_network_subnets[0]['share_network_id']
|
||||
if self.share_network_subnets else None)
|
||||
|
||||
_extra_keys = ['backend_details', 'share_network_subnet_ids']
|
||||
|
||||
|
||||
class ShareServerBackendDetails(BASE, ManilaBase):
|
||||
@ -1090,6 +1127,16 @@ class ShareServerBackendDetails(BASE, ManilaBase):
|
||||
nullable=False)
|
||||
|
||||
|
||||
class ShareServerShareNetworkSubnetMapping(BASE, ManilaBase):
|
||||
"""Represents the Share Server and Share Network Subnet mapping."""
|
||||
__tablename__ = 'share_server_share_network_subnet_mappings'
|
||||
id = Column(Integer, primary_key=True)
|
||||
share_server_id = Column(
|
||||
String(36), ForeignKey('share_servers.id'), nullable=False)
|
||||
share_network_subnet_id = Column(
|
||||
String(36), ForeignKey('share_network_subnets.id'), nullable=False)
|
||||
|
||||
|
||||
class ShareNetworkSecurityServiceAssociation(BASE, ManilaBase):
|
||||
"""Association table between compute_zones and compute_nodes tables."""
|
||||
|
||||
@ -1121,6 +1168,10 @@ class NetworkAllocation(BASE, ManilaBase):
|
||||
share_server_id = Column(String(36), ForeignKey('share_servers.id'),
|
||||
nullable=False)
|
||||
|
||||
# NOTE(felipe_rodrigues): admin allocation does not have subnet.
|
||||
share_network_subnet_id = Column(
|
||||
String(36), ForeignKey('share_network_subnets.id'), nullable=True)
|
||||
|
||||
|
||||
class DriverPrivateData(BASE, ManilaBase):
|
||||
"""Represents a private data as key-value pairs for a driver."""
|
||||
|
@ -232,6 +232,11 @@ class ShareNetworkSubnetNotFound(NotFound):
|
||||
" found.")
|
||||
|
||||
|
||||
class ShareNetworkSubnetNotFoundByShareServer(NotFound):
|
||||
message = _("Share network subnet could not be found by "
|
||||
"%(share_server_id)s.")
|
||||
|
||||
|
||||
class ShareServerNotFound(NotFound):
|
||||
message = _("Share server %(share_server_id)s could not be found.")
|
||||
|
||||
@ -241,6 +246,11 @@ class ShareServerNotFoundByFilters(ShareServerNotFound):
|
||||
"filters: %(filters_description)s.")
|
||||
|
||||
|
||||
class AllocationsNotFoundForShareServer(NotFound):
|
||||
message = _("No allocations found for the share server "
|
||||
"%(share_server_id)s on the subnet.")
|
||||
|
||||
|
||||
class InvalidShareNetwork(Invalid):
|
||||
message = _("Invalid share network: %(reason)s")
|
||||
|
||||
|
@ -134,3 +134,8 @@ class NetworkBaseAPI(db_base.Base, metaclass=abc.ABCMeta):
|
||||
"should be configured to 'True'.")
|
||||
raise exception.NetworkBadConfigurationException(reason=msg)
|
||||
return self._enabled_ip_versions
|
||||
|
||||
@abc.abstractmethod
|
||||
def include_network_info(self, share_network_subnet):
|
||||
"""Includes share-network-subnet with plugin specific data."""
|
||||
pass
|
||||
|
@ -121,9 +121,16 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
||||
**self._neutron_api_kwargs)
|
||||
return self._neutron_api
|
||||
|
||||
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 include_network_info(self, share_network_subnet):
|
||||
"""Includes share-network-subnet with plugin specific data."""
|
||||
self._store_neutron_net_info(None, share_network_subnet, save_db=False)
|
||||
|
||||
def _store_neutron_net_info(self, context, share_network_subnet,
|
||||
save_db=True):
|
||||
self._save_neutron_network_data(context, share_network_subnet,
|
||||
save_db=save_db)
|
||||
self._save_neutron_subnet_data(context, share_network_subnet,
|
||||
save_db=save_db)
|
||||
|
||||
def allocate_network(self, context, share_server, share_network=None,
|
||||
share_network_subnet=None, **kwargs):
|
||||
@ -202,6 +209,11 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
||||
'cidr': share_network_subnet['cidr'],
|
||||
'mtu': share_network_subnet['mtu'],
|
||||
}
|
||||
# NOTE(felipe_rodrigues): admin plugin does not have any Manila
|
||||
# share net subnet, its data is from manila configuration file.
|
||||
if self.label != 'admin':
|
||||
port_dict['share_network_subnet_id'] = (
|
||||
share_network_subnet['id'])
|
||||
|
||||
# There should not be existing allocations with the same port_id.
|
||||
try:
|
||||
@ -332,6 +344,12 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
||||
'cidr': share_network_subnet['cidr'],
|
||||
'mtu': share_network_subnet['mtu'],
|
||||
}
|
||||
# NOTE(felipe_rodrigues): admin plugin does not have any Manila
|
||||
# share net subnet, its data is from manila configuration file.
|
||||
if self.label != 'admin':
|
||||
port_dict['share_network_subnet_id'] = (
|
||||
share_network_subnet['id'])
|
||||
|
||||
return self.db.network_allocation_create(context, port_dict)
|
||||
|
||||
def _delete_port(self, context, port):
|
||||
@ -354,7 +372,8 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
||||
share_network_subnet['neutron_net_id'])
|
||||
return 'segments' in net_info
|
||||
|
||||
def _save_neutron_network_data(self, context, share_network_subnet):
|
||||
def _save_neutron_network_data(self, context, share_network_subnet,
|
||||
save_db=True):
|
||||
net_info = self.neutron_api.get_network(
|
||||
share_network_subnet['neutron_net_id'])
|
||||
segmentation_id = None
|
||||
@ -389,11 +408,12 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
||||
}
|
||||
share_network_subnet.update(provider_nw_dict)
|
||||
|
||||
if self.label != 'admin':
|
||||
if self.label != 'admin' and save_db:
|
||||
self.db.share_network_subnet_update(
|
||||
context, share_network_subnet['id'], provider_nw_dict)
|
||||
|
||||
def _save_neutron_subnet_data(self, context, share_network_subnet):
|
||||
def _save_neutron_subnet_data(self, context, share_network_subnet,
|
||||
save_db=True):
|
||||
subnet_info = self.neutron_api.get_subnet(
|
||||
share_network_subnet['neutron_subnet_id'])
|
||||
|
||||
@ -404,7 +424,7 @@ class NeutronNetworkPlugin(network.NetworkBaseAPI):
|
||||
}
|
||||
share_network_subnet.update(subnet_values)
|
||||
|
||||
if self.label != 'admin':
|
||||
if self.label != 'admin' and save_db:
|
||||
self.db.share_network_subnet_update(
|
||||
context, share_network_subnet['id'], subnet_values)
|
||||
|
||||
@ -576,7 +596,8 @@ class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
|
||||
"local_link_information": local_links}
|
||||
return arguments
|
||||
|
||||
def _save_neutron_network_data(self, context, share_network_subnet):
|
||||
def _save_neutron_network_data(self, context, share_network_subnet,
|
||||
save_db=True):
|
||||
"""Store the Neutron network info.
|
||||
|
||||
In case of dynamic multi segments the segment is determined while
|
||||
@ -589,12 +610,14 @@ class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
|
||||
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_subnet)
|
||||
self._save_neutron_network_mtu(context, share_network_subnet,
|
||||
save_db=save_db)
|
||||
return
|
||||
super(NeutronBindNetworkPlugin, self)._save_neutron_network_data(
|
||||
context, share_network_subnet)
|
||||
context, share_network_subnet, save_db=save_db)
|
||||
|
||||
def _save_neutron_network_mtu(self, context, share_network_subnet):
|
||||
def _save_neutron_network_mtu(self, context, share_network_subnet,
|
||||
save_db=True):
|
||||
"""Store the Neutron network mtu.
|
||||
|
||||
In case of dynamic multi segments only the mtu needs storing before
|
||||
@ -608,7 +631,7 @@ class NeutronBindNetworkPlugin(NeutronNetworkPlugin):
|
||||
}
|
||||
share_network_subnet.update(mtu_dict)
|
||||
|
||||
if self.label != 'admin':
|
||||
if self.label != 'admin' and save_db:
|
||||
self.db.share_network_subnet_update(
|
||||
context, share_network_subnet['id'], mtu_dict)
|
||||
|
||||
|
@ -257,7 +257,11 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
|
||||
'available': len(ips)}
|
||||
raise exception.NetworkBadConfigurationException(reason=msg)
|
||||
|
||||
def _save_network_info(self, context, share_network_subnet):
|
||||
def include_network_info(self, share_network_subnet):
|
||||
"""Includes share-network-subnet with plugin specific data."""
|
||||
self._save_network_info(None, share_network_subnet, save_db=False)
|
||||
|
||||
def _save_network_info(self, context, share_network_subnet, save_db=True):
|
||||
"""Update share-network-subnet with plugin specific data."""
|
||||
data = {
|
||||
'network_type': self.network_type,
|
||||
@ -268,7 +272,7 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
|
||||
'mtu': self.mtu,
|
||||
}
|
||||
share_network_subnet.update(data)
|
||||
if self.label != 'admin':
|
||||
if self.label != 'admin' and save_db:
|
||||
self.db.share_network_subnet_update(
|
||||
context, share_network_subnet['id'], data)
|
||||
|
||||
@ -303,6 +307,9 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
|
||||
'ip_version': share_network_subnet['ip_version'],
|
||||
'mtu': share_network_subnet['mtu'],
|
||||
}
|
||||
if self.label != 'admin':
|
||||
data['share_network_subnet_id'] = (
|
||||
share_network_subnet['id'])
|
||||
allocations.append(
|
||||
self.db.network_allocation_create(context, data))
|
||||
return allocations
|
||||
@ -354,6 +361,9 @@ class StandaloneNetworkPlugin(network.NetworkBaseAPI):
|
||||
'ip_version': share_network_subnet['ip_version'],
|
||||
'mtu': share_network_subnet['mtu'],
|
||||
}
|
||||
if self.label != 'admin':
|
||||
data['share_network_subnet_id'] = (
|
||||
share_network_subnet['id'])
|
||||
self.db.network_allocation_create(context, data)
|
||||
remaining_allocations.remove(allocation)
|
||||
|
||||
|
@ -99,6 +99,11 @@ deprecated_share_network_reset_status = policy.DeprecatedRule(
|
||||
deprecated_reason=DEPRECATED_REASON,
|
||||
deprecated_since=versionutils.deprecated.WALLABY
|
||||
)
|
||||
deprecated_share_network_subnet_create_check = policy.DeprecatedRule(
|
||||
name=BASE_POLICY_NAME % 'subnet_create_check',
|
||||
check_str=base.RULE_DEFAULT
|
||||
)
|
||||
|
||||
|
||||
share_network_policies = [
|
||||
policy.DocumentedRuleDefault(
|
||||
@ -284,6 +289,20 @@ share_network_policies = [
|
||||
],
|
||||
deprecated_rule=deprecated_share_network_get_all
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=BASE_POLICY_NAME % 'subnet_create_check',
|
||||
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
|
||||
scope_types=['system', 'project'],
|
||||
description="Check the feasibility of create a new share network "
|
||||
"subnet for share network.",
|
||||
operations=[
|
||||
{
|
||||
'method': 'POST',
|
||||
'path': '/share-networks/{share_network_id}/action'
|
||||
}
|
||||
],
|
||||
deprecated_rule=deprecated_share_network_subnet_create_check
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -27,9 +27,13 @@ class AvailabilityZoneFilter(base_host.BaseHostFilter):
|
||||
props = spec.get('resource_properties', {})
|
||||
request_az_id = props.get('availability_zone_id',
|
||||
spec.get('availability_zone_id'))
|
||||
az_request_multiple_subnet_support_map = spec.get(
|
||||
'az_request_multiple_subnet_support_map', {})
|
||||
request_azs = spec.get('availability_zones')
|
||||
host_az_id = host_state.service['availability_zone_id']
|
||||
host_az = host_state.service['availability_zone']['name']
|
||||
host_single_subnet_only = (
|
||||
not host_state.share_server_multiple_subnet_support)
|
||||
|
||||
host_satisfied = True
|
||||
if request_az_id is not None:
|
||||
@ -38,4 +42,15 @@ class AvailabilityZoneFilter(base_host.BaseHostFilter):
|
||||
if request_azs:
|
||||
host_satisfied = host_satisfied and host_az in request_azs
|
||||
|
||||
# Only validates the multiple subnet support in case it can deny the
|
||||
# host:
|
||||
# 1. host is satisfying the AZ
|
||||
# 2. There is a map to be checked
|
||||
# 3. The host does not support a multiple subnet
|
||||
if (host_satisfied and az_request_multiple_subnet_support_map and
|
||||
host_single_subnet_only):
|
||||
host_satisfied = (
|
||||
not az_request_multiple_subnet_support_map.get(host_az_id,
|
||||
False))
|
||||
|
||||
return host_satisfied
|
||||
|
@ -151,6 +151,8 @@ class HostState(object):
|
||||
self.ipv4_support = None
|
||||
self.ipv6_support = None
|
||||
self.security_service_update_support = False
|
||||
self.network_allocation_update_support = False
|
||||
self.share_server_multiple_subnet_support = False
|
||||
|
||||
# PoolState for all pools
|
||||
self.pools = {}
|
||||
@ -346,6 +348,14 @@ class HostState(object):
|
||||
pool_cap['security_service_update_support'] = (
|
||||
self.security_service_update_support)
|
||||
|
||||
if 'network_allocation_update_support' not in pool_cap:
|
||||
pool_cap['network_allocation_update_support'] = (
|
||||
self.network_allocation_update_support)
|
||||
|
||||
if 'share_server_multiple_subnet_support' not in pool_cap:
|
||||
pool_cap['share_server_multiple_subnet_support'] = (
|
||||
self.share_server_multiple_subnet_support)
|
||||
|
||||
if self.ipv4_support is not None:
|
||||
pool_cap['ipv4_support'] = self.ipv4_support
|
||||
|
||||
@ -377,6 +387,10 @@ class HostState(object):
|
||||
self.ipv6_support = capability['ipv6_support']
|
||||
self.security_service_update_support = capability.get(
|
||||
'security_service_update_support', False)
|
||||
self.network_allocation_update_support = capability.get(
|
||||
'network_allocation_update_support', False)
|
||||
self.share_server_multiple_subnet_support = capability.get(
|
||||
'share_server_multiple_subnet_support', False)
|
||||
|
||||
def consume_from_share(self, share):
|
||||
"""Incrementally update host state from an share."""
|
||||
@ -477,6 +491,10 @@ class PoolState(HostState):
|
||||
'sg_consistent_snapshot_support')
|
||||
self.security_service_update_support = capability.get(
|
||||
'security_service_update_support', False)
|
||||
self.network_allocation_update_support = capability.get(
|
||||
'network_allocation_update_support', False)
|
||||
self.share_server_multiple_subnet_support = capability.get(
|
||||
'share_server_multiple_subnet_support', False)
|
||||
|
||||
def update_pools(self, capability):
|
||||
# Do nothing, since we don't have pools within pool, yet
|
||||
|
@ -60,7 +60,11 @@ def generate_stats(host_state, properties):
|
||||
'ipv4_support': host_state.ipv4_support,
|
||||
'ipv6_support': host_state.ipv6_support,
|
||||
'security_service_update_support': (
|
||||
host_state.security_service_update_support)
|
||||
host_state.security_service_update_support),
|
||||
'network_allocation_update_support': (
|
||||
host_state.network_allocation_update_support),
|
||||
'share_server_multiple_subnet_support': (
|
||||
host_state.share_server_multiple_subnet_support)
|
||||
}
|
||||
|
||||
host_caps = host_state.capabilities
|
||||
|
@ -93,6 +93,30 @@ def locked_security_service_update_operation(operation):
|
||||
return wrapped
|
||||
|
||||
|
||||
def locked_share_server_update_allocations_operation(operation):
|
||||
"""Lock decorator for share server update allocations operation.
|
||||
|
||||
Takes a named lock prior to executing the operation. The lock is named with
|
||||
the ids of the share network and the region to be updated.
|
||||
"""
|
||||
|
||||
def wrapped(*args, **kwargs):
|
||||
az_id = kwargs.get('availability_zone_id')
|
||||
share_net_id = kwargs.get('share_network_id')
|
||||
|
||||
@coordination.synchronized(
|
||||
'locked-share-server-update-allocations-operation-%(net)s-%(az)s'
|
||||
% {
|
||||
'net': share_net_id,
|
||||
'az': az_id,
|
||||
})
|
||||
def locked_share_server_allocations_operation(*_args, **_kwargs):
|
||||
return operation(*_args, **_kwargs)
|
||||
return locked_share_server_allocations_operation(*args, **kwargs)
|
||||
|
||||
return wrapped
|
||||
|
||||
|
||||
class API(base.Base):
|
||||
"""API for interacting with the share manager."""
|
||||
|
||||
@ -105,13 +129,17 @@ class API(base.Base):
|
||||
|
||||
def _get_all_availability_zones_with_subnets(self, context,
|
||||
share_network_id):
|
||||
compatible_azs = []
|
||||
compatible_azs_name = []
|
||||
compatible_azs_multiple = {}
|
||||
for az in self.db.availability_zone_get_all(context):
|
||||
if self.db.share_network_subnet_get_by_availability_zone_id(
|
||||
subnets = (
|
||||
self.db.share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id=share_network_id,
|
||||
availability_zone_id=az['id']):
|
||||
compatible_azs.append(az['name'])
|
||||
return compatible_azs
|
||||
availability_zone_id=az['id']))
|
||||
if subnets:
|
||||
compatible_azs_multiple[az['id']] = len(subnets) > 1
|
||||
compatible_azs_name.append(az['name'])
|
||||
return compatible_azs_name, compatible_azs_multiple
|
||||
|
||||
def _check_if_share_quotas_exceeded(self, context, quota_exception,
|
||||
share_size, operation='create'):
|
||||
@ -189,7 +217,8 @@ class API(base.Base):
|
||||
snapshot_id=None, availability_zone=None, metadata=None,
|
||||
share_network_id=None, share_type=None, is_public=False,
|
||||
share_group_id=None, share_group_snapshot_member=None,
|
||||
availability_zones=None, scheduler_hints=None):
|
||||
availability_zones=None, scheduler_hints=None,
|
||||
az_request_multiple_subnet_support_map=None):
|
||||
"""Create new share."""
|
||||
|
||||
self._check_metadata_properties(metadata)
|
||||
@ -345,13 +374,15 @@ class API(base.Base):
|
||||
# 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)
|
||||
compatible_azs_name, compatible_azs_multiple = (
|
||||
self._get_all_availability_zones_with_subnets(
|
||||
context, share_network_id))
|
||||
if not availability_zones:
|
||||
availability_zones = azs_with_subnet
|
||||
availability_zones = compatible_azs_name
|
||||
else:
|
||||
availability_zones = (
|
||||
[az for az in availability_zones if az in azs_with_subnet])
|
||||
[az for az in availability_zones
|
||||
if az in compatible_azs_name])
|
||||
if not availability_zones:
|
||||
msg = _(
|
||||
"The share network is not supported within any requested "
|
||||
@ -359,6 +390,12 @@ class API(base.Base):
|
||||
"'availability_zones' extra-spec and the availability "
|
||||
"zones of the share network subnets")
|
||||
raise exception.InvalidInput(message=msg)
|
||||
if az_request_multiple_subnet_support_map:
|
||||
az_request_multiple_subnet_support_map.update(
|
||||
compatible_azs_multiple)
|
||||
else:
|
||||
az_request_multiple_subnet_support_map = (
|
||||
compatible_azs_multiple)
|
||||
|
||||
try:
|
||||
share = self.db.share_create(context, options,
|
||||
@ -391,7 +428,9 @@ class API(base.Base):
|
||||
availability_zone=availability_zone, share_group=share_group,
|
||||
share_group_snapshot_member=share_group_snapshot_member,
|
||||
share_type_id=share_type_id, availability_zones=availability_zones,
|
||||
snapshot_host=snapshot_host, scheduler_hints=scheduler_hints)
|
||||
snapshot_host=snapshot_host, scheduler_hints=scheduler_hints,
|
||||
az_request_multiple_subnet_support_map=(
|
||||
az_request_multiple_subnet_support_map))
|
||||
|
||||
# Retrieve the share with instance details
|
||||
share = self.db.share_get(context, share['id'])
|
||||
@ -468,7 +507,8 @@ class API(base.Base):
|
||||
host=None, availability_zone=None,
|
||||
share_group=None, share_group_snapshot_member=None,
|
||||
share_type_id=None, availability_zones=None,
|
||||
snapshot_host=None, scheduler_hints=None):
|
||||
snapshot_host=None, scheduler_hints=None,
|
||||
az_request_multiple_subnet_support_map=None):
|
||||
request_spec, share_instance = (
|
||||
self.create_share_instance_and_get_request_spec(
|
||||
context, share, availability_zone=availability_zone,
|
||||
@ -476,7 +516,9 @@ class API(base.Base):
|
||||
share_network_id=share_network_id,
|
||||
share_type_id=share_type_id,
|
||||
availability_zones=availability_zones,
|
||||
snapshot_host=snapshot_host))
|
||||
snapshot_host=snapshot_host,
|
||||
az_request_multiple_subnet_support_map=(
|
||||
az_request_multiple_subnet_support_map)))
|
||||
|
||||
if share_group_snapshot_member:
|
||||
# Inherit properties from the share_group_snapshot_member
|
||||
@ -518,7 +560,8 @@ class API(base.Base):
|
||||
self, context, share, availability_zone=None,
|
||||
share_group=None, host=None, share_network_id=None,
|
||||
share_type_id=None, cast_rules_to_readonly=False,
|
||||
availability_zones=None, snapshot_host=None):
|
||||
availability_zones=None, snapshot_host=None,
|
||||
az_request_multiple_subnet_support_map=None):
|
||||
|
||||
availability_zone_id = None
|
||||
if availability_zone:
|
||||
@ -590,6 +633,8 @@ class API(base.Base):
|
||||
'share_group': share_group,
|
||||
'availability_zone_id': availability_zone_id,
|
||||
'availability_zones': availability_zones,
|
||||
'az_request_multiple_subnet_support_map': (
|
||||
az_request_multiple_subnet_support_map),
|
||||
}
|
||||
return request_spec, share_instance
|
||||
|
||||
@ -643,6 +688,7 @@ class API(base.Base):
|
||||
except exception.OverQuota as e:
|
||||
self._check_if_replica_quotas_exceeded(context, e, share['size'])
|
||||
|
||||
az_request_multiple_subnet_support_map = {}
|
||||
if share_network_id:
|
||||
if availability_zone:
|
||||
try:
|
||||
@ -652,24 +698,31 @@ class API(base.Base):
|
||||
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:
|
||||
az_id = az.get('id')
|
||||
subnets = (
|
||||
self.db.
|
||||
share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id, az_id))
|
||||
if not subnets:
|
||||
msg = _("Share replica cannot be created because the "
|
||||
"share network is not available within the "
|
||||
"specified availability zone.")
|
||||
raise exception.InvalidShare(message=msg)
|
||||
az_request_multiple_subnet_support_map[az_id] = (
|
||||
len(subnets) > 1)
|
||||
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)
|
||||
compatible_azs_name, compatible_azs_multiple = (
|
||||
self._get_all_availability_zones_with_subnets(
|
||||
context, share_network_id))
|
||||
if not type_azs:
|
||||
type_azs = azs_subnet
|
||||
type_azs = compatible_azs_name
|
||||
else:
|
||||
type_azs = (
|
||||
[az for az in type_azs if az in azs_subnet])
|
||||
[az for az in type_azs if az in compatible_azs_name])
|
||||
if not type_azs:
|
||||
msg = _(
|
||||
"The share network is not supported within any "
|
||||
@ -677,6 +730,8 @@ class API(base.Base):
|
||||
"'availability_zones' extra-spec and the availability "
|
||||
"zones of the share network subnets")
|
||||
raise exception.InvalidInput(message=msg)
|
||||
az_request_multiple_subnet_support_map.update(
|
||||
compatible_azs_multiple)
|
||||
|
||||
if share['replication_type'] == constants.REPLICATION_TYPE_READABLE:
|
||||
cast_rules_to_readonly = True
|
||||
@ -690,7 +745,9 @@ class API(base.Base):
|
||||
share_network_id=share_network_id,
|
||||
share_type_id=share['instance']['share_type_id'],
|
||||
cast_rules_to_readonly=cast_rules_to_readonly,
|
||||
availability_zones=type_azs)
|
||||
availability_zones=type_azs,
|
||||
az_request_multiple_subnet_support_map=(
|
||||
az_request_multiple_subnet_support_map))
|
||||
)
|
||||
QUOTAS.commit(
|
||||
context, reservations, project_id=share['project_id'],
|
||||
@ -860,9 +917,8 @@ class API(base.Base):
|
||||
if share_server['status'] != constants.STATUS_ACTIVE:
|
||||
msg = _("The provided share server is not active.")
|
||||
raise exception.InvalidShareServer(reason=msg)
|
||||
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['share_network_id'] = (
|
||||
share_server['share_network_id'])
|
||||
|
||||
try:
|
||||
share_network = self.db.share_network_get(
|
||||
@ -1322,7 +1378,7 @@ class API(base.Base):
|
||||
|
||||
values = {
|
||||
'host': host,
|
||||
'share_network_subnet_id': share_net_subnet['id'],
|
||||
'share_network_subnets': [share_net_subnet],
|
||||
'status': constants.STATUS_MANAGING,
|
||||
'is_auto_deletable': False,
|
||||
'identifier': identifier,
|
||||
@ -2659,11 +2715,11 @@ class API(base.Base):
|
||||
# we should deny this operation.
|
||||
dest_az = self.db.availability_zone_get(
|
||||
context, service['availability_zone']['name'])
|
||||
compatible_subnet = (
|
||||
self.db.share_network_subnet_get_by_availability_zone_id(
|
||||
compatible_subnets = (
|
||||
self.db.share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, new_share_network_id, dest_az['id']))
|
||||
|
||||
if not compatible_subnet:
|
||||
if not compatible_subnets:
|
||||
msg = _("The share network %(network)s does not have a subnet "
|
||||
"that spans the destination host availability zone.")
|
||||
payload = {'network': new_share_network_id}
|
||||
@ -2671,11 +2727,8 @@ class API(base.Base):
|
||||
|
||||
net_changes_identified = False
|
||||
if new_share_network:
|
||||
current_subnet = self.db.share_network_subnet_get(
|
||||
context, share_server['share_network_subnet_id'])
|
||||
for key in ['neutron_net_id', 'neutron_subnet_id']:
|
||||
if current_subnet[key] != compatible_subnet[key]:
|
||||
net_changes_identified = True
|
||||
net_changes_identified = not share_utils.is_az_subnets_compatible(
|
||||
share_server['share_network_subnets'], compatible_subnets)
|
||||
|
||||
# NOTE(carloss): Refreshing the list of shares since something could've
|
||||
# changed from the initial list.
|
||||
@ -3118,28 +3171,44 @@ class API(base.Base):
|
||||
'hosts_check', new_security_service_id,
|
||||
current_security_service_id=current_security_service_id)
|
||||
|
||||
# check if there is an entry being processed
|
||||
return self._do_update_validate_hosts(
|
||||
context, share_network['id'], backend_hosts, update_key,
|
||||
new_security_service_id=new_security_service_id,
|
||||
current_security_service_id=current_security_service_id)
|
||||
|
||||
def _do_update_validate_hosts(
|
||||
self, context, share_network_id,
|
||||
backend_hosts, update_key, new_share_network_subnet=None,
|
||||
new_security_service_id=None, current_security_service_id=None):
|
||||
|
||||
# check if there is an entry being processed.
|
||||
update_value = self.db.async_operation_data_get(
|
||||
context, share_network['id'], update_key)
|
||||
context, share_network_id, update_key)
|
||||
if not update_value:
|
||||
# Create a new entry, send all asynchronous rpcs and return
|
||||
# Create a new entry, send all asynchronous rpcs and return.
|
||||
hosts_to_validate = {}
|
||||
for host in backend_hosts:
|
||||
hosts_to_validate[host] = None
|
||||
self.db.async_operation_data_update(
|
||||
context, share_network['id'],
|
||||
context, share_network_id,
|
||||
{update_key: json.dumps(hosts_to_validate)})
|
||||
for host in backend_hosts:
|
||||
(self.share_rpcapi.
|
||||
check_update_share_network_security_service(
|
||||
context, host, share_network['id'],
|
||||
new_security_service_id,
|
||||
current_security_service_id=(
|
||||
current_security_service_id)))
|
||||
if new_share_network_subnet:
|
||||
(self.share_rpcapi.
|
||||
check_update_share_server_network_allocations(
|
||||
context, host, share_network_id,
|
||||
new_share_network_subnet))
|
||||
else:
|
||||
(self.share_rpcapi.
|
||||
check_update_share_network_security_service(
|
||||
context, host, share_network_id,
|
||||
new_security_service_id,
|
||||
current_security_service_id=(
|
||||
current_security_service_id)))
|
||||
return None, hosts_to_validate
|
||||
|
||||
else:
|
||||
# process current existing hosts and update them if needed
|
||||
# process current existing hosts and update them if needed.
|
||||
current_hosts = json.loads(update_value)
|
||||
hosts_to_include = (
|
||||
set(backend_hosts).difference(set(current_hosts.keys())))
|
||||
@ -3147,24 +3216,30 @@ class API(base.Base):
|
||||
for host in backend_hosts:
|
||||
hosts_to_validate[host] = current_hosts.get(host, None)
|
||||
|
||||
# Check if there is any unsupported host
|
||||
# Check if there is any unsupported host.
|
||||
if any(hosts_to_validate[host] is False for host in backend_hosts):
|
||||
return False, hosts_to_validate
|
||||
|
||||
# Update the list of hosts to be validated
|
||||
# Update the list of hosts to be validated.
|
||||
if hosts_to_include:
|
||||
self.db.async_operation_data_update(
|
||||
context, share_network['id'],
|
||||
context, share_network_id,
|
||||
{update_key: json.dumps(hosts_to_validate)})
|
||||
|
||||
for host in hosts_to_include:
|
||||
# send asynchronous check only for new backend hosts
|
||||
(self.share_rpcapi.
|
||||
check_update_share_network_security_service(
|
||||
context, host, share_network['id'],
|
||||
new_security_service_id,
|
||||
current_security_service_id=(
|
||||
current_security_service_id)))
|
||||
# send asynchronous check only for new backend hosts.
|
||||
if new_share_network_subnet:
|
||||
(self.share_rpcapi.
|
||||
check_update_share_server_network_allocations(
|
||||
context, host, share_network_id,
|
||||
new_share_network_subnet))
|
||||
else:
|
||||
(self.share_rpcapi.
|
||||
check_update_share_network_security_service(
|
||||
context, host, share_network_id,
|
||||
new_security_service_id,
|
||||
current_security_service_id=(
|
||||
current_security_service_id)))
|
||||
|
||||
return None, hosts_to_validate
|
||||
|
||||
@ -3190,7 +3265,6 @@ class API(base.Base):
|
||||
curr_sec_serv_id = (
|
||||
current_security_service['id']
|
||||
if current_security_service else None)
|
||||
|
||||
key = self.get_security_service_update_key(
|
||||
'hosts_check', new_security_service['id'],
|
||||
current_security_service_id=curr_sec_serv_id)
|
||||
@ -3306,3 +3380,251 @@ class API(base.Base):
|
||||
|
||||
LOG.info('Security service update has been started for share network '
|
||||
'%(share_net_id)s.', {'share_net_id': share_network['id']})
|
||||
|
||||
@locked_share_server_update_allocations_operation
|
||||
def _share_server_update_allocations_validate_hosts(
|
||||
self, context, backend_hosts, update_key, share_network_id=None,
|
||||
neutron_net_id=None, neutron_subnet_id=None,
|
||||
availability_zone_id=None):
|
||||
|
||||
new_share_network_subnet = {
|
||||
'neutron_net_id': neutron_net_id,
|
||||
'neutron_subnet_id': neutron_subnet_id,
|
||||
'availability_zone_id': availability_zone_id,
|
||||
}
|
||||
return self._do_update_validate_hosts(
|
||||
context, share_network_id, backend_hosts, update_key,
|
||||
new_share_network_subnet=new_share_network_subnet)
|
||||
|
||||
def get_share_server_update_allocations_key(
|
||||
self, share_network_id, availability_zone_id):
|
||||
return ('share_server_update_allocations_' + share_network_id + '_' +
|
||||
str(availability_zone_id) + '_' + 'hosts_check')
|
||||
|
||||
def _share_server_update_allocations_initial_checks(
|
||||
self, context, share_network, share_servers):
|
||||
|
||||
api_common.check_share_network_is_active(share_network)
|
||||
if not share_network['network_allocation_update_support']:
|
||||
msg = _("Updating network allocations is not supported on this "
|
||||
"share network (%(sn_id)s) while it has shares. "
|
||||
"See the capability 'network_allocation_update_support'."
|
||||
) % {"sn_id": share_network["id"]}
|
||||
raise exception.InvalidShareNetwork(reason=msg)
|
||||
|
||||
backend_hosts = set()
|
||||
for share_server in share_servers:
|
||||
share_server_id = share_server['id']
|
||||
if share_server['status'] != constants.STATUS_ACTIVE:
|
||||
msg = _('The share server %(server)s in the specified '
|
||||
'availability zone subnet is not currently '
|
||||
'available.') % {'server': share_server_id}
|
||||
raise exception.InvalidShareNetwork(reason=msg)
|
||||
|
||||
# We need an admin context to validate these hosts.
|
||||
admin_ctx = manila_context.get_admin_context()
|
||||
# Make sure the host is in the list of available hosts.
|
||||
utils.validate_service_host(admin_ctx, share_server['host'])
|
||||
|
||||
# Create a set of backend hosts.
|
||||
backend_hosts.add(share_server['host'])
|
||||
|
||||
shares = self.db.share_get_all_by_share_server(
|
||||
context, share_server_id)
|
||||
shares_not_available = [
|
||||
share['id']
|
||||
for share in shares if
|
||||
share['status'] != constants.STATUS_AVAILABLE]
|
||||
|
||||
if shares_not_available:
|
||||
msg = _("The share server (%(server_id)s) in the specified "
|
||||
"availability zone subnet has some shares that are "
|
||||
"not available: "
|
||||
"%(share_ids)s.") % {
|
||||
'server_id': share_server_id,
|
||||
'share_ids': shares_not_available,
|
||||
}
|
||||
raise exception.InvalidShareNetwork(reason=msg)
|
||||
|
||||
shares_rules_not_available = [
|
||||
share['id'] for share in shares if
|
||||
share['instance'][
|
||||
'access_rules_status'] != constants.STATUS_ACTIVE]
|
||||
|
||||
if shares_rules_not_available:
|
||||
msg = _("The share server (%(server_id)s) in the specified "
|
||||
"availability zone subnet has either these shares or "
|
||||
"one of their replicas or migration copies that are "
|
||||
"not available: %(share_ids)s.") % {
|
||||
'server_id': share_server_id,
|
||||
'share_ids': shares_rules_not_available,
|
||||
}
|
||||
raise exception.InvalidShareNetwork(reason=msg)
|
||||
|
||||
busy_shares = []
|
||||
for share in shares:
|
||||
try:
|
||||
self._check_is_share_busy(share)
|
||||
except exception.ShareBusyException:
|
||||
busy_shares.append(share['id'])
|
||||
if busy_shares:
|
||||
msg = _("The share server (%(server_id)s) in the specified "
|
||||
"availability zone subnet has some shares that are "
|
||||
"busy as part of an active task: "
|
||||
"%(share_ids)s.") % {
|
||||
'server_id': share_server_id,
|
||||
'share_ids': busy_shares,
|
||||
}
|
||||
raise exception.InvalidShareNetwork(reason=msg)
|
||||
|
||||
return backend_hosts
|
||||
|
||||
def check_update_share_server_network_allocations(
|
||||
self, context, share_network, new_share_network_subnet,
|
||||
reset_operation):
|
||||
|
||||
backend_hosts = self._share_server_update_allocations_initial_checks(
|
||||
context, share_network, new_share_network_subnet['share_servers'])
|
||||
|
||||
update_key = self.get_share_server_update_allocations_key(
|
||||
share_network['id'],
|
||||
new_share_network_subnet['availability_zone_id'])
|
||||
if reset_operation:
|
||||
self.db.async_operation_data_delete(context, share_network['id'],
|
||||
update_key)
|
||||
try:
|
||||
compatible, hosts_info = (
|
||||
self._share_server_update_allocations_validate_hosts(
|
||||
context, backend_hosts, update_key,
|
||||
share_network_id=share_network['id'],
|
||||
neutron_net_id=(
|
||||
new_share_network_subnet.get('neutron_net_id')),
|
||||
neutron_subnet_id=(
|
||||
new_share_network_subnet.get('neutron_subnet_id')),
|
||||
availability_zone_id=new_share_network_subnet.get(
|
||||
"availability_zone_id")))
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
# Due to an internal error, we will delete the entry.
|
||||
self.db.async_operation_data_delete(
|
||||
context, share_network['id'], update_key)
|
||||
msg = _(
|
||||
"The server's allocations cannot be updated on availability "
|
||||
"zone %(zone_id)s of the share network %(share_net_id)s, "
|
||||
"since at least one of its backend hosts do not support this "
|
||||
"operation.") % {
|
||||
'share_net_id': share_network['id'],
|
||||
'zone_id': new_share_network_subnet['availability_zone_id']}
|
||||
raise exception.InvalidShareNetwork(reason=msg)
|
||||
|
||||
return {
|
||||
'compatible': compatible,
|
||||
'hosts_check_result': hosts_info
|
||||
}
|
||||
|
||||
def update_share_server_network_allocations(
|
||||
self, context, share_network, new_share_network_subnet):
|
||||
|
||||
backend_hosts = self._share_server_update_allocations_initial_checks(
|
||||
context, share_network, new_share_network_subnet['share_servers'])
|
||||
|
||||
update_key = self.get_share_server_update_allocations_key(
|
||||
share_network['id'],
|
||||
new_share_network_subnet['availability_zone_id'])
|
||||
|
||||
# check if there is an entry being processed at this moment.
|
||||
update_value = self.db.async_operation_data_get(
|
||||
context, share_network['id'], update_key)
|
||||
if not update_value:
|
||||
msg = _(
|
||||
'The share network %(share_net_id)s cannot start the update '
|
||||
'process since no check operation was found. Before starting '
|
||||
'the update operation, a "check" operation must be triggered '
|
||||
'to validate if all backend hosts support the provided '
|
||||
'configuration paramaters.') % {
|
||||
'share_net_id': share_network['id']
|
||||
}
|
||||
raise exception.InvalidShareNetwork(reason=msg)
|
||||
|
||||
subnet_info = {
|
||||
'availability_zone_id':
|
||||
new_share_network_subnet.get("availability_zone_id"),
|
||||
'neutron_net_id':
|
||||
new_share_network_subnet.get('neutron_net_id'),
|
||||
'neutron_subnet_id':
|
||||
new_share_network_subnet.get('neutron_subnet_id'),
|
||||
}
|
||||
try:
|
||||
result, __ = self._share_server_update_allocations_validate_hosts(
|
||||
context, backend_hosts, update_key,
|
||||
share_network_id=share_network['id'],
|
||||
neutron_net_id=(
|
||||
new_share_network_subnet.get('neutron_net_id')),
|
||||
neutron_subnet_id=(
|
||||
new_share_network_subnet.get('neutron_subnet_id')),
|
||||
availability_zone_id=new_share_network_subnet.get(
|
||||
"availability_zone_id"))
|
||||
except Exception:
|
||||
# Due to an internal error, we will delete the entry.
|
||||
self.db.async_operation_data_delete(
|
||||
context, share_network['id'], update_key)
|
||||
msg = _(
|
||||
"The server's allocations cannot be updated on availability "
|
||||
"zone %(zone_id)s of the share network %(share_net_id)s, "
|
||||
"since an internal error occurred."
|
||||
"operation.") % {
|
||||
'share_net_id': share_network['id'],
|
||||
'zone_id': subnet_info['availability_zone_id']
|
||||
}
|
||||
raise exception.InvalidShareNetwork(reason=msg)
|
||||
|
||||
if result is False:
|
||||
msg = _(
|
||||
"The server's allocations cannot be updated on availability "
|
||||
"zone %(zone_id)s of the share network %(share_net_id)s, "
|
||||
"since at least one of its backend hosts do not support this "
|
||||
"operation.") % {
|
||||
'share_net_id': share_network['id'],
|
||||
'zone_id': subnet_info['availability_zone_id']
|
||||
}
|
||||
raise exception.InvalidShareNetwork(reason=msg)
|
||||
elif result is None:
|
||||
msg = _(
|
||||
'Not all of the validation has been completed yet. A '
|
||||
'validation check is in progress. This operation can be '
|
||||
'retried.')
|
||||
raise exception.InvalidShareNetwork(reason=msg)
|
||||
|
||||
# change db to start the update.
|
||||
self.db.share_network_update(
|
||||
context, share_network['id'],
|
||||
{'status': constants.STATUS_NETWORK_CHANGE})
|
||||
share_servers_ids = [ss['id'] for ss in
|
||||
new_share_network_subnet['share_servers']]
|
||||
self.db.share_servers_update(
|
||||
context, share_servers_ids,
|
||||
{'status': constants.STATUS_SERVER_NETWORK_CHANGE})
|
||||
|
||||
# create the new subnet.
|
||||
new_share_network_subnet_db = self.db.share_network_subnet_create(
|
||||
context, new_share_network_subnet)
|
||||
|
||||
# triggering the actual update.
|
||||
for backend_host in backend_hosts:
|
||||
self.share_rpcapi.update_share_server_network_allocations(
|
||||
context, backend_host, share_network['id'],
|
||||
new_share_network_subnet_db['id'])
|
||||
|
||||
# Erase db entry, since we won't need it anymore.
|
||||
self.db.async_operation_data_delete(
|
||||
context, share_network['id'], update_key)
|
||||
|
||||
LOG.info('Share servers allocations update have been started for '
|
||||
'share network %(share_net_id)s on its availability zone '
|
||||
'%(az_id)s with new subnet %(subnet_id)s.',
|
||||
{
|
||||
'share_net_id': share_network['id'],
|
||||
'az_id': new_share_network_subnet['availability_zone_id'],
|
||||
'subnet_id': new_share_network_subnet_db['id'],
|
||||
})
|
||||
return new_share_network_subnet_db
|
||||
|
@ -277,6 +277,10 @@ class ShareDriver(object):
|
||||
# in-use share networks. This property will be saved in every new share
|
||||
# server.
|
||||
self.security_service_update_support = False
|
||||
# Indicates whether a driver supports adding subnet with its
|
||||
# allocations to an in-use share network availability zone. This
|
||||
# property will be saved in every new share server.
|
||||
self.network_allocation_update_support = False
|
||||
self.dhss_mandatory_security_service_association = {}
|
||||
|
||||
self.pools = []
|
||||
@ -1323,6 +1327,9 @@ class ShareDriver(object):
|
||||
goodness_function=self.get_goodness_function(),
|
||||
security_service_update_support=(
|
||||
self.security_service_update_support),
|
||||
network_allocation_update_support=(
|
||||
self.network_allocation_update_support),
|
||||
share_server_multiple_subnet_support=False,
|
||||
)
|
||||
if isinstance(data, dict):
|
||||
common.update(data)
|
||||
@ -3341,3 +3348,265 @@ class ShareDriver(object):
|
||||
otherwise.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def check_update_share_server_network_allocations(
|
||||
self, context, share_server, current_network_allocations,
|
||||
new_share_network_subnet, security_services, share_instances,
|
||||
share_instances_rules):
|
||||
""""Check if the share server network allocation update is supported.
|
||||
|
||||
:param context: The 'context.RequestContext' object for the request.
|
||||
:param share_server: Reference to the share server object that will be
|
||||
updated.
|
||||
:param current_network_allocations: All network allocations associated
|
||||
with the share server that will be updated:
|
||||
|
||||
Example::
|
||||
|
||||
{
|
||||
'admin_network_allocations':
|
||||
[
|
||||
{
|
||||
'ip_address': '10.193.154.11',
|
||||
'ip_version': 4,
|
||||
'cidr': '10.193.154.0/28',
|
||||
'gateway': '10.193.154.1',
|
||||
'mtu': 1500,
|
||||
'network_type': 'vlan',
|
||||
'segmentation_id': 3000,
|
||||
'mac_address': ' AA:AA:AA:AA:AA:AA',
|
||||
...
|
||||
},
|
||||
],
|
||||
'subnets':
|
||||
[
|
||||
{
|
||||
'share_network_subnet_id': '0bdeaa8c6db3-3bc10d67',
|
||||
'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3',
|
||||
'neutron_subnet_id': '3bc10d67-2598-4122-bb62',
|
||||
'network_allocations':
|
||||
[
|
||||
{
|
||||
'ip_address': '10.193.154.10',
|
||||
'ip_version': 4,
|
||||
'cidr': '10.193.154.0/28',
|
||||
'gateway': '10.193.154.1',
|
||||
'mtu': 1500,
|
||||
'network_type': 'vlan',
|
||||
'segmentation_id': 3000,
|
||||
'mac_address': ' AA:AA:AA:AA:AA:AA',
|
||||
...
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
:param new_share_network_subnet: dict containing the subnet data that
|
||||
has to be checked if it can be added to the share server:
|
||||
|
||||
Example::
|
||||
|
||||
{
|
||||
'availability_zone_id': '0bdeaa8c6db3-3bc10d67',
|
||||
'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3',
|
||||
'neutron_subnet_id': '3bc10d67-2598-4122-bb62',
|
||||
'ip_version': 4,
|
||||
'cidr': '10.193.154.0/28',
|
||||
'gateway': '10.193.154.1',
|
||||
'mtu': 1500,
|
||||
'network_type': 'vlan',
|
||||
'segmentation_id': 3000,
|
||||
}
|
||||
|
||||
:param security_services: list of security services configured with
|
||||
this share server.
|
||||
:param share_instances: A list of share instances that belong to the
|
||||
share server that is affected by the update.
|
||||
:param share_instances_rules: A list of access rules, grouped by share
|
||||
instance, in the following format.
|
||||
|
||||
Example::
|
||||
|
||||
[
|
||||
{
|
||||
'share_instance_id': '3bc10d67-2598-4122-bb62-0bdeaa8c6db3',
|
||||
'access_rules':
|
||||
[
|
||||
{
|
||||
'access_id':'906d0094-3e34-4d6c-a184-d08a908033e3',
|
||||
'access_type':'ip',
|
||||
'access_key':None,
|
||||
'access_to':'10.0.0.1',
|
||||
'access_level':'rw'
|
||||
...
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
:return Boolean indicating whether the update is possible or not. It is
|
||||
the driver responsibility to log the reason why not accepting the
|
||||
update.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
def update_share_server_network_allocations(
|
||||
self, context, share_server, current_network_allocations,
|
||||
new_network_allocations, security_services, shares, snapshots):
|
||||
"""Updates a share server's network allocations.
|
||||
|
||||
:param context: The 'context.RequestContext' object for the request.
|
||||
:param share_server: reference to the share server that have to update
|
||||
network allocations.
|
||||
:param current_network_allocations: all network allocations associated
|
||||
with the share server that will be updated
|
||||
|
||||
Example::
|
||||
|
||||
{
|
||||
'admin_network_allocations':
|
||||
[
|
||||
{
|
||||
'ip_address': '10.193.154.11',
|
||||
'ip_version': 4,
|
||||
'cidr': '10.193.154.0/28',
|
||||
'gateway': '10.193.154.1',
|
||||
'mtu': 1500,
|
||||
'network_type': 'vlan',
|
||||
'segmentation_id': 3000,
|
||||
'mac_address': ' AA:AA:AA:AA:AA:AA',
|
||||
},
|
||||
...
|
||||
],
|
||||
'subnets':
|
||||
[
|
||||
{
|
||||
'share_network_subnet_id': '0bdeaa8c6db3-3bc10d67',
|
||||
'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3',
|
||||
'neutron_subnet_id': '3bc10d67-2598-4122-bb62',
|
||||
'network_allocations':
|
||||
[
|
||||
{
|
||||
'ip_address': '10.193.154.10',
|
||||
'ip_version': 4,
|
||||
'cidr': '10.193.154.0/28',
|
||||
'gateway': '10.193.154.1',
|
||||
'mtu': 1500,
|
||||
'network_type': 'vlan',
|
||||
'segmentation_id': 3000,
|
||||
'mac_address': ' AA:AA:AA:AA:AA:AA',
|
||||
},
|
||||
...
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
:param new_network_allocations: allocations that must be configured in
|
||||
the share server.
|
||||
|
||||
Example::
|
||||
|
||||
{
|
||||
'share_network_subnet_id': '0bdeaa8c6db3-3bc10d67',
|
||||
'neutron_net_id': '2598-4122-bb62-0bdeaa8c6db3',
|
||||
'neutron_subnet_id': '3bc10d67-2598-4122-bb62',
|
||||
'network_allocations':
|
||||
[
|
||||
{
|
||||
'ip_address': '10.193.154.10',
|
||||
'ip_version': 4,
|
||||
'cidr': '10.193.154.0/28',
|
||||
'gateway': '10.193.154.1',
|
||||
'mtu': 1500,
|
||||
'network_type': 'vlan',
|
||||
'segmentation_id': 3000,
|
||||
'mac_address': 'AA:AA:AA:AA:AA:AA',
|
||||
...
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
:param security_services: list of security services configured with
|
||||
this share server.
|
||||
:param shares: All shares in the share server.
|
||||
:param snapshots: All snapshots in the share server.
|
||||
|
||||
:raises: Exception.
|
||||
By raising an exception, the share server and all its shares and
|
||||
snapshots instances will be set to 'error'. The error can contain
|
||||
the field 'details_data' as a dict with the key 'server_details'
|
||||
containing the backend details dict that will be saved to share
|
||||
server.
|
||||
|
||||
:return If the update changes the shares export locations or snapshots
|
||||
export locations, this method should return a dictionary
|
||||
containing a list of share instances and snapshot instances
|
||||
indexed by their id's, where each instance should provide a
|
||||
dict with the relevant information that need to be updated.
|
||||
Also, the returned dict can contain the updated back end
|
||||
details to be saved in the database.
|
||||
|
||||
Example::
|
||||
|
||||
{
|
||||
'share_updates':
|
||||
{
|
||||
'4363eb92-23ca-4888-9e24-502387816e2a':
|
||||
[
|
||||
{
|
||||
'path': '1.2.3.4:/foo',
|
||||
'metadata': {},
|
||||
'is_admin_only': False
|
||||
},
|
||||
{
|
||||
'path': '5.6.7.8:/foo',
|
||||
'metadata': {},
|
||||
'is_admin_only': True
|
||||
},
|
||||
],
|
||||
...
|
||||
},
|
||||
'snapshot_updates':
|
||||
{
|
||||
'bc4e3b28-0832-4168-b688-67fdc3e9d408':
|
||||
{
|
||||
'provider_location': '/snapshots/foo/bar_1',
|
||||
'export_locations':
|
||||
[
|
||||
{
|
||||
'path': '1.2.3.4:/snapshots/foo/bar_1',
|
||||
'is_admin_only': False,
|
||||
},
|
||||
{
|
||||
'path': '5.6.7.8:/snapshots/foo/bar_1',
|
||||
'is_admin_only': True,
|
||||
},
|
||||
],
|
||||
},
|
||||
'2e62b7ea-4e30-445f-bc05-fd523ca62941':
|
||||
{
|
||||
'provider_location': '/snapshots/foo/bar_2',
|
||||
'export_locations':
|
||||
[
|
||||
{
|
||||
'path': '1.2.3.4:/snapshots/foo/bar_2',
|
||||
'is_admin_only': False,
|
||||
},
|
||||
{
|
||||
'path': '5.6.7.8:/snapshots/foo/bar_2',
|
||||
'is_admin_only': True,
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
'server_details':
|
||||
{
|
||||
'new_share_server_info_key':
|
||||
'new_share_server_info_value',
|
||||
},
|
||||
}
|
||||
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
@ -296,6 +296,8 @@ class ContainerShareDriver(driver.ShareDriver, driver.ExecuteMixin):
|
||||
|
||||
@utils.synchronized("veth-lock", external=True)
|
||||
def _setup_server(self, network_info, metadata=None):
|
||||
# NOTE(felipe_rodrigues): keep legacy network_info support as a dict.
|
||||
network_info = network_info[0]
|
||||
msg = "Creating share server '%s'."
|
||||
server_id = self._get_container_name(network_info["server_id"])
|
||||
LOG.debug(msg, server_id)
|
||||
|
@ -290,6 +290,9 @@ class EMCShareDriver(driver.ShareDriver):
|
||||
|
||||
def _setup_server(self, network_info, metadata=None):
|
||||
"""Set up and configures share server with given network parameters."""
|
||||
# NOTE(felipe_rodrigues): keep legacy network_info support as a dict.
|
||||
network_info = network_info[0]
|
||||
|
||||
return self.plugin.setup_server(network_info, metadata)
|
||||
|
||||
def _teardown_server(self, server_details, security_services=None):
|
||||
|
@ -892,6 +892,9 @@ class GenericShareDriver(driver.ExecuteMixin, driver.ShareDriver):
|
||||
return 0
|
||||
|
||||
def _setup_server(self, network_info, metadata=None):
|
||||
# NOTE(felipe_rodrigues): keep legacy network_info support as a dict.
|
||||
network_info = network_info[0]
|
||||
|
||||
msg = "Creating share server '%s'."
|
||||
LOG.debug(msg, network_info['server_id'])
|
||||
server = self.service_instance_manager.set_up_service_instance(
|
||||
|
@ -432,6 +432,8 @@ class HPE3ParShareDriver(driver.ShareDriver):
|
||||
'vfs': vfs}
|
||||
|
||||
def _setup_server(self, network_info, metadata=None):
|
||||
# NOTE(felipe_rodrigues): keep legacy network_info support as a dict.
|
||||
network_info = network_info[0]
|
||||
|
||||
LOG.debug("begin _setup_server with %s", network_info)
|
||||
|
||||
|
@ -223,6 +223,9 @@ class HuaweiNasDriver(driver.ShareDriver):
|
||||
|
||||
def _setup_server(self, network_info, metadata=None):
|
||||
"""Set up share server with given network parameters."""
|
||||
# NOTE(felipe_rodrigues): keep legacy network_info support as a dict.
|
||||
network_info = network_info[0]
|
||||
|
||||
return self.plugin.setup_server(network_info, metadata)
|
||||
|
||||
def _teardown_server(self, server_details, security_services=None):
|
||||
|
@ -135,6 +135,8 @@ class NetAppCmodeMultiSvmShareDriver(driver.ShareDriver):
|
||||
self.admin_network_api)
|
||||
|
||||
def _setup_server(self, network_info, metadata=None):
|
||||
# NOTE(felipe_rodrigues): keep legacy network_info support as a dict.
|
||||
network_info = network_info[0]
|
||||
return self.library.setup_server(network_info, metadata)
|
||||
|
||||
def _teardown_server(self, server_details, **kwargs):
|
||||
|
@ -1658,6 +1658,7 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
2. Build the list of export_locations for each share
|
||||
3. Release all resources from the source share server
|
||||
"""
|
||||
new_network_alloc = new_network_alloc[0]
|
||||
src_backend_name = share_utils.extract_host(
|
||||
source_share_server['host'], level='backend_name')
|
||||
src_vserver, src_client = self._get_vserver(
|
||||
@ -2013,7 +2014,7 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
dns_ips = set()
|
||||
domains = set()
|
||||
# Read all dns-ips and domains from other security services
|
||||
for sec_svc in network_info['security_services']:
|
||||
for sec_svc in network_info[0]['security_services']:
|
||||
if sec_svc['type'] == current_type:
|
||||
# skip the one that we are replacing
|
||||
continue
|
||||
|
@ -243,7 +243,7 @@ def add_hooks(f):
|
||||
class ShareManager(manager.SchedulerDependentManager):
|
||||
"""Manages NAS storages."""
|
||||
|
||||
RPC_API_VERSION = '1.22'
|
||||
RPC_API_VERSION = '1.23'
|
||||
|
||||
def __init__(self, share_driver=None, service_name=None, *args, **kwargs):
|
||||
"""Load the driver from args, or from flags."""
|
||||
@ -666,20 +666,25 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
raise exception.InvalidShareServer(reason=msg % error_params)
|
||||
parent_share_same_dest = (snapshot['share']['instance']['host']
|
||||
== share_instance['host'])
|
||||
share_network_subnet_id = None
|
||||
share_network_subnets = None
|
||||
if share_network_id:
|
||||
share_network_subnet = (
|
||||
self.db.share_network_subnet_get_by_availability_zone_id(
|
||||
share_network_subnets = (
|
||||
self.db.share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id,
|
||||
availability_zone_id=share_instance.get(
|
||||
'availability_zone_id')))
|
||||
if not share_network_subnet:
|
||||
if not share_network_subnets:
|
||||
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_subnets = (
|
||||
parent_share_server['share_network_subnets'])
|
||||
|
||||
# NOTE(felipe_rodrigues): it can retrieve the available share
|
||||
# servers using one single subnet_id from the availability zone
|
||||
# subnets, because if the share server has one, it will have
|
||||
# all subnets on that availability zone.
|
||||
share_network_subnet_id = share_network_subnets[0]['id']
|
||||
|
||||
def get_available_share_servers():
|
||||
if parent_share_server and parent_share_same_dest:
|
||||
@ -725,10 +730,12 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
context,
|
||||
{
|
||||
'host': self.host,
|
||||
'share_network_subnet_id': share_network_subnet_id,
|
||||
'share_network_subnets': share_network_subnets,
|
||||
'status': constants.STATUS_CREATING,
|
||||
'security_service_update_support': (
|
||||
self.driver.security_service_update_support),
|
||||
'network_allocation_update_support': (
|
||||
self.driver.network_allocation_update_support),
|
||||
}
|
||||
)
|
||||
|
||||
@ -796,28 +803,29 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
migration.
|
||||
"""
|
||||
|
||||
share_network_subnet = (
|
||||
self.db.share_network_subnet_get_by_availability_zone_id(
|
||||
share_network_subnets = (
|
||||
self.db.share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, new_share_network_id,
|
||||
availability_zone_id=availability_zone_id))
|
||||
if not share_network_subnet:
|
||||
if not share_network_subnets:
|
||||
raise exception.ShareNetworkSubnetNotFound(
|
||||
share_network_subnet_id=None)
|
||||
share_network_subnet_id = share_network_subnet['id']
|
||||
|
||||
server_metadata = {} if not server_metadata else server_metadata
|
||||
|
||||
@utils.synchronized("share_manager_%s" % share_network_subnet_id,
|
||||
external=True)
|
||||
@utils.synchronized(
|
||||
"share_manager_%s" % share_network_subnets[0]['id'], external=True)
|
||||
def _wrapped_provide_share_server_for_migration():
|
||||
destination_share_server = self.db.share_server_create(
|
||||
context,
|
||||
{
|
||||
'host': self.host,
|
||||
'share_network_subnet_id': share_network_subnet_id,
|
||||
'share_network_subnets': share_network_subnets,
|
||||
'status': constants.STATUS_CREATING,
|
||||
'security_service_update_support': (
|
||||
self.driver.security_service_update_support),
|
||||
'network_allocation_update_support': (
|
||||
self.driver.network_allocation_update_support),
|
||||
}
|
||||
)
|
||||
|
||||
@ -917,7 +925,7 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
|
||||
def _provide_share_server_for_share_group(self, context,
|
||||
share_network_id,
|
||||
share_network_subnet_id,
|
||||
share_network_subnets,
|
||||
share_group_ref,
|
||||
share_group_snapshot=None):
|
||||
"""Gets or creates share_server and updates share group with its id.
|
||||
@ -935,10 +943,8 @@ 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_network_subnets: Share network subnets where existing
|
||||
share server should be found or created.
|
||||
:param share_group_ref: Share Group model
|
||||
:param share_group_snapshot: Optional -- ShareGroupSnapshot model. If
|
||||
supplied, driver will use it to choose
|
||||
@ -962,6 +968,11 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
@utils.synchronized("share_manager_%s" % share_network_id,
|
||||
external=True)
|
||||
def _wrapped_provide_share_server_for_share_group():
|
||||
# NOTE(felipe_rodrigues): it can retrieve the available share
|
||||
# servers using one single subnet_id from the availability zone
|
||||
# subnets, because if the share server has one, it will have
|
||||
# all subnets on that availability zone.
|
||||
share_network_subnet_id = share_network_subnets[0]['id']
|
||||
try:
|
||||
available_share_servers = (
|
||||
self.db
|
||||
@ -996,10 +1007,12 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
context,
|
||||
{
|
||||
'host': self.host,
|
||||
'share_network_subnet_id': share_network_subnet_id,
|
||||
'share_network_subnets': share_network_subnets,
|
||||
'status': constants.STATUS_CREATING,
|
||||
'security_service_update_support': (
|
||||
self.driver.security_service_update_support),
|
||||
'network_allocation_update_support': (
|
||||
self.driver.network_allocation_update_support),
|
||||
}
|
||||
)
|
||||
|
||||
@ -3037,13 +3050,13 @@ 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 subnet %(subnet)s and share network "
|
||||
"share network subnets %(subnets)s and share network "
|
||||
"%(network)s cannot be deleted unless this share server "
|
||||
"has been removed.")
|
||||
msg_args = {
|
||||
'share': share_id,
|
||||
'server': share_server['id'],
|
||||
'subnet': share_server['share_network_subnet_id'],
|
||||
'subnets': share_server['share_network_subnet_ids'],
|
||||
'network': share_instance['share_network_id']
|
||||
}
|
||||
LOG.warning(msg, msg_args)
|
||||
@ -3130,8 +3143,11 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
server = self.db.share_server_get(context, share_server_id)
|
||||
|
||||
try:
|
||||
# NOTE(felipe_rodrigues): Manila does not support manage share
|
||||
# server with multiple allocations, so it can get the first
|
||||
# subnet_id element.
|
||||
share_network_subnet = self.db.share_network_subnet_get(
|
||||
context, server['share_network_subnet_id'])
|
||||
context, server['share_network_subnet_ids'][0])
|
||||
share_network = self.db.share_network_get(
|
||||
context, share_network_subnet['share_network_id'])
|
||||
|
||||
@ -3217,7 +3233,9 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
self.db.share_server_update(
|
||||
context, share_server_id,
|
||||
{'status': constants.STATUS_ACTIVE,
|
||||
'identifier': new_identifier})
|
||||
'identifier': new_identifier,
|
||||
'network_allocation_update_support': (
|
||||
self.driver.network_allocation_update_support)})
|
||||
|
||||
except Exception:
|
||||
msg = "Error managing share server %s"
|
||||
@ -4039,56 +4057,105 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
self._publish_service_capabilities(context)
|
||||
|
||||
def _form_server_setup_info(self, context, share_server, share_network,
|
||||
share_network_subnet):
|
||||
share_network_subnets):
|
||||
share_server_id = share_server['id']
|
||||
# Network info is used by driver for setting up share server
|
||||
# and getting server info on share creation.
|
||||
network_allocations = self.db.network_allocations_get_for_share_server(
|
||||
context, share_server_id, label='user')
|
||||
admin_network_allocations = (
|
||||
self.db.network_allocations_get_for_share_server(
|
||||
context, share_server_id, label='admin'))
|
||||
# NOTE(vponomaryov): following network_info fields are deprecated:
|
||||
# 'segmentation_id', 'cidr' and 'network_type'.
|
||||
# And they should be used from network allocations directly.
|
||||
# They should be removed right after no one uses them.
|
||||
network_info = {
|
||||
'server_id': share_server['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_subnet['network_type'],
|
||||
}
|
||||
|
||||
# NOTE(felipe_rodrigues): items in the network_info list contain
|
||||
# same values for the keys: server_id, admin_network_allocations,
|
||||
# security_services and backend_details.
|
||||
network_info = []
|
||||
for share_network_subnet in share_network_subnets:
|
||||
network_allocations = (
|
||||
self.db.network_allocations_get_for_share_server(
|
||||
context, share_server_id, label='user',
|
||||
subnet_id=share_network_subnet['id']))
|
||||
# NOTE(vponomaryov): following network_info fields are deprecated:
|
||||
# 'segmentation_id', 'cidr' and 'network_type'.
|
||||
# And they should be used from network allocations directly.
|
||||
# They should be removed right after no one uses them.
|
||||
network_info.append({
|
||||
'server_id': share_server['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_subnet['network_type'],
|
||||
})
|
||||
return network_info
|
||||
|
||||
def _handle_setup_server_error(self, context, share_server_id, e):
|
||||
details = getattr(e, "detail_data", {})
|
||||
if isinstance(details, dict):
|
||||
server_details = details.get("server_details", {})
|
||||
if not isinstance(server_details, dict):
|
||||
LOG.debug(
|
||||
("Cannot save non-dict data (%(data)s) provided as "
|
||||
"'server details' of failed share server '%(server)s'."),
|
||||
{"server": share_server_id, "data": server_details})
|
||||
else:
|
||||
invalid_details = []
|
||||
for key, value in server_details.items():
|
||||
try:
|
||||
self.db.share_server_backend_details_set(
|
||||
context, share_server_id, {key: value})
|
||||
except Exception:
|
||||
invalid_details.append("%(key)s: %(value)s" % {
|
||||
'key': str(key),
|
||||
'value': str(value)
|
||||
})
|
||||
if invalid_details:
|
||||
LOG.debug(
|
||||
("Following server details cannot be written to db : "
|
||||
"%s"), str("\n".join(invalid_details)))
|
||||
else:
|
||||
LOG.debug(
|
||||
("Cannot save non-dict data (%(data)s) provided as 'detail "
|
||||
"data' of failed share server '%(server)s'."),
|
||||
{"server": share_server_id, "data": details})
|
||||
|
||||
self.db.share_server_update(
|
||||
context, share_server_id, {'status': constants.STATUS_ERROR})
|
||||
|
||||
def _setup_server(self, context, share_server, metadata):
|
||||
subnets = share_server['share_network_subnets']
|
||||
if not subnets:
|
||||
raise exception.NetworkBadConfigurationException(
|
||||
reason="share server does not have subnet")
|
||||
|
||||
# all subnets reside on same share network, get it from the first one.
|
||||
share_network_id = subnets[0]['share_network_id']
|
||||
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_network_id)
|
||||
self.driver.allocate_network(context, share_server, share_network,
|
||||
share_network_subnet)
|
||||
share_network = self.db.share_network_get(context,
|
||||
share_network_id)
|
||||
for share_network_subnet in subnets:
|
||||
self.driver.allocate_network(
|
||||
context, share_server, share_network, share_network_subnet)
|
||||
self.driver.allocate_admin_network(context, share_server)
|
||||
|
||||
# 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, share_network_subnet)
|
||||
self._validate_segmentation_id(network_info)
|
||||
# Get share_network_subnets in case they were updated.
|
||||
share_network_subnets = (
|
||||
self.db.share_network_subnet_get_all_by_share_server_id(
|
||||
context, share_server['id']))
|
||||
|
||||
network_info_list = self._form_server_setup_info(
|
||||
context, share_server, share_network, share_network_subnets)
|
||||
for network_info in network_info_list:
|
||||
self._validate_segmentation_id(network_info)
|
||||
|
||||
# NOTE(vponomaryov): Save security services data to share server
|
||||
# details table to remove dependency from share network after
|
||||
# creation operation. It will allow us to delete share server and
|
||||
# share network separately without dependency on each other.
|
||||
for security_service in network_info['security_services']:
|
||||
for security_service in network_info_list[0]['security_services']:
|
||||
ss_type = security_service['type']
|
||||
data = {
|
||||
'name': security_service['name'],
|
||||
@ -4105,7 +4172,7 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
{'security_service_' + ss_type: jsonutils.dumps(data)})
|
||||
|
||||
server_info = self.driver.setup_server(
|
||||
network_info, metadata=metadata)
|
||||
network_info_list, metadata=metadata)
|
||||
|
||||
self.driver.update_network_allocation(context, share_server)
|
||||
self.driver.update_admin_network_allocation(context, share_server)
|
||||
@ -4120,42 +4187,7 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
'identifier', share_server['id'])})
|
||||
except Exception as e:
|
||||
with excutils.save_and_reraise_exception():
|
||||
details = getattr(e, "detail_data", {})
|
||||
|
||||
if isinstance(details, dict):
|
||||
server_details = details.get("server_details", {})
|
||||
if not isinstance(server_details, dict):
|
||||
LOG.debug(
|
||||
("Cannot save non-dict data (%(data)s) "
|
||||
"provided as 'server details' of "
|
||||
"failed share server '%(server)s'."),
|
||||
{"server": share_server["id"],
|
||||
"data": server_details})
|
||||
else:
|
||||
invalid_details = []
|
||||
for key, value in server_details.items():
|
||||
try:
|
||||
self.db.share_server_backend_details_set(
|
||||
context, share_server['id'], {key: value})
|
||||
except Exception:
|
||||
invalid_details.append("%(key)s: %(value)s" % {
|
||||
'key': key,
|
||||
'value': value
|
||||
})
|
||||
if invalid_details:
|
||||
LOG.debug(
|
||||
("Following server details "
|
||||
"cannot be written to db : %s"),
|
||||
"\n".join(invalid_details))
|
||||
else:
|
||||
LOG.debug(
|
||||
("Cannot save non-dict data (%(data)s) provided as "
|
||||
"'detail data' of failed share server '%(server)s'."),
|
||||
{"server": share_server["id"], "data": details})
|
||||
|
||||
self.db.share_server_update(
|
||||
context, share_server['id'],
|
||||
{'status': constants.STATUS_ERROR})
|
||||
self._handle_setup_server_error(context, share_server['id'], e)
|
||||
self.driver.deallocate_network(context, share_server['id'])
|
||||
|
||||
def _validate_segmentation_id(self, network_info):
|
||||
@ -4200,8 +4232,11 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
@utils.require_driver_initialized
|
||||
def delete_share_server(self, context, share_server):
|
||||
|
||||
subnet_id = (share_server['share_network_subnet_ids'][0]
|
||||
if share_server['share_network_subnet_ids'] else None)
|
||||
|
||||
@utils.synchronized(
|
||||
"share_manager_%s" % share_server['share_network_subnet_id'])
|
||||
"share_manager_%s" % 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:
|
||||
@ -4443,8 +4478,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_subnet = share_server['share_network_subnet']
|
||||
share_network_id = share_network_subnet['share_network_id']
|
||||
share_network_id = (
|
||||
share_server['share_network_id'])
|
||||
|
||||
if share_network_id and not self.driver.driver_handles_share_servers:
|
||||
self.db.share_group_update(
|
||||
@ -4457,14 +4492,17 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
|
||||
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)
|
||||
subnets = (
|
||||
self.db.share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id, availability_zone_id))
|
||||
|
||||
if not subnets:
|
||||
raise exception.ShareNetworkSubnetNotFound(
|
||||
share_network_subnet_id=None)
|
||||
try:
|
||||
share_server, share_group_ref = (
|
||||
self._provide_share_server_for_share_group(
|
||||
context, share_network_id, subnet.get('id'),
|
||||
share_group_ref,
|
||||
context, share_network_id, subnets, share_group_ref,
|
||||
share_group_snapshot=snap_ref,
|
||||
)
|
||||
)
|
||||
@ -4764,8 +4802,8 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
'share_network_id': share_server.get('share_network_id'),
|
||||
'created_at': share_server.get('created_at'),
|
||||
'backend_details': share_server.get('backend_details'),
|
||||
'share_network_subnet_id':
|
||||
share_server.get('share_network_subnet_id', None),
|
||||
'share_network_subnet_ids':
|
||||
share_server.get('share_network_subnet_ids', []),
|
||||
'is_auto_deletable': share_server.get('is_auto_deletable', None),
|
||||
'identifier': share_server.get('identifier', None),
|
||||
'network_allocations': share_server.get('network_allocations',
|
||||
@ -5101,11 +5139,10 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
if not create_server_on_backend:
|
||||
dest_share_server = self.db.share_server_get(
|
||||
context, dest_share_server['id'])
|
||||
current_subnet = dest_share_server['share_network_subnet']
|
||||
old_subnet = source_share_server['share_network_subnet']
|
||||
for key in ['neutron_net_id', 'neutron_subnet_id']:
|
||||
if current_subnet.get(key) != old_subnet.get(key):
|
||||
net_changes_identified = True
|
||||
net_changes_identified = (
|
||||
not share_utils.is_az_subnets_compatible(
|
||||
dest_share_server['share_network_subnets'],
|
||||
source_share_server['share_network_subnets']))
|
||||
|
||||
# NOTE(carloss): Even though the share back end won't need to
|
||||
# create a share server, if a network change was identified,
|
||||
@ -5115,11 +5152,14 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
# In such case, the migration will be disruptive, since the old
|
||||
# allocations will be replaced by the new ones.
|
||||
if net_changes_identified:
|
||||
share_network_subnet = self.db.share_network_subnet_get(
|
||||
context, dest_share_server['share_network_subnet_id'])
|
||||
self.driver.allocate_network(
|
||||
context, dest_share_server, new_share_network,
|
||||
share_network_subnet)
|
||||
share_network_subnets = (
|
||||
self.db.
|
||||
share_network_subnet_get_all_by_share_server_id(
|
||||
context, dest_share_server['id']))
|
||||
for share_network_subnet in share_network_subnets:
|
||||
self.driver.allocate_network(
|
||||
context, dest_share_server, new_share_network,
|
||||
share_network_subnet)
|
||||
self.driver.allocate_admin_network(
|
||||
context, dest_share_server)
|
||||
# Refresh the share server so it will have the network
|
||||
@ -5503,11 +5543,11 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
{'task_state': constants.TASK_STATE_MIGRATION_COMPLETING})
|
||||
|
||||
# Retrieve network allocations reserved for the new share server
|
||||
dest_sns = dest_share_server['share_network_subnet']
|
||||
dest_sns_id = dest_sns['id']
|
||||
dest_sn_id = dest_sns['share_network_id']
|
||||
dest_snss = dest_share_server['share_network_subnets']
|
||||
dest_sn_id = dest_snss[0]['share_network_id']
|
||||
dest_sn = self.db.share_network_get(context, dest_sn_id)
|
||||
dest_sns = self.db.share_network_subnet_get(context, dest_sns_id)
|
||||
dest_snss = self.db.share_network_subnet_get_all_by_share_server_id(
|
||||
context, dest_share_server['id'])
|
||||
|
||||
migration_reused_network_allocations = (len(
|
||||
self.db.network_allocations_get_for_share_server(
|
||||
@ -5519,16 +5559,20 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
else source_share_server)
|
||||
|
||||
new_network_allocations = self._form_server_setup_info(
|
||||
context, server_to_get_allocations, dest_sn, dest_sns)
|
||||
context, server_to_get_allocations, dest_sn, dest_snss)
|
||||
|
||||
model_update = self.driver.share_server_migration_complete(
|
||||
context, source_share_server, dest_share_server, share_instances,
|
||||
snapshot_instances, new_network_allocations)
|
||||
|
||||
if not migration_reused_network_allocations:
|
||||
network_allocations = []
|
||||
for net_allocation in new_network_allocations:
|
||||
network_allocations += net_allocation['network_allocations']
|
||||
|
||||
all_allocations = [
|
||||
new_network_allocations['network_allocations'],
|
||||
new_network_allocations['admin_network_allocations']
|
||||
network_allocations,
|
||||
new_network_allocations[0]['admin_network_allocations']
|
||||
]
|
||||
for allocations in all_allocations:
|
||||
for allocation in allocations:
|
||||
@ -5726,7 +5770,8 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
snapshot_instances)
|
||||
|
||||
@locked_share_network_operation
|
||||
def _check_share_network_update_finished(self, context, share_network_id):
|
||||
def _check_share_network_update_finished(
|
||||
self, context, share_network_id=None):
|
||||
# Check if this share network is already active
|
||||
share_network = self.db.share_network_get(context, share_network_id)
|
||||
if share_network['status'] == constants.STATUS_NETWORK_ACTIVE:
|
||||
@ -5775,14 +5820,14 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
filters={'share_network_id': share_network_id})
|
||||
|
||||
for share_server in share_servers:
|
||||
share_network_subnet = share_server['share_network_subnet']
|
||||
share_network_subnet_id = share_network_subnet['id']
|
||||
|
||||
# Get share_network_subnet in case it was updated.
|
||||
share_network_subnet = self.db.share_network_subnet_get(
|
||||
context, share_network_subnet_id)
|
||||
share_network_subnets = (
|
||||
self.db.share_network_subnet_get_all_by_share_server_id(
|
||||
context, share_server['id']))
|
||||
|
||||
network_info = self._form_server_setup_info(
|
||||
context, share_server, share_network, share_network_subnet)
|
||||
context, share_server, share_network, share_network_subnets)
|
||||
|
||||
share_instances = (
|
||||
self.db.share_instances_get_all_by_share_server(
|
||||
@ -5883,7 +5928,8 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
|
||||
# Check if all share servers have already finished their updates in
|
||||
# order to properly update share network status
|
||||
self._check_share_network_update_finished(context, share_network['id'])
|
||||
self._check_share_network_update_finished(
|
||||
context, share_network_id=share_network['id'])
|
||||
|
||||
def update_share_network_security_service(
|
||||
self, context, share_network_id, new_security_service_id,
|
||||
@ -5925,3 +5971,234 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
LOG.debug('A share network security service check was requested '
|
||||
'but no entries were found in database. Ignoring call '
|
||||
'and returning.')
|
||||
|
||||
@api.locked_share_server_update_allocations_operation
|
||||
def _update_share_server_allocations_check_operation(
|
||||
self, context, is_supported, share_network_id=None,
|
||||
availability_zone_id=None):
|
||||
update_key = self.share_api.get_share_server_update_allocations_key(
|
||||
share_network_id, availability_zone_id)
|
||||
current_hosts_info = self.db.async_operation_data_get(
|
||||
context, share_network_id, update_key)
|
||||
if current_hosts_info:
|
||||
current_hosts = json.loads(current_hosts_info)
|
||||
current_hosts[self.host] = is_supported
|
||||
self.db.async_operation_data_update(
|
||||
context, share_network_id,
|
||||
{update_key: json.dumps(current_hosts)})
|
||||
else:
|
||||
LOG.debug('A share network subnet create check was requested '
|
||||
'but no entries were found in database. Ignoring call '
|
||||
'and returning.')
|
||||
|
||||
def _get_subnet_allocations(self, context, share_server_id,
|
||||
share_network_subnet):
|
||||
|
||||
network_allocations = (
|
||||
self.db.network_allocations_get_for_share_server(
|
||||
context, share_server_id, label='user',
|
||||
subnet_id=share_network_subnet['id']))
|
||||
|
||||
return {
|
||||
'share_network_subnet_id': share_network_subnet['id'],
|
||||
'neutron_net_id': share_network_subnet['neutron_net_id'],
|
||||
'neutron_subnet_id': share_network_subnet['neutron_subnet_id'],
|
||||
'network_allocations': network_allocations,
|
||||
}
|
||||
|
||||
def _form_network_allocations(self, context, share_server_id,
|
||||
share_network_subnets):
|
||||
|
||||
subnet_allocations = []
|
||||
for share_network_subnet in share_network_subnets:
|
||||
subnet_allocations.append(self._get_subnet_allocations(
|
||||
context, share_server_id, share_network_subnet))
|
||||
|
||||
admin_network_allocations = (
|
||||
self.db.network_allocations_get_for_share_server(
|
||||
context, share_server_id, label='admin'))
|
||||
|
||||
return {
|
||||
'admin_network_allocations': admin_network_allocations,
|
||||
'subnets': subnet_allocations,
|
||||
}
|
||||
|
||||
def check_update_share_server_network_allocations(
|
||||
self, context, share_network_id, new_share_network_subnet):
|
||||
|
||||
share_network = self.db.share_network_get(
|
||||
context, share_network_id)
|
||||
az_subnets = (
|
||||
self.db.share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id,
|
||||
new_share_network_subnet['availability_zone_id'],
|
||||
fallback_to_default=False)
|
||||
)
|
||||
self.driver.network_api.include_network_info(new_share_network_subnet)
|
||||
|
||||
# all subnets have the same set of share servers, so do the check from
|
||||
# servers in the first subnet.
|
||||
share_servers = az_subnets[0]['share_servers'] if az_subnets else []
|
||||
is_supported = True
|
||||
for share_server in share_servers:
|
||||
|
||||
current_network_allocations = self._form_network_allocations(
|
||||
context, share_server['id'], az_subnets)
|
||||
|
||||
share_instances = (
|
||||
self.db.share_instances_get_all_by_share_server(
|
||||
context, share_server['id'], with_share_data=True))
|
||||
share_instance_ids = [sn.id for sn in share_instances]
|
||||
|
||||
share_instances_rules = []
|
||||
for share_instance_id in share_instance_ids:
|
||||
instance_rules = {
|
||||
'share_instance_id': share_instance_id,
|
||||
'access_rules': (
|
||||
self.db.share_access_get_all_for_instance(
|
||||
context, share_instance_id))
|
||||
}
|
||||
share_instances_rules.append(instance_rules)
|
||||
|
||||
if self.driver.check_update_share_server_network_allocations(
|
||||
context, share_server, current_network_allocations,
|
||||
new_share_network_subnet,
|
||||
share_network['security_services'],
|
||||
share_instances, share_instances_rules):
|
||||
# Check the next share server.
|
||||
continue
|
||||
else:
|
||||
# At least one share server doesn't support this update.
|
||||
is_supported = False
|
||||
break
|
||||
|
||||
self._update_share_server_allocations_check_operation(
|
||||
context, is_supported, share_network_id=share_network_id,
|
||||
availability_zone_id=(
|
||||
new_share_network_subnet['availability_zone_id']))
|
||||
|
||||
def _do_update_share_server_network_allocations(
|
||||
self, context, share_server, share_network, new_subnet,
|
||||
current_network_allocations, share_instances,
|
||||
snapshot_instance_ids):
|
||||
|
||||
self.driver.allocate_network(
|
||||
context, share_server, share_network, new_subnet)
|
||||
new_network_allocations = self._get_subnet_allocations(
|
||||
context, share_server['id'], new_subnet)
|
||||
if not new_network_allocations['network_allocations']:
|
||||
raise exception.AllocationsNotFoundForShareServer(
|
||||
share_server_id=share_server['id'])
|
||||
|
||||
# NOTE(felipe_rodrigues): all allocations have the same network
|
||||
# segmentation info, so validation from the first one.
|
||||
self._validate_segmentation_id(
|
||||
new_network_allocations['network_allocations'][0])
|
||||
|
||||
model_update = self.driver.update_share_server_network_allocations(
|
||||
context, share_server, current_network_allocations,
|
||||
new_network_allocations, share_network['security_services'],
|
||||
share_instances, snapshot_instance_ids)
|
||||
|
||||
self.driver.update_network_allocation(context, share_server)
|
||||
|
||||
driver_backend_details = model_update.get('server_details')
|
||||
if driver_backend_details:
|
||||
self.db.share_server_backend_details_set(
|
||||
context, share_server['id'], driver_backend_details)
|
||||
|
||||
share_updates = model_update.get('share_updates', {})
|
||||
for share_instance_id, export_locations in share_updates.items():
|
||||
self.db.share_export_locations_update(
|
||||
context, share_instance_id, export_locations)
|
||||
|
||||
snapshot_updates = model_update.get('snapshot_updates', {})
|
||||
for snap_instance_id, model_update in snapshot_updates.items():
|
||||
snapshot_export_locations = model_update.pop(
|
||||
'export_locations', [])
|
||||
if model_update:
|
||||
self.db.share_snapshot_instance_update(
|
||||
context, snap_instance_id, model_update)
|
||||
|
||||
if snapshot_export_locations:
|
||||
export_locations_update = []
|
||||
for exp_location in snapshot_export_locations:
|
||||
updated_el = {
|
||||
'path': exp_location['path'],
|
||||
'is_admin_only': exp_location['is_admin_only'],
|
||||
}
|
||||
export_locations_update.append(updated_el)
|
||||
self.db.share_snapshot_instance_export_locations_update(
|
||||
context, snap_instance_id, export_locations_update)
|
||||
|
||||
def update_share_server_network_allocations(
|
||||
self, context, share_network_id, new_share_network_subnet_id):
|
||||
|
||||
share_network = self.db.share_network_get(
|
||||
context, share_network_id)
|
||||
new_subnet = self.db.share_network_subnet_get(
|
||||
context, new_share_network_subnet_id)
|
||||
current_subnets = (
|
||||
self.db.share_network_subnets_get_all_by_availability_zone_id(
|
||||
context, share_network_id,
|
||||
new_subnet['availability_zone_id'],
|
||||
fallback_to_default=False)
|
||||
)
|
||||
current_subnets = [subnet for subnet in current_subnets
|
||||
if subnet['id'] != new_share_network_subnet_id]
|
||||
share_servers = (
|
||||
self.db.share_server_get_all_by_host_and_share_subnet_valid(
|
||||
context, self.host, new_share_network_subnet_id,
|
||||
server_status=constants.STATUS_SERVER_NETWORK_CHANGE))
|
||||
for share_server in share_servers:
|
||||
|
||||
share_server_id = share_server['id']
|
||||
current_network_allocations = self._form_network_allocations(
|
||||
context, share_server_id, current_subnets)
|
||||
share_instances = (
|
||||
self.db.share_instances_get_all_by_share_server(
|
||||
context, share_server_id, with_share_data=True))
|
||||
share_instance_ids = [x['id'] for x in share_instances]
|
||||
snapshot_instances = (
|
||||
self.db.share_snapshot_instance_get_all_with_filters(
|
||||
context,
|
||||
{'share_instance_ids': share_instance_ids}))
|
||||
snapshot_instance_ids = [x['id'] for x in snapshot_instances]
|
||||
|
||||
try:
|
||||
self._do_update_share_server_network_allocations(
|
||||
context, share_server, share_network, new_subnet,
|
||||
current_network_allocations, share_instances,
|
||||
snapshot_instances)
|
||||
except Exception as e:
|
||||
msg = ('Failed to update allocations of share server '
|
||||
'%(server_id)s on subnet %(subnet_id)s: %(e)s.')
|
||||
data = {
|
||||
'server_id': share_server_id,
|
||||
'subnet_id': new_share_network_subnet_id,
|
||||
'e': str(e),
|
||||
}
|
||||
LOG.exception(msg, data)
|
||||
|
||||
# Set resources to error. Allocations configuration must be
|
||||
# fixed before restoring it to active again.
|
||||
self._handle_setup_server_error(context, share_server_id, e)
|
||||
self._update_resource_status(
|
||||
context, constants.STATUS_ERROR,
|
||||
share_instance_ids=share_instance_ids,
|
||||
snapshot_instance_ids=snapshot_instance_ids)
|
||||
|
||||
continue
|
||||
|
||||
msg = _(
|
||||
"Network allocations was successfully updated on share "
|
||||
"server %s.") % share_server['id']
|
||||
LOG.info(msg)
|
||||
self.db.share_server_update(
|
||||
context, share_server['id'],
|
||||
{'status': constants.STATUS_ACTIVE})
|
||||
|
||||
# Check if all share servers have already finished their updates in
|
||||
# order to properly update share network status.
|
||||
self._check_share_network_update_finished(
|
||||
context, share_network_id=share_network['id'])
|
||||
|
@ -81,6 +81,8 @@ class ShareAPI(object):
|
||||
and share_server_get_progress()
|
||||
1.22 - Add update_share_network_security_service() and
|
||||
check_update_share_network_security_service()
|
||||
1.23 - Add update_share_server_network_allocations() and
|
||||
check_update_share_server_network_allocations()
|
||||
"""
|
||||
|
||||
BASE_RPC_API_VERSION = '1.0'
|
||||
@ -89,7 +91,7 @@ class ShareAPI(object):
|
||||
super(ShareAPI, self).__init__()
|
||||
target = messaging.Target(topic=CONF.share_topic,
|
||||
version=self.BASE_RPC_API_VERSION)
|
||||
self.client = rpc.get_client(target, version_cap='1.22')
|
||||
self.client = rpc.get_client(target, version_cap='1.23')
|
||||
|
||||
def create_share_instance(self, context, share_instance, host,
|
||||
request_spec, filter_properties,
|
||||
@ -462,3 +464,25 @@ class ShareAPI(object):
|
||||
share_network_id=share_network_id,
|
||||
new_security_service_id=new_security_service_id,
|
||||
current_security_service_id=current_security_service_id)
|
||||
|
||||
def check_update_share_server_network_allocations(
|
||||
self, context, dest_host, share_network_id,
|
||||
new_share_network_subnet):
|
||||
host = utils.extract_host(dest_host)
|
||||
call_context = self.client.prepare(server=host, version='1.23')
|
||||
call_context.cast(
|
||||
context,
|
||||
'check_update_share_server_network_allocations',
|
||||
share_network_id=share_network_id,
|
||||
new_share_network_subnet=new_share_network_subnet)
|
||||
|
||||
def update_share_server_network_allocations(
|
||||
self, context, dest_host, share_network_id,
|
||||
new_share_network_subnet_id):
|
||||
host = utils.extract_host(dest_host)
|
||||
call_context = self.client.prepare(server=host, version='1.23')
|
||||
call_context.cast(
|
||||
context,
|
||||
'update_share_server_network_allocations',
|
||||
share_network_id=share_network_id,
|
||||
new_share_network_subnet_id=new_share_network_subnet_id)
|
||||
|
@ -152,3 +152,22 @@ def _usage_from_share(share_ref, share_instance_ref, **extra_usage_info):
|
||||
|
||||
def get_recent_db_migration_id():
|
||||
return migration.version()
|
||||
|
||||
|
||||
def is_az_subnets_compatible(subnet_list, new_subnet_list):
|
||||
if len(subnet_list) != len(new_subnet_list):
|
||||
return False
|
||||
|
||||
for subnet in subnet_list:
|
||||
found_compatible = False
|
||||
for new_subnet in new_subnet_list:
|
||||
if (subnet.get('neutron_net_id') ==
|
||||
new_subnet.get('neutron_net_id') and
|
||||
subnet.get('neutron_subnet_id') ==
|
||||
new_subnet.get('neutron_subnet_id')):
|
||||
found_compatible = True
|
||||
break
|
||||
if not found_compatible:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
@ -24,6 +24,7 @@ import webob
|
||||
import webob.exc
|
||||
|
||||
from manila.api import common
|
||||
from manila.db import api as db_api
|
||||
from manila import exception
|
||||
from manila import policy
|
||||
from manila import test
|
||||
@ -354,6 +355,108 @@ class MiscFunctionsTest(test.TestCase):
|
||||
common.parse_is_public,
|
||||
'fakefakefake')
|
||||
|
||||
@ddt.data(None, 'fake_az')
|
||||
def test__get_existing_subnets(self, az):
|
||||
default_subnets = 'fake_default_subnets'
|
||||
mock_get_default_subnets = self.mock_object(
|
||||
db_api, 'share_network_subnet_get_default_subnets',
|
||||
mock.Mock(return_value=default_subnets))
|
||||
subnets = 'fake_subnets'
|
||||
mock_get_subnets = self.mock_object(
|
||||
db_api, 'share_network_subnets_get_all_by_availability_zone_id',
|
||||
mock.Mock(return_value=subnets))
|
||||
|
||||
net_id = 'fake_net'
|
||||
context = 'fake_context'
|
||||
res_subnets = common._get_existing_subnets(context, net_id, az)
|
||||
|
||||
if az:
|
||||
self.assertEqual(subnets, res_subnets)
|
||||
mock_get_subnets.assert_called_once_with(context, net_id, az,
|
||||
fallback_to_default=False)
|
||||
mock_get_default_subnets.assert_not_called()
|
||||
else:
|
||||
self.assertEqual(default_subnets, res_subnets)
|
||||
mock_get_subnets.assert_not_called()
|
||||
mock_get_default_subnets.assert_called_once_with(context, net_id)
|
||||
|
||||
def test_validate_subnet_create(self):
|
||||
mock_check_net = self.mock_object(common, 'check_net_id_and_subnet_id')
|
||||
net = 'fake_net'
|
||||
mock_get_net = self.mock_object(db_api, 'share_network_get',
|
||||
mock.Mock(return_value=net))
|
||||
az_id = 'fake_az_id'
|
||||
az = {'id': az_id}
|
||||
mock_get_az = self.mock_object(db_api, 'availability_zone_get',
|
||||
mock.Mock(return_value=az))
|
||||
subnets = 'fake_subnets'
|
||||
mock_get_subnets = self.mock_object(common, '_get_existing_subnets',
|
||||
mock.Mock(return_value=subnets))
|
||||
|
||||
net_id = 'fake_net_id'
|
||||
context = 'fake_context'
|
||||
az_name = 'fake_az'
|
||||
data = {'availability_zone': az_name}
|
||||
res_net, res_subnets = common.validate_subnet_create(
|
||||
context, net_id, data, True)
|
||||
|
||||
self.assertEqual(net, res_net)
|
||||
self.assertEqual(subnets, res_subnets)
|
||||
self.assertEqual(data['availability_zone_id'], az_id)
|
||||
mock_check_net.assert_called_once_with(data)
|
||||
mock_get_net.assert_called_once_with(context, net_id)
|
||||
mock_get_az.assert_called_once_with(context, az_name)
|
||||
mock_get_subnets.assert_called_once_with(context, net_id, az_id)
|
||||
|
||||
def test_validate_subnet_create_net_not_found(self):
|
||||
|
||||
self.mock_object(common, 'check_net_id_and_subnet_id')
|
||||
self.mock_object(db_api, 'share_network_get',
|
||||
mock.Mock(side_effect=exception.ShareNetworkNotFound(
|
||||
share_network_id="fake_id")))
|
||||
|
||||
net_id = 'fake_net_id'
|
||||
context = 'fake_context'
|
||||
az_name = 'fake_az'
|
||||
data = {'availability_zone': az_name}
|
||||
self.assertRaises(webob.exc.HTTPNotFound,
|
||||
common.validate_subnet_create,
|
||||
context, net_id, data, True)
|
||||
|
||||
def test_validate_subnet_create_az_not_found(self):
|
||||
self.mock_object(common, 'check_net_id_and_subnet_id')
|
||||
self.mock_object(db_api, 'share_network_get',
|
||||
mock.Mock(return_value='fake_net'))
|
||||
self.mock_object(
|
||||
db_api, 'availability_zone_get',
|
||||
mock.Mock(side_effect=exception.AvailabilityZoneNotFound(
|
||||
id='fake_id')))
|
||||
|
||||
net_id = 'fake_net_id'
|
||||
context = 'fake_context'
|
||||
az_name = 'fake_az'
|
||||
data = {'availability_zone': az_name}
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
common.validate_subnet_create,
|
||||
context, net_id, data, True)
|
||||
|
||||
def test_validate_subnet_create_multiple_subnet_not_support(self):
|
||||
self.mock_object(common, 'check_net_id_and_subnet_id')
|
||||
self.mock_object(db_api, 'share_network_get',
|
||||
mock.Mock(return_value='fake_net'))
|
||||
self.mock_object(db_api, 'availability_zone_get',
|
||||
mock.Mock(return_value={'id': 'fake_az_id'}))
|
||||
self.mock_object(common, '_get_existing_subnets',
|
||||
mock.Mock(return_value='fake_subnets'))
|
||||
|
||||
net_id = 'fake_net_id'
|
||||
context = 'fake_context'
|
||||
az_name = 'fake_az'
|
||||
data = {'availability_zone': az_name}
|
||||
self.assertRaises(webob.exc.HTTPConflict,
|
||||
common.validate_subnet_create,
|
||||
context, net_id, data, False)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ViewBuilderTest(test.TestCase):
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
from unittest import mock
|
||||
|
||||
import copy
|
||||
import ddt
|
||||
from webob import exc
|
||||
|
||||
@ -36,14 +37,15 @@ fake_share_server_list = {
|
||||
'host': 'fake_host',
|
||||
'share_network_name': 'fake_sn_name',
|
||||
'share_network_id': 'fake_sn_id',
|
||||
'share_network_subnet_id': 'fake_sns_id',
|
||||
'share_network_subnet_ids': ['fake_sns_id'],
|
||||
'project_id': 'fake_project_id',
|
||||
'id': 'fake_server_id',
|
||||
'is_auto_deletable': False,
|
||||
'task_state': None,
|
||||
'source_share_server_id': None,
|
||||
'identifier': 'fake_id',
|
||||
'security_service_update_support': False
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False
|
||||
},
|
||||
{
|
||||
'status': constants.STATUS_ERROR,
|
||||
@ -51,14 +53,15 @@ fake_share_server_list = {
|
||||
'host': 'fake_host_2',
|
||||
'share_network_name': 'fake_sn_id_2',
|
||||
'share_network_id': 'fake_sn_id_2',
|
||||
'share_network_subnet_id': 'fake_sns_id_2',
|
||||
'share_network_subnet_ids': ['fake_sns_id_2'],
|
||||
'project_id': 'fake_project_id_2',
|
||||
'id': 'fake_server_id_2',
|
||||
'is_auto_deletable': True,
|
||||
'task_state': None,
|
||||
'source_share_server_id': None,
|
||||
'identifier': 'fake_id_2',
|
||||
'security_service_update_support': False
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False
|
||||
|
||||
},
|
||||
]
|
||||
@ -87,7 +90,7 @@ 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',
|
||||
'share_network_subnet_ids': ['fake_sns_id'],
|
||||
'project_id': 'fake_project_id',
|
||||
'id': 'fake_server_id',
|
||||
'backend_details': {
|
||||
@ -98,7 +101,8 @@ fake_share_server_get_result = {
|
||||
'task_state': None,
|
||||
'source_share_server_id': None,
|
||||
'identifier': 'fake_id',
|
||||
'security_service_update_support': False
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,10 +128,11 @@ 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_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.share_network_subnets = kwargs.get('share_network_subnets', [{
|
||||
'id': 'fake_sns_id', 'share_network_id': 'fake_sn_id'}])
|
||||
self.share_network_subnet_ids = kwargs.get(
|
||||
'share_network_subnet_ids',
|
||||
[sn['id'] for sn in self.share_network_subnets])
|
||||
self.status = kwargs.get('status', constants.STATUS_ACTIVE)
|
||||
self.project_id = 'fake_project_id'
|
||||
self.identifier = kwargs.get('identifier', 'fake_id')
|
||||
@ -137,6 +142,9 @@ class FakeShareServer(object):
|
||||
self.backend_details = share_server_backend_details
|
||||
self.security_service_update_support = kwargs.get(
|
||||
'security_service_update_support', False)
|
||||
self.network_allocation_update_support = kwargs.get(
|
||||
'network_allocation_update_support', False)
|
||||
self.share_network_id = kwargs.get('share_network_id', 'fake_sn_id')
|
||||
|
||||
def __getitem__(self, item):
|
||||
return getattr(self, item)
|
||||
@ -147,15 +155,17 @@ def fake_share_server_get_all():
|
||||
FakeShareServer(),
|
||||
FakeShareServer(id='fake_server_id_2',
|
||||
host='fake_host_2',
|
||||
share_network_subnet={
|
||||
share_network_subnets=[{
|
||||
'id': 'fake_sns_id_2',
|
||||
'share_network_id': 'fake_sn_id_2',
|
||||
},
|
||||
}],
|
||||
share_network_id='fake_sn_id_2',
|
||||
identifier='fake_id_2',
|
||||
task_state=None,
|
||||
is_auto_deletable=True,
|
||||
status=constants.STATUS_ERROR,
|
||||
security_service_update_support=False)
|
||||
security_service_update_support=False,
|
||||
network_allocation_update_support=False),
|
||||
]
|
||||
return fake_share_servers
|
||||
|
||||
@ -184,7 +194,7 @@ class FakeRequestWithProjectId(FakeRequestAdmin):
|
||||
class FakeRequestWithShareNetworkSubnetId(FakeRequestAdmin):
|
||||
GET = {
|
||||
'share_network_subnet_id':
|
||||
fake_share_server_get_all()[0].share_network_subnet_id,
|
||||
fake_share_server_get_all()[0].share_network_subnet_ids,
|
||||
}
|
||||
|
||||
|
||||
@ -347,20 +357,43 @@ class ShareServerAPITest(test.TestCase):
|
||||
ctxt, self.resource_name, 'index')
|
||||
self.assertEqual(0, len(result['share_servers']))
|
||||
|
||||
def test_show(self):
|
||||
@ddt.data({'version': '2.70', 'share_network_name': ''},
|
||||
{'version': '2.70', 'share_network_name': 'fake_sn_name'},
|
||||
{'version': '2.68', 'share_network_name': 'fake_sn_name'})
|
||||
@ddt.unpack
|
||||
def test_show(self, version, share_network_name):
|
||||
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)
|
||||
request, ctxt = self._prepare_request('/show', use_admin_context=True,
|
||||
version=version)
|
||||
|
||||
share_network = copy.deepcopy(
|
||||
fake_share_network_get_list['share_networks'][0])
|
||||
share_server = copy.deepcopy(
|
||||
fake_share_server_get_result['share_server'])
|
||||
|
||||
if version == '2.68':
|
||||
share_server['share_network_subnet_id'] = \
|
||||
share_server['share_network_subnet_ids'][0]
|
||||
share_server.pop('share_network_subnet_ids')
|
||||
share_server.pop('network_allocation_update_support')
|
||||
|
||||
share_network['name'] = share_network_name
|
||||
if share_network['name']:
|
||||
share_server['share_network_name'] = share_network['name']
|
||||
else:
|
||||
share_server['share_network_name'] = share_network['id']
|
||||
|
||||
self.mock_object(db_api, 'share_network_get', mock.Mock(
|
||||
return_value=fake_share_network_get_list['share_networks'][0]))
|
||||
return_value=share_network))
|
||||
result = self.controller.show(
|
||||
request,
|
||||
fake_share_server_get_result['share_server']['id'])
|
||||
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'])
|
||||
self.assertEqual(fake_share_server_get_result['share_server'],
|
||||
ctxt, share_server['id'])
|
||||
self.assertEqual(share_server,
|
||||
result['share_server'])
|
||||
|
||||
@ddt.data(
|
||||
@ -389,7 +422,7 @@ class ShareServerAPITest(test.TestCase):
|
||||
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'])
|
||||
.share_network_subnets[0]['share_network_id'])
|
||||
db_api.share_network_get.assert_called_once_with(
|
||||
ctxt, exp_share_net_id)
|
||||
|
||||
|
@ -242,7 +242,7 @@ class ShareAPITest(test.TestCase):
|
||||
self.mock_object(common, 'check_share_network_is_active',
|
||||
mock.Mock(return_value=True))
|
||||
self.mock_object(
|
||||
db, 'share_network_subnet_get_by_availability_zone_id',
|
||||
db, 'share_network_subnets_get_all_by_availability_zone_id',
|
||||
mock.Mock(return_value={'id': 'fakesubnetid'}))
|
||||
|
||||
body = {"share": copy.deepcopy(shr)}
|
||||
@ -339,6 +339,8 @@ class ShareAPITest(test.TestCase):
|
||||
}
|
||||
parent_share_net = 444
|
||||
fake_share_net = {'id': parent_share_net}
|
||||
share_net_subnets = [db_utils.create_share_network_subnet(
|
||||
id='fake_subnet_id', share_network_id=fake_share_net['id'])]
|
||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||
display_name=shr['name'],
|
||||
display_description=shr['description'],
|
||||
@ -361,7 +363,8 @@ class ShareAPITest(test.TestCase):
|
||||
self.mock_object(common, 'check_share_network_is_active',
|
||||
mock.Mock(return_value=True))
|
||||
self.mock_object(
|
||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||
db, 'share_network_subnets_get_all_by_availability_zone_id',
|
||||
mock.Mock(return_value=share_net_subnets))
|
||||
|
||||
body = {"share": copy.deepcopy(shr)}
|
||||
req = fakes.HTTPRequest.blank('/v1/fake/shares')
|
||||
@ -391,6 +394,8 @@ class ShareAPITest(test.TestCase):
|
||||
"share_network_id": parent_share_net
|
||||
}
|
||||
fake_share_net = {'id': parent_share_net}
|
||||
share_net_subnets = [db_utils.create_share_network_subnet(
|
||||
id='fake_subnet_id', share_network_id=fake_share_net['id'])]
|
||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||
display_name=shr['name'],
|
||||
display_description=shr['description'],
|
||||
@ -413,7 +418,8 @@ class ShareAPITest(test.TestCase):
|
||||
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
||||
return_value=fake_share_net))
|
||||
self.mock_object(
|
||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||
db, 'share_network_subnets_get_all_by_availability_zone_id',
|
||||
mock.Mock(return_value=share_net_subnets))
|
||||
|
||||
body = {"share": copy.deepcopy(shr)}
|
||||
req = fakes.HTTPRequest.blank('/v1/fake/shares')
|
||||
@ -468,6 +474,8 @@ class ShareAPITest(test.TestCase):
|
||||
"share_network_id": parent_share_net
|
||||
}
|
||||
fake_share_net = {'id': parent_share_net}
|
||||
share_net_subnets = [db_utils.create_share_network_subnet(
|
||||
id='fake_subnet_id', share_network_id=fake_share_net['id'])]
|
||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||
display_name=shr['name'],
|
||||
display_description=shr['description'],
|
||||
@ -490,7 +498,8 @@ class ShareAPITest(test.TestCase):
|
||||
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
||||
return_value=fake_share_net))
|
||||
self.mock_object(
|
||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||
db, 'share_network_subnets_get_all_by_availability_zone_id',
|
||||
mock.Mock(return_value=share_net_subnets))
|
||||
|
||||
body = {"share": copy.deepcopy(shr)}
|
||||
req = fakes.HTTPRequest.blank('/v1/fake/shares', version=microversion)
|
||||
@ -558,7 +567,7 @@ class ShareAPITest(test.TestCase):
|
||||
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',
|
||||
db, 'share_network_subnets_get_all_by_availability_zone_id',
|
||||
mock.Mock(return_value=None))
|
||||
self.mock_object(common, 'check_share_network_is_active')
|
||||
|
||||
|
@ -20,6 +20,7 @@ import ddt
|
||||
from oslo_db import exception as db_exception
|
||||
|
||||
from manila.api import common
|
||||
from manila.api.openstack import api_version_request as api_version
|
||||
from manila.api.v2 import share_network_subnets
|
||||
from manila.db import api as db_api
|
||||
from manila import exception
|
||||
@ -61,16 +62,17 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
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_server = db_utils.create_share_server(
|
||||
share_network_subnets=[self.subnet])
|
||||
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']
|
||||
self.subnet['share_servers'] = [self.share_server]
|
||||
|
||||
mock_sns_get = self.mock_object(
|
||||
db_api, 'share_network_subnet_get',
|
||||
@ -150,6 +152,7 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
req = fakes.HTTPRequest.blank('/subnets/%s' % self.subnet['id'],
|
||||
version="2.51")
|
||||
context = req.environ['manila.context']
|
||||
self.subnet['share_servers'] = [self.share_server]
|
||||
|
||||
mock_sns_get = self.mock_object(
|
||||
db_api, 'share_network_subnet_get',
|
||||
@ -182,7 +185,10 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
req = fakes.HTTPRequest.blank('/subnets/%s' % self.subnet['id'],
|
||||
version="2.51")
|
||||
context = req.environ['manila.context']
|
||||
self.subnet['share_servers'] = [self.share_server]
|
||||
|
||||
mock_network_get = self.mock_object(
|
||||
db_api, 'share_network_get')
|
||||
mock_sns_get = self.mock_object(
|
||||
db_api, 'share_network_subnet_get',
|
||||
mock.Mock(return_value=self.subnet))
|
||||
@ -196,6 +202,8 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
self.share_network['id'],
|
||||
self.subnet['id'])
|
||||
|
||||
mock_network_get.assert_called_once_with(
|
||||
context, self.share_network['id'])
|
||||
mock_sns_get.assert_called_once_with(
|
||||
context, self.subnet['id'])
|
||||
mock_all_get_all_shares_by_ss.assert_called_once_with(
|
||||
@ -204,34 +212,6 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
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'],
|
||||
@ -241,131 +221,145 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
}
|
||||
return body
|
||||
|
||||
def test_subnet_create(self):
|
||||
req = fakes.HTTPRequest.blank('/subnets', version="2.51")
|
||||
@ddt.data({'version': "2.51", 'has_share_servers': False},
|
||||
{'version': "2.70", 'has_share_servers': False},
|
||||
{'version': "2.70", 'has_share_servers': True})
|
||||
@ddt.unpack
|
||||
def test_subnet_create(self, version, has_share_servers):
|
||||
req = fakes.HTTPRequest.blank('/subnets', version=version)
|
||||
multiple_subnet_support = (req.api_version_request >=
|
||||
api_version.APIVersionRequest("2.70"))
|
||||
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_subnet = copy.deepcopy(self.subnet)
|
||||
if has_share_servers:
|
||||
expected_subnet['share_servers'] = [self.share_server]
|
||||
|
||||
mock_validate_subnet_create = self.mock_object(
|
||||
common, 'validate_subnet_create',
|
||||
mock.Mock(return_value=(self.share_network, [expected_subnet])))
|
||||
mock_subnet_create = self.mock_object(
|
||||
db_api, 'share_network_subnet_create',
|
||||
mock.Mock(return_value=expected_subnet))
|
||||
mock_update_net_allocations = self.mock_object(
|
||||
self.controller.share_api,
|
||||
'update_share_server_network_allocations',
|
||||
mock.Mock(return_value=expected_subnet))
|
||||
mock_share_network_subnet_get = self.mock_object(
|
||||
db_api, 'share_network_subnet_get',
|
||||
mock.Mock(return_value=expected_subnet))
|
||||
|
||||
fake_data = body['share-network-subnet']
|
||||
fake_data['share_network_id'] = self.share_network['id']
|
||||
res = self.controller.create(
|
||||
req, body['share-network-subnet']['share_network_id'], body)
|
||||
|
||||
view_subnet = {
|
||||
'id': expected_subnet.get('id'),
|
||||
'availability_zone': expected_subnet.get('availability_zone'),
|
||||
'share_network_id': expected_subnet.get('share_network_id'),
|
||||
'share_network_name': expected_subnet['share_network_name'],
|
||||
'created_at': expected_subnet.get('created_at'),
|
||||
'segmentation_id': expected_subnet.get('segmentation_id'),
|
||||
'neutron_subnet_id': expected_subnet.get('neutron_subnet_id'),
|
||||
'updated_at': expected_subnet.get('updated_at'),
|
||||
'neutron_net_id': expected_subnet.get('neutron_net_id'),
|
||||
'ip_version': expected_subnet.get('ip_version'),
|
||||
'cidr': expected_subnet.get('cidr'),
|
||||
'network_type': expected_subnet.get('network_type'),
|
||||
'mtu': expected_subnet.get('mtu'),
|
||||
'gateway': expected_subnet.get('gateway')
|
||||
}
|
||||
self.assertEqual(view_subnet, res['share_network_subnet'])
|
||||
mock_share_network_subnet_get.assert_called_once_with(
|
||||
context, expected_subnet['id'])
|
||||
mock_validate_subnet_create.assert_called_once_with(
|
||||
context, sn_id, fake_data, multiple_subnet_support)
|
||||
if has_share_servers:
|
||||
fake_data['share_servers'] = [self.share_server]
|
||||
mock_update_net_allocations.assert_called_once_with(
|
||||
context, self.share_network, fake_data)
|
||||
else:
|
||||
mock_subnet_create.assert_called_once_with(
|
||||
context, fake_data)
|
||||
|
||||
@ddt.data({'exception1': exception.ServiceIsDown(),
|
||||
'exc_raise': exc.HTTPInternalServerError},
|
||||
{'exception1': exception.InvalidShareNetwork(),
|
||||
'exc_raise': exc.HTTPBadRequest},
|
||||
{'exception1': db_exception.DBError(),
|
||||
'exc_raise': exc.HTTPInternalServerError})
|
||||
@ddt.unpack
|
||||
def test_subnet_create_fail_update_network_allocation(self, exception1,
|
||||
exc_raise):
|
||||
req = fakes.HTTPRequest.blank('/subnets', version="2.70")
|
||||
multiple_subnet_support = (req.api_version_request >=
|
||||
api_version.APIVersionRequest("2.70"))
|
||||
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))
|
||||
expected_subnet = copy.deepcopy(self.subnet)
|
||||
expected_subnet['share_servers'] = [self.share_server]
|
||||
|
||||
self.controller.create(
|
||||
req, body['share-network-subnet']['share_network_id'], body)
|
||||
mock_validate_subnet_create = self.mock_object(
|
||||
common, 'validate_subnet_create',
|
||||
mock.Mock(return_value=(self.share_network, [expected_subnet])))
|
||||
mock_update_net_allocations = self.mock_object(
|
||||
self.controller.share_api,
|
||||
'update_share_server_network_allocations',
|
||||
mock.Mock(side_effect=exception1))
|
||||
|
||||
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'])
|
||||
fake_data = body['share-network-subnet']
|
||||
fake_data['share_network_id'] = self.share_network['id']
|
||||
fake_data['share_servers'] = [self.share_server]
|
||||
|
||||
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.assertRaises(exc_raise,
|
||||
self.controller.create,
|
||||
req,
|
||||
fake_sn_id,
|
||||
body['share-network-subnet']['share_network_id'],
|
||||
body)
|
||||
mock_sn_get.assert_called_once_with(context, fake_sn_id)
|
||||
|
||||
def test_subnet_create_az_not_found(self):
|
||||
mock_validate_subnet_create.assert_called_once_with(
|
||||
context, sn_id, fake_data, multiple_subnet_support)
|
||||
mock_update_net_allocations.assert_called_once_with(
|
||||
context, self.share_network, fake_data)
|
||||
|
||||
def test_subnet_create_invalid_body(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']
|
||||
|
||||
body = {}
|
||||
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']
|
||||
@ddt.data("2.51", "2.70")
|
||||
def test_subnet_create_subnet_db_error(self, version):
|
||||
req = fakes.HTTPRequest.blank('/subnets', version=version)
|
||||
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(
|
||||
expected_subnet = copy.deepcopy(self.subnet)
|
||||
self.mock_object(
|
||||
common, 'validate_subnet_create',
|
||||
mock.Mock(return_value=(self.share_network, [expected_subnet])))
|
||||
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,
|
||||
'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'])
|
||||
|
@ -776,6 +776,13 @@ class ShareNetworkAPITest(test.TestCase):
|
||||
share_nw,
|
||||
self.body)
|
||||
|
||||
def test_update_invalid_body(self):
|
||||
self.assertRaises(webob_exc.HTTPUnprocessableEntity,
|
||||
self.controller.update,
|
||||
self.req,
|
||||
'fake_sn_id',
|
||||
None)
|
||||
|
||||
@mock.patch.object(db_api, 'share_network_get', mock.Mock())
|
||||
def test_update_invalid_key_in_use(self):
|
||||
share_nw = fake_share_network.copy()
|
||||
@ -829,8 +836,8 @@ class ShareNetworkAPITest(test.TestCase):
|
||||
self.mock_object(
|
||||
self.controller, '_share_network_subnets_contain_share_servers',
|
||||
mock.Mock(return_value=False))
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnet',
|
||||
mock.Mock(return_value=fake_share_network_subnet))
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnets',
|
||||
mock.Mock(return_value=[fake_share_network_subnet]))
|
||||
self.mock_object(db_api, 'share_network_subnet_update')
|
||||
|
||||
body = {share_networks.RESOURCE_NAME: {'neutron_subnet_id':
|
||||
@ -844,18 +851,20 @@ class ShareNetworkAPITest(test.TestCase):
|
||||
self.req,
|
||||
share_nw,
|
||||
body)
|
||||
db_api.share_network_subnet_get_default_subnet.assert_called_once_with(
|
||||
self.context, share_nw)
|
||||
(db_api.share_network_subnet_get_default_subnets.
|
||||
assert_called_once_with(self.context, share_nw))
|
||||
db_api.share_network_subnet_update.assert_called_once_with(
|
||||
self.context, fake_share_network_subnet['id'],
|
||||
body['share_network'])
|
||||
|
||||
@ddt.data((webob_exc.HTTPBadRequest, fake_share_network_subnet, None,
|
||||
@ddt.data((webob_exc.HTTPBadRequest, 1, None,
|
||||
'new subnet'),
|
||||
(webob_exc.HTTPBadRequest, 2, None,
|
||||
'new subnet'),
|
||||
(webob_exc.HTTPBadRequest, None, 'neutron net', None))
|
||||
@ddt.unpack
|
||||
def test_update_default_subnet_errors(self, exception_to_raise,
|
||||
get_default_subnet_return,
|
||||
get_default_subnet_return_length,
|
||||
neutron_net_id, neutron_subnet_id):
|
||||
share_nw = 'fake network id'
|
||||
self.mock_object(db_api, 'share_network_get',
|
||||
@ -863,15 +872,21 @@ class ShareNetworkAPITest(test.TestCase):
|
||||
self.mock_object(
|
||||
self.controller, '_share_network_subnets_contain_share_servers',
|
||||
mock.Mock(return_value=False))
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnet',
|
||||
mock.Mock(return_value=get_default_subnet_return))
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnets',
|
||||
mock.Mock(return_value=None))
|
||||
|
||||
if get_default_subnet_return:
|
||||
if get_default_subnet_return_length:
|
||||
fake_subnet = copy.deepcopy(fake_share_network_subnet)
|
||||
fake_subnet['neutron_net_id'] = None
|
||||
fake_subnet['neutron_subnet_id'] = None
|
||||
db_api.share_network_subnet_get_default_subnet.return_value = (
|
||||
fake_subnet)
|
||||
|
||||
if get_default_subnet_return_length == 1:
|
||||
(db_api.share_network_subnet_get_default_subnets.
|
||||
return_value) = [fake_subnet]
|
||||
elif get_default_subnet_return_length == 2:
|
||||
(db_api.share_network_subnet_get_default_subnets.
|
||||
return_value) = [fake_subnet, fake_subnet]
|
||||
|
||||
body = {
|
||||
share_networks.RESOURCE_NAME: {
|
||||
'neutron_net_id': neutron_net_id,
|
||||
@ -885,8 +900,8 @@ class ShareNetworkAPITest(test.TestCase):
|
||||
share_nw,
|
||||
body)
|
||||
|
||||
db_api.share_network_subnet_get_default_subnet.assert_called_once_with(
|
||||
self.context, share_nw)
|
||||
(db_api.share_network_subnet_get_default_subnets.
|
||||
assert_called_once_with(self.context, share_nw))
|
||||
|
||||
@ddt.data(*set(("1.0", "2.25", "2.26", api_version._MAX_API_VERSION)))
|
||||
def test_add_security_service(self, microversion):
|
||||
@ -1620,3 +1635,82 @@ class ShareNetworkAPITest(test.TestCase):
|
||||
db_api.share_network_update.assert_called_once_with(
|
||||
request.environ['manila.context'],
|
||||
share_network['id'], {'status': 'active'})
|
||||
|
||||
@ddt.data([], ['fake_server'])
|
||||
def test_share_network_subnet_create_check(self, servers):
|
||||
body = {
|
||||
'share_network_subnet_create_check': {
|
||||
'reset_operation': False,
|
||||
'availability_zone': 'fake_az',
|
||||
}
|
||||
}
|
||||
request = fakes.HTTPRequest.blank(
|
||||
'/share-networks', use_admin_context=True, version='2.70')
|
||||
context = request.environ['manila.context']
|
||||
|
||||
share_net = 'fake_net'
|
||||
subnet = {'share_servers': servers}
|
||||
existing_subnets = [subnet]
|
||||
mock_validate_subnet = self.mock_object(
|
||||
common, 'validate_subnet_create',
|
||||
mock.Mock(return_value=(share_net, existing_subnets)))
|
||||
share_api_return = {
|
||||
'compatible': not bool(servers),
|
||||
'hosts_check_result': {}
|
||||
}
|
||||
mock_check_update = self.mock_object(
|
||||
self.controller.share_api,
|
||||
'check_update_share_server_network_allocations',
|
||||
mock.Mock(return_value=share_api_return))
|
||||
subnet_view = 'fake_subnet'
|
||||
mock_view = self.mock_object(
|
||||
self.controller._view_builder,
|
||||
'build_share_network_subnet_create_check',
|
||||
mock.Mock(return_value=subnet_view))
|
||||
|
||||
net_id = 'fake_net_id'
|
||||
response = self.controller.share_network_subnet_create_check(
|
||||
request, net_id, body)
|
||||
|
||||
self.assertEqual(subnet_view, response)
|
||||
data = body['share_network_subnet_create_check']
|
||||
mock_validate_subnet.assert_called_once_with(
|
||||
context, net_id, data, True)
|
||||
if servers:
|
||||
data['share_servers'] = servers
|
||||
mock_check_update.assert_called_once_with(
|
||||
context, share_net, data, False)
|
||||
else:
|
||||
mock_check_update.assert_not_called()
|
||||
mock_view.assert_called_once_with(request, share_api_return)
|
||||
|
||||
@ddt.data(
|
||||
(exception.ServiceIsDown(message='fake'),
|
||||
webob_exc.HTTPInternalServerError),
|
||||
(exception.InvalidShareNetwork(message='fake'),
|
||||
webob_exc.HTTPBadRequest))
|
||||
@ddt.unpack
|
||||
def test_share_network_subnet_create_check_api_failed(
|
||||
self, captured_exception, exception_to_be_raised):
|
||||
body = {
|
||||
'share_network_subnet_create_check': {
|
||||
'reset_operation': False,
|
||||
'availability_zone': 'fake_az',
|
||||
}
|
||||
}
|
||||
request = fakes.HTTPRequest.blank(
|
||||
'/share-networks', use_admin_context=True, version='2.70')
|
||||
share_net = 'fake_net'
|
||||
subnet = {'share_servers': 'fake_server'}
|
||||
existing_subnets = [subnet]
|
||||
self.mock_object(
|
||||
common, 'validate_subnet_create',
|
||||
mock.Mock(return_value=(share_net, existing_subnets)))
|
||||
self.mock_object(
|
||||
self.controller.share_api,
|
||||
'check_update_share_server_network_allocations',
|
||||
mock.Mock(side_effect=captured_exception))
|
||||
|
||||
self.assertRaises(exception_to_be_raised,
|
||||
self.controller.share_network_subnet_create_check,
|
||||
request, 'fake_net_id', body)
|
||||
|
@ -120,17 +120,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_net_subnet = [db_utils.create_share_network_subnet(
|
||||
share_network_id=share_network['id'])]
|
||||
share_server = db_utils.create_share_server(
|
||||
share_network_subnet_id=share_net_subnet['id'],
|
||||
share_network_subnet_id=share_net_subnet[0]['id'],
|
||||
host='fake_host',
|
||||
identifier='fake_identifier',
|
||||
is_auto_deletable=False)
|
||||
is_auto_deletable=False,
|
||||
share_network_subnets=share_net_subnet)
|
||||
|
||||
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',
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnets',
|
||||
mock.Mock(return_value=share_net_subnet))
|
||||
self.mock_object(utils, 'validate_service_host')
|
||||
|
||||
@ -151,7 +152,8 @@ class ShareServerControllerTest(test.TestCase):
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
'host': 'fake_host',
|
||||
'share_network_id':
|
||||
share_server['share_network_subnet']['share_network_id'],
|
||||
(share_server['share_network_subnets'][0]
|
||||
['share_network_id']),
|
||||
'created_at': share_server['created_at'],
|
||||
'backend_details': {},
|
||||
'identifier': share_server['identifier'],
|
||||
@ -163,12 +165,12 @@ class ShareServerControllerTest(test.TestCase):
|
||||
'fake_net_name')
|
||||
else:
|
||||
expected_result['share_server']['share_network_name'] = (
|
||||
share_net_subnet['share_network_id'])
|
||||
share_net_subnet[0]['share_network_id'])
|
||||
|
||||
req_params = body['share_server']
|
||||
manage_share_server_mock.assert_called_once_with(
|
||||
context, req_params['identifier'], req_params['host'],
|
||||
share_net_subnet, req_params['driver_options'])
|
||||
share_net_subnet[0], req_params['driver_options'])
|
||||
|
||||
self.assertEqual(expected_result, result)
|
||||
|
||||
@ -178,32 +180,23 @@ class ShareServerControllerTest(test.TestCase):
|
||||
def test_manage_invalid(self):
|
||||
req = fakes.HTTPRequest.blank('/manage_share_server',
|
||||
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'])
|
||||
share_net_subnet = [db_utils.create_share_network_subnet(
|
||||
share_network_id=share_network['id'])]
|
||||
|
||||
body = {
|
||||
'share_server': self._setup_manage_test_request_body()
|
||||
}
|
||||
body['share_server']['driver_options'] = []
|
||||
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',
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnets',
|
||||
mock.Mock(return_value=share_net_subnet))
|
||||
|
||||
manage_share_server_mock = self.mock_object(
|
||||
share_api.API, 'manage_share_server',
|
||||
mock.Mock(side_effect=exception.InvalidInput('foobar')))
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.manage, req, body)
|
||||
|
||||
req_params = body['share_server']
|
||||
manage_share_server_mock.assert_called_once_with(
|
||||
context, req_params['identifier'], req_params['host'],
|
||||
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', version="2.49")
|
||||
@ -211,12 +204,12 @@ class ShareServerControllerTest(test.TestCase):
|
||||
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'])
|
||||
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',
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnets',
|
||||
mock.Mock(return_value=share_net_subnet))
|
||||
self.mock_object(utils, 'validate_service_host')
|
||||
|
||||
@ -281,12 +274,12 @@ class ShareServerControllerTest(test.TestCase):
|
||||
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'])
|
||||
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',
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnets',
|
||||
mock.Mock(return_value=share_net_subnet))
|
||||
self.mock_object(common, 'check_share_network_is_active',
|
||||
mock.Mock(return_value=True))
|
||||
@ -296,7 +289,7 @@ class ShareServerControllerTest(test.TestCase):
|
||||
{'share_server': self._setup_manage_test_request_body()})
|
||||
|
||||
common.check_share_network_is_active.assert_called_once_with(
|
||||
share_net_subnet['share_network'])
|
||||
share_net_subnet[0]['share_network'])
|
||||
policy.check_policy.assert_called_once_with(
|
||||
context, self.resource_name, 'manage_share_server')
|
||||
|
||||
@ -305,12 +298,12 @@ class ShareServerControllerTest(test.TestCase):
|
||||
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'])
|
||||
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',
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnets',
|
||||
mock.Mock(return_value=share_net_subnet))
|
||||
self.mock_object(utils, 'validate_service_host')
|
||||
self.mock_object(common, 'check_share_network_is_active',
|
||||
@ -321,7 +314,7 @@ class ShareServerControllerTest(test.TestCase):
|
||||
{'share_server': self._setup_manage_test_request_body()})
|
||||
|
||||
common.check_share_network_is_active.assert_called_once_with(
|
||||
share_net_subnet['share_network'])
|
||||
share_net_subnet[0]['share_network'])
|
||||
policy.check_policy.assert_called_once_with(
|
||||
context, self.resource_name, 'manage_share_server')
|
||||
|
||||
@ -377,16 +370,16 @@ class ShareServerControllerTest(test.TestCase):
|
||||
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'])
|
||||
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)
|
||||
share_net_subnet[0]['id'] if body_contains_subnet else None)
|
||||
|
||||
self.mock_object(
|
||||
db_api, 'share_network_subnet_get',
|
||||
db_api, 'share_network_subnet_get_all_with_same_az',
|
||||
mock.Mock(side_effect=exception.ShareNetworkSubnetNotFound(
|
||||
share_network_subnet_id='fake')))
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnet',
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnets',
|
||||
mock.Mock(return_value=None))
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
@ -397,10 +390,47 @@ class ShareServerControllerTest(test.TestCase):
|
||||
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'])
|
||||
(db_api.share_network_subnet_get_all_with_same_az.
|
||||
assert_called_once_with(context, share_net_subnet[0]['id']))
|
||||
else:
|
||||
(db_api.share_network_subnet_get_default_subnet
|
||||
(db_api.share_network_subnet_get_default_subnets
|
||||
.assert_called_once_with(
|
||||
context, body['share_server']['share_network_id']))
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test__validate_manage_share_server_error_multiple_subnet(
|
||||
self, body_contains_subnet):
|
||||
req = fakes.HTTPRequest.blank('/manage', version="2.70")
|
||||
context = req.environ['manila.context']
|
||||
share_network = db_utils.create_share_network()
|
||||
body = {'share_server': self._setup_manage_test_request_body()}
|
||||
share_net_subnets = [
|
||||
db_utils.create_share_network_subnet(
|
||||
share_network_id=share_network['id']),
|
||||
db_utils.create_share_network_subnet(
|
||||
share_network_id=share_network['id'], id='fake_sns_id_2'),
|
||||
]
|
||||
body['share_server']['share_network_subnet_id'] = (
|
||||
share_net_subnets[0]['id'] if body_contains_subnet else None)
|
||||
|
||||
self.mock_object(
|
||||
db_api, 'share_network_subnet_get_all_with_same_az',
|
||||
mock.Mock(return_value=share_net_subnets))
|
||||
self.mock_object(db_api, 'share_network_subnet_get_default_subnets',
|
||||
mock.Mock(return_value=share_net_subnets))
|
||||
|
||||
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_all_with_same_az.
|
||||
assert_called_once_with(context, share_net_subnets[0]['id']))
|
||||
else:
|
||||
(db_api.share_network_subnet_get_default_subnets
|
||||
.assert_called_once_with(
|
||||
context, body['share_server']['share_network_id']))
|
||||
|
||||
@ -442,6 +472,23 @@ class ShareServerControllerTest(test.TestCase):
|
||||
|
||||
get_mock.assert_called_once_with(context, 'fake_server_id')
|
||||
|
||||
def test_unmanage_share_server_multiple_subnets_fail(self):
|
||||
"""Tests unmanaging share servers"""
|
||||
server = self._setup_unmanage_tests(multiple_subnets=True)
|
||||
get_mock = self.mock_object(db_api, 'share_server_get',
|
||||
mock.Mock(return_value=server))
|
||||
req = fakes.HTTPRequest.blank('/unmanage_share_server', version="2.70")
|
||||
context = req.environ['manila.context']
|
||||
body = {'unmanage': {'force': True}}
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.unmanage,
|
||||
req,
|
||||
server['id'],
|
||||
body)
|
||||
|
||||
get_mock.assert_called_once_with(context, server['id'])
|
||||
|
||||
@ddt.data(constants.STATUS_MANAGING, constants.STATUS_DELETING,
|
||||
constants.STATUS_CREATING, constants.STATUS_UNMANAGING)
|
||||
def test_unmanage_share_server_invalid_statuses(self, status):
|
||||
@ -461,18 +508,24 @@ class ShareServerControllerTest(test.TestCase):
|
||||
|
||||
get_mock.assert_called_once_with(context, server['id'])
|
||||
|
||||
def _setup_unmanage_tests(self, status=constants.STATUS_ACTIVE):
|
||||
server = db_utils.create_share_server(
|
||||
id='fake_server_id', status=status)
|
||||
def _setup_unmanage_tests(self, status=constants.STATUS_ACTIVE,
|
||||
multiple_subnets=False):
|
||||
share_network = db_utils.create_share_network()
|
||||
network_subnet = db_utils.create_share_network_subnet(
|
||||
share_network_id=share_network['id'])
|
||||
network_subnets = [db_utils.create_share_network_subnet(
|
||||
id='fake_sns_id', share_network_id=share_network['id'])]
|
||||
if multiple_subnets:
|
||||
share_network1 = db_utils.create_share_network()
|
||||
network_subnets.append(db_utils.create_share_network_subnet(
|
||||
share_network_id=share_network1['id'], id='fake_sns_id_2'))
|
||||
server = db_utils.create_share_server(
|
||||
id='fake_server_id', status=status,
|
||||
share_network_subnets=network_subnets)
|
||||
self.mock_object(db_api, 'share_server_get',
|
||||
mock.Mock(return_value=server))
|
||||
self.mock_object(db_api, 'share_network_get',
|
||||
mock.Mock(return_value=share_network))
|
||||
self.mock_object(db_api, 'share_network_subnet_get',
|
||||
mock.Mock(return_value=network_subnet))
|
||||
mock.Mock(return_value=network_subnets))
|
||||
return server
|
||||
|
||||
@ddt.data(exception.ShareServerInUse, exception.PolicyNotAuthorized)
|
||||
@ -505,13 +558,11 @@ class ShareServerControllerTest(test.TestCase):
|
||||
'/v2/share-servers/fake_server_id/', version="2.63")
|
||||
context = req.environ['manila.context']
|
||||
share_server = db_utils.create_share_server()
|
||||
network_subnet = db_utils.create_share_network_subnet()
|
||||
network_subnets = [db_utils.create_share_network_subnet()]
|
||||
share_server['share_network_subnets'] = network_subnets
|
||||
share_network = db_utils.create_share_network()
|
||||
get_mock = self.mock_object(
|
||||
db_api, 'share_server_get', mock.Mock(return_value=share_server))
|
||||
get_subnet_mock = self.mock_object(
|
||||
db_api, 'share_network_subnet_get',
|
||||
mock.Mock(return_value=network_subnet))
|
||||
get_network_mock = self.mock_object(
|
||||
db_api, 'share_network_get',
|
||||
mock.Mock(return_value=share_network))
|
||||
@ -526,10 +577,9 @@ class ShareServerControllerTest(test.TestCase):
|
||||
'fake_server_id',
|
||||
body)
|
||||
get_mock.assert_called_once_with(context, 'fake_server_id')
|
||||
get_subnet_mock.assert_called_once_with(
|
||||
context, share_server.get('share_network_subnet_id'))
|
||||
get_network_mock.assert_called_once_with(
|
||||
context, network_subnet['share_network_id'])
|
||||
context,
|
||||
share_server['share_network_subnets'][0]['share_network_id'])
|
||||
is_active_mock.assert_called_once_with(share_network)
|
||||
|
||||
def _get_server_migration_request(self, server_id, version='2.57'):
|
||||
@ -589,11 +639,12 @@ class ShareServerControllerTest(test.TestCase):
|
||||
def test__share_server_migration_start_conflict(self, api_exception,
|
||||
expected_exception):
|
||||
share_network = db_utils.create_share_network()
|
||||
share_network_subnet = db_utils.create_share_network_subnet(
|
||||
share_network_id=share_network['id'])
|
||||
share_network_subnet = [db_utils.create_share_network_subnet(
|
||||
share_network_id=share_network['id'])]
|
||||
server = db_utils.create_share_server(
|
||||
id='fake_server_id', status=constants.STATUS_ACTIVE,
|
||||
share_network_subnet_id=share_network_subnet['id'])
|
||||
share_network_subnet_id=share_network_subnet[0]['id'])
|
||||
server['share_network_subnets'] = share_network_subnet
|
||||
req = self._get_server_migration_request(server['id'])
|
||||
context = req.environ['manila.context']
|
||||
body = {
|
||||
|
@ -715,6 +715,8 @@ class ShareAPITest(test.TestCase):
|
||||
"share_network_id": "fakenetid"
|
||||
}
|
||||
fake_network = {'id': 'fakenetid'}
|
||||
share_net_subnets = [db_utils.create_share_network_subnet(
|
||||
id='fake_subnet_id', share_network_id=fake_network['id'])]
|
||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||
display_name=shr['name'],
|
||||
display_description=shr['description'],
|
||||
@ -728,7 +730,8 @@ class ShareAPITest(test.TestCase):
|
||||
self.mock_object(common, 'check_share_network_is_active',
|
||||
mock.Mock(return_value=True))
|
||||
self.mock_object(
|
||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||
db, 'share_network_subnets_get_all_by_availability_zone_id',
|
||||
mock.Mock(return_value=share_net_subnets))
|
||||
|
||||
body = {"share": copy.deepcopy(shr)}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/shares', version='2.7')
|
||||
@ -1342,6 +1345,8 @@ class ShareAPITest(test.TestCase):
|
||||
}
|
||||
parent_share_net = 444
|
||||
fake_network = {'id': parent_share_net}
|
||||
share_net_subnets = [db_utils.create_share_network_subnet(
|
||||
id='fake_subnet_id', share_network_id=fake_network['id'])]
|
||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||
display_name=shr['name'],
|
||||
display_description=shr['description'],
|
||||
@ -1364,7 +1369,8 @@ class ShareAPITest(test.TestCase):
|
||||
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
||||
return_value=fake_network))
|
||||
self.mock_object(
|
||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||
db, 'share_network_subnets_get_all_by_availability_zone_id',
|
||||
mock.Mock(return_value=share_net_subnets))
|
||||
|
||||
body = {"share": copy.deepcopy(shr)}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/shares', version='2.7')
|
||||
@ -1391,6 +1397,8 @@ class ShareAPITest(test.TestCase):
|
||||
"snapshot_id": 333,
|
||||
"share_network_id": parent_share_net,
|
||||
}
|
||||
share_net_subnets = [db_utils.create_share_network_subnet(
|
||||
id='fake_subnet_id', share_network_id=parent_share_net)]
|
||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||
display_name=shr['name'],
|
||||
display_description=shr['description'],
|
||||
@ -1413,7 +1421,8 @@ class ShareAPITest(test.TestCase):
|
||||
self.mock_object(common, 'check_share_network_is_active',
|
||||
mock.Mock(return_value=True))
|
||||
self.mock_object(
|
||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||
db, 'share_network_subnets_get_all_by_availability_zone_id',
|
||||
mock.Mock(return_value=share_net_subnets))
|
||||
|
||||
body = {"share": copy.deepcopy(shr)}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/shares', version='2.7')
|
||||
|
@ -65,6 +65,9 @@ class ViewBuilderTestCase(test.TestCase):
|
||||
status_and_sec_serv_update = (
|
||||
api_version.APIVersionRequest(microversion) >=
|
||||
api_version.APIVersionRequest('2.63'))
|
||||
network_allocation_update_support = (
|
||||
api_version.APIVersionRequest(microversion) >=
|
||||
api_version.APIVersionRequest('2.69'))
|
||||
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
|
||||
expected_keys = {
|
||||
'id', 'name', 'project_id', 'created_at', 'updated_at',
|
||||
@ -85,6 +88,8 @@ class ViewBuilderTestCase(test.TestCase):
|
||||
expected_keys.add('nova_net_id')
|
||||
if status_and_sec_serv_update:
|
||||
expected_keys.update({'status', 'security_service_update_support'})
|
||||
if network_allocation_update_support:
|
||||
expected_keys.add('network_allocation_update_support')
|
||||
|
||||
result = self.builder.build_share_network(req, share_network_data)
|
||||
self.assertEqual(1, len(result))
|
||||
@ -137,6 +142,10 @@ class ViewBuilderTestCase(test.TestCase):
|
||||
status_and_sec_serv_update = (
|
||||
api_version.APIVersionRequest(microversion) >=
|
||||
api_version.APIVersionRequest('2.63'))
|
||||
network_allocation_update_support = (
|
||||
api_version.APIVersionRequest(microversion) >=
|
||||
api_version.APIVersionRequest('2.69'))
|
||||
|
||||
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
|
||||
expected_networks_list = []
|
||||
for share_network in share_networks:
|
||||
@ -181,7 +190,13 @@ class ViewBuilderTestCase(test.TestCase):
|
||||
expected_data.update(
|
||||
{'status': 'active',
|
||||
'security_service_update_support': False})
|
||||
if network_allocation_update_support:
|
||||
share_network.update(
|
||||
{'network_allocation_update_support': None})
|
||||
expected_data.update(
|
||||
{'network_allocation_update_support': None})
|
||||
expected_networks_list.append(expected_data)
|
||||
|
||||
expected = {'share_networks': expected_networks_list}
|
||||
|
||||
result = self.builder.build_share_networks(req, share_networks,
|
||||
@ -248,3 +263,20 @@ class ViewBuilderTestCase(test.TestCase):
|
||||
hosts_result)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_build_share_network_subnet_create_check(self, is_admin):
|
||||
req = fakes.HTTPRequest.blank('/share-networks',
|
||||
use_admin_context=is_admin)
|
||||
hosts_result = {
|
||||
'compatible': True,
|
||||
'hosts_check_result': {'hostA': True}
|
||||
}
|
||||
expected = {'compatible': True}
|
||||
if is_admin:
|
||||
expected['hosts_check_result'] = hosts_result['hosts_check_result']
|
||||
|
||||
result = self.builder.build_share_network_subnet_create_check(
|
||||
req, hosts_result)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
@ -446,26 +446,28 @@ class ManilaCmdManageTestCase(test.TestCase):
|
||||
share_servers = 'server_id_a,server_id_b'
|
||||
share_server_list = [server.strip()
|
||||
for server in share_servers.split(",")]
|
||||
capability = 'security_service_update_support'
|
||||
values_to_update = {
|
||||
capability: True
|
||||
}
|
||||
capabilities = "security_service_update_support" \
|
||||
",network_allocation_update_support"
|
||||
capabilities_list = capabilities.split(",")
|
||||
values_to_update = [
|
||||
{capabilities_list[0]: True,
|
||||
capabilities_list[1]: True}]
|
||||
|
||||
with mock.patch('sys.stdout', new=io.StringIO()) as output:
|
||||
self.server_cmds.update_share_server_capabilities(
|
||||
share_servers, capability, True)
|
||||
share_servers, capabilities, True)
|
||||
|
||||
expected_op = ("The capability(ies) %(cap)s of the following share "
|
||||
"server(s) %(servers)s was(were) updated to "
|
||||
"%(value)s.") % {
|
||||
'cap': [capability],
|
||||
'cap': capabilities_list,
|
||||
'servers': share_server_list,
|
||||
'value': True,
|
||||
}
|
||||
|
||||
self.assertEqual(expected_op, output.getvalue().strip())
|
||||
db.share_servers_update.assert_called_once_with(
|
||||
'admin_ctxt', share_server_list, values_to_update)
|
||||
'admin_ctxt', share_server_list, values_to_update[0])
|
||||
|
||||
def test_share_server_update_capability_not_supported(self):
|
||||
share_servers = 'server_id_a'
|
||||
|
@ -3084,3 +3084,94 @@ class ShareIsSoftDeleted(BaseMigrationChecks):
|
||||
self.test_case.assertFalse(hasattr(s, 'is_soft_deleted'))
|
||||
self.test_case.assertFalse(hasattr(s,
|
||||
'scheduled_to_be_deleted_at'))
|
||||
|
||||
|
||||
@map_to_migration('a87e0fb17dee')
|
||||
class ShareServerMultipleSubnets(BaseMigrationChecks):
|
||||
|
||||
def setup_upgrade_data(self, engine):
|
||||
user_id = 'user_id_multiple_subnets'
|
||||
project_id = 'project_id_multiple_subnets'
|
||||
|
||||
# Create share network
|
||||
share_network_data = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'user_id': user_id,
|
||||
'project_id': project_id,
|
||||
}
|
||||
sn_table = utils.load_table('share_networks', engine)
|
||||
engine.execute(sn_table.insert(share_network_data))
|
||||
|
||||
# Create share network subnets
|
||||
share_network_subnet_data = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'share_network_id': share_network_data['id']
|
||||
}
|
||||
sns_table = utils.load_table('share_network_subnets', engine)
|
||||
engine.execute(sns_table.insert(share_network_subnet_data))
|
||||
|
||||
# Create share server
|
||||
share_server_data = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'host': 'fake_host',
|
||||
'status': 'active',
|
||||
'share_network_subnet_id': share_network_subnet_data['id'],
|
||||
}
|
||||
ss_table = utils.load_table('share_servers', engine)
|
||||
engine.execute(ss_table.insert(share_server_data))
|
||||
|
||||
def check_upgrade(self, engine, data):
|
||||
ss_sns_map_table = utils.load_table(
|
||||
'share_server_share_network_subnet_mappings', engine)
|
||||
ss_table = utils.load_table('share_servers', engine)
|
||||
sns_table = utils.load_table('share_network_subnets', engine)
|
||||
na_table = utils.load_table('network_allocations', engine)
|
||||
|
||||
na_record = engine.execute(na_table.select()).first()
|
||||
self.test_case.assertFalse(na_record is None)
|
||||
self.test_case.assertTrue(
|
||||
hasattr(na_record, 'share_network_subnet_id'))
|
||||
|
||||
for map_record in engine.execute(ss_sns_map_table.select()):
|
||||
self.test_case.assertTrue(
|
||||
hasattr(map_record, 'share_network_subnet_id'))
|
||||
self.test_case.assertTrue(
|
||||
hasattr(map_record, 'share_server_id'))
|
||||
|
||||
ss_record = engine.execute(
|
||||
ss_table
|
||||
.select()
|
||||
.where(ss_table.c.id == map_record['share_server_id'])
|
||||
).first()
|
||||
self.test_case.assertFalse(ss_record is None)
|
||||
self.test_case.assertFalse(
|
||||
hasattr(ss_record, 'share_network_subnet_id'))
|
||||
self.test_case.assertTrue(
|
||||
hasattr(ss_record, 'network_allocation_update_support'))
|
||||
|
||||
sns_record = engine.execute(
|
||||
sns_table
|
||||
.select()
|
||||
.where(sns_table.c.id == map_record['share_network_subnet_id'])
|
||||
).first()
|
||||
self.test_case.assertFalse(sns_record is None)
|
||||
|
||||
def check_downgrade(self, engine):
|
||||
ss_table = utils.load_table('share_servers', engine)
|
||||
na_table = utils.load_table('network_allocations', engine)
|
||||
self.test_case.assertRaises(
|
||||
sa_exc.NoSuchTableError, utils.load_table,
|
||||
'share_server_share_network_subnet_mappings', engine)
|
||||
|
||||
for ss_record in engine.execute(ss_table.select()):
|
||||
self.test_case.assertTrue(
|
||||
hasattr(ss_record, 'share_network_subnet_id'))
|
||||
self.test_case.assertFalse(
|
||||
hasattr(ss_record, 'network_allocation_update_support'))
|
||||
|
||||
na_record = engine.execute(
|
||||
na_table
|
||||
.select()
|
||||
).first()
|
||||
self.test_case.assertFalse(
|
||||
hasattr(na_record, 'share_network_subnet_id'))
|
||||
|
@ -366,8 +366,7 @@ class ShareDatabaseAPITestCase(test.TestCase):
|
||||
|
||||
def test_share_filter_all_by_share_server(self):
|
||||
share_network = db_utils.create_share_network()
|
||||
share_server = db_utils.create_share_server(
|
||||
share_network_id=share_network['id'])
|
||||
share_server = db_utils.create_share_server()
|
||||
share = db_utils.create_share(share_server_id=share_server['id'],
|
||||
share_network_id=share_network['id'])
|
||||
|
||||
@ -379,8 +378,7 @@ class ShareDatabaseAPITestCase(test.TestCase):
|
||||
|
||||
def test_share_in_recycle_bin_filter_all_by_share_server(self):
|
||||
share_network = db_utils.create_share_network()
|
||||
share_server = db_utils.create_share_server(
|
||||
share_network_id=share_network['id'])
|
||||
share_server = db_utils.create_share_server()
|
||||
share = db_utils.create_share(share_server_id=share_server['id'],
|
||||
share_network_id=share_network['id'],
|
||||
is_soft_deleted=True)
|
||||
@ -393,8 +391,7 @@ class ShareDatabaseAPITestCase(test.TestCase):
|
||||
|
||||
def test_share_in_recycle_bin_filter_all_by_share_network(self):
|
||||
share_network = db_utils.create_share_network()
|
||||
share_server = db_utils.create_share_server(
|
||||
share_network_id=share_network['id'])
|
||||
share_server = db_utils.create_share_server()
|
||||
share = db_utils.create_share(share_server_id=share_server['id'],
|
||||
share_network_id=share_network['id'],
|
||||
is_soft_deleted=True)
|
||||
@ -798,7 +795,7 @@ class ShareDatabaseAPITestCase(test.TestCase):
|
||||
db_utils.create_share_replica(share_id=share_2['id'])
|
||||
expected_ss_keys = {
|
||||
'backend_details', 'host', 'id',
|
||||
'share_network_subnet_id', 'status',
|
||||
'share_network_subnet_ids', 'status',
|
||||
}
|
||||
expected_share_keys = {
|
||||
'project_id', 'share_type_id', 'display_name',
|
||||
@ -846,7 +843,7 @@ class ShareDatabaseAPITestCase(test.TestCase):
|
||||
share_server_id=share_server['id'])
|
||||
expected_ss_keys = {
|
||||
'backend_details', 'host', 'id',
|
||||
'share_network_subnet_id', 'status',
|
||||
'share_network_subnet_ids', 'status',
|
||||
}
|
||||
expected_share_keys = {
|
||||
'project_id', 'share_type_id', 'display_name',
|
||||
@ -911,7 +908,7 @@ class ShareDatabaseAPITestCase(test.TestCase):
|
||||
session = db_api.get_session()
|
||||
expected_ss_keys = {
|
||||
'backend_details', 'host', 'id',
|
||||
'share_network_subnet_id', 'status',
|
||||
'share_network_subnet_ids', 'status',
|
||||
}
|
||||
expected_share_keys = {
|
||||
'project_id', 'share_type_id', 'display_name',
|
||||
@ -999,7 +996,7 @@ class ShareDatabaseAPITestCase(test.TestCase):
|
||||
)
|
||||
expected_extra_keys = {
|
||||
'backend_details', 'host', 'id',
|
||||
'share_network_subnet_id', 'status',
|
||||
'share_network_subnet_ids', 'status',
|
||||
}
|
||||
with session.begin():
|
||||
share_replica = db_api.share_replica_get(
|
||||
@ -2866,11 +2863,12 @@ class ShareNetworkSubnetDatabaseAPITestCase(BaseDatabaseAPITestCase):
|
||||
{'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)
|
||||
share_net_subnets = [
|
||||
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']
|
||||
share_server['share_network_subnets'] = share_net_subnets
|
||||
db_api.share_server_create(self.fake_context, share_server)
|
||||
|
||||
result = db_api.share_network_subnet_get(self.fake_context,
|
||||
@ -2880,8 +2878,11 @@ class ShareNetworkSubnetDatabaseAPITestCase(BaseDatabaseAPITestCase):
|
||||
len(result['share_servers']))
|
||||
|
||||
for index, share_server in enumerate(share_servers):
|
||||
self._check_fields(expected=share_server,
|
||||
actual=result['share_servers'][index])
|
||||
result = db_api.share_network_subnet_get_all_by_share_server_id(
|
||||
self.fake_context, share_server['id'])
|
||||
for key, value in share_server['share_network_subnets'][0].items():
|
||||
if key != 'share_servers':
|
||||
self.assertEqual(value, result[0][key])
|
||||
|
||||
def test_get_not_found(self):
|
||||
db_api.share_network_subnet_create(self.fake_context, self.subnet_dict)
|
||||
@ -2967,18 +2968,43 @@ class ShareNetworkSubnetDatabaseAPITestCase(BaseDatabaseAPITestCase):
|
||||
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(
|
||||
result = db_api.share_network_subnets_get_all_by_availability_zone_id(
|
||||
self.fake_context, self.subnet_dict['share_network_id'], az['id'])
|
||||
|
||||
self._check_fields(expected=self.subnet_dict, actual=result)
|
||||
self._check_fields(expected=self.subnet_dict, actual=result[0])
|
||||
|
||||
def test_get_az_subnets(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_all_with_same_az(
|
||||
self.fake_context, self.subnet_dict['id'])
|
||||
|
||||
self.subnet_dict['share_network'] = None
|
||||
|
||||
self._check_fields(expected=self.subnet_dict, actual=result[0])
|
||||
|
||||
def test_get_az_subnets_not_found(self):
|
||||
self.assertRaises(
|
||||
exception.ShareNetworkSubnetNotFound,
|
||||
db_api.share_network_subnet_get_all_with_same_az,
|
||||
self.fake_context, 'share_network_subnet_id')
|
||||
|
||||
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(
|
||||
result = db_api.share_network_subnet_get_default_subnets(
|
||||
self.fake_context, self.subnet_dict['share_network_id'])
|
||||
|
||||
self._check_fields(expected=self.subnet_dict, actual=result)
|
||||
self._check_fields(expected=self.subnet_dict, actual=result[0])
|
||||
|
||||
def test_get_by_share_server_id_not_found(self):
|
||||
self.assertRaises(
|
||||
exception.ShareNetworkSubnetNotFoundByShareServer,
|
||||
db_api.share_network_subnet_get_all_by_share_server_id,
|
||||
self.fake_context, 'share_server_id')
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@ -3144,13 +3170,21 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
|
||||
self.ctxt = context.RequestContext(user_id='user_id',
|
||||
project_id='project_id',
|
||||
is_admin=True)
|
||||
self.share_net_subnets = [
|
||||
db_utils.create_share_network_subnet(
|
||||
id=uuidutils.generate_uuid(),
|
||||
share_network_id=uuidutils.generate_uuid())]
|
||||
|
||||
def test_share_server_get(self):
|
||||
expected = db_utils.create_share_server()
|
||||
expected = db_utils.create_share_server(
|
||||
share_network_subnets=self.share_net_subnets)
|
||||
server = db_api.share_server_get(self.ctxt, expected['id'])
|
||||
self.assertEqual(expected['id'], server['id'])
|
||||
self.assertEqual(expected.share_network_subnet_id,
|
||||
server.share_network_subnet_id)
|
||||
self.assertEqual(expected.share_network_subnets[0]['id'],
|
||||
server.share_network_subnets[0]['id'])
|
||||
self.assertEqual(
|
||||
expected.share_network_subnets[0]['share_network_id'],
|
||||
server.share_network_subnets[0]['share_network_id'])
|
||||
self.assertEqual(expected.host, server.host)
|
||||
self.assertEqual(expected.status, server.status)
|
||||
|
||||
@ -3160,10 +3194,14 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
|
||||
db_api.share_server_get, self.ctxt, fake_id)
|
||||
|
||||
def test_create(self):
|
||||
server = db_utils.create_share_server()
|
||||
server = db_utils.create_share_server(
|
||||
share_network_subnets=self.share_net_subnets)
|
||||
self.assertTrue(server['id'])
|
||||
self.assertEqual(server.share_network_subnet_id,
|
||||
server['share_network_subnet_id'])
|
||||
self.assertEqual(server.share_network_subnets[0]['id'],
|
||||
server['share_network_subnets'][0]['id'])
|
||||
self.assertEqual(
|
||||
server.share_network_subnets[0]['share_network_id'],
|
||||
server['share_network_subnets'][0]['share_network_id'])
|
||||
self.assertEqual(server.host, server['host'])
|
||||
self.assertEqual(server.status, server['status'])
|
||||
|
||||
@ -3181,17 +3219,23 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
|
||||
self.ctxt, fake_id)
|
||||
|
||||
def test_update(self):
|
||||
share_net_subnets_update = [
|
||||
db_utils.create_share_network_subnet(
|
||||
id=uuidutils.generate_uuid(),
|
||||
share_network_id=uuidutils.generate_uuid())]
|
||||
update = {
|
||||
'share_network_id': 'update_net',
|
||||
'share_network_subnets': share_net_subnets_update,
|
||||
'host': 'update_host',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
}
|
||||
server = db_utils.create_share_server()
|
||||
server = db_utils.create_share_server(
|
||||
share_network_subnets=self.share_net_subnets)
|
||||
updated_server = db_api.share_server_update(self.ctxt, server['id'],
|
||||
update)
|
||||
self.assertEqual(server['id'], updated_server['id'])
|
||||
self.assertEqual(update['share_network_id'],
|
||||
updated_server.share_network_id)
|
||||
self.assertEqual(
|
||||
update['share_network_subnets'][0]['share_network_id'],
|
||||
updated_server.share_network_subnets[0]['share_network_id'])
|
||||
self.assertEqual(update['host'], updated_server.host)
|
||||
self.assertEqual(update['status'], updated_server.status)
|
||||
|
||||
@ -3201,7 +3245,8 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
|
||||
db_api.share_server_update,
|
||||
self.ctxt, fake_id, {})
|
||||
|
||||
def test_get_all_by_host_and_share_net_valid(self):
|
||||
@ddt.data(None, constants.STATUS_SERVER_NETWORK_CHANGE)
|
||||
def test_get_all_by_host_and_share_net_valid(self, server_status):
|
||||
subnet_1 = {
|
||||
'id': '1',
|
||||
'share_network_id': '1',
|
||||
@ -3210,31 +3255,41 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
|
||||
'id': '2',
|
||||
'share_network_id': '2',
|
||||
}
|
||||
valid = {
|
||||
'share_network_subnet_id': '1',
|
||||
share_net_subnets1 = db_utils.create_share_network_subnet(**subnet_1)
|
||||
share_net_subnets2 = db_utils.create_share_network_subnet(**subnet_2)
|
||||
valid_no_status = {
|
||||
'share_network_subnets': [share_net_subnets1],
|
||||
'host': 'host1',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
}
|
||||
valid_with_status = {
|
||||
'share_network_subnets': [share_net_subnets1],
|
||||
'host': 'host1',
|
||||
'status': constants.STATUS_SERVER_NETWORK_CHANGE,
|
||||
}
|
||||
invalid = {
|
||||
'share_network_subnet_id': '2',
|
||||
'share_network_subnets': [share_net_subnets2],
|
||||
'host': 'host1',
|
||||
'status': constants.STATUS_ERROR,
|
||||
}
|
||||
other = {
|
||||
'share_network_subnet_id': '1',
|
||||
'share_network_subnets': [share_net_subnets1],
|
||||
'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)
|
||||
if server_status:
|
||||
valid = db_utils.create_share_server(**valid_with_status)
|
||||
else:
|
||||
valid = db_utils.create_share_server(**valid_no_status)
|
||||
db_utils.create_share_server(**invalid)
|
||||
db_utils.create_share_server(**other)
|
||||
|
||||
servers = db_api.share_server_get_all_by_host_and_share_subnet_valid(
|
||||
self.ctxt,
|
||||
host='host1',
|
||||
share_subnet_id='1')
|
||||
share_subnet_id='1',
|
||||
server_status=server_status)
|
||||
|
||||
self.assertEqual(valid['id'], servers[0]['id'])
|
||||
|
||||
def test_get_all_by_host_and_share_net_not_found(self):
|
||||
@ -3246,17 +3301,14 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
|
||||
|
||||
def test_get_all(self):
|
||||
srv1 = {
|
||||
'share_network_id': '1',
|
||||
'host': 'host1',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
}
|
||||
srv2 = {
|
||||
'share_network_id': '1',
|
||||
'host': 'host1',
|
||||
'status': constants.STATUS_ERROR,
|
||||
}
|
||||
srv3 = {
|
||||
'share_network_id': '2',
|
||||
'host': 'host2',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
}
|
||||
@ -3296,7 +3348,10 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
|
||||
|
||||
def test_get_with_details(self):
|
||||
values = {
|
||||
'share_network_subnet_id': 'fake-share-net-id',
|
||||
'share_network_subnets': [
|
||||
db_utils.create_share_network_subnet(
|
||||
id='fake_subnet_id',
|
||||
share_network_id='fake_share_net_id')],
|
||||
'host': 'hostname',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
}
|
||||
@ -3308,8 +3363,11 @@ 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_subnet_id'],
|
||||
server.share_network_subnet_id)
|
||||
self.assertEqual(values['share_network_subnets'][0]['id'],
|
||||
server.share_network_subnets[0]['id'])
|
||||
self.assertEqual(
|
||||
values['share_network_subnets'][0]['share_network_id'],
|
||||
server.share_network_subnets[0]['share_network_id'])
|
||||
self.assertEqual(values['host'], server.host)
|
||||
self.assertEqual(values['status'], server.status)
|
||||
self.assertDictEqual(server['backend_details'], details)
|
||||
@ -3331,7 +3389,6 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
|
||||
def test_share_server_search_by_identifier(self, identifier):
|
||||
|
||||
server = {
|
||||
'share_network_id': 'fake-share-net-id',
|
||||
'host': 'hostname',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
'is_auto_deletable': True,
|
||||
@ -3360,21 +3417,18 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
|
||||
server_3_is_auto_deletable,
|
||||
expected_len):
|
||||
server1 = {
|
||||
'share_network_id': 'fake-share-net-id',
|
||||
'host': 'hostname',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
'is_auto_deletable': server_1_is_auto_deletable,
|
||||
'updated_at': datetime.datetime(2018, 5, 1)
|
||||
}
|
||||
server2 = {
|
||||
'share_network_id': 'fake-share-net-id',
|
||||
'host': 'hostname',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
'is_auto_deletable': server_2_is_auto_deletable,
|
||||
'updated_at': datetime.datetime(2018, 5, 1)
|
||||
}
|
||||
server3 = {
|
||||
'share_network_id': 'fake-share-net-id',
|
||||
'host': 'hostname',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
'is_auto_deletable': server_3_is_auto_deletable,
|
||||
@ -3403,7 +3457,7 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
|
||||
share_network_subnet = db_utils.create_share_network_subnet(
|
||||
id=uuidutils.generate_uuid(),
|
||||
share_network_id=share_network_id)
|
||||
server_data['share_network_subnet_id'] = share_network_subnet['id']
|
||||
server_data['share_network_subnets'] = [share_network_subnet]
|
||||
db_utils.create_share_server(**server_data)
|
||||
db_utils.create_share_server()
|
||||
filter_keys = filters.keys()
|
||||
@ -3417,7 +3471,7 @@ class ShareServerDatabaseAPITestCase(test.TestCase):
|
||||
self.assertEqual(share_network_subnet['share_network_id'],
|
||||
filters[key])
|
||||
self.assertEqual(share_network_subnet['id'],
|
||||
result['share_network_subnet_id'])
|
||||
result['share_network_subnets'][0]['id'])
|
||||
else:
|
||||
self.assertEqual(result[key], filters[key])
|
||||
|
||||
@ -3534,27 +3588,32 @@ class NetworkAllocationsDatabaseAPITestCase(test.TestCase):
|
||||
self.user_id = 'user_id'
|
||||
self.project_id = 'project_id'
|
||||
self.share_server_id = 'foo_share_server_id'
|
||||
self.share_network_subnet_id = 'foo_share_network_subnet_id'
|
||||
self.ctxt = context.RequestContext(
|
||||
user_id=self.user_id, project_id=self.project_id, is_admin=True)
|
||||
self.user_network_allocations = [
|
||||
{'share_server_id': self.share_server_id,
|
||||
'ip_address': '1.1.1.1',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
'label': None},
|
||||
'label': None,
|
||||
'share_network_subnet_id': self.share_network_subnet_id},
|
||||
{'share_server_id': self.share_server_id,
|
||||
'ip_address': '2.2.2.2',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
'label': 'user'},
|
||||
'label': 'user',
|
||||
'share_network_subnet_id': self.share_network_subnet_id},
|
||||
]
|
||||
self.admin_network_allocations = [
|
||||
{'share_server_id': self.share_server_id,
|
||||
'ip_address': '3.3.3.3',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
'label': 'admin'},
|
||||
'label': 'admin',
|
||||
'share_network_subnet_id': None},
|
||||
{'share_server_id': self.share_server_id,
|
||||
'ip_address': '4.4.4.4',
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
'label': 'admin'},
|
||||
'label': 'admin',
|
||||
'share_network_subnet_id': None},
|
||||
]
|
||||
|
||||
def _setup_network_allocations_get_for_share_server(self):
|
||||
@ -3566,10 +3625,17 @@ class NetworkAllocationsDatabaseAPITestCase(test.TestCase):
|
||||
}
|
||||
db_api.share_network_create(self.ctxt, share_network_data)
|
||||
|
||||
# Create share network subnet
|
||||
share_network_subnet_data = {
|
||||
'id': self.share_network_subnet_id,
|
||||
'share_network_id': self.user_id,
|
||||
}
|
||||
db_api.share_network_subnet_create(self.ctxt,
|
||||
share_network_subnet_data)
|
||||
|
||||
# Create share server
|
||||
share_server_data = {
|
||||
'id': self.share_server_id,
|
||||
'share_network_id': share_network_data['id'],
|
||||
'host': 'fake_host',
|
||||
'status': 'active',
|
||||
}
|
||||
@ -3644,6 +3710,20 @@ class NetworkAllocationsDatabaseAPITestCase(test.TestCase):
|
||||
self.ctxt,
|
||||
id='fake')
|
||||
|
||||
def test_network_allocation_get_by_subnet_id(self):
|
||||
self._setup_network_allocations_get_for_share_server()
|
||||
|
||||
result = db_api.network_allocations_get_for_share_server(
|
||||
self.ctxt, self.share_server_id,
|
||||
subnet_id=self.share_network_subnet_id)
|
||||
|
||||
self.assertEqual(2, len(result))
|
||||
|
||||
for network_allocation in result:
|
||||
self.assertIsInstance(network_allocation, models.NetworkAllocation)
|
||||
self.assertEqual(self.share_network_subnet_id,
|
||||
network_allocation.share_network_subnet_id)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_network_allocation_get_read_deleted(self, read_deleted):
|
||||
self._setup_network_allocations_get_for_share_server()
|
||||
@ -3798,8 +3878,7 @@ class PurgeDeletedTest(test.TestCase):
|
||||
# create share server
|
||||
db_utils.create_share_server(
|
||||
id=uuidutils.generate_uuid(),
|
||||
deleted_at=self._days_ago(start, end),
|
||||
share_network_id=network.id)
|
||||
deleted_at=self._days_ago(start, end))
|
||||
# create snapshot
|
||||
db_api.share_snapshot_create(
|
||||
self.context, {'share_id': share['id'],
|
||||
@ -4360,6 +4439,9 @@ class ShareResourcesAPITestCase(test.TestCase):
|
||||
share_id = uuidutils.generate_uuid()
|
||||
share_network_id = uuidutils.generate_uuid()
|
||||
share_network_subnet_id = uuidutils.generate_uuid()
|
||||
share_net_subnets = [db_utils.create_share_network_subnet(
|
||||
id=share_network_subnet_id,
|
||||
share_network_id=share_network_id)]
|
||||
if '@' in current_host:
|
||||
if '#' in current_host:
|
||||
new_host = 'new-controller-X@backendX#poolX'
|
||||
@ -4400,15 +4482,15 @@ class ShareResourcesAPITestCase(test.TestCase):
|
||||
status=constants.STATUS_DELETING),
|
||||
# share servers
|
||||
db_utils.create_share_server(
|
||||
share_network_subnet_id=share_network_subnet_id,
|
||||
share_network_subnets=share_net_subnets,
|
||||
host='controller-0@fancystore01',
|
||||
status=constants.STATUS_ACTIVE),
|
||||
db_utils.create_share_server(
|
||||
share_network_subnet_id=share_network_subnet_id,
|
||||
share_network_subnets=share_net_subnets,
|
||||
host='controller-0@otherstore02#pool100',
|
||||
status=constants.STATUS_ERROR),
|
||||
db_utils.create_share_server(
|
||||
share_network_subnet_id=share_network_subnet_id,
|
||||
share_network_subnets=share_net_subnets,
|
||||
host='controller-2@beststore07',
|
||||
status=constants.STATUS_DELETING),
|
||||
|
||||
@ -4425,8 +4507,9 @@ class ShareResourcesAPITestCase(test.TestCase):
|
||||
self.context, filters={'share_id': share_id})
|
||||
share_groups = db_api.share_group_get_all(
|
||||
self.context, filters={'share_network_id': share_network_id})
|
||||
share_servers = db_api._server_get_query(self.context).filter_by(
|
||||
share_network_subnet_id=share_network_subnet_id).all()
|
||||
share_servers = db_api._server_get_query(self.context).filter(
|
||||
models.ShareServer.share_network_subnets.any(
|
||||
id=share_net_subnets[0]['id'])).all()
|
||||
self.assertEqual(3, len(share_instances))
|
||||
self.assertEqual(3, len(share_groups))
|
||||
self.assertEqual(3, len(share_servers))
|
||||
@ -4450,6 +4533,9 @@ class ShareResourcesAPITestCase(test.TestCase):
|
||||
share_id = uuidutils.generate_uuid()
|
||||
share_network_id = uuidutils.generate_uuid()
|
||||
share_network_subnet_id = uuidutils.generate_uuid()
|
||||
share_net_subnets = [db_utils.create_share_network_subnet(
|
||||
id=share_network_subnet_id,
|
||||
share_network_id=share_network_id)]
|
||||
if '@' in current_host:
|
||||
if '#' in current_host:
|
||||
new_host = 'new-controller-X@backendX#poolX'
|
||||
@ -4493,15 +4579,15 @@ class ShareResourcesAPITestCase(test.TestCase):
|
||||
status=constants.STATUS_DELETING),
|
||||
# share servers
|
||||
db_utils.create_share_server(
|
||||
share_network_subnet_id=share_network_subnet_id,
|
||||
share_network_subnets=share_net_subnets,
|
||||
host='controller-0@fancystore01#pool100',
|
||||
status=constants.STATUS_ACTIVE),
|
||||
db_utils.create_share_server(
|
||||
share_network_subnet_id=share_network_subnet_id,
|
||||
share_network_subnets=share_net_subnets,
|
||||
host='controller-2@fancystore01',
|
||||
status=constants.STATUS_ERROR),
|
||||
db_utils.create_share_server(
|
||||
share_network_subnet_id=share_network_subnet_id,
|
||||
share_network_subnets=share_net_subnets,
|
||||
host='controller-2@beststore07#pool200',
|
||||
status=constants.STATUS_DELETING),
|
||||
]
|
||||
@ -4513,8 +4599,9 @@ class ShareResourcesAPITestCase(test.TestCase):
|
||||
self.context, filters={'share_id': share_id})
|
||||
share_groups = db_api.share_group_get_all(
|
||||
self.context, filters={'share_network_id': share_network_id})
|
||||
share_servers = db_api._server_get_query(self.context).filter_by(
|
||||
share_network_subnet_id=share_network_subnet_id).all()
|
||||
share_servers = db_api._server_get_query(self.context).filter(
|
||||
models.ShareServer.share_network_subnets.any(
|
||||
id=share_net_subnets[0]['id'])).all()
|
||||
|
||||
updated_resources = [
|
||||
res for res in share_instances + share_groups + share_servers
|
||||
|
@ -214,7 +214,6 @@ def create_share_server(**kwargs):
|
||||
backend_details = kwargs.pop('backend_details', {})
|
||||
srv = {
|
||||
'host': 'host1',
|
||||
'share_network_subnet_id': 'fake_srv_id',
|
||||
'status': constants.STATUS_ACTIVE
|
||||
}
|
||||
share_srv = _create_db_row(db.share_server_create, srv, kwargs)
|
||||
|
@ -305,7 +305,6 @@ def fake_share_server_get():
|
||||
'status': constants.STATUS_ACTIVE,
|
||||
'updated_at': None,
|
||||
'host': 'fake_host',
|
||||
'share_network_subnet_id': 'fake_sn_id',
|
||||
'share_network_name': 'fake_sn_name',
|
||||
'project_id': 'fake_project_id',
|
||||
'id': 'fake_share_server_id',
|
||||
|
@ -122,6 +122,7 @@ fake_network_allocation = {
|
||||
'cidr': fake_share_network_subnet['cidr'],
|
||||
'gateway': fake_share_network_subnet['gateway'],
|
||||
'mtu': 1509,
|
||||
'share_network_subnet_id': fake_share_network_subnet['id'],
|
||||
}
|
||||
|
||||
fake_nw_info = {
|
||||
@ -187,6 +188,7 @@ fake_network_allocation_multi = {
|
||||
'cidr': fake_neutron_subnet['cidr'],
|
||||
'gateway': fake_neutron_subnet['gateway_ip'],
|
||||
'mtu': fake_neutron_network_multi['mtu'],
|
||||
'share_network_subnet_id': fake_share_network['id'],
|
||||
}
|
||||
|
||||
fake_binding_profile = {
|
||||
@ -240,9 +242,11 @@ class NeutronNetworkPluginTest(test.TestCase):
|
||||
|
||||
has_provider_nw_ext.assert_any_call()
|
||||
save_nw_data.assert_called_once_with(self.fake_context,
|
||||
fake_share_network_subnet)
|
||||
fake_share_network_subnet,
|
||||
save_db=True)
|
||||
save_subnet_data.assert_called_once_with(self.fake_context,
|
||||
fake_share_network_subnet)
|
||||
fake_share_network_subnet,
|
||||
save_db=True)
|
||||
self.plugin.neutron_api.create_port.assert_called_once_with(
|
||||
fake_share_network['project_id'],
|
||||
network_id=fake_share_network_subnet['neutron_net_id'],
|
||||
@ -401,6 +405,7 @@ class NeutronNetworkPluginTest(test.TestCase):
|
||||
'ip_version': fake_share_network_subnet['ip_version'],
|
||||
'cidr': fake_share_network_subnet['cidr'],
|
||||
'mtu': fake_share_network_subnet['mtu'],
|
||||
'share_network_subnet_id': fake_share_network_subnet['id'],
|
||||
} for x in ['192.168.0.11', '192.168.0.12']]
|
||||
|
||||
if side_effect:
|
||||
@ -961,9 +966,11 @@ class NeutronBindNetworkPluginTest(test.TestCase):
|
||||
|
||||
self.bind_plugin._has_provider_network_extension.assert_any_call()
|
||||
save_nw_data.assert_called_once_with(self.fake_context,
|
||||
fake_share_network_subnet)
|
||||
fake_share_network_subnet,
|
||||
save_db=True)
|
||||
save_subnet_data.assert_called_once_with(self.fake_context,
|
||||
fake_share_network_subnet)
|
||||
fake_share_network_subnet,
|
||||
save_db=True)
|
||||
expected_kwargs = {
|
||||
'binding:vnic_type': 'baremetal',
|
||||
'host_id': 'foohost1',
|
||||
@ -1486,9 +1493,11 @@ class NeutronBindSingleNetworkPluginTest(test.TestCase):
|
||||
|
||||
self.bind_plugin._has_provider_network_extension.assert_any_call()
|
||||
save_nw_data.assert_called_once_with(self.fake_context,
|
||||
fake_share_network_subnet)
|
||||
fake_share_network_subnet,
|
||||
save_db=True)
|
||||
save_subnet_data.assert_called_once_with(self.fake_context,
|
||||
fake_share_network_subnet)
|
||||
fake_share_network_subnet,
|
||||
save_db=True)
|
||||
expected_kwargs = {
|
||||
'binding:vnic_type': 'baremetal',
|
||||
'host_id': 'foohost1',
|
||||
@ -1713,9 +1722,11 @@ class NeutronBindNetworkPluginWithNormalTypeTest(test.TestCase):
|
||||
|
||||
self.bind_plugin._has_provider_network_extension.assert_any_call()
|
||||
save_nw_data.assert_called_once_with(self.fake_context,
|
||||
fake_share_network_subnet)
|
||||
fake_share_network_subnet,
|
||||
save_db=True)
|
||||
save_subnet_data.assert_called_once_with(self.fake_context,
|
||||
fake_share_network_subnet)
|
||||
fake_share_network_subnet,
|
||||
save_db=True)
|
||||
expected_kwargs = {
|
||||
'binding:vnic_type': 'normal',
|
||||
'host_id': 'foohost1',
|
||||
@ -1800,9 +1811,11 @@ class NeutronBindSingleNetworkPluginWithNormalTypeTest(test.TestCase):
|
||||
|
||||
self.bind_plugin._has_provider_network_extension.assert_any_call()
|
||||
save_nw_data.assert_called_once_with(self.fake_context,
|
||||
fake_share_network_subnet)
|
||||
fake_share_network_subnet,
|
||||
save_db=True)
|
||||
save_subnet_data.assert_called_once_with(self.fake_context,
|
||||
fake_share_network_subnet)
|
||||
fake_share_network_subnet,
|
||||
save_db=True)
|
||||
expected_kwargs = {
|
||||
'binding:vnic_type': 'normal',
|
||||
'host_id': 'foohost1',
|
||||
@ -1866,3 +1879,23 @@ class NeutronBindSingleNetworkPluginWithNormalTypeTest(test.TestCase):
|
||||
self.assertRaises(exception.NetworkBadConfigurationException,
|
||||
self.bind_plugin._get_matched_ip_address,
|
||||
fix_ips, version)
|
||||
|
||||
def _setup_include_network_info(self):
|
||||
data = {
|
||||
'DEFAULT': {
|
||||
'neutron_net_id': 'fake net id',
|
||||
'neutron_subnet_id': 'fake subnet id',
|
||||
'neutron_physical_net_name': 'net1',
|
||||
}
|
||||
}
|
||||
with test_utils.create_temp_config_with_opts(data):
|
||||
instance = plugin.NeutronNetworkPlugin()
|
||||
|
||||
return instance
|
||||
|
||||
def test_include_network_info(self):
|
||||
instance = self._setup_include_network_info()
|
||||
self.mock_object(instance, '_store_neutron_net_info')
|
||||
instance.include_network_info(fake_share_network)
|
||||
instance._store_neutron_net_info.assert_called_once_with(
|
||||
None, fake_share_network, save_db=False)
|
||||
|
@ -346,7 +346,8 @@ class StandaloneNetworkPluginTest(test.TestCase):
|
||||
ip_version=6,
|
||||
mtu=1500))
|
||||
|
||||
def test_allocate_network_one_ip_address_ipv4_no_usages_exist(self):
|
||||
@ddt.data('admin', 'user')
|
||||
def test_allocate_network_one_ip_address_ipv4_no_usages_exist(self, label):
|
||||
data = {
|
||||
'DEFAULT': {
|
||||
'standalone_network_plugin_network_type': 'vlan',
|
||||
@ -356,8 +357,9 @@ class StandaloneNetworkPluginTest(test.TestCase):
|
||||
},
|
||||
}
|
||||
with test_utils.create_temp_config_with_opts(data):
|
||||
instance = plugin.StandaloneNetworkPlugin()
|
||||
self.mock_object(instance.db, 'share_network_subnet_update')
|
||||
instance = plugin.StandaloneNetworkPlugin(label=label)
|
||||
if label != 'admin':
|
||||
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',
|
||||
@ -376,15 +378,18 @@ class StandaloneNetworkPluginTest(test.TestCase):
|
||||
'ip_version': 4,
|
||||
'mtu': 1500,
|
||||
}
|
||||
instance.db.share_network_subnet_update.assert_called_once_with(
|
||||
fake_context, fake_share_network_subnet['id'], na_data)
|
||||
if label != 'admin':
|
||||
instance.db.share_network_subnet_update.assert_called_once_with(
|
||||
fake_context, fake_share_network_subnet['id'], na_data)
|
||||
na_data['share_network_subnet_id'] = \
|
||||
fake_share_network_subnet['id']
|
||||
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(
|
||||
fake_context,
|
||||
dict(share_server_id=fake_share_server['id'],
|
||||
ip_address='10.0.0.2', status=constants.STATUS_ACTIVE,
|
||||
label='user', **na_data))
|
||||
label=label, **na_data))
|
||||
|
||||
def test_allocate_network_two_ip_addresses_ipv4_two_usages_exist(self):
|
||||
ctxt = type('FakeCtxt', (object,), {'fake': ['10.0.0.2', '10.0.0.4']})
|
||||
@ -428,6 +433,7 @@ class StandaloneNetworkPluginTest(test.TestCase):
|
||||
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')])
|
||||
na_data['share_network_subnet_id'] = fake_share_network_subnet['id']
|
||||
instance.db.network_allocation_create.assert_has_calls([
|
||||
mock.call(
|
||||
ctxt,
|
||||
@ -522,6 +528,10 @@ class StandaloneNetworkPluginTest(test.TestCase):
|
||||
if not label:
|
||||
instance.db.share_network_subnet_update.assert_called_once_with(
|
||||
fake_context, fake_share_network_subnet['id'], network_data)
|
||||
data_list[0]['share_network_subnet_id'] = (
|
||||
fake_share_network_subnet['id'])
|
||||
data_list[1]['share_network_subnet_id'] = (
|
||||
fake_share_network_subnet['id'])
|
||||
instance._verify_share_network_subnet.assert_called_once_with(
|
||||
fake_share_server['id'], fake_share_network_subnet)
|
||||
|
||||
@ -536,3 +546,22 @@ class StandaloneNetworkPluginTest(test.TestCase):
|
||||
instance.unmanage_network_allocations('context', 'server_id')
|
||||
instance.deallocate_network.assert_called_once_with(
|
||||
'context', 'server_id')
|
||||
|
||||
def _setup_include_network_info(self):
|
||||
data = {
|
||||
'DEFAULT': {
|
||||
'standalone_network_plugin_gateway': '192.168.0.1',
|
||||
'standalone_network_plugin_mask': '24',
|
||||
},
|
||||
}
|
||||
with test_utils.create_temp_config_with_opts(data):
|
||||
instance = plugin.StandaloneNetworkPlugin()
|
||||
|
||||
return instance
|
||||
|
||||
def test_include_network_info(self):
|
||||
instance = self._setup_include_network_info()
|
||||
self.mock_object(instance, '_save_network_info')
|
||||
instance.include_network_info(fake_share_network)
|
||||
instance._save_network_info.assert_called_once_with(
|
||||
None, fake_share_network, save_db=False)
|
||||
|
@ -101,6 +101,8 @@ class HostFiltersTestCase(test.TestCase):
|
||||
}
|
||||
request = self._make_zone_request(None)
|
||||
request['request_spec']['availability_zones'] = supported_azs
|
||||
request['request_spec']['az_request_multiple_subnet_support_map'] = \
|
||||
{'zone2': 2}
|
||||
host = fakes.FakeHostState('host1', {'service': service})
|
||||
|
||||
self.assertEqual(host_passes, self.filter.host_passes(host, request))
|
||||
|
@ -214,6 +214,8 @@ class HostManagerTestCase(test.TestCase):
|
||||
'replication_domain': None,
|
||||
'sg_consistent_snapshot_support': None,
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
},
|
||||
}, {
|
||||
'name': 'host2@back1#BBB',
|
||||
@ -244,6 +246,8 @@ class HostManagerTestCase(test.TestCase):
|
||||
'replication_domain': None,
|
||||
'sg_consistent_snapshot_support': None,
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
},
|
||||
}, {
|
||||
'name': 'host2@back2#CCC',
|
||||
@ -274,6 +278,8 @@ class HostManagerTestCase(test.TestCase):
|
||||
'replication_domain': None,
|
||||
'sg_consistent_snapshot_support': None,
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
},
|
||||
},
|
||||
]
|
||||
@ -326,6 +332,8 @@ class HostManagerTestCase(test.TestCase):
|
||||
'replication_domain': None,
|
||||
'sg_consistent_snapshot_support': None,
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
},
|
||||
}, {
|
||||
'name': 'host2@BBB#pool2',
|
||||
@ -357,6 +365,8 @@ class HostManagerTestCase(test.TestCase):
|
||||
'replication_domain': None,
|
||||
'sg_consistent_snapshot_support': None,
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
},
|
||||
}, {
|
||||
'name': 'host3@CCC#pool3',
|
||||
@ -388,6 +398,8 @@ class HostManagerTestCase(test.TestCase):
|
||||
'replication_domain': None,
|
||||
'sg_consistent_snapshot_support': None,
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
},
|
||||
}, {
|
||||
'name': 'host4@DDD#pool4a',
|
||||
@ -419,6 +431,8 @@ class HostManagerTestCase(test.TestCase):
|
||||
'replication_domain': None,
|
||||
'sg_consistent_snapshot_support': None,
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
},
|
||||
}, {
|
||||
'name': 'host4@DDD#pool4b',
|
||||
@ -450,6 +464,8 @@ class HostManagerTestCase(test.TestCase):
|
||||
'replication_domain': None,
|
||||
'sg_consistent_snapshot_support': None,
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
},
|
||||
},
|
||||
]
|
||||
@ -514,6 +530,8 @@ class HostManagerTestCase(test.TestCase):
|
||||
'replication_domain': None,
|
||||
'sg_consistent_snapshot_support': None,
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
},
|
||||
}, {
|
||||
'name': 'host2@back1#BBB',
|
||||
@ -544,6 +562,8 @@ class HostManagerTestCase(test.TestCase):
|
||||
'replication_domain': None,
|
||||
'sg_consistent_snapshot_support': None,
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
},
|
||||
},
|
||||
]
|
||||
@ -602,6 +622,8 @@ class HostManagerTestCase(test.TestCase):
|
||||
'replication_domain': None,
|
||||
'sg_consistent_snapshot_support': None,
|
||||
'security_service_update_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
},
|
||||
},
|
||||
]
|
||||
|
@ -372,7 +372,7 @@ class ContainerShareDriverTestCase(test.TestCase):
|
||||
before, after)
|
||||
|
||||
def test__setup_server_container_fails(self):
|
||||
network_info = cont_fakes.fake_network()
|
||||
network_info = [cont_fakes.fake_network()]
|
||||
self.mock_object(self._driver.container, 'start_container')
|
||||
self._driver.container.start_container.side_effect = KeyError()
|
||||
|
||||
@ -380,21 +380,21 @@ class ContainerShareDriverTestCase(test.TestCase):
|
||||
self._driver._setup_server, network_info)
|
||||
|
||||
def test__setup_server_ok(self):
|
||||
network_info = cont_fakes.fake_network()
|
||||
server_id = self._driver._get_container_name(network_info["server_id"])
|
||||
network_info = [cont_fakes.fake_network()]
|
||||
server_id = self._driver._get_container_name(
|
||||
network_info[0]["server_id"])
|
||||
self.mock_object(self._driver.container, 'start_container')
|
||||
self.mock_object(self._driver, '_get_veth_state')
|
||||
self.mock_object(self._driver, '_get_corresponding_veth',
|
||||
mock.Mock(return_value='veth0'))
|
||||
self.mock_object(self._driver, '_connect_to_network')
|
||||
|
||||
self.assertEqual(network_info['server_id'],
|
||||
self.assertEqual(network_info[0]['server_id'],
|
||||
self._driver._setup_server(network_info)['id'])
|
||||
self._driver.container.start_container.assert_called_once_with(
|
||||
server_id)
|
||||
self._driver._connect_to_network.assert_called_once_with(server_id,
|
||||
network_info,
|
||||
'veth0')
|
||||
self._driver._connect_to_network.assert_called_once_with(
|
||||
server_id, network_info[0], 'veth0')
|
||||
|
||||
def test_manage_existing(self):
|
||||
|
||||
|
@ -145,6 +145,8 @@ class EMCShareFrameworkTestCase(test.TestCase):
|
||||
data['max_shares_per_share_server'] = -1
|
||||
data['max_share_server_size'] = -1
|
||||
data['security_service_update_support'] = False
|
||||
data['share_server_multiple_subnet_support'] = False
|
||||
data['network_allocation_update_support'] = False
|
||||
self.assertEqual(data, self.driver._stats)
|
||||
|
||||
def _fake_safe_get(self, value):
|
||||
@ -214,3 +216,9 @@ class EMCShareFrameworkTestCase(test.TestCase):
|
||||
expected = None
|
||||
actual = self.driver.get_default_filter_function()
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
def test_setup_server(self):
|
||||
network_info = [{}]
|
||||
expected = None
|
||||
result = self.driver._setup_server(network_info)
|
||||
self.assertEqual(expected, result)
|
||||
|
@ -34,6 +34,7 @@ import time
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from manila.common import constants
|
||||
@ -141,6 +142,7 @@ class DummyDriver(driver.ShareDriver):
|
||||
"share_backend_name") or "DummyDriver"
|
||||
self.migration_progress = {}
|
||||
self.security_service_update_support = True
|
||||
self.network_allocation_update_support = True
|
||||
|
||||
def _verify_configuration(self):
|
||||
allowed_driver_methods = [m for m in dir(self) if m[0] != '_']
|
||||
@ -184,24 +186,40 @@ class DummyDriver(driver.ShareDriver):
|
||||
"s_id": snapshot["snapshot_id"].replace("-", "_"),
|
||||
"si_id": snapshot["id"].replace("-", "_")}
|
||||
|
||||
def _generate_export_locations(self, mountpoint, share_server=None):
|
||||
details = share_server["backend_details"] if share_server else {
|
||||
"primary_public_ip": "10.0.0.10",
|
||||
"secondary_public_ip": "10.0.0.20",
|
||||
"service_ip": "11.0.0.11",
|
||||
def _get_export(self, mountpoint, ip, is_admin_only, preferred):
|
||||
return {
|
||||
"path": "%(ip)s:%(mp)s" % {"ip": ip, "mp": mountpoint},
|
||||
"metadata": {
|
||||
"preferred": preferred,
|
||||
},
|
||||
"is_admin_only": is_admin_only,
|
||||
}
|
||||
return [
|
||||
{
|
||||
"path": "%(ip)s:%(mp)s" % {"ip": ip, "mp": mountpoint},
|
||||
"metadata": {
|
||||
"preferred": preferred,
|
||||
},
|
||||
"is_admin_only": is_admin_only,
|
||||
} for ip, is_admin_only, preferred in (
|
||||
(details["primary_public_ip"], False, True),
|
||||
(details["secondary_public_ip"], False, False),
|
||||
(details["service_ip"], True, False))
|
||||
]
|
||||
|
||||
def _generate_export_locations(self, mountpoint, share_server=None):
|
||||
if share_server:
|
||||
subnet_allocations = jsonutils.loads(
|
||||
share_server["backend_details"]["subnet_allocations"])
|
||||
service_ip = share_server["backend_details"]["service_ip"]
|
||||
else:
|
||||
subnet_allocations = [{
|
||||
"primary_public_ip": "10.0.0.10",
|
||||
"secondary_public_ip": "10.0.0.20",
|
||||
}]
|
||||
service_ip = "11.0.0.11"
|
||||
|
||||
export_locations = [
|
||||
self._get_export(mountpoint, service_ip, True, False)]
|
||||
for subnet_allocation in subnet_allocations:
|
||||
export_locations.append(
|
||||
self._get_export(
|
||||
mountpoint, subnet_allocation["primary_public_ip"],
|
||||
False, True))
|
||||
export_locations.append(
|
||||
self._get_export(
|
||||
mountpoint, subnet_allocation["secondary_public_ip"],
|
||||
False, False))
|
||||
|
||||
return export_locations
|
||||
|
||||
def _create_share(self, share, share_server=None):
|
||||
share_proto = share["share_proto"]
|
||||
@ -410,16 +428,25 @@ class DummyDriver(driver.ShareDriver):
|
||||
Redefine it within share driver when it is going to handle share
|
||||
servers.
|
||||
"""
|
||||
common_net_info = network_info[0]
|
||||
server_details = {
|
||||
"primary_public_ip": network_info[
|
||||
"network_allocations"][0]["ip_address"],
|
||||
"secondary_public_ip": network_info[
|
||||
"network_allocations"][1]["ip_address"],
|
||||
"service_ip": network_info[
|
||||
"service_ip": common_net_info[
|
||||
"admin_network_allocations"][0]["ip_address"],
|
||||
"username": "fake_username",
|
||||
"server_id": network_info['server_id']
|
||||
"server_id": common_net_info['server_id'],
|
||||
}
|
||||
|
||||
subnet_allocations = []
|
||||
for subnet_info in network_info:
|
||||
subnet_allocations.append({
|
||||
"primary_public_ip": subnet_info[
|
||||
"network_allocations"][0]["ip_address"],
|
||||
"secondary_public_ip": subnet_info[
|
||||
"network_allocations"][1]["ip_address"]
|
||||
})
|
||||
|
||||
server_details['subnet_allocations'] = jsonutils.dumps(
|
||||
subnet_allocations)
|
||||
return server_details
|
||||
|
||||
@slow_me_down
|
||||
@ -460,6 +487,7 @@ class DummyDriver(driver.ShareDriver):
|
||||
"share_group_stats": {
|
||||
"consistent_snapshot_support": "pool",
|
||||
},
|
||||
'share_server_multiple_subnet_support': True,
|
||||
}
|
||||
if self.configuration.replication_domain:
|
||||
data["replication_type"] = "readable"
|
||||
@ -828,9 +856,12 @@ class DummyDriver(driver.ShareDriver):
|
||||
"private storage." % identifier)
|
||||
raise exception.ShareBackendException(msg=msg)
|
||||
|
||||
return [server_details['primary_public_ip'],
|
||||
server_details['secondary_public_ip'],
|
||||
server_details['service_ip']]
|
||||
ips = [server_details['service_ip']]
|
||||
subnet_allocations = jsonutils.loads(
|
||||
server_details['subnet_allocations'])
|
||||
for subnet_allocation in subnet_allocations:
|
||||
ips += list(subnet_allocation.values())
|
||||
return ips
|
||||
|
||||
@slow_me_down
|
||||
def manage_server(self, context, share_server, identifier, driver_options):
|
||||
@ -889,3 +920,65 @@ class DummyDriver(driver.ShareDriver):
|
||||
share_instance_rules, new_security_service,
|
||||
current_security_service=None):
|
||||
return True
|
||||
|
||||
def check_update_share_server_network_allocations(
|
||||
self, context, share_server, current_network_allocations,
|
||||
new_share_network_subnet, security_services, share_instances,
|
||||
share_instances_rules):
|
||||
|
||||
LOG.debug("Share server %(server)s can be updated with allocations "
|
||||
"from new subnet.", {'server': share_server['id']})
|
||||
return True
|
||||
|
||||
def update_share_server_network_allocations(
|
||||
self, context, share_server, current_network_allocations,
|
||||
new_network_allocations, security_services, shares, snapshots):
|
||||
|
||||
subnet_allocations = jsonutils.loads(
|
||||
share_server['backend_details']['subnet_allocations'])
|
||||
subnet_allocations.append({
|
||||
'primary_public_ip': new_network_allocations[
|
||||
'network_allocations'][0]['ip_address'],
|
||||
'secondary_public_ip': new_network_allocations[
|
||||
'network_allocations'][1]['ip_address'],
|
||||
})
|
||||
new_server = {
|
||||
"backend_details": {
|
||||
"subnet_allocations": jsonutils.dumps(subnet_allocations),
|
||||
"service_ip": share_server["backend_details"]["service_ip"],
|
||||
}
|
||||
}
|
||||
shares_updates = {}
|
||||
for instance in shares:
|
||||
|
||||
share_name = self._get_share_name(instance)
|
||||
mountpoint = "/path/to/fake/share/%s" % share_name
|
||||
export_locations = self._generate_export_locations(
|
||||
mountpoint, share_server=new_server)
|
||||
shares_updates.update(
|
||||
{instance['id']: export_locations}
|
||||
)
|
||||
|
||||
snapshot_updates = {}
|
||||
for instance in snapshots:
|
||||
snapshot_name = self._get_snapshot_name(instance)
|
||||
mountpoint = "/path/to/fake/snapshot/%s" % snapshot_name
|
||||
snap_export_locations = self._generate_export_locations(
|
||||
mountpoint, share_server=new_server)
|
||||
snapshot_updates.update(
|
||||
{instance['id']: {
|
||||
'provider_location': mountpoint,
|
||||
'export_locations': snap_export_locations}}
|
||||
)
|
||||
|
||||
LOG.debug(
|
||||
"Network update allocations of dummy share server with ID '%s' "
|
||||
"has been completed.", share_server["id"])
|
||||
return {
|
||||
"share_updates": shares_updates,
|
||||
"snapshot_updates": snapshot_updates,
|
||||
"server_details": {
|
||||
"subnet_allocations": (
|
||||
new_server["backend_details"]["subnet_allocations"])
|
||||
},
|
||||
}
|
||||
|
@ -270,6 +270,8 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
|
||||
'ipv4_support': True,
|
||||
'ipv6_support': False,
|
||||
'security_service_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
}
|
||||
self.assertEqual(test_data, self._driver._stats)
|
||||
|
||||
|
@ -750,6 +750,8 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
'max_share_server_size': -1,
|
||||
'max_shares_per_share_server': -1,
|
||||
'security_service_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
}
|
||||
|
||||
result = self.driver.get_share_stats(refresh=True)
|
||||
@ -824,6 +826,8 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
'create_share_from_snapshot_support': True,
|
||||
'revert_to_snapshot_support': False,
|
||||
'security_service_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'mount_snapshot_support': False,
|
||||
'share_group_stats': {
|
||||
'consistent_snapshot_support': None,
|
||||
@ -872,6 +876,8 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
'create_share_from_snapshot_support': True,
|
||||
'revert_to_snapshot_support': False,
|
||||
'security_service_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
'mount_snapshot_support': False,
|
||||
'share_group_stats': {
|
||||
'consistent_snapshot_support': None,
|
||||
@ -926,7 +932,7 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
|
||||
self.init_driver()
|
||||
|
||||
network_info = {
|
||||
network_info = [{
|
||||
'network_allocations': [
|
||||
{'ip_address': constants.EXPECTED_IP_1234}],
|
||||
'cidr': '/'.join((constants.EXPECTED_IP_1234,
|
||||
@ -934,7 +940,7 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
'network_type': constants.EXPECTED_VLAN_TYPE,
|
||||
'segmentation_id': constants.EXPECTED_VLAN_TAG,
|
||||
'server_id': constants.EXPECTED_SERVER_ID,
|
||||
}
|
||||
}]
|
||||
|
||||
expected_result = {
|
||||
'share_server_name': constants.EXPECTED_SERVER_ID,
|
||||
@ -964,7 +970,7 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
|
||||
self.init_driver()
|
||||
|
||||
network_info = {
|
||||
network_info = [{
|
||||
'network_allocations': [
|
||||
{'ip_address': constants.EXPECTED_IP_1234}],
|
||||
'cidr': '/'.join((constants.EXPECTED_IP_1234,
|
||||
@ -972,7 +978,7 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
'network_type': constants.EXPECTED_VXLAN_TYPE,
|
||||
'segmentation_id': constants.EXPECTED_VLAN_TAG,
|
||||
'server_id': constants.EXPECTED_SERVER_ID,
|
||||
}
|
||||
}]
|
||||
metadata = {'request_host': constants.EXPECTED_HOST}
|
||||
|
||||
self.assertRaises(exception.NetworkBadConfigurationException,
|
||||
@ -984,7 +990,7 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
|
||||
self.init_driver()
|
||||
|
||||
network_info = {
|
||||
network_info = [{
|
||||
'network_allocations': [
|
||||
{'ip_address': constants.EXPECTED_IP_1234}],
|
||||
'cidr': '/'.join((constants.EXPECTED_IP_1234,
|
||||
@ -992,7 +998,7 @@ class HPE3ParDriverTestCase(test.TestCase):
|
||||
'network_type': constants.EXPECTED_VLAN_TYPE,
|
||||
'segmentation_id': constants.EXPECTED_VLAN_TAG,
|
||||
'server_id': constants.EXPECTED_SERVER_ID,
|
||||
}
|
||||
}]
|
||||
metadata = {'request_host': constants.EXPECTED_HOST}
|
||||
|
||||
expected_vfs = self.driver.fpgs[
|
||||
|
@ -1181,7 +1181,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
'id': 'fake_network_allocation_id',
|
||||
'ip_address': '111.111.111.109',
|
||||
}]
|
||||
self.fake_network_info = {
|
||||
self.fake_network_info = [{
|
||||
'server_id': '0',
|
||||
'segmentation_id': '2',
|
||||
'cidr': '111.111.111.0/24',
|
||||
@ -1190,7 +1190,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
'security_services': '',
|
||||
'network_allocations': self.fake_network_allocations,
|
||||
'network_type': 'vlan',
|
||||
}
|
||||
}]
|
||||
self.fake_active_directory = {
|
||||
'type': 'active_directory',
|
||||
'dns_ip': '100.97.5.5',
|
||||
@ -2435,6 +2435,8 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
"ipv4_support": True,
|
||||
"ipv6_support": False,
|
||||
"security_service_update_support": False,
|
||||
"share_server_multiple_subnet_support": False,
|
||||
"network_allocation_update_support": False,
|
||||
}
|
||||
|
||||
if replication_support:
|
||||
@ -3323,7 +3325,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
|
||||
def test_setup_server_invalid_ipv4(self):
|
||||
netwot_info_invali_ipv4 = self.fake_network_info
|
||||
netwot_info_invali_ipv4['network_allocations'][0]['ip_address'] = (
|
||||
netwot_info_invali_ipv4[0]['network_allocations'][0]['ip_address'] = (
|
||||
"::1/128")
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.driver._setup_server,
|
||||
@ -3332,7 +3334,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
@dec_driver_handles_share_servers
|
||||
def test_setup_server_network_type_error(self):
|
||||
vxlan_netwotk_info = self.fake_network_info
|
||||
vxlan_netwotk_info['network_type'] = 'vxlan'
|
||||
vxlan_netwotk_info[0]['network_type'] = 'vxlan'
|
||||
self.assertRaises(exception.NetworkBadConfigurationException,
|
||||
self.driver.setup_server,
|
||||
vxlan_netwotk_info)
|
||||
@ -3412,13 +3414,13 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
logical_port='CTE0.A.H0;CTE0.A.H2;CTE0.B.H0;BOND0')
|
||||
self.driver.plugin.configuration.manila_huawei_conf_file = (
|
||||
self.fake_conf_file)
|
||||
fake_network_info = {
|
||||
fake_network_info = [{
|
||||
'server_id': '0',
|
||||
'segmentation_id': None,
|
||||
'cidr': '111.111.111.0/24',
|
||||
'network_allocations': self.fake_network_allocations,
|
||||
'network_type': None,
|
||||
}
|
||||
}]
|
||||
self.mock_object(self.driver.plugin, '_get_online_port',
|
||||
mock.Mock(return_value=(['CTE0.A.H0', 'CTE0.A.H2',
|
||||
'CTE0.B.H0'], ['BOND0'])))
|
||||
@ -3476,7 +3478,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
return self.driver.plugin.helper.do_call(*args, **kwargs)
|
||||
|
||||
fake_network_info = self.fake_network_info
|
||||
fake_network_info['security_services'] = [
|
||||
fake_network_info[0]['security_services'] = [
|
||||
self.fake_active_directory, self.fake_ldap]
|
||||
self.mock_object(self.driver.plugin.helper, "delete_vlan")
|
||||
self.mock_object(self.driver.plugin.helper, "delete_AD_config")
|
||||
@ -3509,7 +3511,8 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
@dec_driver_handles_share_servers
|
||||
def test_setup_server_with_ad_domain_success(self):
|
||||
fake_network_info = self.fake_network_info
|
||||
fake_network_info['security_services'] = [self.fake_active_directory]
|
||||
fake_network_info[0]['security_services'] = (
|
||||
[self.fake_active_directory])
|
||||
self.mock_object(self.driver.plugin.helper,
|
||||
"get_AD_config",
|
||||
mock.Mock(
|
||||
@ -3531,8 +3534,8 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
@dec_driver_handles_share_servers
|
||||
def test_setup_server_with_ldap_domain_success(self, server_ips):
|
||||
fake_network_info = self.fake_network_info
|
||||
fake_network_info['security_services'] = [self.fake_ldap]
|
||||
fake_network_info['security_services'][0]['server'] = server_ips
|
||||
fake_network_info[0]['security_services'] = [self.fake_ldap]
|
||||
fake_network_info[0]['security_services'][0]['server'] = server_ips
|
||||
self.mock_object(
|
||||
self.driver.plugin.helper,
|
||||
"get_LDAP_config",
|
||||
@ -3547,8 +3550,8 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
def test_setup_server_with_ldap_domain_fail(self):
|
||||
server_ips = "100.97.5.87,100.97.5.88,100.97.5.89,100.97.5.86"
|
||||
fake_network_info = self.fake_network_info
|
||||
fake_network_info['security_services'] = [self.fake_ldap]
|
||||
fake_network_info['security_services'][0]['server'] = server_ips
|
||||
fake_network_info[0]['security_services'] = [self.fake_ldap]
|
||||
fake_network_info[0]['security_services'][0]['server'] = server_ips
|
||||
self.mock_object(
|
||||
self.driver.plugin.helper,
|
||||
"get_LDAP_config",
|
||||
@ -3573,7 +3576,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
@dec_driver_handles_share_servers
|
||||
def test_setup_server_with_security_service_invalid(self, data):
|
||||
fake_network_info = self.fake_network_info
|
||||
fake_network_info['security_services'] = [data]
|
||||
fake_network_info[0]['security_services'] = [data]
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.driver.setup_server,
|
||||
fake_network_info)
|
||||
@ -3592,7 +3595,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
'server': '',
|
||||
'domain': ''},
|
||||
]
|
||||
fake_network_info['security_services'] = ss
|
||||
fake_network_info[0]['security_services'] = ss
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.driver.setup_server,
|
||||
fake_network_info)
|
||||
@ -3600,7 +3603,8 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
@dec_driver_handles_share_servers
|
||||
def test_setup_server_dns_exist_error(self):
|
||||
fake_network_info = self.fake_network_info
|
||||
fake_network_info['security_services'] = [self.fake_active_directory]
|
||||
fake_network_info[0]['security_services'] = (
|
||||
[self.fake_active_directory])
|
||||
self.mock_object(self.driver.plugin.helper,
|
||||
"get_DNS_ip_address",
|
||||
mock.Mock(return_value=['100.97.5.85']))
|
||||
@ -3612,7 +3616,8 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
@dec_driver_handles_share_servers
|
||||
def test_setup_server_ad_exist_error(self):
|
||||
fake_network_info = self.fake_network_info
|
||||
fake_network_info['security_services'] = [self.fake_active_directory]
|
||||
fake_network_info[0]['security_services'] = (
|
||||
[self.fake_active_directory])
|
||||
self.mock_object(self.driver.plugin.helper,
|
||||
"get_AD_config",
|
||||
mock.Mock(
|
||||
@ -3626,7 +3631,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
@dec_driver_handles_share_servers
|
||||
def test_setup_server_ldap_exist_error(self):
|
||||
fake_network_info = self.fake_network_info
|
||||
fake_network_info['security_services'] = [self.fake_ldap]
|
||||
fake_network_info[0]['security_services'] = [self.fake_ldap]
|
||||
self.mock_object(self.driver.plugin.helper,
|
||||
"get_LDAP_config",
|
||||
mock.Mock(
|
||||
@ -3642,7 +3647,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
fake_active_directory = self.fake_active_directory
|
||||
ip_list = "100.97.5.5,100.97.5.6,100.97.5.7,100.97.5.8"
|
||||
fake_active_directory['dns_ip'] = ip_list
|
||||
fake_network_info['security_services'] = [fake_active_directory]
|
||||
fake_network_info[0]['security_services'] = [fake_active_directory]
|
||||
self.mock_object(
|
||||
self.driver.plugin.helper,
|
||||
"get_AD_config",
|
||||
@ -3655,7 +3660,8 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
||||
@dec_driver_handles_share_servers
|
||||
def test_setup_server_with_ad_domain_fail(self):
|
||||
fake_network_info = self.fake_network_info
|
||||
fake_network_info['security_services'] = [self.fake_active_directory]
|
||||
fake_network_info[0]['security_services'] = (
|
||||
[self.fake_active_directory])
|
||||
self.mock_object(self.driver.plugin,
|
||||
'_get_wait_interval',
|
||||
mock.Mock(return_value=1))
|
||||
|
@ -2852,7 +2852,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.fake_src_share_server,
|
||||
self.fake_dest_share_server,
|
||||
share_instances, [],
|
||||
fake.NETWORK_INFO
|
||||
[fake.NETWORK_INFO]
|
||||
)
|
||||
|
||||
expected_share_updates = {
|
||||
@ -2932,7 +2932,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.fake_dest_share_server,
|
||||
self.fake_src_vserver,
|
||||
self.mock_src_client, [fake.SHARE_INSTANCE],
|
||||
fake.NETWORK_INFO)
|
||||
[fake.NETWORK_INFO])
|
||||
|
||||
dm_session_mock.update_snapmirror_svm.assert_called_once_with(
|
||||
self.fake_src_share_server, self.fake_dest_share_server
|
||||
@ -2977,7 +2977,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.fake_src_share_server,
|
||||
self.fake_dest_share_server,
|
||||
[fake.SHARE_INSTANCE], [],
|
||||
fake.NETWORK_INFO)
|
||||
[fake.NETWORK_INFO])
|
||||
|
||||
self.library._get_vserver.assert_has_calls([
|
||||
mock.call(share_server=self.fake_src_share_server,
|
||||
@ -3513,7 +3513,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
fake_vserver_client, 'modify_active_directory_security_service')
|
||||
|
||||
self.library.update_share_server_security_service(
|
||||
fake_context, fake.SHARE_SERVER, fake_net_info,
|
||||
fake_context, fake.SHARE_SERVER, [fake_net_info],
|
||||
new_sec_service, current_security_service=curr_sec_service)
|
||||
|
||||
dns_ips = set()
|
||||
@ -3530,7 +3530,7 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
mock_get_vserver.assert_called_once_with(
|
||||
share_server=fake.SHARE_SERVER)
|
||||
mock_check_update.assert_called_once_with(
|
||||
fake_context, fake.SHARE_SERVER, fake_net_info, new_sec_service,
|
||||
fake_context, fake.SHARE_SERVER, [fake_net_info], new_sec_service,
|
||||
current_security_service=curr_sec_service)
|
||||
|
||||
if curr_sec_service is None:
|
||||
@ -3565,13 +3565,13 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.assertRaises(
|
||||
exception.NetAppException,
|
||||
self.library.update_share_server_security_service,
|
||||
fake_context, fake.SHARE_SERVER, fake_net_info,
|
||||
fake_context, fake.SHARE_SERVER, [fake_net_info],
|
||||
new_sec_service, current_security_service=curr_sec_service)
|
||||
|
||||
mock_get_vserver.assert_called_once_with(
|
||||
share_server=fake.SHARE_SERVER)
|
||||
mock_check_update.assert_called_once_with(
|
||||
fake_context, fake.SHARE_SERVER, fake_net_info,
|
||||
fake_context, fake.SHARE_SERVER, [fake_net_info],
|
||||
new_sec_service, current_security_service=curr_sec_service)
|
||||
|
||||
@ddt.data(
|
||||
|
@ -1182,23 +1182,23 @@ class GenericShareDriverTestCase(test.TestCase):
|
||||
|
||||
def test__setup_server(self):
|
||||
sim = self._driver.instance_manager
|
||||
net_info = {
|
||||
net_info = [{
|
||||
'server_id': 'fake',
|
||||
'neutron_net_id': 'fake-net-id',
|
||||
'neutron_subnet_id': 'fake-subnet-id',
|
||||
}
|
||||
}]
|
||||
self._driver.setup_server(net_info)
|
||||
sim.set_up_service_instance.assert_called_once_with(
|
||||
self._context, net_info)
|
||||
self._context, net_info[0])
|
||||
|
||||
def test__setup_server_revert(self):
|
||||
|
||||
def raise_exception(*args, **kwargs):
|
||||
raise exception.ServiceInstanceException
|
||||
|
||||
net_info = {'server_id': 'fake',
|
||||
'neutron_net_id': 'fake-net-id',
|
||||
'neutron_subnet_id': 'fake-subnet-id'}
|
||||
net_info = [{'server_id': 'fake',
|
||||
'neutron_net_id': 'fake-net-id',
|
||||
'neutron_subnet_id': 'fake-subnet-id'}]
|
||||
self.mock_object(self._driver.service_instance_manager,
|
||||
'set_up_service_instance',
|
||||
mock.Mock(side_effect=raise_exception))
|
||||
|
@ -447,6 +447,8 @@ class ACCESSShareDriverTestCase(test.TestCase):
|
||||
'share_group_stats': {'consistent_snapshot_support': None},
|
||||
'snapshot_support': True,
|
||||
'security_service_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
}
|
||||
|
||||
self.assertEqual(data, self._driver._stats)
|
||||
|
@ -374,6 +374,8 @@ class ZFSonLinuxShareDriverTestCase(test.TestCase):
|
||||
'ipv4_support': True,
|
||||
'ipv6_support': False,
|
||||
'security_service_update_support': False,
|
||||
'share_server_multiple_subnet_support': False,
|
||||
'network_allocation_update_support': False,
|
||||
}
|
||||
if replication_domain:
|
||||
expected['replication_type'] = 'readable'
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -971,6 +971,37 @@ class ShareDriverTestCase(test.TestCase):
|
||||
{'id', 'fake_sec_service_id'},
|
||||
current_security_service=None)
|
||||
|
||||
def test_check_update_share_server_network_allocations(self):
|
||||
share_driver = self._instantiate_share_driver(None, True)
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
share_driver.check_update_share_server_network_allocations,
|
||||
'fake_context',
|
||||
{'id', 'share_server_id'},
|
||||
{'admin_network_allocations': [], 'subnets': []},
|
||||
{"id": "fake_subnet_id"},
|
||||
[{"id": "fake_security_service_id"}],
|
||||
[{'id', 'fake_share_instance_id'}],
|
||||
[{"id": "fake_rule_id"}])
|
||||
|
||||
def test_update_share_server_network_allocations(self):
|
||||
share_driver = self._instantiate_share_driver(None, True)
|
||||
self.assertRaises(
|
||||
NotImplementedError,
|
||||
share_driver.update_share_server_network_allocations,
|
||||
'fake_context',
|
||||
{'id', 'share_server_id'},
|
||||
{'admin_network_allocations': [], 'subnets': []},
|
||||
{
|
||||
'share_network_subnet_id': 'fake_share_network_subnet_id',
|
||||
'neutron_net_id': 'fake_neutron_net_id',
|
||||
'neutron_subnet_id': 'fake_neutron_subnet_id',
|
||||
'network_allocations': []
|
||||
},
|
||||
[{"id": "fake_security_service_id"}],
|
||||
[{"id": "fake_share_id"}],
|
||||
[{"id": "fake_snapshot_id"}])
|
||||
|
||||
def test_create_share_group_from_sg_snapshot_with_no_members(self):
|
||||
share_driver = self._instantiate_share_driver(None, False)
|
||||
fake_share_group_dict = {}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -48,6 +48,17 @@ class ShareRpcAPITestCase(test.TestCase):
|
||||
share_group_snapshot = {'id': 'fake_share_group_id'}
|
||||
host = 'fake_host'
|
||||
share_server = db_utils.create_share_server(host=host)
|
||||
share_network_subnet = {
|
||||
'availability_zone_id': 'fake_az_id',
|
||||
'neutron_net_id': 'fake_neutron_net_id',
|
||||
'neutron_subnet_id': 'fake_neutron_subnet_id',
|
||||
'ip_version': 4,
|
||||
'cidr': '127.0.0.0/28',
|
||||
'gateway': '127.0.0.1',
|
||||
'mtu': 1500,
|
||||
'network_type': 'vlan',
|
||||
'segmentation_id': 3000,
|
||||
}
|
||||
self.fake_share = jsonutils.to_primitive(share)
|
||||
# mock out the getattr on the share db model object since jsonutils
|
||||
# doesn't know about those extra attributes to pull in
|
||||
@ -61,6 +72,8 @@ class ShareRpcAPITestCase(test.TestCase):
|
||||
self.fake_share_group_snapshot = jsonutils.to_primitive(
|
||||
share_group_snapshot)
|
||||
self.fake_host = jsonutils.to_primitive(host)
|
||||
self.fake_share_network_subnet = jsonutils.to_primitive(
|
||||
share_network_subnet)
|
||||
self.ctxt = context.RequestContext('fake_user', 'fake_project')
|
||||
self.rpcapi = share_rpcapi.ShareAPI()
|
||||
|
||||
@ -476,3 +489,21 @@ class ShareRpcAPITestCase(test.TestCase):
|
||||
share_network_id='fake_net_id',
|
||||
new_security_service_id='fake_sec_service_id',
|
||||
current_security_service_id='fake_sec_service_id')
|
||||
|
||||
def test_check_update_share_server_network_allocations(self):
|
||||
self._test_share_api(
|
||||
'check_update_share_server_network_allocations',
|
||||
rpc_method='cast',
|
||||
version='1.23',
|
||||
dest_host=self.fake_host,
|
||||
share_network_id='fake_net_id',
|
||||
new_share_network_subnet=self.fake_share_network_subnet)
|
||||
|
||||
def test_update_share_server_network_allocations(self):
|
||||
self._test_share_api(
|
||||
'update_share_server_network_allocations',
|
||||
rpc_method='cast',
|
||||
version='1.23',
|
||||
dest_host=self.fake_host,
|
||||
share_network_id='fake_net_id',
|
||||
new_share_network_subnet_id='new_share_network_subnet_id')
|
||||
|
@ -165,6 +165,33 @@ class ShareUtilsTestCase(test.TestCase):
|
||||
replica = share_utils.get_active_replica(replica_list)
|
||||
self.assertIsNone(replica)
|
||||
|
||||
@ddt.data(
|
||||
{'fake_subnet': [{'neutron_net_id': 'fake_nn_id',
|
||||
'neutron_subnet_id': 'fake_nsb_id'}],
|
||||
'fake_new_subnet': [{'neutron_net_id': 'fake_nn_id',
|
||||
'neutron_subnet_id': 'fake_nsb_id'}],
|
||||
'is_compatible': True},
|
||||
{'fake_subnet': [{'neutron_net_id': 'fake_nn_id',
|
||||
'neutron_subnet_id': 'fake_nsb_id'}],
|
||||
'fake_new_subnet': [{'neutron_net_id': 'fake_nn_id',
|
||||
'neutron_subnet_id': 'fake_nsb_id2'}],
|
||||
'is_compatible': False},
|
||||
{'fake_subnet': [{'neutron_net_id': 'fake_nn_id',
|
||||
'neutron_subnet_id': 'fake_nsb_id'},
|
||||
{'neutron_net_id': 'fake_nn_id2',
|
||||
'neutron_subnet_id': 'fake_nsb_id2'}],
|
||||
'fake_new_subnet': [{'neutron_net_id': 'fake_nn_id',
|
||||
'neutron_subnet_id': 'fake_nsb_id'}],
|
||||
'is_compatible': False}
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_is_az_subnets_compatible(self, fake_subnet, fake_new_subnet,
|
||||
is_compatible):
|
||||
expected_result = is_compatible
|
||||
result = share_utils.is_az_subnets_compatible(fake_subnet,
|
||||
fake_new_subnet)
|
||||
self.assertEqual(expected_result, result)
|
||||
|
||||
|
||||
class NotifyUsageTestCase(test.TestCase):
|
||||
@mock.patch('manila.share.utils._usage_from_share')
|
||||
|
@ -88,6 +88,9 @@ class NetworkBaseAPITestCase(test.TestCase):
|
||||
def unmanage_network_allocations(self, context, share_server_id):
|
||||
pass
|
||||
|
||||
def include_network_info(self, share_network_subnet):
|
||||
pass
|
||||
|
||||
self.assertRaises(TypeError, FakeNetworkAPI)
|
||||
|
||||
def test_inherit_network_base_api_allocate_not_redefined(self):
|
||||
@ -103,6 +106,9 @@ class NetworkBaseAPITestCase(test.TestCase):
|
||||
def unmanage_network_allocations(self, context, share_server_id):
|
||||
pass
|
||||
|
||||
def include_network_info(self, share_network_subnet):
|
||||
pass
|
||||
|
||||
self.assertRaises(TypeError, FakeNetworkAPI)
|
||||
|
||||
def test_inherit_network_base_api(self):
|
||||
@ -121,6 +127,9 @@ class NetworkBaseAPITestCase(test.TestCase):
|
||||
def unmanage_network_allocations(self, context, share_server_id):
|
||||
pass
|
||||
|
||||
def include_network_info(self, share_network_subnet):
|
||||
pass
|
||||
|
||||
result = FakeNetworkAPI()
|
||||
|
||||
self.assertTrue(hasattr(result, '_verify_share_network'))
|
||||
@ -143,6 +152,9 @@ class NetworkBaseAPITestCase(test.TestCase):
|
||||
def unmanage_network_allocations(self, context, share_server_id):
|
||||
pass
|
||||
|
||||
def include_network_info(self, share_network_subnet):
|
||||
pass
|
||||
|
||||
result = FakeNetworkAPI()
|
||||
|
||||
result._verify_share_network('foo_id', {'id': 'bar_id'})
|
||||
@ -163,6 +175,9 @@ class NetworkBaseAPITestCase(test.TestCase):
|
||||
def unmanage_network_allocations(self, context, share_server_id):
|
||||
pass
|
||||
|
||||
def include_network_info(self, share_network_subnet):
|
||||
pass
|
||||
|
||||
result = FakeNetworkAPI()
|
||||
|
||||
self.assertRaises(
|
||||
@ -190,10 +205,13 @@ class NetworkBaseAPITestCase(test.TestCase):
|
||||
def unmanage_network_allocations(self, context, share_server_id):
|
||||
pass
|
||||
|
||||
network.CONF.set_default('network_plugin_ipv6_enabled',
|
||||
network_plugin_ipv6_enabled)
|
||||
network.CONF.set_default('network_plugin_ipv4_enabled',
|
||||
network_plugin_ipv4_enabled)
|
||||
def include_network_info(self, share_network_subnet):
|
||||
pass
|
||||
|
||||
network.CONF.set_default(
|
||||
'network_plugin_ipv6_enabled', network_plugin_ipv6_enabled)
|
||||
network.CONF.set_default(
|
||||
'network_plugin_ipv4_enabled', network_plugin_ipv4_enabled)
|
||||
|
||||
result = FakeNetworkAPI()
|
||||
|
||||
|
@ -89,6 +89,7 @@ class ServiceFlagsTestCase(test.TestCase):
|
||||
app = service.Service.create(host=host, binary=binary)
|
||||
app.start()
|
||||
app.stop()
|
||||
app.wait()
|
||||
ref = db.service_get(context.get_admin_context(), app.service_id)
|
||||
db.service_destroy(context.get_admin_context(), app.service_id)
|
||||
self.assertFalse(ref['disabled'])
|
||||
@ -123,6 +124,13 @@ service_create = {
|
||||
'report_count': 0,
|
||||
'availability_zone': 'nova',
|
||||
}
|
||||
service_create_other_az = {
|
||||
'host': host,
|
||||
'binary': binary,
|
||||
'topic': topic,
|
||||
'report_count': 0,
|
||||
'availability_zone': 'other-zone',
|
||||
}
|
||||
service_ref = {
|
||||
'host': host,
|
||||
'binary': binary,
|
||||
@ -200,6 +208,58 @@ class ServiceTestCase(test.TestCase):
|
||||
service.db.service_update.assert_called_once_with(
|
||||
mock.ANY, service_ref['id'], mock.ANY)
|
||||
|
||||
@mock.patch.object(service.db, 'service_get_by_args',
|
||||
mock.Mock(side_effect=fake_service_get_by_args))
|
||||
@mock.patch.object(service.db, 'service_create',
|
||||
mock.Mock(return_value=service_ref))
|
||||
@mock.patch.object(service.db, 'service_get',
|
||||
mock.Mock(return_value=service_ref))
|
||||
@mock.patch.object(service.db, 'service_update',
|
||||
mock.Mock(return_value=service_ref.
|
||||
update({'report_count': 1})))
|
||||
def test_report_state_newly_connected_different_az(self):
|
||||
serv = service.Service(host, binary, topic, CONF.fake_manager)
|
||||
serv.availability_zone = 'other-zone'
|
||||
serv.start()
|
||||
serv.model_disconnected = True
|
||||
serv.report_state()
|
||||
self.assertFalse(serv.model_disconnected)
|
||||
service.db.service_get_by_args.assert_called_once_with(
|
||||
mock.ANY, host, binary)
|
||||
service.db.service_create.assert_called_once_with(
|
||||
mock.ANY, service_create_other_az)
|
||||
service.db.service_get.assert_called_once_with(
|
||||
mock.ANY, service_ref['id'])
|
||||
service.db.service_update.assert_called_once_with(
|
||||
mock.ANY, service_ref['id'], mock.ANY)
|
||||
|
||||
@mock.patch.object(service.db, 'service_get_by_args',
|
||||
mock.Mock(side_effect=fake_service_get_by_args))
|
||||
@mock.patch.object(service.db, 'service_create',
|
||||
mock.Mock(return_value=service_ref))
|
||||
@mock.patch.object(service.db, 'service_get',
|
||||
mock.Mock(side_effect=[exception.NotFound,
|
||||
service_ref]))
|
||||
@mock.patch.object(service.db, 'service_update',
|
||||
mock.Mock(return_value=service_ref.
|
||||
update({'report_count': 1})))
|
||||
def test_report_state_newly_connected_not_found(self):
|
||||
serv = service.Service(host, binary, topic, CONF.fake_manager)
|
||||
serv.start()
|
||||
serv.model_disconnected = True
|
||||
serv.report_state()
|
||||
self.assertFalse(serv.model_disconnected)
|
||||
service.db.service_get_by_args.assert_called_once_with(
|
||||
mock.ANY, host, binary)
|
||||
service.db.service_create.assert_has_calls([
|
||||
mock.call(mock.ANY, service_create),
|
||||
mock.call(mock.ANY, service_create)])
|
||||
service.db.service_get.assert_has_calls([
|
||||
mock.call(mock.ANY, service_ref['id']),
|
||||
mock.call(mock.ANY, service_ref['id'])])
|
||||
service.db.service_update.assert_called_once_with(
|
||||
mock.ANY, service_ref['id'], mock.ANY)
|
||||
|
||||
def test_report_state_service_not_ready(self):
|
||||
with mock.patch.object(service, 'db') as mock_db:
|
||||
mock_db.service_get.return_value = service_ref
|
||||
|
@ -0,0 +1,25 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add support for multiple subnet per availability zone. The multiple
|
||||
configuration can be done either on share server deployment or updating
|
||||
a pre-existent share server.
|
||||
|
||||
The new field ``network_allocation_update_support`` was added to share
|
||||
server's model This field defaults to ``False``, and all of the
|
||||
already deployed share servers are going to get the default value even if
|
||||
their backend support it. Administrators will be able to update the field
|
||||
value using ``manila-manage`` commands.
|
||||
|
||||
The driver will report its support for adding a subnet on a pre-existent
|
||||
share server through ``network_allocation_update_support``. Also, it will
|
||||
report the support for creating the server with multiple subnets with the
|
||||
``share_server_multiple_subnet_support``. The scheduler will filter out
|
||||
backend that does not handle this request during some operations. Example,
|
||||
creating a share with a share network containing multiple subnets, only
|
||||
hosts that support this deployment will be selected.
|
||||
deprecations:
|
||||
- |
|
||||
Remove 'share_network_subnet_id' attribute from share server view and
|
||||
add 'share_network_subnet_ids' starting with microversion '2.70'. The share
|
||||
server has a list of subnets.
|
Loading…
Reference in New Issue
Block a user