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:
Felipe Rodrigues
2022-01-18 10:59:06 -03:00
committed by Fernando Ferraz
parent 3ce3854ae9
commit 2b57d15c64
70 changed files with 4463 additions and 999 deletions
+52
View File
@@ -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
+5 -1
View File
@@ -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.
+5 -5
View File
@@ -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)
+7 -2
View File
@@ -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')
+38 -54
View File
@@ -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(
+58 -2
View File
@@ -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):
+19 -14
View File
@@ -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)
+18 -1
View File
@@ -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')
+14 -3
View File
@@ -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'])
+2 -1
View File
@@ -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:
+35 -16
View File
@@ -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
+84 -15
View File
@@ -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
+59 -8
View File
@@ -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."""
+10
View File
@@ -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")
+5
View File
@@ -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)
+12 -2
View File
@@ -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)
+19
View File
@@ -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
+18
View File
@@ -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
+5 -1
View File
@@ -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
+377 -55
View File
@@ -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
+269
View File
@@ -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()
+2
View File
@@ -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)
+3
View File
@@ -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):
+3
View File
@@ -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
+406 -129
View File
@@ -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'])
+25 -1
View File
@@ -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)
+19
View File
@@ -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
+103
View File
@@ -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):
+54 -21
View File
@@ -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)
+14 -5
View File
@@ -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')
+117 -123
View File
@@ -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'])
+107 -13
View File
@@ -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)
+107 -56
View File
@@ -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 = {
+12 -3
View File
@@ -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)
+9 -7
View File
@@ -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'))
+154 -67
View File
@@ -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
-1
View File
@@ -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)
-1
View File
@@ -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)
+119 -26
View File
@@ -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']))