Add security service update for in-use share networks
This patch implements the update of security service's association with in-use share networks. The following changes were added: - New share network APIs: `share_network_security_service_update` and `share_network_reset_state`. - A new `status` attribute was added to share network model to identify when it's in a modification state, called 'network_change'. Other supported status that were added: 'active' and 'error'. - New 'security_service_update_support' property was added to both share server and share network models, to identify when this resources are able to process security service update for in-use share networks. - New driver interface was added to support update of security service's configuration of a given share server. DocImpact APIImpact Partially Implements: bp add-security-service-in-use-share-networks Co-Authored-By: Carlos Eduardo <ces.eduardo98@gmail.com> Co-Authored-By: Douglas Viroel <viroel@gmail.com> Co-Authored-By: Andre Beltrami <debeltrami@gmail.com> Change-Id: I129a794dfd2d179fa2b9a2fed050459d6f00b0de
This commit is contained in:
parent
0a2ae6ff51
commit
2bc27c5678
@ -254,6 +254,18 @@ def check_net_id_and_subnet_id(body):
|
|||||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
|
|
||||||
|
def check_share_network_is_active(share_network):
|
||||||
|
network_status = share_network.get('status')
|
||||||
|
if network_status != constants.STATUS_NETWORK_ACTIVE:
|
||||||
|
msg = _("The share network %(id)s used isn't in an 'active' state. "
|
||||||
|
"Current status is %(status)s. The action may be retried "
|
||||||
|
"after the share network has changed its state.") % {
|
||||||
|
'id': share_network['id'],
|
||||||
|
'status': share_network.get('status'),
|
||||||
|
}
|
||||||
|
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
|
|
||||||
class ViewBuilder(object):
|
class ViewBuilder(object):
|
||||||
"""Model API responses as dictionaries."""
|
"""Model API responses as dictionaries."""
|
||||||
|
|
||||||
|
@ -165,13 +165,19 @@ REST_API_VERSION_HISTORY = """
|
|||||||
which can add minimum and maximum share size restrictions
|
which can add minimum and maximum share size restrictions
|
||||||
on a per share-type granularity.
|
on a per share-type granularity.
|
||||||
* 2.62 - Added quota control to per share size.
|
* 2.62 - Added quota control to per share size.
|
||||||
|
* 2.63 - Changed the existing behavior of 'add_security_service' action on
|
||||||
|
the share network's endpoint to allow the addition of security
|
||||||
|
services, even when the share network is in use. Also, added new
|
||||||
|
actions on the share network's endpoint:
|
||||||
|
'update_security_service', 'update_security_service_check' and
|
||||||
|
'add_security_service_check'.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The minimum and maximum versions of the API supported
|
# The minimum and maximum versions of the API supported
|
||||||
# The default api version request is defined to be the
|
# The default api version request is defined to be the
|
||||||
# minimum version of the API supported.
|
# minimum version of the API supported.
|
||||||
_MIN_API_VERSION = "2.0"
|
_MIN_API_VERSION = "2.0"
|
||||||
_MAX_API_VERSION = "2.62"
|
_MAX_API_VERSION = "2.63"
|
||||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
@ -341,3 +341,15 @@ user documentation.
|
|||||||
2.62
|
2.62
|
||||||
----
|
----
|
||||||
Added quota control to per share size.
|
Added quota control to per share size.
|
||||||
|
|
||||||
|
2.63
|
||||||
|
----
|
||||||
|
Added the possibility to attach security services to share networks in use.
|
||||||
|
Also, an attached security service can be replaced for another one of
|
||||||
|
the same 'type'. In order to support those operations a 'status' field was
|
||||||
|
added in the share networks as well as, a new property called
|
||||||
|
'security_service_update_support' was included in the share networks and
|
||||||
|
share servers. Also new action APIs have been added to the share-networks
|
||||||
|
endpoint: 'update_security_service', 'update_security_service_check' and
|
||||||
|
'add_security_service_check'.
|
||||||
|
|
||||||
|
@ -330,12 +330,14 @@ class ShareMixin(object):
|
|||||||
|
|
||||||
if share_network_id:
|
if share_network_id:
|
||||||
try:
|
try:
|
||||||
self.share_api.get_share_network(
|
share_network = self.share_api.get_share_network(
|
||||||
context,
|
context,
|
||||||
share_network_id)
|
share_network_id)
|
||||||
except exception.ShareNetworkNotFound as e:
|
except exception.ShareNetworkNotFound as e:
|
||||||
raise exc.HTTPNotFound(explanation=e.msg)
|
raise exc.HTTPNotFound(explanation=e.msg)
|
||||||
kwargs['share_network_id'] = share_network_id
|
|
||||||
|
common.check_share_network_is_active(share_network)
|
||||||
|
|
||||||
if availability_zone_id:
|
if availability_zone_id:
|
||||||
if not db.share_network_subnet_get_by_availability_zone_id(
|
if not db.share_network_subnet_get_by_availability_zone_id(
|
||||||
context, share_network_id,
|
context, share_network_id,
|
||||||
@ -402,6 +404,8 @@ class ShareMixin(object):
|
|||||||
|
|
||||||
if share_type:
|
if share_type:
|
||||||
kwargs['share_type'] = share_type
|
kwargs['share_type'] = share_type
|
||||||
|
if share_network_id:
|
||||||
|
kwargs['share_network_id'] = share_network_id
|
||||||
new_share = self.share_api.create(context,
|
new_share = self.share_api.create(context,
|
||||||
share_proto,
|
share_proto,
|
||||||
size,
|
size,
|
||||||
@ -430,6 +434,11 @@ class ShareMixin(object):
|
|||||||
access_data.pop('metadata', None)
|
access_data.pop('metadata', None)
|
||||||
share = self.share_api.get(context, id)
|
share = self.share_api.get(context, id)
|
||||||
|
|
||||||
|
share_network_id = share.get('share_network_id')
|
||||||
|
if share_network_id:
|
||||||
|
share_network = db.share_network_get(context, share_network_id)
|
||||||
|
common.check_share_network_is_active(share_network)
|
||||||
|
|
||||||
if (not allow_on_error_status and
|
if (not allow_on_error_status and
|
||||||
self._any_instance_has_errored_rules(share)):
|
self._any_instance_has_errored_rules(share)):
|
||||||
msg = _("Access rules cannot be added while the share or any of "
|
msg = _("Access rules cannot be added while the share or any of "
|
||||||
@ -471,6 +480,13 @@ class ShareMixin(object):
|
|||||||
access_id = body.get(
|
access_id = body.get(
|
||||||
'deny_access', body.get('os-deny_access'))['access_id']
|
'deny_access', body.get('os-deny_access'))['access_id']
|
||||||
|
|
||||||
|
share = self.share_api.get(context, id)
|
||||||
|
share_network_id = share.get('share_network_id', None)
|
||||||
|
|
||||||
|
if share_network_id:
|
||||||
|
share_network = db.share_network_get(context, share_network_id)
|
||||||
|
common.check_share_network_is_active(share_network)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
access = self.share_api.access_get(context, access_id)
|
access = self.share_api.access_get(context, access_id)
|
||||||
if access.share_id != id:
|
if access.share_id != id:
|
||||||
|
@ -19,7 +19,6 @@ import copy
|
|||||||
from oslo_db import exception as db_exception
|
from oslo_db import exception as db_exception
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
import six
|
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
import webob
|
import webob
|
||||||
from webob import exc
|
from webob import exc
|
||||||
@ -28,11 +27,13 @@ from manila.api import common
|
|||||||
from manila.api.openstack import api_version_request as api_version
|
from manila.api.openstack import api_version_request as api_version
|
||||||
from manila.api.openstack import wsgi
|
from manila.api.openstack import wsgi
|
||||||
from manila.api.views import share_networks as share_networks_views
|
from manila.api.views import share_networks as share_networks_views
|
||||||
|
from manila.common import constants
|
||||||
from manila.db import api as db_api
|
from manila.db import api as db_api
|
||||||
from manila import exception
|
from manila import exception
|
||||||
from manila.i18n import _
|
from manila.i18n import _
|
||||||
from manila import policy
|
from manila import policy
|
||||||
from manila import quota
|
from manila import quota
|
||||||
|
from manila import share
|
||||||
from manila.share import rpcapi as share_rpcapi
|
from manila.share import rpcapi as share_rpcapi
|
||||||
from manila import utils
|
from manila import utils
|
||||||
|
|
||||||
@ -42,14 +43,20 @@ LOG = log.getLogger(__name__)
|
|||||||
QUOTAS = quota.QUOTAS
|
QUOTAS = quota.QUOTAS
|
||||||
|
|
||||||
|
|
||||||
class ShareNetworkController(wsgi.Controller):
|
class ShareNetworkController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||||
"""The Share Network API controller for the OpenStack API."""
|
"""The Share Network API controller for the OpenStack API."""
|
||||||
|
|
||||||
|
resource_name = 'share_network'
|
||||||
_view_builder_class = share_networks_views.ViewBuilder
|
_view_builder_class = share_networks_views.ViewBuilder
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(ShareNetworkController, self).__init__()
|
super(ShareNetworkController, self).__init__()
|
||||||
self.share_rpcapi = share_rpcapi.ShareAPI()
|
self.share_rpcapi = share_rpcapi.ShareAPI()
|
||||||
|
self.share_api = share.API()
|
||||||
|
|
||||||
|
valid_statuses = {
|
||||||
|
'status': set(constants.SHARE_NETWORK_STATUSES)
|
||||||
|
}
|
||||||
|
|
||||||
def show(self, req, id):
|
def show(self, req, id):
|
||||||
"""Return data about the requested network info."""
|
"""Return data about the requested network info."""
|
||||||
@ -59,7 +66,7 @@ class ShareNetworkController(wsgi.Controller):
|
|||||||
try:
|
try:
|
||||||
share_network = db_api.share_network_get(context, id)
|
share_network = db_api.share_network_get(context, id)
|
||||||
except exception.ShareNetworkNotFound as e:
|
except exception.ShareNetworkNotFound as e:
|
||||||
raise exc.HTTPNotFound(explanation=six.text_type(e))
|
raise exc.HTTPNotFound(explanation=e.msg)
|
||||||
|
|
||||||
return self._view_builder.build_share_network(req, share_network)
|
return self._view_builder.build_share_network(req, share_network)
|
||||||
|
|
||||||
@ -70,6 +77,9 @@ class ShareNetworkController(wsgi.Controller):
|
|||||||
def _share_network_contains_subnets(self, share_network):
|
def _share_network_contains_subnets(self, share_network):
|
||||||
return len(share_network['share_network_subnets']) > 1
|
return len(share_network['share_network_subnets']) > 1
|
||||||
|
|
||||||
|
def _update(self, *args, **kwargs):
|
||||||
|
db_api.share_network_update(*args, **kwargs)
|
||||||
|
|
||||||
def delete(self, req, id):
|
def delete(self, req, id):
|
||||||
"""Delete specified share network."""
|
"""Delete specified share network."""
|
||||||
context = req.environ['manila.context']
|
context = req.environ['manila.context']
|
||||||
@ -78,7 +88,7 @@ class ShareNetworkController(wsgi.Controller):
|
|||||||
try:
|
try:
|
||||||
share_network = db_api.share_network_get(context, id)
|
share_network = db_api.share_network_get(context, id)
|
||||||
except exception.ShareNetworkNotFound as e:
|
except exception.ShareNetworkNotFound as e:
|
||||||
raise exc.HTTPNotFound(explanation=six.text_type(e))
|
raise exc.HTTPNotFound(explanation=e.msg)
|
||||||
|
|
||||||
share_instances = (
|
share_instances = (
|
||||||
db_api.share_instances_get_all_by_share_network(context, id)
|
db_api.share_instances_get_all_by_share_network(context, id)
|
||||||
@ -251,7 +261,7 @@ class ShareNetworkController(wsgi.Controller):
|
|||||||
try:
|
try:
|
||||||
share_network = db_api.share_network_get(context, id)
|
share_network = db_api.share_network_get(context, id)
|
||||||
except exception.ShareNetworkNotFound as e:
|
except exception.ShareNetworkNotFound as e:
|
||||||
raise exc.HTTPNotFound(explanation=six.text_type(e))
|
raise exc.HTTPNotFound(explanation=e.msg)
|
||||||
|
|
||||||
update_values = body[RESOURCE_NAME]
|
update_values = body[RESOURCE_NAME]
|
||||||
|
|
||||||
@ -397,56 +407,62 @@ class ShareNetworkController(wsgi.Controller):
|
|||||||
share_network['id'])
|
share_network['id'])
|
||||||
return self._view_builder.build_share_network(req, share_network)
|
return self._view_builder.build_share_network(req, share_network)
|
||||||
|
|
||||||
def action(self, req, id, body):
|
@wsgi.action("add_security_service")
|
||||||
_actions = {
|
def add_security_service(self, req, id, body):
|
||||||
'add_security_service': self._add_security_service,
|
|
||||||
'remove_security_service': self._remove_security_service
|
|
||||||
}
|
|
||||||
for action, data in body.items():
|
|
||||||
try:
|
|
||||||
return _actions[action](req, id, data)
|
|
||||||
except KeyError:
|
|
||||||
msg = _("Share networks does not have %s action") % action
|
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
|
||||||
|
|
||||||
def _add_security_service(self, req, id, data):
|
|
||||||
"""Associate share network with a given security service."""
|
"""Associate share network with a given security service."""
|
||||||
context = req.environ['manila.context']
|
context = req.environ['manila.context']
|
||||||
policy.check_policy(context, RESOURCE_NAME, 'add_security_service')
|
|
||||||
share_network = db_api.share_network_get(context, id)
|
share_network = db_api.share_network_get(context, id)
|
||||||
if self._share_network_subnets_contain_share_servers(share_network):
|
policy.check_policy(context, RESOURCE_NAME, 'add_security_service',
|
||||||
msg = _("Cannot add security services. Share network is used.")
|
target_obj=share_network)
|
||||||
raise exc.HTTPForbidden(explanation=msg)
|
try:
|
||||||
security_service = db_api.security_service_get(
|
data = body['add_security_service']
|
||||||
context, data['security_service_id'])
|
|
||||||
for attached_service in share_network['security_services']:
|
security_service = db_api.security_service_get(
|
||||||
if attached_service['type'] == security_service['type']:
|
context, data['security_service_id'])
|
||||||
msg = _("Cannot add security service to share network. "
|
except KeyError:
|
||||||
"Security service with '%(ss_type)s' type already "
|
msg = "Malformed request body"
|
||||||
"added to '%(sn_id)s' share network") % {
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
'ss_type': security_service['type'],
|
|
||||||
'sn_id': share_network['id']}
|
contain_share_servers = (
|
||||||
raise exc.HTTPConflict(explanation=msg)
|
self._share_network_subnets_contain_share_servers(share_network))
|
||||||
|
|
||||||
|
support_adding_to_in_use_networks = (
|
||||||
|
req.api_version_request >= api_version.APIVersionRequest("2.63"))
|
||||||
|
|
||||||
|
if contain_share_servers:
|
||||||
|
if not support_adding_to_in_use_networks:
|
||||||
|
msg = _("Cannot add security services. Share network is used.")
|
||||||
|
raise exc.HTTPForbidden(explanation=msg)
|
||||||
|
try:
|
||||||
|
self.share_api.update_share_network_security_service(
|
||||||
|
context, share_network, security_service)
|
||||||
|
except exception.ServiceIsDown as e:
|
||||||
|
raise exc.HTTPConflict(explanation=e.msg)
|
||||||
|
except exception.InvalidShareNetwork as e:
|
||||||
|
raise exc.HTTPBadRequest(explanation=e.msg)
|
||||||
|
except exception.InvalidSecurityService as e:
|
||||||
|
raise exc.HTTPConflict(explanation=e.msg)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
share_network = db_api.share_network_add_security_service(
|
share_network = db_api.share_network_add_security_service(
|
||||||
context,
|
context,
|
||||||
id,
|
id,
|
||||||
data['security_service_id'])
|
data['security_service_id'])
|
||||||
except KeyError:
|
|
||||||
msg = "Malformed request body"
|
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
|
||||||
except exception.NotFound as e:
|
except exception.NotFound as e:
|
||||||
raise exc.HTTPNotFound(explanation=six.text_type(e))
|
raise exc.HTTPNotFound(explanation=e.msg)
|
||||||
except exception.ShareNetworkSecurityServiceAssociationError as e:
|
except exception.ShareNetworkSecurityServiceAssociationError as e:
|
||||||
raise exc.HTTPBadRequest(explanation=six.text_type(e))
|
raise exc.HTTPBadRequest(explanation=e.msg)
|
||||||
|
|
||||||
return self._view_builder.build_share_network(req, share_network)
|
return self._view_builder.build_share_network(req, share_network)
|
||||||
|
|
||||||
def _remove_security_service(self, req, id, data):
|
@wsgi.action('remove_security_service')
|
||||||
|
def remove_security_service(self, req, id, body):
|
||||||
"""Dissociate share network from a given security service."""
|
"""Dissociate share network from a given security service."""
|
||||||
context = req.environ['manila.context']
|
context = req.environ['manila.context']
|
||||||
policy.check_policy(context, RESOURCE_NAME, 'remove_security_service')
|
|
||||||
share_network = db_api.share_network_get(context, id)
|
share_network = db_api.share_network_get(context, id)
|
||||||
|
policy.check_policy(context, RESOURCE_NAME, 'remove_security_service',
|
||||||
|
target_obj=share_network)
|
||||||
|
data = body['remove_security_service']
|
||||||
|
|
||||||
if self._share_network_subnets_contain_share_servers(share_network):
|
if self._share_network_subnets_contain_share_servers(share_network):
|
||||||
msg = _("Cannot remove security services. Share network is used.")
|
msg = _("Cannot remove security services. Share network is used.")
|
||||||
@ -460,12 +476,152 @@ class ShareNetworkController(wsgi.Controller):
|
|||||||
msg = "Malformed request body"
|
msg = "Malformed request body"
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
except exception.NotFound as e:
|
except exception.NotFound as e:
|
||||||
raise exc.HTTPNotFound(explanation=six.text_type(e))
|
raise exc.HTTPNotFound(explanation=e.msg)
|
||||||
except exception.ShareNetworkSecurityServiceDissociationError as e:
|
except exception.ShareNetworkSecurityServiceDissociationError as e:
|
||||||
raise exc.HTTPBadRequest(explanation=six.text_type(e))
|
raise exc.HTTPBadRequest(explanation=e.msg)
|
||||||
|
|
||||||
return self._view_builder.build_share_network(req, share_network)
|
return self._view_builder.build_share_network(req, share_network)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version('2.63')
|
||||||
|
@wsgi.action('update_security_service')
|
||||||
|
@wsgi.response(202)
|
||||||
|
def update_security_service(self, req, id, body):
|
||||||
|
"""Update security service parameters from a given share network."""
|
||||||
|
context = req.environ['manila.context']
|
||||||
|
share_network = db_api.share_network_get(context, id)
|
||||||
|
policy.check_policy(context, RESOURCE_NAME, 'update_security_service',
|
||||||
|
target_obj=share_network)
|
||||||
|
try:
|
||||||
|
data = body['update_security_service']
|
||||||
|
|
||||||
|
current_security_service = db_api.security_service_get(
|
||||||
|
context, data['current_service_id']
|
||||||
|
)
|
||||||
|
new_security_service = db_api.security_service_get(
|
||||||
|
context, data['new_service_id']
|
||||||
|
)
|
||||||
|
except KeyError:
|
||||||
|
msg = "Malformed request body."
|
||||||
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
except exception.NotFound:
|
||||||
|
msg = ("The current security service or the new security service "
|
||||||
|
"doesn't exist.")
|
||||||
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.share_api.update_share_network_security_service(
|
||||||
|
context, share_network, new_security_service,
|
||||||
|
current_security_service=current_security_service)
|
||||||
|
except exception.ServiceIsDown as e:
|
||||||
|
raise exc.HTTPConflict(explanation=e.msg)
|
||||||
|
except exception.InvalidShareNetwork as e:
|
||||||
|
raise exc.HTTPBadRequest(explanation=e.msg)
|
||||||
|
except exception.InvalidSecurityService as e:
|
||||||
|
raise exc.HTTPConflict(explanation=e.msg)
|
||||||
|
|
||||||
|
try:
|
||||||
|
share_network = db_api.share_network_update_security_service(
|
||||||
|
context,
|
||||||
|
id,
|
||||||
|
data['current_service_id'],
|
||||||
|
data['new_service_id'])
|
||||||
|
except exception.NotFound as e:
|
||||||
|
raise exc.HTTPNotFound(explanation=e.msg)
|
||||||
|
except (exception.ShareNetworkSecurityServiceDissociationError,
|
||||||
|
exception.ShareNetworkSecurityServiceAssociationError) as e:
|
||||||
|
raise exc.HTTPBadRequest(explanation=e.msg)
|
||||||
|
|
||||||
|
return self._view_builder.build_share_network(req, share_network)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version('2.63')
|
||||||
|
@wsgi.action('update_security_service_check')
|
||||||
|
@wsgi.response(202)
|
||||||
|
def check_update_security_service(self, req, id, body):
|
||||||
|
"""Check the feasibility of updating a security service."""
|
||||||
|
context = req.environ['manila.context']
|
||||||
|
share_network = db_api.share_network_get(context, id)
|
||||||
|
policy.check_policy(context, RESOURCE_NAME,
|
||||||
|
'update_security_service_check',
|
||||||
|
target_obj=share_network)
|
||||||
|
try:
|
||||||
|
data = body['update_security_service_check']
|
||||||
|
|
||||||
|
current_security_service = db_api.security_service_get(
|
||||||
|
context, data['current_service_id']
|
||||||
|
)
|
||||||
|
new_security_service = db_api.security_service_get(
|
||||||
|
context, data['new_service_id']
|
||||||
|
)
|
||||||
|
except KeyError:
|
||||||
|
msg = "Malformed request body."
|
||||||
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
except exception.NotFound:
|
||||||
|
msg = ("The current security service or the new security service "
|
||||||
|
"doesn't exist.")
|
||||||
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
|
reset_check = utils.get_bool_from_api_params('reset_operation', data)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = (
|
||||||
|
self.share_api.check_share_network_security_service_update(
|
||||||
|
context, share_network, new_security_service,
|
||||||
|
current_security_service=current_security_service,
|
||||||
|
reset_operation=reset_check))
|
||||||
|
except exception.ServiceIsDown as e:
|
||||||
|
raise exc.HTTPConflict(explanation=e.msg)
|
||||||
|
except exception.InvalidShareNetwork as e:
|
||||||
|
raise exc.HTTPBadRequest(explanation=e.msg)
|
||||||
|
except exception.InvalidSecurityService as e:
|
||||||
|
raise exc.HTTPConflict(explanation=e.msg)
|
||||||
|
|
||||||
|
return self._view_builder.build_security_service_update_check(
|
||||||
|
req, data, result)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version('2.63')
|
||||||
|
@wsgi.action("add_security_service_check")
|
||||||
|
@wsgi.response(202)
|
||||||
|
def check_add_security_service(self, req, id, body):
|
||||||
|
"""Check the feasibility of associate a new security service."""
|
||||||
|
context = req.environ['manila.context']
|
||||||
|
share_network = db_api.share_network_get(context, id)
|
||||||
|
policy.check_policy(context, RESOURCE_NAME,
|
||||||
|
'add_security_service_check',
|
||||||
|
target_obj=share_network)
|
||||||
|
data = body['add_security_service_check']
|
||||||
|
try:
|
||||||
|
security_service = db_api.security_service_get(
|
||||||
|
context, data['security_service_id'])
|
||||||
|
except KeyError:
|
||||||
|
msg = "Malformed request body."
|
||||||
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
except exception.NotFound:
|
||||||
|
msg = ("Security service %s doesn't exist."
|
||||||
|
) % data['security_service_id']
|
||||||
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
|
reset_check = utils.get_bool_from_api_params('reset_operation', data)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result = (
|
||||||
|
self.share_api.check_share_network_security_service_update(
|
||||||
|
context, share_network, security_service,
|
||||||
|
reset_operation=reset_check))
|
||||||
|
except exception.ServiceIsDown as e:
|
||||||
|
raise exc.HTTPConflict(explanation=e.msg)
|
||||||
|
except exception.InvalidShareNetwork as e:
|
||||||
|
raise exc.HTTPBadRequest(explanation=e.msg)
|
||||||
|
except exception.InvalidSecurityService as e:
|
||||||
|
raise exc.HTTPConflict(explanation=e.msg)
|
||||||
|
|
||||||
|
return self._view_builder.build_security_service_update_check(
|
||||||
|
req, data, result)
|
||||||
|
|
||||||
|
@wsgi.Controller.api_version('2.63')
|
||||||
|
@wsgi.action('reset_status')
|
||||||
|
def reset_status(self, req, id, body):
|
||||||
|
return self._reset_status(req, id, body)
|
||||||
|
|
||||||
|
|
||||||
def create_resource():
|
def create_resource():
|
||||||
return wsgi.Resource(ShareNetworkController())
|
return wsgi.Resource(ShareNetworkController())
|
||||||
|
@ -162,6 +162,10 @@ class ShareReplicationController(wsgi.Controller, wsgi.AdminActionsMixin):
|
|||||||
|
|
||||||
share_network_id = share_ref.get('share_network_id', None)
|
share_network_id = share_ref.get('share_network_id', None)
|
||||||
|
|
||||||
|
if share_network_id:
|
||||||
|
share_network = db.share_network_get(context, share_network_id)
|
||||||
|
common.check_share_network_is_active(share_network)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
new_replica = self.share_api.create_share_replica(
|
new_replica = self.share_api.create_share_replica(
|
||||||
context, share_ref, availability_zone=availability_zone,
|
context, share_ref, availability_zone=availability_zone,
|
||||||
@ -226,6 +230,11 @@ class ShareReplicationController(wsgi.Controller, wsgi.AdminActionsMixin):
|
|||||||
msg = _("No replica exists with ID %s.")
|
msg = _("No replica exists with ID %s.")
|
||||||
raise exc.HTTPNotFound(explanation=msg % id)
|
raise exc.HTTPNotFound(explanation=msg % id)
|
||||||
|
|
||||||
|
share_network_id = replica.get('share_network_id')
|
||||||
|
if share_network_id:
|
||||||
|
share_network = db.share_network_get(context, share_network_id)
|
||||||
|
common.check_share_network_is_active(share_network)
|
||||||
|
|
||||||
replica_state = replica.get('replica_state')
|
replica_state = replica.get('replica_state')
|
||||||
|
|
||||||
if replica_state == constants.REPLICA_STATE_ACTIVE:
|
if replica_state == constants.REPLICA_STATE_ACTIVE:
|
||||||
|
@ -18,6 +18,7 @@ from six.moves import http_client
|
|||||||
import webob
|
import webob
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
|
from manila.api import common
|
||||||
from manila.api.openstack import wsgi
|
from manila.api.openstack import wsgi
|
||||||
from manila.api.v1 import share_servers
|
from manila.api.v1 import share_servers
|
||||||
from manila.api.views import share_server_migration as server_migration_views
|
from manila.api.views import share_server_migration as server_migration_views
|
||||||
@ -105,6 +106,17 @@ class ShareServerController(share_servers.ShareServerController,
|
|||||||
except exception.ShareServerNotFound as e:
|
except exception.ShareServerNotFound as e:
|
||||||
raise exc.HTTPNotFound(explanation=e.msg)
|
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')
|
||||||
|
|
||||||
|
share_network = db_api.share_network_get(context, share_network_id)
|
||||||
|
common.check_share_network_is_active(share_network)
|
||||||
|
|
||||||
allowed_statuses = [constants.STATUS_ERROR, constants.STATUS_ACTIVE,
|
allowed_statuses = [constants.STATUS_ERROR, constants.STATUS_ACTIVE,
|
||||||
constants.STATUS_MANAGE_ERROR,
|
constants.STATUS_MANAGE_ERROR,
|
||||||
constants.STATUS_UNMANAGE_ERROR]
|
constants.STATUS_UNMANAGE_ERROR]
|
||||||
@ -172,6 +184,8 @@ class ShareServerController(share_servers.ShareServerController,
|
|||||||
"with API version >= 2.51.") % share_network_id
|
"with API version >= 2.51.") % share_network_id
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
|
common.check_share_network_is_active(network_subnet['share_network'])
|
||||||
|
|
||||||
if share_utils.extract_host(host, 'pool'):
|
if share_utils.extract_host(host, 'pool'):
|
||||||
msg = _("Host parameter should not contain pool.")
|
msg = _("Host parameter should not contain pool.")
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
@ -242,6 +256,13 @@ class ShareServerController(share_servers.ShareServerController,
|
|||||||
msg = _("Share network %s not "
|
msg = _("Share network %s not "
|
||||||
"found.") % new_share_network_id
|
"found.") % new_share_network_id
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
common.check_share_network_is_active(new_share_network)
|
||||||
|
else:
|
||||||
|
share_network_id = (
|
||||||
|
share_server['share_network_subnet']['share_network_id'])
|
||||||
|
current_share_network = db_api.share_network_get(
|
||||||
|
context, share_network_id)
|
||||||
|
common.check_share_network_is_active(current_share_network)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.share_api.share_server_migration_start(
|
self.share_api.share_server_migration_start(
|
||||||
@ -359,6 +380,13 @@ class ShareServerController(share_servers.ShareServerController,
|
|||||||
msg = _("Share network %s not "
|
msg = _("Share network %s not "
|
||||||
"found.") % new_share_network_id
|
"found.") % new_share_network_id
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
common.check_share_network_is_active(new_share_network)
|
||||||
|
else:
|
||||||
|
share_network_id = (
|
||||||
|
share_server['share_network_subnet']['share_network_id'])
|
||||||
|
current_share_network = db_api.share_network_get(
|
||||||
|
context, share_network_id)
|
||||||
|
common.check_share_network_is_active(current_share_network)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
result = self.share_api.share_server_migration_check(
|
result = self.share_api.share_server_migration_check(
|
||||||
|
@ -27,6 +27,7 @@ from manila.api.openstack import wsgi
|
|||||||
from manila.api.v1 import share_snapshots
|
from manila.api.v1 import share_snapshots
|
||||||
from manila.api.views import share_snapshots as snapshot_views
|
from manila.api.views import share_snapshots as snapshot_views
|
||||||
from manila.common import constants
|
from manila.common import constants
|
||||||
|
from manila.db import api as db_api
|
||||||
from manila import exception
|
from manila import exception
|
||||||
from manila.i18n import _
|
from manila.i18n import _
|
||||||
from manila import share
|
from manila import share
|
||||||
@ -162,6 +163,13 @@ class ShareSnapshotsController(share_snapshots.ShareSnapshotMixin,
|
|||||||
msg = _("Required parameter %s is empty.") % parameter
|
msg = _("Required parameter %s is empty.") % parameter
|
||||||
raise exc_response(explanation=msg)
|
raise exc_response(explanation=msg)
|
||||||
|
|
||||||
|
def _check_if_share_share_network_is_active(self, context, snapshot):
|
||||||
|
share_network_id = snapshot['share'].get('share_network_id')
|
||||||
|
if share_network_id:
|
||||||
|
share_network = db_api.share_network_get(
|
||||||
|
context, share_network_id)
|
||||||
|
common.check_share_network_is_active(share_network)
|
||||||
|
|
||||||
def _allow(self, req, id, body, enable_ipv6=False):
|
def _allow(self, req, id, body, enable_ipv6=False):
|
||||||
context = req.environ['manila.context']
|
context = req.environ['manila.context']
|
||||||
|
|
||||||
@ -184,6 +192,8 @@ class ShareSnapshotsController(share_snapshots.ShareSnapshotMixin,
|
|||||||
|
|
||||||
snapshot = self.share_api.get_snapshot(context, id)
|
snapshot = self.share_api.get_snapshot(context, id)
|
||||||
|
|
||||||
|
self._check_if_share_share_network_is_active(context, snapshot)
|
||||||
|
|
||||||
self._check_mount_snapshot_support(context, snapshot)
|
self._check_mount_snapshot_support(context, snapshot)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -212,6 +222,8 @@ class ShareSnapshotsController(share_snapshots.ShareSnapshotMixin,
|
|||||||
|
|
||||||
self._check_mount_snapshot_support(context, snapshot)
|
self._check_mount_snapshot_support(context, snapshot)
|
||||||
|
|
||||||
|
self._check_if_share_share_network_is_active(context, snapshot)
|
||||||
|
|
||||||
access = self.share_api.snapshot_access_get(context, access_id)
|
access = self.share_api.snapshot_access_get(context, access_id)
|
||||||
|
|
||||||
if access['share_snapshot_id'] != snapshot['id']:
|
if access['share_snapshot_id'] != snapshot['id']:
|
||||||
|
@ -18,6 +18,7 @@ from six.moves import http_client
|
|||||||
import webob
|
import webob
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
|
from manila.api import common
|
||||||
from manila.api.openstack import api_version_request as api_version
|
from manila.api.openstack import api_version_request as api_version
|
||||||
from manila.api.openstack import wsgi
|
from manila.api.openstack import wsgi
|
||||||
from manila.api.v1 import share_manage
|
from manila.api.v1 import share_manage
|
||||||
@ -256,6 +257,13 @@ class ShareController(shares.ShareMixin,
|
|||||||
msg = _("Share network %s not "
|
msg = _("Share network %s not "
|
||||||
"found.") % new_share_network_id
|
"found.") % new_share_network_id
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
raise exc.HTTPBadRequest(explanation=msg)
|
||||||
|
common.check_share_network_is_active(new_share_network)
|
||||||
|
else:
|
||||||
|
share_network_id = share.get('share_network_id', None)
|
||||||
|
if share_network_id:
|
||||||
|
current_share_network = db.share_network_get(
|
||||||
|
context, share_network_id)
|
||||||
|
common.check_share_network_is_active(current_share_network)
|
||||||
|
|
||||||
new_share_type_id = params.get('new_share_type_id', None)
|
new_share_type_id = params.get('new_share_type_id', None)
|
||||||
if new_share_type_id:
|
if new_share_type_id:
|
||||||
|
@ -21,7 +21,8 @@ class ViewBuilder(common.ViewBuilder):
|
|||||||
|
|
||||||
_collection_name = 'share_networks'
|
_collection_name = 'share_networks'
|
||||||
_detail_version_modifiers = ["add_gateway", "add_mtu", "add_nova_net_id",
|
_detail_version_modifiers = ["add_gateway", "add_mtu", "add_nova_net_id",
|
||||||
"add_subnets"]
|
"add_subnets",
|
||||||
|
"add_status_and_sec_service_update_fields"]
|
||||||
|
|
||||||
def build_share_network(self, request, share_network):
|
def build_share_network(self, request, share_network):
|
||||||
"""View of a share network."""
|
"""View of a share network."""
|
||||||
@ -35,6 +36,25 @@ class ViewBuilder(common.ViewBuilder):
|
|||||||
request, share_network, is_detail)
|
request, share_network, is_detail)
|
||||||
for share_network in share_networks]}
|
for share_network in share_networks]}
|
||||||
|
|
||||||
|
def build_security_service_update_check(self, request, params, result):
|
||||||
|
"""View of security service add or update check."""
|
||||||
|
context = request.environ['manila.context']
|
||||||
|
requested_operation = {
|
||||||
|
'operation': ('update_security_service'
|
||||||
|
if params.get('current_service_id')
|
||||||
|
else 'add_security_service'),
|
||||||
|
'current_security_service': params.get('current_service_id'),
|
||||||
|
'new_security_service': (params.get('new_service_id') or
|
||||||
|
params.get('security_service_id'))
|
||||||
|
}
|
||||||
|
view = {
|
||||||
|
'compatible': result['compatible'],
|
||||||
|
'requested_operation': requested_operation,
|
||||||
|
}
|
||||||
|
if context.is_admin:
|
||||||
|
view['hosts_check_result'] = result['hosts_check_result']
|
||||||
|
return view
|
||||||
|
|
||||||
def _update_share_network_info(self, request, share_network):
|
def _update_share_network_info(self, request, share_network):
|
||||||
for sns in share_network.get('share_network_subnets') or []:
|
for sns in share_network.get('share_network_subnets') or []:
|
||||||
if sns.get('is_default') and sns.get('is_default') is True:
|
if sns.get('is_default') and sns.get('is_default') is True:
|
||||||
@ -108,3 +128,10 @@ class ViewBuilder(common.ViewBuilder):
|
|||||||
@common.ViewBuilder.versioned_method("1.0", "2.25")
|
@common.ViewBuilder.versioned_method("1.0", "2.25")
|
||||||
def add_nova_net_id(self, context, network_dict, network):
|
def add_nova_net_id(self, context, network_dict, network):
|
||||||
network_dict['nova_net_id'] = None
|
network_dict['nova_net_id'] = None
|
||||||
|
|
||||||
|
@common.ViewBuilder.versioned_method("2.63")
|
||||||
|
def add_status_and_sec_service_update_fields(
|
||||||
|
self, context, network_dict, network):
|
||||||
|
network_dict['status'] = network.get('status')
|
||||||
|
network_dict['security_service_update_support'] = network.get(
|
||||||
|
'security_service_update_support')
|
||||||
|
@ -23,7 +23,8 @@ class ViewBuilder(common.ViewBuilder):
|
|||||||
_detail_version_modifiers = [
|
_detail_version_modifiers = [
|
||||||
"add_is_auto_deletable_and_identifier_fields",
|
"add_is_auto_deletable_and_identifier_fields",
|
||||||
"add_share_network_subnet_id_field",
|
"add_share_network_subnet_id_field",
|
||||||
"add_task_state_and_source_server_fields"
|
"add_task_state_and_source_server_fields",
|
||||||
|
"add_sec_service_update_fields"
|
||||||
]
|
]
|
||||||
|
|
||||||
def build_share_server(self, request, share_server):
|
def build_share_server(self, request, share_server):
|
||||||
@ -82,3 +83,9 @@ class ViewBuilder(common.ViewBuilder):
|
|||||||
share_server_dict['task_state'] = share_server['task_state']
|
share_server_dict['task_state'] = share_server['task_state']
|
||||||
share_server_dict['source_share_server_id'] = (
|
share_server_dict['source_share_server_id'] = (
|
||||||
share_server['source_share_server_id'])
|
share_server['source_share_server_id'])
|
||||||
|
|
||||||
|
@common.ViewBuilder.versioned_method("2.63")
|
||||||
|
def add_sec_service_update_fields(
|
||||||
|
self, context, share_server_dict, share_server):
|
||||||
|
share_server_dict['security_service_update_support'] = share_server[
|
||||||
|
'security_service_update_support']
|
||||||
|
@ -78,6 +78,10 @@ HOST_UPDATE_HELP_MSG = ("A fully qualified host string is of the format "
|
|||||||
HOST_UPDATE_CURRENT_HOST_HELP = ("Current share host name. %s" %
|
HOST_UPDATE_CURRENT_HOST_HELP = ("Current share host name. %s" %
|
||||||
HOST_UPDATE_HELP_MSG)
|
HOST_UPDATE_HELP_MSG)
|
||||||
HOST_UPDATE_NEW_HOST_HELP = "New share host name. %s" % HOST_UPDATE_HELP_MSG
|
HOST_UPDATE_NEW_HOST_HELP = "New share host name. %s" % HOST_UPDATE_HELP_MSG
|
||||||
|
SHARE_SERVERS_UPDATE_HELP = ("List of share servers to be updated, separated "
|
||||||
|
"by commas.")
|
||||||
|
SHARE_SERVERS_UPDATE_CAPABILITIES_HELP = (
|
||||||
|
"List of share server capabilities to be updated, separated by commas.")
|
||||||
|
|
||||||
|
|
||||||
# Decorators for actions
|
# Decorators for actions
|
||||||
@ -399,6 +403,42 @@ class ShareCommands(object):
|
|||||||
print(msg % msg_args)
|
print(msg % msg_args)
|
||||||
|
|
||||||
|
|
||||||
|
class ShareServerCommands(object):
|
||||||
|
@args('--share_servers', required=True,
|
||||||
|
help=SHARE_SERVERS_UPDATE_HELP)
|
||||||
|
@args('--capabilities', required=True,
|
||||||
|
help=SHARE_SERVERS_UPDATE_CAPABILITIES_HELP)
|
||||||
|
@args('--value', required=False, type=bool, default=False,
|
||||||
|
help="If those capabilities will be enabled (True) or disabled "
|
||||||
|
"(False)")
|
||||||
|
def update_share_server_capabilities(self, share_servers, capabilities,
|
||||||
|
value=False):
|
||||||
|
"""Update the share server capabilities.
|
||||||
|
|
||||||
|
This method receives a list of share servers and capabilities
|
||||||
|
in order to have it updated with the value specified. If the value
|
||||||
|
was not specified the default is False.
|
||||||
|
"""
|
||||||
|
share_servers = [server.strip() for server in share_servers.split(",")]
|
||||||
|
capabilities = [cap.strip() for cap in capabilities.split(",")]
|
||||||
|
supported_capabilities = ['security_service_update_support']
|
||||||
|
|
||||||
|
values = dict()
|
||||||
|
for capability in capabilities:
|
||||||
|
if capability not in supported_capabilities:
|
||||||
|
print("One or more capabilities are invalid for this "
|
||||||
|
"operation. The supported capability(ies) is(are) %s."
|
||||||
|
% supported_capabilities)
|
||||||
|
sys.exit(1)
|
||||||
|
values[capability] = value
|
||||||
|
|
||||||
|
ctxt = context.get_admin_context()
|
||||||
|
db.share_servers_update(ctxt, share_servers, values)
|
||||||
|
print("The capability(ies) %s of the following share server(s)"
|
||||||
|
" %s was(were) updated to %s." %
|
||||||
|
(capabilities, share_servers, value))
|
||||||
|
|
||||||
|
|
||||||
CATEGORIES = {
|
CATEGORIES = {
|
||||||
'config': ConfigCommands,
|
'config': ConfigCommands,
|
||||||
'db': DbCommands,
|
'db': DbCommands,
|
||||||
@ -406,6 +446,7 @@ CATEGORIES = {
|
|||||||
'logs': GetLogCommands,
|
'logs': GetLogCommands,
|
||||||
'service': ServiceCommands,
|
'service': ServiceCommands,
|
||||||
'share': ShareCommands,
|
'share': ShareCommands,
|
||||||
|
'share_server': ShareServerCommands,
|
||||||
'shell': ShellCommands,
|
'shell': ShellCommands,
|
||||||
'version': VersionCommands
|
'version': VersionCommands
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,14 @@ STATUS_ACTIVE = 'active'
|
|||||||
STATUS_SERVER_MIGRATING = 'server_migrating'
|
STATUS_SERVER_MIGRATING = 'server_migrating'
|
||||||
STATUS_SERVER_MIGRATING_TO = 'server_migrating_to'
|
STATUS_SERVER_MIGRATING_TO = 'server_migrating_to'
|
||||||
|
|
||||||
|
# Share server update statuses
|
||||||
|
STATUS_SERVER_NETWORK_CHANGE = 'network_change'
|
||||||
|
|
||||||
|
# Share network statuses
|
||||||
|
STATUS_NETWORK_ACTIVE = 'active'
|
||||||
|
STATUS_NETWORK_ERROR = 'error'
|
||||||
|
STATUS_NETWORK_CHANGE = 'network_change'
|
||||||
|
|
||||||
ACCESS_RULES_STATES = (
|
ACCESS_RULES_STATES = (
|
||||||
ACCESS_STATE_QUEUED_TO_APPLY,
|
ACCESS_STATE_QUEUED_TO_APPLY,
|
||||||
ACCESS_STATE_QUEUED_TO_DENY,
|
ACCESS_STATE_QUEUED_TO_DENY,
|
||||||
@ -214,6 +222,13 @@ SHARE_SERVER_STATUSES = (
|
|||||||
STATUS_INACTIVE,
|
STATUS_INACTIVE,
|
||||||
STATUS_SERVER_MIGRATING,
|
STATUS_SERVER_MIGRATING,
|
||||||
STATUS_SERVER_MIGRATING_TO,
|
STATUS_SERVER_MIGRATING_TO,
|
||||||
|
STATUS_SERVER_NETWORK_CHANGE,
|
||||||
|
)
|
||||||
|
|
||||||
|
SHARE_NETWORK_STATUSES = (
|
||||||
|
STATUS_NETWORK_ACTIVE,
|
||||||
|
STATUS_NETWORK_ERROR,
|
||||||
|
STATUS_NETWORK_CHANGE,
|
||||||
)
|
)
|
||||||
|
|
||||||
REPLICA_STATE_ACTIVE = 'active'
|
REPLICA_STATE_ACTIVE = 'active'
|
||||||
|
@ -854,17 +854,34 @@ def share_network_get_all_by_security_service(context, security_service_id):
|
|||||||
|
|
||||||
|
|
||||||
def share_network_add_security_service(context, id, security_service_id):
|
def share_network_add_security_service(context, id, security_service_id):
|
||||||
|
"""Associate a security service with a share network."""
|
||||||
return IMPL.share_network_add_security_service(context,
|
return IMPL.share_network_add_security_service(context,
|
||||||
id,
|
id,
|
||||||
security_service_id)
|
security_service_id)
|
||||||
|
|
||||||
|
|
||||||
def share_network_remove_security_service(context, id, security_service_id):
|
def share_network_remove_security_service(context, id, security_service_id):
|
||||||
|
"""Dissociate a security service from a share network."""
|
||||||
return IMPL.share_network_remove_security_service(context,
|
return IMPL.share_network_remove_security_service(context,
|
||||||
id,
|
id,
|
||||||
security_service_id)
|
security_service_id)
|
||||||
|
|
||||||
|
|
||||||
|
def share_network_security_service_association_get(
|
||||||
|
context, share_network_id, security_service_id):
|
||||||
|
"""Get given share network and security service association."""
|
||||||
|
return IMPL.share_network_security_service_association_get(
|
||||||
|
context, share_network_id, security_service_id)
|
||||||
|
|
||||||
|
|
||||||
|
def share_network_update_security_service(context, id,
|
||||||
|
current_security_service_id,
|
||||||
|
new_security_service_id):
|
||||||
|
"""Update a security service association with a share network."""
|
||||||
|
return IMPL.share_network_update_security_service(
|
||||||
|
context, id, current_security_service_id, new_security_service_id)
|
||||||
|
|
||||||
|
|
||||||
def count_share_networks(context, project_id, user_id=None,
|
def count_share_networks(context, project_id, user_id=None,
|
||||||
share_type_id=None, session=None):
|
share_type_id=None, session=None):
|
||||||
return IMPL.count_share_networks(
|
return IMPL.count_share_networks(
|
||||||
@ -1022,6 +1039,12 @@ def share_server_backend_details_set(context, share_server_id, server_details):
|
|||||||
server_details)
|
server_details)
|
||||||
|
|
||||||
|
|
||||||
|
def share_servers_update(context, share_server_ids, values):
|
||||||
|
"""Updates values of a bunch of share servers at once."""
|
||||||
|
return IMPL.share_servers_update(
|
||||||
|
context, share_server_ids, values)
|
||||||
|
|
||||||
|
|
||||||
##################
|
##################
|
||||||
|
|
||||||
|
|
||||||
@ -1483,3 +1506,22 @@ def backend_info_update(context, host, value=None,
|
|||||||
"""Update hash info for host."""
|
"""Update hash info for host."""
|
||||||
return IMPL.backend_info_update(context, host=host, value=value,
|
return IMPL.backend_info_update(context, host=host, value=value,
|
||||||
delete_existing=delete_existing)
|
delete_existing=delete_existing)
|
||||||
|
|
||||||
|
####################
|
||||||
|
|
||||||
|
|
||||||
|
def async_operation_data_get(context, entity_id, key=None, default=None):
|
||||||
|
"""Get one, list or all key-value pairs for given entity_id."""
|
||||||
|
return IMPL.async_operation_data_get(context, entity_id, key, default)
|
||||||
|
|
||||||
|
|
||||||
|
def async_operation_data_update(context, entity_id, details,
|
||||||
|
delete_existing=False):
|
||||||
|
"""Update key-value pairs for given entity_id."""
|
||||||
|
return IMPL.async_operation_data_update(context, entity_id, details,
|
||||||
|
delete_existing)
|
||||||
|
|
||||||
|
|
||||||
|
def async_operation_data_delete(context, entity_id, key=None):
|
||||||
|
"""Remove one, list or all key-value pairs for given entity_id."""
|
||||||
|
return IMPL.async_operation_data_delete(context, entity_id, key)
|
||||||
|
@ -0,0 +1,90 @@
|
|||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
# not use this file except in compliance with the License. You may obtain
|
||||||
|
# a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
# License for the specific language governing permissions and limitations
|
||||||
|
# under the License.
|
||||||
|
|
||||||
|
"""add_security_service_update_control_fields
|
||||||
|
|
||||||
|
Revision ID: 478c445d8d3e
|
||||||
|
Revises: 0c23aec99b74
|
||||||
|
Create Date: 2020-12-07 12:33:41.444202
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '478c445d8d3e'
|
||||||
|
down_revision = '0c23aec99b74'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
from manila.common import constants
|
||||||
|
from oslo_log import log
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
SHARE_SERVERS_TABLE = 'share_servers'
|
||||||
|
SHARE_NETWORKS_TABLE = 'share_networks'
|
||||||
|
ASYNC_OPERATION_DATA_TABLE = 'async_operation_data'
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
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:
|
||||||
|
op.create_table(
|
||||||
|
ASYNC_OPERATION_DATA_TABLE,
|
||||||
|
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('entity_uuid', sa.String(36),
|
||||||
|
nullable=False, primary_key=True),
|
||||||
|
sa.Column('key', sa.String(255),
|
||||||
|
nullable=False, primary_key=True),
|
||||||
|
sa.Column('value', sa.String(1023), nullable=False),
|
||||||
|
mysql_engine='InnoDB',
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
SHARE_SERVERS_TABLE,
|
||||||
|
sa.Column('security_service_update_support', sa.Boolean,
|
||||||
|
nullable=False, server_default=sa.sql.false())
|
||||||
|
)
|
||||||
|
op.add_column(
|
||||||
|
SHARE_NETWORKS_TABLE,
|
||||||
|
sa.Column('status', sa.String(36), nullable=False,
|
||||||
|
server_default=constants.STATUS_NETWORK_ACTIVE))
|
||||||
|
except Exception:
|
||||||
|
msg_args = {
|
||||||
|
'async_op_table': ASYNC_OPERATION_DATA_TABLE,
|
||||||
|
'sec_serv_column': 'share_servers.security_service_update_support',
|
||||||
|
'shr_net_column': 'share_networks.status',
|
||||||
|
}
|
||||||
|
LOG.error('Table %(async_op_table)s and table columns '
|
||||||
|
'%(sec_serv_column)s and %(shr_net_column)s were not'
|
||||||
|
' created!', msg_args)
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
try:
|
||||||
|
op.drop_table(ASYNC_OPERATION_DATA_TABLE)
|
||||||
|
op.drop_column(SHARE_SERVERS_TABLE, 'security_service_update_support')
|
||||||
|
op.drop_column(SHARE_NETWORKS_TABLE, 'status')
|
||||||
|
except Exception:
|
||||||
|
msg_args = {
|
||||||
|
'async_op_table': ASYNC_OPERATION_DATA_TABLE,
|
||||||
|
'sec_serv_column': 'share_servers.security_service_update_support',
|
||||||
|
'shr_net_column': 'share_networks.status',
|
||||||
|
}
|
||||||
|
LOG.error('Table %(async_op_table)s and table columns '
|
||||||
|
'%(sec_serv_column)s and %(shr_net_column)s were not '
|
||||||
|
'dropped!', msg_args)
|
||||||
|
raise
|
@ -3847,6 +3847,21 @@ def share_network_add_security_service(context, id, security_service_id):
|
|||||||
return share_nw_ref
|
return share_nw_ref
|
||||||
|
|
||||||
|
|
||||||
|
@require_context
|
||||||
|
def share_network_security_service_association_get(
|
||||||
|
context, share_network_id, security_service_id):
|
||||||
|
session = get_session()
|
||||||
|
|
||||||
|
with session.begin():
|
||||||
|
association = (model_query(
|
||||||
|
context,
|
||||||
|
models.ShareNetworkSecurityServiceAssociation,
|
||||||
|
session=session).filter_by(
|
||||||
|
share_network_id=share_network_id).filter_by(
|
||||||
|
security_service_id=security_service_id).first())
|
||||||
|
return association
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def share_network_remove_security_service(context, id, security_service_id):
|
def share_network_remove_security_service(context, id, security_service_id):
|
||||||
session = get_session()
|
session = get_session()
|
||||||
@ -3874,6 +3889,43 @@ def share_network_remove_security_service(context, id, security_service_id):
|
|||||||
return share_nw_ref
|
return share_nw_ref
|
||||||
|
|
||||||
|
|
||||||
|
@require_context
|
||||||
|
def share_network_update_security_service(context, id,
|
||||||
|
current_security_service_id,
|
||||||
|
new_security_service_id):
|
||||||
|
session = get_session()
|
||||||
|
|
||||||
|
with session.begin():
|
||||||
|
share_nw_ref = share_network_get(context, id, session=session)
|
||||||
|
# Check if the old security service exists
|
||||||
|
security_service_get(context, current_security_service_id,
|
||||||
|
session=session)
|
||||||
|
new_security_service_ref = security_service_get(
|
||||||
|
context, new_security_service_id, session=session)
|
||||||
|
|
||||||
|
assoc_ref = (model_query(
|
||||||
|
context,
|
||||||
|
models.ShareNetworkSecurityServiceAssociation,
|
||||||
|
session=session).filter_by(
|
||||||
|
share_network_id=id).filter_by(
|
||||||
|
security_service_id=current_security_service_id).first())
|
||||||
|
|
||||||
|
if assoc_ref:
|
||||||
|
assoc_ref.soft_delete(session)
|
||||||
|
else:
|
||||||
|
msg = "No association defined"
|
||||||
|
raise exception.ShareNetworkSecurityServiceDissociationError(
|
||||||
|
share_network_id=id,
|
||||||
|
security_service_id=current_security_service_id,
|
||||||
|
reason=msg)
|
||||||
|
|
||||||
|
# Add new association
|
||||||
|
share_nw_ref.security_services += [new_security_service_ref]
|
||||||
|
share_nw_ref.save(session=session)
|
||||||
|
|
||||||
|
return share_nw_ref
|
||||||
|
|
||||||
|
|
||||||
@require_context
|
@require_context
|
||||||
def count_share_networks(context, project_id, user_id=None,
|
def count_share_networks(context, project_id, user_id=None,
|
||||||
share_type_id=None, session=None):
|
share_type_id=None, session=None):
|
||||||
@ -4117,7 +4169,10 @@ def share_server_get_all_with_filters(context, filters):
|
|||||||
if filters.get('source_share_server_id'):
|
if filters.get('source_share_server_id'):
|
||||||
query = query.filter_by(
|
query = query.filter_by(
|
||||||
source_share_server_id=filters.get('source_share_server_id'))
|
source_share_server_id=filters.get('source_share_server_id'))
|
||||||
|
if filters.get('share_network_id'):
|
||||||
|
query = query.filter(
|
||||||
|
models.ShareNetworkSubnet.share_network_id ==
|
||||||
|
filters.get('share_network_id'))
|
||||||
return query.all()
|
return query.all()
|
||||||
|
|
||||||
|
|
||||||
@ -4177,6 +4232,20 @@ def share_server_backend_details_delete(context, share_server_id,
|
|||||||
item.soft_delete(session)
|
item.soft_delete(session)
|
||||||
|
|
||||||
|
|
||||||
|
@require_context
|
||||||
|
def share_servers_update(
|
||||||
|
context, share_server_ids, values, session=None):
|
||||||
|
session = session or get_session()
|
||||||
|
|
||||||
|
result = (
|
||||||
|
model_query(
|
||||||
|
context, models.ShareServer, read_deleted="no",
|
||||||
|
session=session).filter(
|
||||||
|
models.ShareServer.id.in_(share_server_ids)).update(
|
||||||
|
values, synchronize_session=False))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
|
|
||||||
def _driver_private_data_query(session, context, entity_id, key=None,
|
def _driver_private_data_query(session, context, entity_id, key=None,
|
||||||
@ -5775,3 +5844,92 @@ def _backend_info_query(session, context, host, read_deleted=False):
|
|||||||
).first()
|
).first()
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
###################
|
||||||
|
|
||||||
|
|
||||||
|
def _async_operation_data_query(session, context, entity_id, key=None,
|
||||||
|
read_deleted=False):
|
||||||
|
query = model_query(
|
||||||
|
context, models.AsynchronousOperationData, session=session,
|
||||||
|
read_deleted=read_deleted,
|
||||||
|
).filter_by(
|
||||||
|
entity_uuid=entity_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(key, list):
|
||||||
|
return query.filter(models.AsynchronousOperationData.key.in_(key))
|
||||||
|
elif key is not None:
|
||||||
|
return query.filter_by(key=key)
|
||||||
|
|
||||||
|
return query
|
||||||
|
|
||||||
|
|
||||||
|
@require_context
|
||||||
|
def async_operation_data_get(context, entity_id, key=None,
|
||||||
|
default=None, session=None):
|
||||||
|
if not session:
|
||||||
|
session = get_session()
|
||||||
|
|
||||||
|
query = _async_operation_data_query(session, context, entity_id, key)
|
||||||
|
|
||||||
|
if key is None or isinstance(key, list):
|
||||||
|
return {item.key: item.value for item in query.all()}
|
||||||
|
else:
|
||||||
|
result = query.first()
|
||||||
|
return result["value"] if result is not None else default
|
||||||
|
|
||||||
|
|
||||||
|
@require_context
|
||||||
|
def async_operation_data_update(context, entity_id, details,
|
||||||
|
delete_existing=False, session=None):
|
||||||
|
new_details = copy.deepcopy(details)
|
||||||
|
|
||||||
|
if not session:
|
||||||
|
session = get_session()
|
||||||
|
|
||||||
|
with session.begin():
|
||||||
|
# Process existing data
|
||||||
|
original_data = session.query(
|
||||||
|
models.AsynchronousOperationData).filter_by(
|
||||||
|
entity_uuid=entity_id).all()
|
||||||
|
|
||||||
|
for data_ref in original_data:
|
||||||
|
in_new_details = data_ref['key'] in new_details
|
||||||
|
|
||||||
|
if in_new_details:
|
||||||
|
new_value = str(new_details.pop(data_ref['key']))
|
||||||
|
data_ref.update({
|
||||||
|
"value": new_value,
|
||||||
|
"deleted": 0,
|
||||||
|
"deleted_at": None
|
||||||
|
})
|
||||||
|
data_ref.save(session=session)
|
||||||
|
elif delete_existing and data_ref['deleted'] != 1:
|
||||||
|
data_ref.update({
|
||||||
|
"deleted": 1, "deleted_at": timeutils.utcnow()
|
||||||
|
})
|
||||||
|
data_ref.save(session=session)
|
||||||
|
|
||||||
|
# Add new data
|
||||||
|
for key, value in new_details.items():
|
||||||
|
data_ref = models.AsynchronousOperationData()
|
||||||
|
data_ref.update({
|
||||||
|
"entity_uuid": entity_id,
|
||||||
|
"key": key,
|
||||||
|
"value": str(value)
|
||||||
|
})
|
||||||
|
data_ref.save(session=session)
|
||||||
|
|
||||||
|
return details
|
||||||
|
|
||||||
|
|
||||||
|
@require_context
|
||||||
|
def async_operation_data_delete(context, entity_id, key=None, session=None):
|
||||||
|
if not session:
|
||||||
|
session = get_session()
|
||||||
|
|
||||||
|
with session.begin():
|
||||||
|
query = _async_operation_data_query(session, context,
|
||||||
|
entity_id, key)
|
||||||
|
query.update({"deleted": 1, "deleted_at": timeutils.utcnow()})
|
||||||
|
@ -188,7 +188,8 @@ class Share(BASE, ManilaBase):
|
|||||||
__tablename__ = 'shares'
|
__tablename__ = 'shares'
|
||||||
_extra_keys = ['name', 'export_location', 'export_locations', 'status',
|
_extra_keys = ['name', 'export_location', 'export_locations', 'status',
|
||||||
'host', 'share_server_id', 'share_network_id',
|
'host', 'share_server_id', 'share_network_id',
|
||||||
'availability_zone', 'access_rules_status', 'share_type_id']
|
'availability_zone', 'access_rules_status', 'share_type_id',
|
||||||
|
'share_network_status']
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@ -227,7 +228,8 @@ class Share(BASE, ManilaBase):
|
|||||||
def __getattr__(self, item):
|
def __getattr__(self, item):
|
||||||
proxified_properties = ('status', 'host', 'share_server_id',
|
proxified_properties = ('status', 'host', 'share_server_id',
|
||||||
'share_network_id', 'availability_zone',
|
'share_network_id', 'availability_zone',
|
||||||
'share_type_id', 'share_type')
|
'share_type_id', 'share_type',
|
||||||
|
'share_network_status')
|
||||||
|
|
||||||
if item in proxified_properties:
|
if item in proxified_properties:
|
||||||
return getattr(self.instance, item, None)
|
return getattr(self.instance, item, None)
|
||||||
@ -920,6 +922,10 @@ class ShareNetwork(BASE, ManilaBase):
|
|||||||
user_id = Column(String(255), nullable=False)
|
user_id = Column(String(255), nullable=False)
|
||||||
name = Column(String(255), nullable=True)
|
name = Column(String(255), nullable=True)
|
||||||
description = Column(String(255), nullable=True)
|
description = Column(String(255), nullable=True)
|
||||||
|
status = Column(Enum(
|
||||||
|
constants.STATUS_NETWORK_ACTIVE, constants.STATUS_NETWORK_ERROR,
|
||||||
|
constants.STATUS_NETWORK_CHANGE),
|
||||||
|
default=constants.STATUS_NETWORK_ACTIVE)
|
||||||
security_services = orm.relationship(
|
security_services = orm.relationship(
|
||||||
"SecurityService",
|
"SecurityService",
|
||||||
secondary="share_network_security_service_association",
|
secondary="share_network_security_service_association",
|
||||||
@ -935,7 +941,7 @@ class ShareNetwork(BASE, ManilaBase):
|
|||||||
'SecurityService.deleted == "False")')
|
'SecurityService.deleted == "False")')
|
||||||
share_instances = orm.relationship(
|
share_instances = orm.relationship(
|
||||||
"ShareInstance",
|
"ShareInstance",
|
||||||
backref='share_network',
|
backref=orm.backref('share_network'),
|
||||||
primaryjoin='and_('
|
primaryjoin='and_('
|
||||||
'ShareNetwork.id == ShareInstance.share_network_id,'
|
'ShareNetwork.id == ShareInstance.share_network_id,'
|
||||||
'ShareInstance.deleted == "False")')
|
'ShareInstance.deleted == "False")')
|
||||||
@ -947,6 +953,18 @@ class ShareNetwork(BASE, ManilaBase):
|
|||||||
'(ShareNetwork.id == ShareNetworkSubnet.share_network_id,'
|
'(ShareNetwork.id == ShareNetworkSubnet.share_network_id,'
|
||||||
'ShareNetworkSubnet.deleted == "False")')
|
'ShareNetworkSubnet.deleted == "False")')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def security_service_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['security_service_update_support'])
|
||||||
|
# NOTE(carloss): all share servers within this share network must
|
||||||
|
# support updating security services in order to have this property
|
||||||
|
# set to True.
|
||||||
|
return all(share_servers_support_updating)
|
||||||
|
|
||||||
|
|
||||||
class ShareNetworkSubnet(BASE, ManilaBase):
|
class ShareNetworkSubnet(BASE, ManilaBase):
|
||||||
"""Represents a share network subnet used by some resources."""
|
"""Represents a share network subnet used by some resources."""
|
||||||
@ -998,6 +1016,10 @@ class ShareNetworkSubnet(BASE, ManilaBase):
|
|||||||
def share_network_name(self):
|
def share_network_name(self):
|
||||||
return self.share_network['name']
|
return self.share_network['name']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def share_network_status(self):
|
||||||
|
return self.share_network['status']
|
||||||
|
|
||||||
|
|
||||||
class ShareServer(BASE, ManilaBase):
|
class ShareServer(BASE, ManilaBase):
|
||||||
"""Represents share server used by share."""
|
"""Represents share server used by share."""
|
||||||
@ -1013,6 +1035,8 @@ class ShareServer(BASE, ManilaBase):
|
|||||||
task_state = Column(String(255), nullable=True)
|
task_state = Column(String(255), nullable=True)
|
||||||
source_share_server_id = Column(String(36), ForeignKey('share_servers.id'),
|
source_share_server_id = Column(String(36), ForeignKey('share_servers.id'),
|
||||||
nullable=True)
|
nullable=True)
|
||||||
|
security_service_update_support = Column(
|
||||||
|
Boolean, nullable=False, default=False)
|
||||||
status = Column(Enum(
|
status = Column(Enum(
|
||||||
constants.STATUS_INACTIVE, constants.STATUS_ACTIVE,
|
constants.STATUS_INACTIVE, constants.STATUS_ACTIVE,
|
||||||
constants.STATUS_ERROR, constants.STATUS_DELETING,
|
constants.STATUS_ERROR, constants.STATUS_DELETING,
|
||||||
@ -1020,7 +1044,8 @@ class ShareServer(BASE, ManilaBase):
|
|||||||
constants.STATUS_MANAGING, constants.STATUS_UNMANAGING,
|
constants.STATUS_MANAGING, constants.STATUS_UNMANAGING,
|
||||||
constants.STATUS_UNMANAGE_ERROR, constants.STATUS_MANAGE_ERROR,
|
constants.STATUS_UNMANAGE_ERROR, constants.STATUS_MANAGE_ERROR,
|
||||||
constants.STATUS_SERVER_MIGRATING,
|
constants.STATUS_SERVER_MIGRATING,
|
||||||
constants.STATUS_SERVER_MIGRATING_TO),
|
constants.STATUS_SERVER_MIGRATING_TO,
|
||||||
|
constants.STATUS_SERVER_NETWORK_CHANGE),
|
||||||
default=constants.STATUS_INACTIVE)
|
default=constants.STATUS_INACTIVE)
|
||||||
network_allocations = orm.relationship(
|
network_allocations = orm.relationship(
|
||||||
"NetworkAllocation",
|
"NetworkAllocation",
|
||||||
@ -1053,6 +1078,10 @@ class ShareServer(BASE, ManilaBase):
|
|||||||
return {model['key']: model['value']
|
return {model['key']: model['value']
|
||||||
for model in self._backend_details}
|
for model in self._backend_details}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def share_network_status(self):
|
||||||
|
return self.share_network_subnet['share_network']['status']
|
||||||
|
|
||||||
_extra_keys = ['backend_details']
|
_extra_keys = ['backend_details']
|
||||||
|
|
||||||
|
|
||||||
@ -1309,6 +1338,14 @@ class BackendInfo(BASE, ManilaBase):
|
|||||||
info_hash = Column(String(255))
|
info_hash = Column(String(255))
|
||||||
|
|
||||||
|
|
||||||
|
class AsynchronousOperationData(BASE, ManilaBase):
|
||||||
|
"""Represents data as key-value pairs for asynchronous operations."""
|
||||||
|
__tablename__ = 'async_operation_data'
|
||||||
|
entity_uuid = Column(String(36), nullable=False, primary_key=True)
|
||||||
|
key = Column(String(255), nullable=False, primary_key=True)
|
||||||
|
value = Column(String(1023), nullable=False)
|
||||||
|
|
||||||
|
|
||||||
def register_models():
|
def register_models():
|
||||||
"""Register Models and create metadata.
|
"""Register Models and create metadata.
|
||||||
|
|
||||||
|
@ -242,6 +242,10 @@ class ShareServerNotFoundByFilters(ShareServerNotFound):
|
|||||||
"filters: %(filters_description)s.")
|
"filters: %(filters_description)s.")
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidShareNetwork(Invalid):
|
||||||
|
message = _("Invalid share network: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
class ShareServerInUse(InUse):
|
class ShareServerInUse(InUse):
|
||||||
message = _("Share server %(share_server_id)s is in use.")
|
message = _("Share server %(share_server_id)s is in use.")
|
||||||
|
|
||||||
@ -597,6 +601,10 @@ class SecurityServiceNotFound(NotFound):
|
|||||||
message = _("Security service %(security_service_id)s could not be found.")
|
message = _("Security service %(security_service_id)s could not be found.")
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidSecurityService(Invalid):
|
||||||
|
message = _("Invalid security service: %(reason)s")
|
||||||
|
|
||||||
|
|
||||||
class ShareNetworkSecurityServiceAssociationError(ManilaException):
|
class ShareNetworkSecurityServiceAssociationError(ManilaException):
|
||||||
message = _("Failed to associate share network %(share_network_id)s"
|
message = _("Failed to associate share network %(share_network_id)s"
|
||||||
" and security service %(security_service_id)s: %(reason)s.")
|
" and security service %(security_service_id)s: %(reason)s.")
|
||||||
|
@ -57,7 +57,22 @@ deprecated_share_network_get_all = policy.DeprecatedRule(
|
|||||||
name=BASE_POLICY_NAME % 'get_all_share_networks',
|
name=BASE_POLICY_NAME % 'get_all_share_networks',
|
||||||
check_str=base.RULE_ADMIN_API
|
check_str=base.RULE_ADMIN_API
|
||||||
)
|
)
|
||||||
|
deprecated_share_network_add_security_service_check = policy.DeprecatedRule(
|
||||||
|
name=BASE_POLICY_NAME % 'add_security_service_check',
|
||||||
|
check_str=base.RULE_DEFAULT
|
||||||
|
)
|
||||||
|
deprecated_share_network_update_security_service = policy.DeprecatedRule(
|
||||||
|
name=BASE_POLICY_NAME % 'update_security_service',
|
||||||
|
check_str=base.RULE_DEFAULT
|
||||||
|
)
|
||||||
|
deprecated_share_network_update_security_service_check = policy.DeprecatedRule(
|
||||||
|
name=BASE_POLICY_NAME % 'update_security_service_check',
|
||||||
|
check_str=base.RULE_DEFAULT
|
||||||
|
)
|
||||||
|
deprecated_share_network_reset_status = policy.DeprecatedRule(
|
||||||
|
name=BASE_POLICY_NAME % 'reset_status',
|
||||||
|
check_str=base.RULE_ADMIN_API
|
||||||
|
)
|
||||||
|
|
||||||
share_network_policies = [
|
share_network_policies = [
|
||||||
policy.DocumentedRuleDefault(
|
policy.DocumentedRuleDefault(
|
||||||
@ -173,6 +188,22 @@ share_network_policies = [
|
|||||||
deprecated_reason=DEPRECATED_REASON,
|
deprecated_reason=DEPRECATED_REASON,
|
||||||
deprecated_since=versionutils.deprecated.WALLABY
|
deprecated_since=versionutils.deprecated.WALLABY
|
||||||
),
|
),
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=BASE_POLICY_NAME % 'add_security_service_check',
|
||||||
|
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
|
||||||
|
scope_types=['system', 'project'],
|
||||||
|
description="Check the feasibility of add security service to a share "
|
||||||
|
"network.",
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'method': 'POST',
|
||||||
|
'path': '/share-networks/{share_network_id}/action'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
deprecated_rule=deprecated_share_network_add_security_service_check,
|
||||||
|
deprecated_reason=DEPRECATED_REASON,
|
||||||
|
deprecated_since=versionutils.deprecated.WALLABY
|
||||||
|
),
|
||||||
policy.DocumentedRuleDefault(
|
policy.DocumentedRuleDefault(
|
||||||
name=BASE_POLICY_NAME % 'remove_security_service',
|
name=BASE_POLICY_NAME % 'remove_security_service',
|
||||||
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
|
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
|
||||||
@ -188,6 +219,52 @@ share_network_policies = [
|
|||||||
deprecated_reason=DEPRECATED_REASON,
|
deprecated_reason=DEPRECATED_REASON,
|
||||||
deprecated_since=versionutils.deprecated.WALLABY
|
deprecated_since=versionutils.deprecated.WALLABY
|
||||||
),
|
),
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=BASE_POLICY_NAME % 'update_security_service',
|
||||||
|
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
|
||||||
|
scope_types=['system', 'project'],
|
||||||
|
description="Update security service from share network.",
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'method': 'POST',
|
||||||
|
'path': '/share-networks/{share_network_id}/action'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
deprecated_rule=deprecated_share_network_update_security_service,
|
||||||
|
deprecated_reason=DEPRECATED_REASON,
|
||||||
|
deprecated_since=versionutils.deprecated.WALLABY
|
||||||
|
),
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=BASE_POLICY_NAME % 'update_security_service_check',
|
||||||
|
check_str=base.SYSTEM_ADMIN_OR_PROJECT_MEMBER,
|
||||||
|
scope_types=['system', 'project'],
|
||||||
|
description="Check the feasibility of update a security service from "
|
||||||
|
"share network.",
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'method': 'POST',
|
||||||
|
'path': '/share-networks/{share_network_id}/action'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
deprecated_rule=deprecated_share_network_update_security_service_check,
|
||||||
|
deprecated_reason=DEPRECATED_REASON,
|
||||||
|
deprecated_since=versionutils.deprecated.WALLABY
|
||||||
|
),
|
||||||
|
policy.DocumentedRuleDefault(
|
||||||
|
name=BASE_POLICY_NAME % 'reset_status',
|
||||||
|
check_str=base.SYSTEM_ADMIN_OR_PROJECT_ADMIN,
|
||||||
|
scope_types=['system', 'project'],
|
||||||
|
description="Reset share network`s status.",
|
||||||
|
operations=[
|
||||||
|
{
|
||||||
|
'method': 'POST',
|
||||||
|
'path': '/share-networks/{share_network_id}/action'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
deprecated_rule=deprecated_share_network_reset_status,
|
||||||
|
deprecated_reason=DEPRECATED_REASON,
|
||||||
|
deprecated_since=versionutils.deprecated.WALLABY
|
||||||
|
),
|
||||||
policy.DocumentedRuleDefault(
|
policy.DocumentedRuleDefault(
|
||||||
name=BASE_POLICY_NAME % 'get_all_share_networks',
|
name=BASE_POLICY_NAME % 'get_all_share_networks',
|
||||||
check_str=base.SYSTEM_READER,
|
check_str=base.SYSTEM_READER,
|
||||||
|
@ -146,6 +146,7 @@ class HostState(object):
|
|||||||
self.replication_domain = None
|
self.replication_domain = None
|
||||||
self.ipv4_support = None
|
self.ipv4_support = None
|
||||||
self.ipv6_support = None
|
self.ipv6_support = None
|
||||||
|
self.security_service_update_support = False
|
||||||
|
|
||||||
# PoolState for all pools
|
# PoolState for all pools
|
||||||
self.pools = {}
|
self.pools = {}
|
||||||
@ -335,6 +336,10 @@ class HostState(object):
|
|||||||
pool_cap['sg_consistent_snapshot_support'] = (
|
pool_cap['sg_consistent_snapshot_support'] = (
|
||||||
self.sg_consistent_snapshot_support)
|
self.sg_consistent_snapshot_support)
|
||||||
|
|
||||||
|
if 'security_service_update_support' not in pool_cap:
|
||||||
|
pool_cap['security_service_update_support'] = (
|
||||||
|
self.security_service_update_support)
|
||||||
|
|
||||||
if self.ipv4_support is not None:
|
if self.ipv4_support is not None:
|
||||||
pool_cap['ipv4_support'] = self.ipv4_support
|
pool_cap['ipv4_support'] = self.ipv4_support
|
||||||
|
|
||||||
@ -364,6 +369,8 @@ class HostState(object):
|
|||||||
self.ipv4_support = capability['ipv4_support']
|
self.ipv4_support = capability['ipv4_support']
|
||||||
if capability.get('ipv6_support') is not None:
|
if capability.get('ipv6_support') is not None:
|
||||||
self.ipv6_support = capability['ipv6_support']
|
self.ipv6_support = capability['ipv6_support']
|
||||||
|
self.security_service_update_support = capability.get(
|
||||||
|
'security_service_update_support', False)
|
||||||
|
|
||||||
def consume_from_share(self, share):
|
def consume_from_share(self, share):
|
||||||
"""Incrementally update host state from an share."""
|
"""Incrementally update host state from an share."""
|
||||||
@ -460,6 +467,8 @@ class PoolState(HostState):
|
|||||||
'replication_domain')
|
'replication_domain')
|
||||||
self.sg_consistent_snapshot_support = capability.get(
|
self.sg_consistent_snapshot_support = capability.get(
|
||||||
'sg_consistent_snapshot_support')
|
'sg_consistent_snapshot_support')
|
||||||
|
self.security_service_update_support = capability.get(
|
||||||
|
'security_service_update_support', False)
|
||||||
|
|
||||||
def update_pools(self, capability):
|
def update_pools(self, capability):
|
||||||
# Do nothing, since we don't have pools within pool, yet
|
# Do nothing, since we don't have pools within pool, yet
|
||||||
|
@ -57,6 +57,8 @@ def generate_stats(host_state, properties):
|
|||||||
host_state.sg_consistent_snapshot_support),
|
host_state.sg_consistent_snapshot_support),
|
||||||
'ipv4_support': host_state.ipv4_support,
|
'ipv4_support': host_state.ipv4_support,
|
||||||
'ipv6_support': host_state.ipv6_support,
|
'ipv6_support': host_state.ipv6_support,
|
||||||
|
'security_service_update_support': (
|
||||||
|
host_state.security_service_update_support)
|
||||||
}
|
}
|
||||||
|
|
||||||
host_caps = host_state.capabilities
|
host_caps = host_state.capabilities
|
||||||
|
@ -94,6 +94,25 @@ class ShareInstanceAccessDatabaseMixin(object):
|
|||||||
context, share_instance_id, updates, with_share_data=True)
|
context, share_instance_id, updates, with_share_data=True)
|
||||||
return share_instance
|
return share_instance
|
||||||
|
|
||||||
|
def update_share_instances_access_rules_status(
|
||||||
|
self, context, status, share_instance_ids):
|
||||||
|
"""Update the access_rules_status of all share instances.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
Before making this call, make sure that all share instances have
|
||||||
|
their status set to a value that will block new operations to
|
||||||
|
happen during this update.
|
||||||
|
|
||||||
|
:param status: Force a state change on all share instances regardless
|
||||||
|
of the prior state.
|
||||||
|
:param share_instance_ids: List of share instance ids to have their
|
||||||
|
access rules status updated.
|
||||||
|
"""
|
||||||
|
updates = {'access_rules_status': status}
|
||||||
|
|
||||||
|
self.db.share_instances_status_update(
|
||||||
|
context, share_instance_ids, updates)
|
||||||
|
|
||||||
@locked_access_rules_operation
|
@locked_access_rules_operation
|
||||||
def get_and_update_share_instance_access_rules(self, context,
|
def get_and_update_share_instance_access_rules(self, context,
|
||||||
filters=None, updates=None,
|
filters=None, updates=None,
|
||||||
@ -321,7 +340,7 @@ class ShareInstanceAccess(ShareInstanceAccessDatabaseMixin):
|
|||||||
add_rules, delete_rules, rules_to_be_removed_from_db,
|
add_rules, delete_rules, rules_to_be_removed_from_db,
|
||||||
share_server)
|
share_server)
|
||||||
|
|
||||||
self._process_driver_rule_updates(
|
self.process_driver_rule_updates(
|
||||||
context, driver_rule_updates, share_instance_id)
|
context, driver_rule_updates, share_instance_id)
|
||||||
|
|
||||||
# Update access rules that are still in 'applying' state
|
# Update access rules that are still in 'applying' state
|
||||||
@ -434,8 +453,8 @@ class ShareInstanceAccess(ShareInstanceAccessDatabaseMixin):
|
|||||||
context, conditionally_change=conditionally_change,
|
context, conditionally_change=conditionally_change,
|
||||||
share_instance_id=share_instance_id)
|
share_instance_id=share_instance_id)
|
||||||
|
|
||||||
def _process_driver_rule_updates(self, context, driver_rule_updates,
|
def process_driver_rule_updates(self, context, driver_rule_updates,
|
||||||
share_instance_id):
|
share_instance_id):
|
||||||
for rule_id, rule_updates in driver_rule_updates.items():
|
for rule_id, rule_updates in driver_rule_updates.items():
|
||||||
if 'state' in rule_updates:
|
if 'state' in rule_updates:
|
||||||
# We allow updates *only* if the state is unchanged from
|
# We allow updates *only* if the state is unchanged from
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
"""
|
"""
|
||||||
Handles all requests relating to shares.
|
Handles all requests relating to shares.
|
||||||
"""
|
"""
|
||||||
|
import json
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
@ -27,7 +28,10 @@ from oslo_utils import strutils
|
|||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from manila.api import common as api_common
|
||||||
from manila.common import constants
|
from manila.common import constants
|
||||||
|
from manila import context as manila_context
|
||||||
|
from manila import coordination
|
||||||
from manila.data import rpcapi as data_rpcapi
|
from manila.data import rpcapi as data_rpcapi
|
||||||
from manila.db import base
|
from manila.db import base
|
||||||
from manila import exception
|
from manila import exception
|
||||||
@ -61,6 +65,29 @@ GB = 1048576 * 1024
|
|||||||
QUOTAS = quota.QUOTAS
|
QUOTAS = quota.QUOTAS
|
||||||
|
|
||||||
|
|
||||||
|
def locked_security_service_update_operation(operation):
|
||||||
|
"""Lock decorator for security service operation.
|
||||||
|
|
||||||
|
Takes a named lock prior to executing the operation. The lock is named with
|
||||||
|
the ids of the security services.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def wrapped(*args, **kwargs):
|
||||||
|
new_id = kwargs.get('new_security_service_id', '')
|
||||||
|
current_id = kwargs.get('current_security_service_id', '')
|
||||||
|
|
||||||
|
@coordination.synchronized(
|
||||||
|
'locked-security-service-update-operation-%(new)s-%(curr)s' % {
|
||||||
|
'new': new_id,
|
||||||
|
'curr': current_id,
|
||||||
|
})
|
||||||
|
def locked_security_service_operation(*_args, **_kwargs):
|
||||||
|
return operation(*_args, **_kwargs)
|
||||||
|
return locked_security_service_operation(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrapped
|
||||||
|
|
||||||
|
|
||||||
class API(base.Base):
|
class API(base.Base):
|
||||||
"""API for interacting with the share manager."""
|
"""API for interacting with the share manager."""
|
||||||
|
|
||||||
@ -69,6 +96,7 @@ class API(base.Base):
|
|||||||
self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI()
|
self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI()
|
||||||
self.share_rpcapi = share_rpcapi.ShareAPI()
|
self.share_rpcapi = share_rpcapi.ShareAPI()
|
||||||
self.access_helper = access.ShareInstanceAccess(self.db, None)
|
self.access_helper = access.ShareInstanceAccess(self.db, None)
|
||||||
|
coordination.LOCK_COORDINATOR.start()
|
||||||
|
|
||||||
def _get_all_availability_zones_with_subnets(self, context,
|
def _get_all_availability_zones_with_subnets(self, context,
|
||||||
share_network_id):
|
share_network_id):
|
||||||
@ -826,6 +854,16 @@ class API(base.Base):
|
|||||||
context, share_server['share_network_subnet_id'])
|
context, share_server['share_network_subnet_id'])
|
||||||
share_data['share_network_id'] = subnet['share_network_id']
|
share_data['share_network_id'] = subnet['share_network_id']
|
||||||
|
|
||||||
|
try:
|
||||||
|
share_network = self.db.share_network_get(
|
||||||
|
context, share_data['share_network_id'])
|
||||||
|
except exception.ShareNetworkNotFound:
|
||||||
|
msg = _("Share network %s was not found."
|
||||||
|
) % share_data['share_network_id']
|
||||||
|
raise exception.InvalidInput(reason=msg)
|
||||||
|
# Check if share network is active, otherwise raise a BadRequest
|
||||||
|
api_common.check_share_network_is_active(share_network)
|
||||||
|
|
||||||
share_data.update({
|
share_data.update({
|
||||||
'user_id': context.user_id,
|
'user_id': context.user_id,
|
||||||
'project_id': context.project_id,
|
'project_id': context.project_id,
|
||||||
@ -2694,3 +2732,338 @@ class API(base.Base):
|
|||||||
'task_state': dest_share_server['task_state']
|
'task_state': dest_share_server['task_state']
|
||||||
})
|
})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def _share_network_update_initial_checks(self, context, share_network,
|
||||||
|
new_security_service,
|
||||||
|
current_security_service=None):
|
||||||
|
api_common.check_share_network_is_active(share_network)
|
||||||
|
|
||||||
|
if not current_security_service:
|
||||||
|
# Since we are adding a new security service, we can't have one
|
||||||
|
# of the same type already associated with this share network
|
||||||
|
for attached_service in share_network['security_services']:
|
||||||
|
if attached_service['type'] == new_security_service['type']:
|
||||||
|
msg = _("Cannot add security service to share network. "
|
||||||
|
"Security service with '%(ss_type)s' type already "
|
||||||
|
"added to '%(sn_id)s' share network") % {
|
||||||
|
'ss_type': new_security_service['type'],
|
||||||
|
'sn_id': share_network['id']
|
||||||
|
}
|
||||||
|
raise exception.InvalidSecurityService(reason=msg)
|
||||||
|
else:
|
||||||
|
# Validations needed only for update operation
|
||||||
|
current_service_is_associated = (
|
||||||
|
self.db.share_network_security_service_association_get(
|
||||||
|
context, share_network['id'],
|
||||||
|
current_security_service['id']))
|
||||||
|
|
||||||
|
if not current_service_is_associated:
|
||||||
|
msg = _("The specified current security service %(service)s "
|
||||||
|
"is not associated to the share network %(network)s."
|
||||||
|
) % {
|
||||||
|
'service': current_security_service['id'],
|
||||||
|
'network': share_network['id']
|
||||||
|
}
|
||||||
|
raise exception.InvalidSecurityService(reason=msg)
|
||||||
|
|
||||||
|
if (current_security_service['type'] !=
|
||||||
|
new_security_service['type']):
|
||||||
|
msg = _("A security service can only be replaced by one of "
|
||||||
|
"the same type. The current security service type is "
|
||||||
|
"'%(ss_type)s' and the new security service type is "
|
||||||
|
"'%(new_ss_type)s'") % {
|
||||||
|
'ss_type': current_security_service['type'],
|
||||||
|
'new_ss_type': new_security_service['type'],
|
||||||
|
'sn_id': share_network['id']
|
||||||
|
}
|
||||||
|
raise exception.InvalidSecurityService(reason=msg)
|
||||||
|
|
||||||
|
share_servers = set()
|
||||||
|
for subnet in share_network['share_network_subnets']:
|
||||||
|
if subnet['share_servers']:
|
||||||
|
share_servers.update(subnet['share_servers'])
|
||||||
|
|
||||||
|
backend_hosts = set()
|
||||||
|
if share_servers:
|
||||||
|
if not share_network['security_service_update_support']:
|
||||||
|
msg = _("Updating security services is not supported on this "
|
||||||
|
"share network (%(sn_id)s) while it has shares. "
|
||||||
|
"See the capability "
|
||||||
|
"'security_service_update_support'.") % {
|
||||||
|
"sn_id": share_network["id"]
|
||||||
|
}
|
||||||
|
raise exception.InvalidShareNetwork(reason=msg)
|
||||||
|
|
||||||
|
# We can only handle "active" share servers for now
|
||||||
|
for share_server in share_servers:
|
||||||
|
if share_server['status'] != constants.STATUS_ACTIVE:
|
||||||
|
msg = _('Some resources exported on share network '
|
||||||
|
'%(shar_net_id)s are not currently available.') % {
|
||||||
|
'shar_net_id': share_network['id']
|
||||||
|
}
|
||||||
|
raise exception.InvalidShareNetwork(reason=msg)
|
||||||
|
# Create a set of backend hosts
|
||||||
|
backend_hosts.add(share_server['host'])
|
||||||
|
|
||||||
|
for backend_host in backend_hosts:
|
||||||
|
# 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, backend_host)
|
||||||
|
|
||||||
|
shares = self.get_all(
|
||||||
|
context, search_opts={'share_network_id': share_network['id']})
|
||||||
|
shares_not_available = [
|
||||||
|
share['id'] for share in shares if
|
||||||
|
share['status'] != constants.STATUS_AVAILABLE]
|
||||||
|
|
||||||
|
if shares_not_available:
|
||||||
|
msg = _("Some shares exported on share network %(sn_id)s are "
|
||||||
|
"not available: %(share_ids)s.") % {
|
||||||
|
'sn_id': share_network['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 = _(
|
||||||
|
"Either these shares or one of their replicas or "
|
||||||
|
"migration copies exported on share network %(sn_id)s "
|
||||||
|
"are not available: %(share_ids)s.") % {
|
||||||
|
'sn_id': share_network['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 = _("Some shares exported on share network %(sn_id)s "
|
||||||
|
"are busy: %(share_ids)s.") % {
|
||||||
|
'sn_id': share_network['id'],
|
||||||
|
'share_ids': busy_shares,
|
||||||
|
}
|
||||||
|
raise exception.InvalidShareNetwork(reason=msg)
|
||||||
|
|
||||||
|
return list(share_servers), list(backend_hosts)
|
||||||
|
|
||||||
|
def get_security_service_update_key(
|
||||||
|
self, operation, new_security_service_id,
|
||||||
|
current_security_service_id=None):
|
||||||
|
if current_security_service_id:
|
||||||
|
return ('share_network_sec_service_update_' +
|
||||||
|
current_security_service_id + '_' +
|
||||||
|
new_security_service_id + '_' + operation)
|
||||||
|
else:
|
||||||
|
return ('share_network_sec_service_add_' +
|
||||||
|
new_security_service_id + '_' + operation)
|
||||||
|
|
||||||
|
@locked_security_service_update_operation
|
||||||
|
def _security_service_update_validate_hosts(
|
||||||
|
self, context, share_network,
|
||||||
|
backend_hosts, share_servers,
|
||||||
|
new_security_service_id=None,
|
||||||
|
current_security_service_id=None):
|
||||||
|
|
||||||
|
# create a key based on users request
|
||||||
|
update_key = self.get_security_service_update_key(
|
||||||
|
'hosts_check', new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id)
|
||||||
|
|
||||||
|
# check if there is an entry being processed
|
||||||
|
update_value = self.db.async_operation_data_get(
|
||||||
|
context, share_network['id'], update_key)
|
||||||
|
if not update_value:
|
||||||
|
# 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'],
|
||||||
|
{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)))
|
||||||
|
return None, hosts_to_validate
|
||||||
|
|
||||||
|
else:
|
||||||
|
# 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())))
|
||||||
|
hosts_to_validate = {}
|
||||||
|
for host in backend_hosts:
|
||||||
|
hosts_to_validate[host] = current_hosts.get(host, None)
|
||||||
|
|
||||||
|
# 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
|
||||||
|
if hosts_to_include:
|
||||||
|
self.db.async_operation_data_update(
|
||||||
|
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)))
|
||||||
|
|
||||||
|
return None, hosts_to_validate
|
||||||
|
|
||||||
|
if all(hosts_to_validate[host] for host in backend_hosts):
|
||||||
|
return True, hosts_to_validate
|
||||||
|
|
||||||
|
return None, current_hosts
|
||||||
|
|
||||||
|
def check_share_network_security_service_update(
|
||||||
|
self, context, share_network, new_security_service,
|
||||||
|
current_security_service=None, reset_operation=False):
|
||||||
|
share_servers, backend_hosts = (
|
||||||
|
self._share_network_update_initial_checks(
|
||||||
|
context, share_network, new_security_service,
|
||||||
|
current_security_service=current_security_service))
|
||||||
|
|
||||||
|
if not backend_hosts:
|
||||||
|
# There is no backend host to validate. Operation is supported.
|
||||||
|
return {
|
||||||
|
'compatible': True,
|
||||||
|
'hosts_check_result': {},
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
if reset_operation:
|
||||||
|
self.db.async_operation_data_delete(context, share_network['id'],
|
||||||
|
key)
|
||||||
|
try:
|
||||||
|
compatible, hosts_info = (
|
||||||
|
self._security_service_update_validate_hosts(
|
||||||
|
context, share_network, backend_hosts, share_servers,
|
||||||
|
new_security_service_id=new_security_service['id'],
|
||||||
|
current_security_service_id=curr_sec_serv_id))
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error(e)
|
||||||
|
# Due to an internal error, we will delete the entry
|
||||||
|
self.db.async_operation_data_delete(
|
||||||
|
context, share_network['id'], key)
|
||||||
|
msg = _(
|
||||||
|
'The share network %(share_net_id)s cannot be updated '
|
||||||
|
'since at least one of its backend hosts do not support '
|
||||||
|
'this operation.') % {
|
||||||
|
'share_net_id': share_network['id']}
|
||||||
|
raise exception.InvalidShareNetwork(reason=msg)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'compatible': compatible,
|
||||||
|
'hosts_check_result': hosts_info
|
||||||
|
}
|
||||||
|
|
||||||
|
def update_share_network_security_service(self, context, share_network,
|
||||||
|
new_security_service,
|
||||||
|
current_security_service=None):
|
||||||
|
share_servers, backend_hosts = (
|
||||||
|
self._share_network_update_initial_checks(
|
||||||
|
context, share_network, new_security_service,
|
||||||
|
current_security_service=current_security_service))
|
||||||
|
if not backend_hosts:
|
||||||
|
# There is no backend host to validate or update.
|
||||||
|
return
|
||||||
|
|
||||||
|
curr_sec_serv_id = (
|
||||||
|
current_security_service['id']
|
||||||
|
if current_security_service else None)
|
||||||
|
|
||||||
|
update_key = self.get_security_service_update_key(
|
||||||
|
'hosts_check', new_security_service['id'],
|
||||||
|
current_security_service_id=curr_sec_serv_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)
|
||||||
|
|
||||||
|
try:
|
||||||
|
result, __ = self._security_service_update_validate_hosts(
|
||||||
|
context, share_network, backend_hosts, share_servers,
|
||||||
|
new_security_service_id=new_security_service['id'],
|
||||||
|
current_security_service_id=curr_sec_serv_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 share network %(share_net_id)s cannot be updated '
|
||||||
|
'since at least one of its backend hosts do not support '
|
||||||
|
'this operation.') % {
|
||||||
|
'share_net_id': share_network['id']}
|
||||||
|
raise exception.InvalidShareNetwork(reason=msg)
|
||||||
|
|
||||||
|
if result is False:
|
||||||
|
msg = _(
|
||||||
|
'The share network %(share_net_id)s cannot be updated '
|
||||||
|
'since at least one of its backend hosts do not support '
|
||||||
|
'this operation.') % {
|
||||||
|
'share_net_id': share_network['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)
|
||||||
|
|
||||||
|
self.db.share_network_update(
|
||||||
|
context, share_network['id'],
|
||||||
|
{'status': constants.STATUS_NETWORK_CHANGE})
|
||||||
|
|
||||||
|
# NOTE(dviroel): We want to change the status for all share servers to
|
||||||
|
# identify when all modifications are made, and update share network
|
||||||
|
# status to 'active' again.
|
||||||
|
share_servers_ids = [ss.id for ss in share_servers]
|
||||||
|
self.db.share_servers_update(
|
||||||
|
context, share_servers_ids,
|
||||||
|
{'status': constants.STATUS_SERVER_NETWORK_CHANGE})
|
||||||
|
|
||||||
|
for backend_host in backend_hosts:
|
||||||
|
self.share_rpcapi.update_share_network_security_service(
|
||||||
|
context, backend_host, share_network['id'],
|
||||||
|
new_security_service['id'],
|
||||||
|
current_security_service_id=curr_sec_serv_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('Security service update has been started for share network '
|
||||||
|
'%(share_net_id)s.', {'share_net_id': share_network['id']})
|
||||||
|
@ -273,6 +273,10 @@ class ShareDriver(object):
|
|||||||
self._stats = {}
|
self._stats = {}
|
||||||
self.ip_versions = None
|
self.ip_versions = None
|
||||||
self.ipv6_implemented = False
|
self.ipv6_implemented = False
|
||||||
|
# Indicates whether a driver supports update of security services for
|
||||||
|
# in-use share networks. This property will be saved in every new share
|
||||||
|
# server.
|
||||||
|
self.security_service_update_support = False
|
||||||
|
|
||||||
self.pools = []
|
self.pools = []
|
||||||
if self.configuration:
|
if self.configuration:
|
||||||
@ -1315,6 +1319,8 @@ class ShareDriver(object):
|
|||||||
replication_domain=self.replication_domain,
|
replication_domain=self.replication_domain,
|
||||||
filter_function=self.get_filter_function(),
|
filter_function=self.get_filter_function(),
|
||||||
goodness_function=self.get_goodness_function(),
|
goodness_function=self.get_goodness_function(),
|
||||||
|
security_service_update_support=(
|
||||||
|
self.security_service_update_support),
|
||||||
)
|
)
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
common.update(data)
|
common.update(data)
|
||||||
@ -3184,3 +3190,134 @@ class ShareDriver(object):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def update_share_server_security_service(
|
||||||
|
self, context, share_server, network_info, share_instances,
|
||||||
|
share_instance_rules, new_security_service,
|
||||||
|
current_security_service=None):
|
||||||
|
"""Updates share server security service configuration.
|
||||||
|
|
||||||
|
If the driver supports different security services, the user can
|
||||||
|
request the addition of a new security service, with a different type.
|
||||||
|
If the user wants to update the current security service configuration,
|
||||||
|
the driver will receive both current and new security services, which
|
||||||
|
will always be of the same type.
|
||||||
|
|
||||||
|
:param context: The 'context.RequestContext' object for the request.
|
||||||
|
:param share_server: Reference to the share server object that will be
|
||||||
|
updated.
|
||||||
|
:param network_info: All network allocation associated with the share
|
||||||
|
server that will be updated.
|
||||||
|
:param share_instances: A list of share instances that belong to the
|
||||||
|
share server that is being updated.
|
||||||
|
:param share_instance_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'
|
||||||
|
...
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
:param new_security_service: New security service object to be
|
||||||
|
configured in the share server.
|
||||||
|
:param current_security_service: When provided, represents the current
|
||||||
|
security service that will be replaced by the
|
||||||
|
'new_security_service'.
|
||||||
|
|
||||||
|
:raises: ShareBackendException.
|
||||||
|
A ShareBackendException should only be raised if the share server
|
||||||
|
failed to update the security service, compromising all its access
|
||||||
|
rules. By raising an exception, the share server and all its share
|
||||||
|
instances will be set to 'error'.
|
||||||
|
:return: None, or a dictionary of updates in the following format.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
|
{
|
||||||
|
'3bc10d67-2598-4122-bb62-0bdeaa8c6db3':
|
||||||
|
{
|
||||||
|
'09960614-8574-4e03-89cf-7cf267b0bd08':
|
||||||
|
{
|
||||||
|
'access_key': 'alice31493e5441b8171d2310d80e37e',
|
||||||
|
'state': 'error',
|
||||||
|
},
|
||||||
|
'28f6eabb-4342-486a-a7f4-45688f0c0295':
|
||||||
|
{
|
||||||
|
'access_key': 'bob0078aa042d5a7325480fd13228b',
|
||||||
|
'state': 'active',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
The top level keys are share_instance_id's which should provide
|
||||||
|
another dictionary of access rules to be updated, indexed by their
|
||||||
|
'access_id'. The inner access rules dictionary should only contain the
|
||||||
|
access rules that need to be updated.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def check_update_share_server_security_service(
|
||||||
|
self, context, share_server, network_info, share_instances,
|
||||||
|
share_instance_rules, new_security_service,
|
||||||
|
current_security_service=None):
|
||||||
|
"""Check if the current share server security service is supported.
|
||||||
|
|
||||||
|
If the driver supports different security services, the user can
|
||||||
|
request the addition of a new security service, with a different type.
|
||||||
|
If the user wants to update the current security service configuration,
|
||||||
|
the driver will receive both current and new security services, which
|
||||||
|
will always be of the same type.
|
||||||
|
|
||||||
|
:param context: The 'context.RequestContext' object for the request.
|
||||||
|
:param share_server: Reference to the share server object that will be
|
||||||
|
updated.
|
||||||
|
:param network_info: All network allocation associated with the share
|
||||||
|
server that will be updated.
|
||||||
|
:param share_instances: A list of share instances that belong to the
|
||||||
|
share server that is affected by the update.
|
||||||
|
:param share_instance_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'
|
||||||
|
...
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
:param new_security_service: New security service object to be
|
||||||
|
configured in the share server.
|
||||||
|
:param current_security_service: When provided, represents the current
|
||||||
|
security service that will be replaced by the
|
||||||
|
'new_security_service'.
|
||||||
|
|
||||||
|
:return: 'True' if the driver support the requested update, 'False'
|
||||||
|
otherwise.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
@ -23,6 +23,7 @@ import copy
|
|||||||
import datetime
|
import datetime
|
||||||
import functools
|
import functools
|
||||||
import hashlib
|
import hashlib
|
||||||
|
import json
|
||||||
from operator import xor
|
from operator import xor
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
@ -183,6 +184,25 @@ def locked_share_replica_operation(operation):
|
|||||||
return wrapped
|
return wrapped
|
||||||
|
|
||||||
|
|
||||||
|
def locked_share_network_operation(operation):
|
||||||
|
"""Lock decorator for share network operations.
|
||||||
|
|
||||||
|
Takes a named lock prior to executing the operation. The lock is named with
|
||||||
|
the id of the share network.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def wrapped(*args, **kwargs):
|
||||||
|
share_network_id = kwargs.get('share_network_id')
|
||||||
|
|
||||||
|
@coordination.synchronized(
|
||||||
|
'locked-share-network-operation-%s' % share_network_id)
|
||||||
|
def locked_network_operation(*_args, **_kwargs):
|
||||||
|
return operation(*_args, **_kwargs)
|
||||||
|
return locked_network_operation(*args, **kwargs)
|
||||||
|
|
||||||
|
return wrapped
|
||||||
|
|
||||||
|
|
||||||
def add_hooks(f):
|
def add_hooks(f):
|
||||||
"""Hook decorator to perform action before and after a share method call
|
"""Hook decorator to perform action before and after a share method call
|
||||||
|
|
||||||
@ -218,7 +238,7 @@ def add_hooks(f):
|
|||||||
class ShareManager(manager.SchedulerDependentManager):
|
class ShareManager(manager.SchedulerDependentManager):
|
||||||
"""Manages NAS storages."""
|
"""Manages NAS storages."""
|
||||||
|
|
||||||
RPC_API_VERSION = '1.21'
|
RPC_API_VERSION = '1.22'
|
||||||
|
|
||||||
def __init__(self, share_driver=None, service_name=None, *args, **kwargs):
|
def __init__(self, share_driver=None, service_name=None, *args, **kwargs):
|
||||||
"""Load the driver from args, or from flags."""
|
"""Load the driver from args, or from flags."""
|
||||||
@ -698,6 +718,8 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
'host': self.host,
|
'host': self.host,
|
||||||
'share_network_subnet_id': share_network_subnet_id,
|
'share_network_subnet_id': share_network_subnet_id,
|
||||||
'status': constants.STATUS_CREATING,
|
'status': constants.STATUS_CREATING,
|
||||||
|
'security_service_update_support': (
|
||||||
|
self.driver.security_service_update_support),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -785,6 +807,8 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
'host': self.host,
|
'host': self.host,
|
||||||
'share_network_subnet_id': share_network_subnet_id,
|
'share_network_subnet_id': share_network_subnet_id,
|
||||||
'status': constants.STATUS_CREATING,
|
'status': constants.STATUS_CREATING,
|
||||||
|
'security_service_update_support': (
|
||||||
|
self.driver.security_service_update_support),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -962,7 +986,9 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
{
|
{
|
||||||
'host': self.host,
|
'host': self.host,
|
||||||
'share_network_subnet_id': share_network_subnet_id,
|
'share_network_subnet_id': share_network_subnet_id,
|
||||||
'status': constants.STATUS_CREATING
|
'status': constants.STATUS_CREATING,
|
||||||
|
'security_service_update_support': (
|
||||||
|
self.driver.security_service_update_support),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -2046,11 +2072,11 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
self._notify_about_share_usage(context, share,
|
self._notify_about_share_usage(context, share,
|
||||||
share_instance, "create.end")
|
share_instance, "create.end")
|
||||||
|
|
||||||
def _update_share_replica_access_rules_state(self, context,
|
def _update_share_instance_access_rules_state(self, context,
|
||||||
share_replica_id, state):
|
share_instance_id, state):
|
||||||
"""Update the access_rules_status for the share replica."""
|
"""Update the access_rules_status for the share instance."""
|
||||||
self.access_helper.get_and_update_share_instance_access_rules_status(
|
self.access_helper.get_and_update_share_instance_access_rules_status(
|
||||||
context, status=state, share_instance_id=share_replica_id)
|
context, status=state, share_instance_id=share_instance_id)
|
||||||
|
|
||||||
def _get_replica_snapshots_for_snapshot(self, context, snapshot_id,
|
def _get_replica_snapshots_for_snapshot(self, context, snapshot_id,
|
||||||
active_replica_id,
|
active_replica_id,
|
||||||
@ -2208,7 +2234,7 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
context, share_replica['id'],
|
context, share_replica['id'],
|
||||||
{'status': constants.STATUS_ERROR,
|
{'status': constants.STATUS_ERROR,
|
||||||
'replica_state': constants.STATUS_ERROR})
|
'replica_state': constants.STATUS_ERROR})
|
||||||
self._update_share_replica_access_rules_state(
|
self._update_share_instance_access_rules_state(
|
||||||
context, share_replica['id'], constants.STATUS_ERROR)
|
context, share_replica['id'], constants.STATUS_ERROR)
|
||||||
self.message_api.create(
|
self.message_api.create(
|
||||||
context,
|
context,
|
||||||
@ -2236,11 +2262,11 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
'progress': '100%'})
|
'progress': '100%'})
|
||||||
|
|
||||||
if replica_ref.get('access_rules_status'):
|
if replica_ref.get('access_rules_status'):
|
||||||
self._update_share_replica_access_rules_state(
|
self._update_share_instance_access_rules_state(
|
||||||
context, share_replica['id'],
|
context, share_replica['id'],
|
||||||
replica_ref.get('access_rules_status'))
|
replica_ref.get('access_rules_status'))
|
||||||
else:
|
else:
|
||||||
self._update_share_replica_access_rules_state(
|
self._update_share_instance_access_rules_state(
|
||||||
context, share_replica['id'],
|
context, share_replica['id'],
|
||||||
constants.STATUS_ACTIVE)
|
constants.STATUS_ACTIVE)
|
||||||
|
|
||||||
@ -2497,7 +2523,7 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
context, updated_replica['id'], updates)
|
context, updated_replica['id'], updates)
|
||||||
|
|
||||||
if updated_replica.get('access_rules_status'):
|
if updated_replica.get('access_rules_status'):
|
||||||
self._update_share_replica_access_rules_state(
|
self._update_share_instance_access_rules_state(
|
||||||
context, share_replica['id'],
|
context, share_replica['id'],
|
||||||
updated_replica.get('access_rules_status'))
|
updated_replica.get('access_rules_status'))
|
||||||
|
|
||||||
@ -3861,6 +3887,7 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
def _report_driver_status(self, context):
|
def _report_driver_status(self, context):
|
||||||
LOG.info('Updating share status')
|
LOG.info('Updating share status')
|
||||||
share_stats = self.driver.get_share_stats(refresh=True)
|
share_stats = self.driver.get_share_stats(refresh=True)
|
||||||
|
|
||||||
if not share_stats:
|
if not share_stats:
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -4629,7 +4656,9 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
'is_auto_deletable': share_server.get('is_auto_deletable', None),
|
'is_auto_deletable': share_server.get('is_auto_deletable', None),
|
||||||
'identifier': share_server.get('identifier', None),
|
'identifier': share_server.get('identifier', None),
|
||||||
'network_allocations': share_server.get('network_allocations',
|
'network_allocations': share_server.get('network_allocations',
|
||||||
None)
|
None),
|
||||||
|
'share_network_status': share_server.get(
|
||||||
|
'share_network_status', None)
|
||||||
}
|
}
|
||||||
return share_server_ref
|
return share_server_ref
|
||||||
|
|
||||||
@ -4680,6 +4709,7 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
'source_share_group_snapshot_member_id': share_instance.get(
|
'source_share_group_snapshot_member_id': share_instance.get(
|
||||||
'source_share_group_snapshot_member_id'),
|
'source_share_group_snapshot_member_id'),
|
||||||
'availability_zone': share_instance.get('availability_zone'),
|
'availability_zone': share_instance.get('availability_zone'),
|
||||||
|
'share_network_status': share_instance.get('share_network_status')
|
||||||
}
|
}
|
||||||
if share_instance_ref['share_server']:
|
if share_instance_ref['share_server']:
|
||||||
share_instance_ref['share_server'] = self._get_share_server_dict(
|
share_instance_ref['share_server'] = self._get_share_server_dict(
|
||||||
@ -5486,3 +5516,204 @@ class ShareManager(manager.SchedulerDependentManager):
|
|||||||
return self.driver.share_server_migration_get_progress(
|
return self.driver.share_server_migration_get_progress(
|
||||||
context, src_share_server, dest_share_server, share_instances,
|
context, src_share_server, dest_share_server, share_instances,
|
||||||
snapshot_instances)
|
snapshot_instances)
|
||||||
|
|
||||||
|
@locked_share_network_operation
|
||||||
|
def _check_share_network_update_finished(self, context, share_network_id):
|
||||||
|
# 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:
|
||||||
|
return
|
||||||
|
|
||||||
|
share_servers = self.db.share_server_get_all_with_filters(
|
||||||
|
context, {'share_network_id': share_network_id}
|
||||||
|
)
|
||||||
|
|
||||||
|
if all([ss['status'] != constants.STATUS_SERVER_NETWORK_CHANGE
|
||||||
|
for ss in share_servers]):
|
||||||
|
# All share servers have updated their configuration
|
||||||
|
self.db.share_network_update(
|
||||||
|
context, share_network_id,
|
||||||
|
{'status': constants.STATUS_NETWORK_ACTIVE})
|
||||||
|
|
||||||
|
def _update_share_network_security_service(
|
||||||
|
self, context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=None, check_only=False):
|
||||||
|
|
||||||
|
new_security_service = self.db.security_service_get(
|
||||||
|
context, new_security_service_id)
|
||||||
|
|
||||||
|
current_security_service = None
|
||||||
|
if current_security_service_id:
|
||||||
|
current_security_service = self.db.security_service_get(
|
||||||
|
context, current_security_service_id)
|
||||||
|
|
||||||
|
new_ss_type = new_security_service['type']
|
||||||
|
backend_details_data = {
|
||||||
|
'name': new_security_service['name'],
|
||||||
|
'ou': new_security_service['ou'],
|
||||||
|
'domain': new_security_service['domain'],
|
||||||
|
'server': new_security_service['server'],
|
||||||
|
'dns_ip': new_security_service['dns_ip'],
|
||||||
|
'user': new_security_service['user'],
|
||||||
|
'type': new_ss_type,
|
||||||
|
'password': new_security_service['password'],
|
||||||
|
}
|
||||||
|
|
||||||
|
share_network = self.db.share_network_get(
|
||||||
|
context, share_network_id)
|
||||||
|
|
||||||
|
share_servers = self.db.share_server_get_all_by_host(
|
||||||
|
context, self.host,
|
||||||
|
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)
|
||||||
|
network_info = self._form_server_setup_info(
|
||||||
|
context, share_server, share_network, share_network_subnet)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Only check if the driver supports this kind of update.
|
||||||
|
if check_only:
|
||||||
|
if self.driver.check_update_share_server_security_service(
|
||||||
|
context, share_server, network_info,
|
||||||
|
share_instances, share_instances_rules,
|
||||||
|
new_security_service,
|
||||||
|
current_security_service=current_security_service):
|
||||||
|
# Check the next share server.
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# At least one share server doesn't support this update
|
||||||
|
return False
|
||||||
|
|
||||||
|
# NOTE(dviroel): We always do backend details update since it
|
||||||
|
# should be the expected configuration for this share server. Any
|
||||||
|
# issue with this operation should be fixed by the admin which will
|
||||||
|
# guarantee that storage and backend_details configurations match.
|
||||||
|
self.db.share_server_backend_details_set(
|
||||||
|
context, share_server['id'],
|
||||||
|
{'security_service_' + new_ss_type: jsonutils.dumps(
|
||||||
|
backend_details_data)})
|
||||||
|
try:
|
||||||
|
updates = self.driver.update_share_server_security_service(
|
||||||
|
context, share_server, network_info,
|
||||||
|
share_instances, share_instances_rules,
|
||||||
|
new_security_service,
|
||||||
|
current_security_service=current_security_service) or {}
|
||||||
|
except Exception:
|
||||||
|
operation = 'add'
|
||||||
|
sec_serv_info = ('new security service %s'
|
||||||
|
% new_security_service_id)
|
||||||
|
if current_security_service_id:
|
||||||
|
operation = 'update'
|
||||||
|
sec_serv_info = ('current security service %s and '
|
||||||
|
% current_security_service_id +
|
||||||
|
sec_serv_info)
|
||||||
|
msg = _("Share server %(server_id)s has failed on security "
|
||||||
|
"service %(operation)s operation for "
|
||||||
|
"%(sec_serv_ids)s.") % {
|
||||||
|
'server_id': share_server['id'],
|
||||||
|
'operation': operation,
|
||||||
|
'sec_serv_ids': sec_serv_info,
|
||||||
|
}
|
||||||
|
LOG.exception(msg)
|
||||||
|
# Set share server to error. Security service configuration
|
||||||
|
# must be fixed before restoring it to active again.
|
||||||
|
self.db.share_server_update(
|
||||||
|
context, share_server['id'],
|
||||||
|
{'status': constants.STATUS_ERROR})
|
||||||
|
|
||||||
|
if current_security_service:
|
||||||
|
# NOTE(dviroel): An already configured security service has
|
||||||
|
# failed on update operation. We will set all share
|
||||||
|
# instances to 'error'.
|
||||||
|
if share_instance_ids:
|
||||||
|
self.db.share_instances_status_update(
|
||||||
|
context, share_instance_ids,
|
||||||
|
{'status': constants.STATUS_ERROR})
|
||||||
|
# Update share instance access rules status
|
||||||
|
(self.access_helper
|
||||||
|
.update_share_instances_access_rules_status(
|
||||||
|
context, constants.SHARE_INSTANCE_RULES_ERROR,
|
||||||
|
share_instance_ids))
|
||||||
|
# Go to the next share server
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Update access rules based on drivers updates
|
||||||
|
for instance_id, rules_updates in updates.items():
|
||||||
|
self.access_helper.process_driver_rule_updates(
|
||||||
|
context, rules_updates, instance_id)
|
||||||
|
|
||||||
|
msg = _("Security service 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})
|
||||||
|
|
||||||
|
if check_only:
|
||||||
|
# All share servers support the requested update
|
||||||
|
return True
|
||||||
|
|
||||||
|
# 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'])
|
||||||
|
|
||||||
|
def update_share_network_security_service(
|
||||||
|
self, context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=None):
|
||||||
|
self._update_share_network_security_service(
|
||||||
|
context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id,
|
||||||
|
check_only=False)
|
||||||
|
|
||||||
|
def check_update_share_network_security_service(
|
||||||
|
self, context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=None):
|
||||||
|
is_supported = self._update_share_network_security_service(
|
||||||
|
context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id,
|
||||||
|
check_only=True)
|
||||||
|
self._update_share_network_security_service_operations(
|
||||||
|
context, share_network_id, is_supported,
|
||||||
|
new_security_service_id=new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id)
|
||||||
|
|
||||||
|
@api.locked_security_service_update_operation
|
||||||
|
def _update_share_network_security_service_operations(
|
||||||
|
self, context, share_network_id, is_supported,
|
||||||
|
new_security_service_id=None,
|
||||||
|
current_security_service_id=None):
|
||||||
|
update_check_key = self.share_api.get_security_service_update_key(
|
||||||
|
'hosts_check', new_security_service_id,
|
||||||
|
current_security_service_id)
|
||||||
|
current_hosts_info = self.db.async_operation_data_get(
|
||||||
|
context, share_network_id, update_check_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_check_key: json.dumps(current_hosts)})
|
||||||
|
else:
|
||||||
|
LOG.debug('A share network security service check was requested '
|
||||||
|
'but no entries were found in database. Ignoring call '
|
||||||
|
'and returning.')
|
||||||
|
@ -79,6 +79,8 @@ class ShareAPI(object):
|
|||||||
1.20 - Add share_instance_id parameter for create_share_server() method
|
1.20 - Add share_instance_id parameter for create_share_server() method
|
||||||
1.21 - Add share_server_migration_start, share_server_migration_check()
|
1.21 - Add share_server_migration_start, share_server_migration_check()
|
||||||
and share_server_get_progress()
|
and share_server_get_progress()
|
||||||
|
1.22 - Add update_share_network_security_service() and
|
||||||
|
check_update_share_network_security_service()
|
||||||
"""
|
"""
|
||||||
|
|
||||||
BASE_RPC_API_VERSION = '1.0'
|
BASE_RPC_API_VERSION = '1.0'
|
||||||
@ -87,7 +89,7 @@ class ShareAPI(object):
|
|||||||
super(ShareAPI, self).__init__()
|
super(ShareAPI, self).__init__()
|
||||||
target = messaging.Target(topic=CONF.share_topic,
|
target = messaging.Target(topic=CONF.share_topic,
|
||||||
version=self.BASE_RPC_API_VERSION)
|
version=self.BASE_RPC_API_VERSION)
|
||||||
self.client = rpc.get_client(target, version_cap='1.21')
|
self.client = rpc.get_client(target, version_cap='1.22')
|
||||||
|
|
||||||
def create_share_instance(self, context, share_instance, host,
|
def create_share_instance(self, context, share_instance, host,
|
||||||
request_spec, filter_properties,
|
request_spec, filter_properties,
|
||||||
@ -436,3 +438,27 @@ class ShareAPI(object):
|
|||||||
call_context.cast(context,
|
call_context.cast(context,
|
||||||
'snapshot_update_access',
|
'snapshot_update_access',
|
||||||
snapshot_instance_id=snapshot_instance['id'])
|
snapshot_instance_id=snapshot_instance['id'])
|
||||||
|
|
||||||
|
def update_share_network_security_service(
|
||||||
|
self, context, dest_host, share_network_id,
|
||||||
|
new_security_service_id, current_security_service_id=None):
|
||||||
|
host = utils.extract_host(dest_host)
|
||||||
|
call_context = self.client.prepare(server=host, version='1.22')
|
||||||
|
call_context.cast(
|
||||||
|
context,
|
||||||
|
'update_share_network_security_service',
|
||||||
|
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_network_security_service(
|
||||||
|
self, context, dest_host, share_network_id,
|
||||||
|
new_security_service_id, current_security_service_id=None):
|
||||||
|
host = utils.extract_host(dest_host)
|
||||||
|
call_context = self.client.prepare(server=host, version='1.22')
|
||||||
|
call_context.cast(
|
||||||
|
context,
|
||||||
|
'check_update_share_network_security_service',
|
||||||
|
share_network_id=share_network_id,
|
||||||
|
new_security_service_id=new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id)
|
||||||
|
@ -23,6 +23,7 @@ from oslo_utils import excutils
|
|||||||
from oslo_utils import strutils
|
from oslo_utils import strutils
|
||||||
import six
|
import six
|
||||||
|
|
||||||
|
from manila.api import common as api_common
|
||||||
from manila.common import constants
|
from manila.common import constants
|
||||||
from manila.db import base
|
from manila.db import base
|
||||||
from manila import exception
|
from manila import exception
|
||||||
@ -109,13 +110,19 @@ class API(base.Base):
|
|||||||
"False, a share_network_id must not be provided.")
|
"False, a share_network_id must not be provided.")
|
||||||
raise exception.InvalidInput(reason=msg)
|
raise exception.InvalidInput(reason=msg)
|
||||||
|
|
||||||
|
share_network = {}
|
||||||
try:
|
try:
|
||||||
if share_network_id:
|
if share_network_id:
|
||||||
self.db.share_network_get(context, share_network_id)
|
share_network = self.db.share_network_get(
|
||||||
|
context, share_network_id)
|
||||||
except exception.ShareNetworkNotFound:
|
except exception.ShareNetworkNotFound:
|
||||||
msg = _("The specified share network does not exist.")
|
msg = _("The specified share network does not exist.")
|
||||||
raise exception.InvalidInput(reason=msg)
|
raise exception.InvalidInput(reason=msg)
|
||||||
|
|
||||||
|
if share_network:
|
||||||
|
# Check if share network is active, otherwise raise a BadRequest
|
||||||
|
api_common.check_share_network_is_active(share_network)
|
||||||
|
|
||||||
if (driver_handles_share_servers and
|
if (driver_handles_share_servers and
|
||||||
not (source_share_group_snapshot_id or share_network_id)):
|
not (source_share_group_snapshot_id or share_network_id)):
|
||||||
msg = _("When using a share type with the "
|
msg = _("When using a share type with the "
|
||||||
|
@ -42,7 +42,8 @@ fake_share_server_list = {
|
|||||||
'is_auto_deletable': False,
|
'is_auto_deletable': False,
|
||||||
'task_state': None,
|
'task_state': None,
|
||||||
'source_share_server_id': None,
|
'source_share_server_id': None,
|
||||||
'identifier': 'fake_id'
|
'identifier': 'fake_id',
|
||||||
|
'security_service_update_support': False
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'status': constants.STATUS_ERROR,
|
'status': constants.STATUS_ERROR,
|
||||||
@ -56,7 +57,9 @@ fake_share_server_list = {
|
|||||||
'is_auto_deletable': True,
|
'is_auto_deletable': True,
|
||||||
'task_state': None,
|
'task_state': None,
|
||||||
'source_share_server_id': None,
|
'source_share_server_id': None,
|
||||||
'identifier': 'fake_id_2'
|
'identifier': 'fake_id_2',
|
||||||
|
'security_service_update_support': False
|
||||||
|
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@ -94,7 +97,8 @@ fake_share_server_get_result = {
|
|||||||
'is_auto_deletable': False,
|
'is_auto_deletable': False,
|
||||||
'task_state': None,
|
'task_state': None,
|
||||||
'source_share_server_id': None,
|
'source_share_server_id': None,
|
||||||
'identifier': 'fake_id'
|
'identifier': 'fake_id',
|
||||||
|
'security_service_update_support': False
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +135,8 @@ class FakeShareServer(object):
|
|||||||
self.task_state = kwargs.get('task_state')
|
self.task_state = kwargs.get('task_state')
|
||||||
self.source_share_server_id = kwargs.get('source_share_server_id')
|
self.source_share_server_id = kwargs.get('source_share_server_id')
|
||||||
self.backend_details = share_server_backend_details
|
self.backend_details = share_server_backend_details
|
||||||
|
self.security_service_update_support = kwargs.get(
|
||||||
|
'security_service_update_support', False)
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
return getattr(self, item)
|
return getattr(self, item)
|
||||||
@ -148,7 +154,8 @@ def fake_share_server_get_all():
|
|||||||
identifier='fake_id_2',
|
identifier='fake_id_2',
|
||||||
task_state=None,
|
task_state=None,
|
||||||
is_auto_deletable=True,
|
is_auto_deletable=True,
|
||||||
status=constants.STATUS_ERROR)
|
status=constants.STATUS_ERROR,
|
||||||
|
security_service_update_support=False)
|
||||||
]
|
]
|
||||||
return fake_share_servers
|
return fake_share_servers
|
||||||
|
|
||||||
|
@ -228,6 +228,7 @@ class ShareAPITest(test.TestCase):
|
|||||||
"availability_zone": "zone1:host1",
|
"availability_zone": "zone1:host1",
|
||||||
"share_network_id": "fakenetid"
|
"share_network_id": "fakenetid"
|
||||||
}
|
}
|
||||||
|
fake_network = {'id': 'fakenetid'}
|
||||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||||
display_name=shr['name'],
|
display_name=shr['name'],
|
||||||
display_description=shr['description'],
|
display_description=shr['description'],
|
||||||
@ -237,7 +238,9 @@ class ShareAPITest(test.TestCase):
|
|||||||
share_network_id=shr['share_network_id']))
|
share_network_id=shr['share_network_id']))
|
||||||
self.mock_object(share_api.API, 'create', create_mock)
|
self.mock_object(share_api.API, 'create', create_mock)
|
||||||
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
||||||
return_value={'id': 'fakenetid'}))
|
return_value=fake_network))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
db, 'share_network_subnet_get_by_availability_zone_id',
|
db, 'share_network_subnet_get_by_availability_zone_id',
|
||||||
mock.Mock(return_value={'id': 'fakesubnetid'}))
|
mock.Mock(return_value={'id': 'fakesubnetid'}))
|
||||||
@ -250,11 +253,50 @@ class ShareAPITest(test.TestCase):
|
|||||||
req.environ['manila.context'], self.resource_name, 'create')
|
req.environ['manila.context'], self.resource_name, 'create')
|
||||||
expected = self._get_expected_share_detailed_response(shr)
|
expected = self._get_expected_share_detailed_response(shr)
|
||||||
expected['share'].pop('snapshot_support')
|
expected['share'].pop('snapshot_support')
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
fake_network)
|
||||||
self.assertEqual(expected, res_dict)
|
self.assertEqual(expected, res_dict)
|
||||||
# pylint: disable=unsubscriptable-object
|
# pylint: disable=unsubscriptable-object
|
||||||
self.assertEqual("fakenetid",
|
self.assertEqual("fakenetid",
|
||||||
create_mock.call_args[1]['share_network_id'])
|
create_mock.call_args[1]['share_network_id'])
|
||||||
|
|
||||||
|
def test_share_create_with_share_net_not_active(self):
|
||||||
|
shr = {
|
||||||
|
"size": 100,
|
||||||
|
"name": "Share Test Name",
|
||||||
|
"description": "Share Test Desc",
|
||||||
|
"share_proto": "fakeproto",
|
||||||
|
"availability_zone": "zone1:host1",
|
||||||
|
"share_network_id": "fakenetid"
|
||||||
|
}
|
||||||
|
share_network = db_utils.create_share_network(
|
||||||
|
status=constants.STATUS_NETWORK_CHANGE)
|
||||||
|
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||||
|
display_name=shr['name'],
|
||||||
|
display_description=shr['description'],
|
||||||
|
size=shr['size'],
|
||||||
|
share_proto=shr['share_proto'].upper(),
|
||||||
|
availability_zone=shr['availability_zone'],
|
||||||
|
share_network_id=shr['share_network_id']))
|
||||||
|
self.mock_object(share_api.API, 'create', create_mock)
|
||||||
|
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
||||||
|
return_value=share_network))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(side_effect=webob.exc.HTTPBadRequest()))
|
||||||
|
|
||||||
|
body = {"share": copy.deepcopy(shr)}
|
||||||
|
req = fakes.HTTPRequest.blank('/shares')
|
||||||
|
self.assertRaises(
|
||||||
|
webob.exc.HTTPBadRequest,
|
||||||
|
self.controller.create,
|
||||||
|
req,
|
||||||
|
body)
|
||||||
|
|
||||||
|
self.mock_policy_check.assert_called_once_with(
|
||||||
|
req.environ['manila.context'], self.resource_name, 'create')
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
share_network)
|
||||||
|
|
||||||
def test_share_create_from_snapshot_without_share_net_no_parent(self):
|
def test_share_create_from_snapshot_without_share_net_no_parent(self):
|
||||||
shr = {
|
shr = {
|
||||||
"size": 100,
|
"size": 100,
|
||||||
@ -296,6 +338,7 @@ class ShareAPITest(test.TestCase):
|
|||||||
"share_network_id": None,
|
"share_network_id": None,
|
||||||
}
|
}
|
||||||
parent_share_net = 444
|
parent_share_net = 444
|
||||||
|
fake_share_net = {'id': parent_share_net}
|
||||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||||
display_name=shr['name'],
|
display_name=shr['name'],
|
||||||
display_description=shr['description'],
|
display_description=shr['description'],
|
||||||
@ -314,7 +357,9 @@ class ShareAPITest(test.TestCase):
|
|||||||
self.mock_object(share_api.API, 'get', mock.Mock(
|
self.mock_object(share_api.API, 'get', mock.Mock(
|
||||||
return_value=parent_share))
|
return_value=parent_share))
|
||||||
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
||||||
return_value={'id': parent_share_net}))
|
return_value=fake_share_net))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||||
|
|
||||||
@ -327,6 +372,8 @@ class ShareAPITest(test.TestCase):
|
|||||||
req.environ['manila.context'], self.resource_name, 'create')
|
req.environ['manila.context'], self.resource_name, 'create')
|
||||||
expected = self._get_expected_share_detailed_response(shr)
|
expected = self._get_expected_share_detailed_response(shr)
|
||||||
expected['share'].pop('snapshot_support')
|
expected['share'].pop('snapshot_support')
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
fake_share_net)
|
||||||
self.assertEqual(expected, res_dict)
|
self.assertEqual(expected, res_dict)
|
||||||
# pylint: disable=unsubscriptable-object
|
# pylint: disable=unsubscriptable-object
|
||||||
self.assertEqual(parent_share_net,
|
self.assertEqual(parent_share_net,
|
||||||
@ -343,6 +390,7 @@ class ShareAPITest(test.TestCase):
|
|||||||
"snapshot_id": 333,
|
"snapshot_id": 333,
|
||||||
"share_network_id": parent_share_net
|
"share_network_id": parent_share_net
|
||||||
}
|
}
|
||||||
|
fake_share_net = {'id': parent_share_net}
|
||||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||||
display_name=shr['name'],
|
display_name=shr['name'],
|
||||||
display_description=shr['description'],
|
display_description=shr['description'],
|
||||||
@ -355,13 +403,15 @@ class ShareAPITest(test.TestCase):
|
|||||||
self.mock_object(share_api.API, 'create', create_mock)
|
self.mock_object(share_api.API, 'create', create_mock)
|
||||||
self.mock_object(share_api.API, 'get_snapshot',
|
self.mock_object(share_api.API, 'get_snapshot',
|
||||||
stubs.stub_snapshot_get)
|
stubs.stub_snapshot_get)
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
parent_share = stubs.stub_share(
|
parent_share = stubs.stub_share(
|
||||||
'1', instance={'share_network_id': parent_share_net},
|
'1', instance={'share_network_id': parent_share_net},
|
||||||
create_share_from_snapshot_support=True)
|
create_share_from_snapshot_support=True)
|
||||||
self.mock_object(share_api.API, 'get', mock.Mock(
|
self.mock_object(share_api.API, 'get', mock.Mock(
|
||||||
return_value=parent_share))
|
return_value=parent_share))
|
||||||
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
||||||
return_value={'id': parent_share_net}))
|
return_value=fake_share_net))
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||||
|
|
||||||
@ -374,6 +424,8 @@ class ShareAPITest(test.TestCase):
|
|||||||
req.environ['manila.context'], self.resource_name, 'create')
|
req.environ['manila.context'], self.resource_name, 'create')
|
||||||
expected = self._get_expected_share_detailed_response(shr)
|
expected = self._get_expected_share_detailed_response(shr)
|
||||||
expected['share'].pop('snapshot_support')
|
expected['share'].pop('snapshot_support')
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
fake_share_net)
|
||||||
self.assertEqual(expected, res_dict)
|
self.assertEqual(expected, res_dict)
|
||||||
# pylint: disable=unsubscriptable-object
|
# pylint: disable=unsubscriptable-object
|
||||||
self.assertEqual(parent_share_net,
|
self.assertEqual(parent_share_net,
|
||||||
@ -415,6 +467,7 @@ class ShareAPITest(test.TestCase):
|
|||||||
"snapshot_id": 333,
|
"snapshot_id": 333,
|
||||||
"share_network_id": parent_share_net
|
"share_network_id": parent_share_net
|
||||||
}
|
}
|
||||||
|
fake_share_net = {'id': parent_share_net}
|
||||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||||
display_name=shr['name'],
|
display_name=shr['name'],
|
||||||
display_description=shr['description'],
|
display_description=shr['description'],
|
||||||
@ -427,13 +480,15 @@ class ShareAPITest(test.TestCase):
|
|||||||
self.mock_object(share_api.API, 'create', create_mock)
|
self.mock_object(share_api.API, 'create', create_mock)
|
||||||
self.mock_object(share_api.API, 'get_snapshot',
|
self.mock_object(share_api.API, 'get_snapshot',
|
||||||
stubs.stub_snapshot_get)
|
stubs.stub_snapshot_get)
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
parent_share = stubs.stub_share(
|
parent_share = stubs.stub_share(
|
||||||
'1', instance={'share_network_id': parent_share_net},
|
'1', instance={'share_network_id': parent_share_net},
|
||||||
create_share_from_snapshot_support=False)
|
create_share_from_snapshot_support=False)
|
||||||
self.mock_object(share_api.API, 'get', mock.Mock(
|
self.mock_object(share_api.API, 'get', mock.Mock(
|
||||||
return_value=parent_share))
|
return_value=parent_share))
|
||||||
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
||||||
return_value={'id': parent_share_net}))
|
return_value=fake_share_net))
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||||
|
|
||||||
@ -446,6 +501,8 @@ class ShareAPITest(test.TestCase):
|
|||||||
req.environ['manila.context'], self.resource_name, 'create')
|
req.environ['manila.context'], self.resource_name, 'create')
|
||||||
expected = self._get_expected_share_detailed_response(shr)
|
expected = self._get_expected_share_detailed_response(shr)
|
||||||
expected['share'].pop('snapshot_support')
|
expected['share'].pop('snapshot_support')
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
fake_share_net)
|
||||||
self.assertDictEqual(expected, res_dict)
|
self.assertDictEqual(expected, res_dict)
|
||||||
# pylint: disable=unsubscriptable-object
|
# pylint: disable=unsubscriptable-object
|
||||||
self.assertEqual(parent_share_net,
|
self.assertEqual(parent_share_net,
|
||||||
@ -503,6 +560,7 @@ class ShareAPITest(test.TestCase):
|
|||||||
self.mock_object(
|
self.mock_object(
|
||||||
db, 'share_network_subnet_get_by_availability_zone_id',
|
db, 'share_network_subnet_get_by_availability_zone_id',
|
||||||
mock.Mock(return_value=None))
|
mock.Mock(return_value=None))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active')
|
||||||
|
|
||||||
body = {"share": fake_share_with_sn}
|
body = {"share": fake_share_with_sn}
|
||||||
|
|
||||||
@ -903,6 +961,29 @@ class ShareActionsTest(test.TestCase):
|
|||||||
self.mock_policy_check.assert_called_once_with(
|
self.mock_policy_check.assert_called_once_with(
|
||||||
req.environ['manila.context'], 'share', 'allow_access')
|
req.environ['manila.context'], 'share', 'allow_access')
|
||||||
|
|
||||||
|
def test_allow_access_with_network_id(self):
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
share = db_utils.create_share(share_network_id=share_network['id'])
|
||||||
|
access = {'access_type': 'user', 'access_to': '1' * 4}
|
||||||
|
|
||||||
|
self.mock_object(share_api.API,
|
||||||
|
'allow_access',
|
||||||
|
mock.Mock(return_value={'fake': 'fake'}))
|
||||||
|
self.mock_object(self.controller._access_view_builder, 'view',
|
||||||
|
mock.Mock(return_value={'access': {'fake': 'fake'}}))
|
||||||
|
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
|
||||||
|
|
||||||
|
id = 'fake_share_id'
|
||||||
|
body = {'os-allow_access': access}
|
||||||
|
expected = {'access': {'fake': 'fake'}}
|
||||||
|
req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id)
|
||||||
|
|
||||||
|
res = self.controller._allow_access(req, id, body)
|
||||||
|
|
||||||
|
self.assertEqual(expected, res)
|
||||||
|
self.mock_policy_check.assert_called_once_with(
|
||||||
|
req.environ['manila.context'], 'share', 'allow_access')
|
||||||
|
|
||||||
@ddt.data(
|
@ddt.data(
|
||||||
{'access_type': 'error_type', 'access_to': '127.0.0.1'},
|
{'access_type': 'error_type', 'access_to': '127.0.0.1'},
|
||||||
{'access_type': 'ip', 'access_to': 'localhost'},
|
{'access_type': 'ip', 'access_to': 'localhost'},
|
||||||
@ -947,6 +1028,23 @@ class ShareActionsTest(test.TestCase):
|
|||||||
self.mock_policy_check.assert_called_once_with(
|
self.mock_policy_check.assert_called_once_with(
|
||||||
req.environ['manila.context'], 'share', 'deny_access')
|
req.environ['manila.context'], 'share', 'deny_access')
|
||||||
|
|
||||||
|
def test_deny_access_with_share_network_id(self):
|
||||||
|
self.mock_object(share_api.API, "deny_access", mock.Mock())
|
||||||
|
self.mock_object(share_api.API, "access_get", _fake_access_get)
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
share = db_utils.create_share(share_network_id=share_network['id'])
|
||||||
|
self.mock_object(share_api.API, 'get', mock.Mock(return_value=share))
|
||||||
|
|
||||||
|
id = 'fake_share_id'
|
||||||
|
body = {"os-deny_access": {"access_id": 'fake_acces_id'}}
|
||||||
|
req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id)
|
||||||
|
|
||||||
|
res = self.controller._deny_access(req, id, body)
|
||||||
|
|
||||||
|
self.assertEqual(202, res.status_int)
|
||||||
|
self.mock_policy_check.assert_called_once_with(
|
||||||
|
req.environ['manila.context'], 'share', 'deny_access')
|
||||||
|
|
||||||
def test_deny_access_not_found(self):
|
def test_deny_access_not_found(self):
|
||||||
def _stub_deny_access(*args, **kwargs):
|
def _stub_deny_access(*args, **kwargs):
|
||||||
pass
|
pass
|
||||||
|
@ -28,8 +28,10 @@ from manila.api.v2 import share_networks
|
|||||||
from manila.db import api as db_api
|
from manila.db import api as db_api
|
||||||
from manila import exception
|
from manila import exception
|
||||||
from manila import quota
|
from manila import quota
|
||||||
|
from manila.share import api as share_api
|
||||||
from manila import test
|
from manila import test
|
||||||
from manila.tests.api import fakes
|
from manila.tests.api import fakes
|
||||||
|
from manila.tests import db_utils
|
||||||
|
|
||||||
|
|
||||||
fake_share_network_subnet = {
|
fake_share_network_subnet = {
|
||||||
@ -54,7 +56,9 @@ fake_share_network = {
|
|||||||
'name': 'fake name',
|
'name': 'fake name',
|
||||||
'description': 'fake description',
|
'description': 'fake description',
|
||||||
'security_services': [],
|
'security_services': [],
|
||||||
'share_network_subnets': []
|
'share_network_subnets': [],
|
||||||
|
'security_service_update_support': True,
|
||||||
|
'status': 'active'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -79,6 +83,8 @@ fake_sn_with_ss_shortened = {
|
|||||||
'name': 'test-sn',
|
'name': 'test-sn',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ADD_UPDATE_SEC_SERVICE_VERSION = '2.63'
|
||||||
|
|
||||||
QUOTAS = quota.QUOTAS
|
QUOTAS = quota.QUOTAS
|
||||||
|
|
||||||
|
|
||||||
@ -91,6 +97,7 @@ class ShareNetworkAPITest(test.TestCase):
|
|||||||
self.req = fakes.HTTPRequest.blank('/share-networks')
|
self.req = fakes.HTTPRequest.blank('/share-networks')
|
||||||
self.body = {share_networks.RESOURCE_NAME: {'name': 'fake name'}}
|
self.body = {share_networks.RESOURCE_NAME: {'name': 'fake name'}}
|
||||||
self.context = self.req.environ['manila.context']
|
self.context = self.req.environ['manila.context']
|
||||||
|
self.share_api = share_api.API()
|
||||||
|
|
||||||
def _check_share_network_view_shortened(self, view, share_nw):
|
def _check_share_network_view_shortened(self, view, share_nw):
|
||||||
self.assertEqual(share_nw['id'], view['id'])
|
self.assertEqual(share_nw['id'], view['id'])
|
||||||
@ -874,7 +881,7 @@ class ShareNetworkAPITest(test.TestCase):
|
|||||||
self.context, share_nw)
|
self.context, share_nw)
|
||||||
|
|
||||||
@ddt.data(*set(("1.0", "2.25", "2.26", api_version._MAX_API_VERSION)))
|
@ddt.data(*set(("1.0", "2.25", "2.26", api_version._MAX_API_VERSION)))
|
||||||
def test_action_add_security_service(self, microversion):
|
def test_add_security_service(self, microversion):
|
||||||
share_network_id = 'fake network id'
|
share_network_id = 'fake network id'
|
||||||
security_service_id = 'fake ss id'
|
security_service_id = 'fake ss id'
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
@ -884,15 +891,123 @@ class ShareNetworkAPITest(test.TestCase):
|
|||||||
security_service_id}}
|
security_service_id}}
|
||||||
|
|
||||||
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
|
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
|
||||||
with mock.patch.object(self.controller, '_add_security_service',
|
with mock.patch.object(self.controller, 'add_security_service',
|
||||||
mock.Mock()):
|
mock.Mock()):
|
||||||
self.controller.action(req, share_network_id, body)
|
self.controller.add_security_service(req, share_network_id, body)
|
||||||
self.controller._add_security_service.assert_called_once_with(
|
self.controller.add_security_service.assert_called_once_with(
|
||||||
req, share_network_id, body['add_security_service'])
|
req, share_network_id, body)
|
||||||
|
|
||||||
@mock.patch.object(db_api, 'share_network_get', mock.Mock())
|
def _setup_add_sec_services_with_servers_tests(
|
||||||
@mock.patch.object(db_api, 'security_service_get', mock.Mock())
|
self, share_network, security_service, network_is_active=True,
|
||||||
def test_action_add_security_service_conflict(self):
|
version=ADD_UPDATE_SEC_SERVICE_VERSION,
|
||||||
|
share_api_update_services_action=mock.Mock()):
|
||||||
|
self.mock_object(
|
||||||
|
db_api, 'share_network_get', mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(
|
||||||
|
db_api, 'security_service_get',
|
||||||
|
mock.Mock(return_value=security_service))
|
||||||
|
self.mock_object(
|
||||||
|
self.controller, '_share_network_subnets_contain_share_servers',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
|
self.mock_object(
|
||||||
|
self.controller.share_api, 'update_share_network_security_service',
|
||||||
|
share_api_update_services_action)
|
||||||
|
self.mock_object(
|
||||||
|
common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=network_is_active))
|
||||||
|
self.mock_object(db_api, 'share_network_add_security_service')
|
||||||
|
self.mock_object(self.controller._view_builder, 'build_share_network')
|
||||||
|
|
||||||
|
body = {
|
||||||
|
'add_security_service': {
|
||||||
|
'security_service_id': security_service['id']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/add_security_service', version=version, use_admin_context=True)
|
||||||
|
context = req.environ['manila.context']
|
||||||
|
|
||||||
|
return req, context, body
|
||||||
|
|
||||||
|
def test_add_security_service_with_servers(self):
|
||||||
|
security_service = db_utils.create_security_service()
|
||||||
|
security_service_id = security_service['id']
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
share_network_id = share_network['id']
|
||||||
|
req, context, body = self._setup_add_sec_services_with_servers_tests(
|
||||||
|
share_network, security_service)
|
||||||
|
|
||||||
|
self.controller.add_security_service(req, share_network_id, body)
|
||||||
|
|
||||||
|
db_api.security_service_get.assert_called_once_with(
|
||||||
|
context, security_service_id)
|
||||||
|
(self.controller._share_network_subnets_contain_share_servers.
|
||||||
|
assert_called_once_with(share_network))
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network_id)
|
||||||
|
(self.controller.share_api.update_share_network_security_service.
|
||||||
|
assert_called_once_with(context, share_network, security_service))
|
||||||
|
|
||||||
|
def test_add_security_service_with_server_invalid_version(self):
|
||||||
|
security_service = db_utils.create_security_service()
|
||||||
|
security_service_id = security_service['id']
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
share_network_id = share_network['id']
|
||||||
|
req, context, body = self._setup_add_sec_services_with_servers_tests(
|
||||||
|
share_network, security_service, version='2.59')
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
webob_exc.HTTPForbidden,
|
||||||
|
self.controller.add_security_service,
|
||||||
|
req, share_network_id, body
|
||||||
|
)
|
||||||
|
|
||||||
|
db_api.security_service_get.assert_called_once_with(
|
||||||
|
context, security_service_id)
|
||||||
|
(self.controller._share_network_subnets_contain_share_servers.
|
||||||
|
assert_called_once_with(share_network))
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network_id)
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
(exception.ServiceIsDown(message='fake'), webob_exc.HTTPConflict),
|
||||||
|
(exception.InvalidShareNetwork(message='fake'),
|
||||||
|
webob_exc.HTTPBadRequest)
|
||||||
|
)
|
||||||
|
@ddt.unpack
|
||||||
|
def test_add_security_service_with_server_update_failed(
|
||||||
|
self, side_effect, exception_to_raise):
|
||||||
|
security_service = db_utils.create_security_service()
|
||||||
|
security_service_id = security_service['id']
|
||||||
|
share_network_id = fake_share_network['id']
|
||||||
|
fake_share_network['security_service_update_support'] = True
|
||||||
|
action = mock.Mock(side_effect=side_effect)
|
||||||
|
|
||||||
|
req, context, body = self._setup_add_sec_services_with_servers_tests(
|
||||||
|
fake_share_network, security_service,
|
||||||
|
share_api_update_services_action=action)
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception_to_raise,
|
||||||
|
self.controller.add_security_service,
|
||||||
|
req, share_network_id, body
|
||||||
|
)
|
||||||
|
|
||||||
|
db_api.security_service_get.assert_called_once_with(
|
||||||
|
context, security_service_id)
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network_id)
|
||||||
|
(self.controller.share_api.update_share_network_security_service.
|
||||||
|
assert_called_once_with(context, fake_share_network,
|
||||||
|
security_service))
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
(exception.NotFound(message='fake'), webob_exc.HTTPNotFound),
|
||||||
|
(exception.ShareNetworkSecurityServiceAssociationError(message='fake'),
|
||||||
|
webob_exc.HTTPBadRequest))
|
||||||
|
@ddt.unpack
|
||||||
|
def test_action_add_security_service_conflict(self, captured_exception,
|
||||||
|
expected_raised_exception):
|
||||||
share_network = fake_share_network.copy()
|
share_network = fake_share_network.copy()
|
||||||
share_network['security_services'] = [{'id': 'security_service_1',
|
share_network['security_services'] = [{'id': 'security_service_1',
|
||||||
'type': 'ldap'}]
|
'type': 'ldap'}]
|
||||||
@ -900,28 +1015,148 @@ class ShareNetworkAPITest(test.TestCase):
|
|||||||
'type': 'ldap'}
|
'type': 'ldap'}
|
||||||
body = {'add_security_service': {'security_service_id':
|
body = {'add_security_service': {'security_service_id':
|
||||||
security_service['id']}}
|
security_service['id']}}
|
||||||
|
request = fakes.HTTPRequest.blank(
|
||||||
|
'/share-networks', use_admin_context=True)
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
self.controller, '_share_network_subnets_contain_share_servers',
|
self.controller, '_share_network_subnets_contain_share_servers',
|
||||||
mock.Mock(return_value=False))
|
mock.Mock(return_value=False))
|
||||||
|
update_sec_serv_mock = self.mock_object(
|
||||||
|
self.controller.share_api, 'update_share_network_security_service')
|
||||||
|
self.mock_object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(db_api, 'security_service_get',
|
||||||
|
mock.Mock(return_value=security_service))
|
||||||
|
self.mock_object(share_networks.policy, 'check_policy')
|
||||||
|
self.mock_object(
|
||||||
|
db_api, 'share_network_add_security_service',
|
||||||
|
mock.Mock(side_effect=captured_exception))
|
||||||
|
|
||||||
db_api.security_service_get.return_value = security_service
|
db_api.security_service_get.return_value = security_service
|
||||||
db_api.share_network_get.return_value = share_network
|
db_api.share_network_get.return_value = share_network
|
||||||
with mock.patch.object(share_networks.policy, 'check_policy',
|
self.assertRaises(expected_raised_exception,
|
||||||
mock.Mock()):
|
self.controller.add_security_service,
|
||||||
self.assertRaises(webob_exc.HTTPConflict,
|
request,
|
||||||
self.controller.action,
|
share_network['id'],
|
||||||
self.req,
|
body)
|
||||||
share_network['id'],
|
|
||||||
body)
|
db_api.share_network_get.assert_called_once_with(
|
||||||
db_api.share_network_get.assert_called_once_with(
|
request.environ['manila.context'], share_network['id'])
|
||||||
self.req.environ['manila.context'], share_network['id'])
|
db_api.security_service_get.assert_called_once_with(
|
||||||
db_api.security_service_get.assert_called_once_with(
|
request.environ['manila.context'], security_service['id'])
|
||||||
self.req.environ['manila.context'], security_service['id'])
|
share_networks.policy.check_policy.assert_called_once_with(
|
||||||
share_networks.policy.check_policy.assert_called_once_with(
|
request.environ['manila.context'],
|
||||||
self.req.environ['manila.context'],
|
share_networks.RESOURCE_NAME,
|
||||||
share_networks.RESOURCE_NAME,
|
'add_security_service', target_obj=share_network)
|
||||||
'add_security_service',
|
update_sec_serv_mock.assert_called_once_with(
|
||||||
)
|
request.environ['manila.context'], share_network,
|
||||||
|
security_service)
|
||||||
|
|
||||||
|
def _setup_update_sec_services_with_servers_tests(
|
||||||
|
self, share_network, security_services,
|
||||||
|
version=ADD_UPDATE_SEC_SERVICE_VERSION,
|
||||||
|
share_api_update_services_action=mock.Mock()):
|
||||||
|
|
||||||
|
self.mock_object(
|
||||||
|
db_api, 'share_network_get', mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(
|
||||||
|
db_api, 'security_service_get',
|
||||||
|
mock.Mock(side_effect=security_services))
|
||||||
|
self.mock_object(
|
||||||
|
self.controller.share_api, 'update_share_network_security_service',
|
||||||
|
share_api_update_services_action)
|
||||||
|
self.mock_object(self.controller._view_builder, 'build_share_network')
|
||||||
|
self.mock_object(db_api, 'share_network_update_security_service')
|
||||||
|
|
||||||
|
body = {
|
||||||
|
'update_security_service': {
|
||||||
|
'current_service_id': security_services[0]['id'],
|
||||||
|
'new_service_id': security_services[1]['id']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/add_security_service', version=version, use_admin_context=True)
|
||||||
|
context = req.environ['manila.context']
|
||||||
|
|
||||||
|
return req, context, body
|
||||||
|
|
||||||
|
def test_update_security_service_service_not_found(self):
|
||||||
|
security_services = [
|
||||||
|
db_utils.create_security_service() for i in range(2)]
|
||||||
|
share_network = copy.deepcopy(fake_share_network)
|
||||||
|
share_network['security_service_update_support'] = True
|
||||||
|
|
||||||
|
req, context, body = (
|
||||||
|
self._setup_update_sec_services_with_servers_tests(
|
||||||
|
share_network, security_services))
|
||||||
|
|
||||||
|
db_api.security_service_get.side_effect = exception.NotFound('fake')
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
webob_exc.HTTPBadRequest,
|
||||||
|
self.controller.update_security_service,
|
||||||
|
req, share_network['id'], body)
|
||||||
|
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network['id'])
|
||||||
|
db_api.security_service_get.assert_has_calls(
|
||||||
|
[mock.call(context, security_services[0]['id'])]
|
||||||
|
)
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
(exception.ServiceIsDown(message='fake'), webob_exc.HTTPConflict),
|
||||||
|
(exception.InvalidShareNetwork(message='fake'),
|
||||||
|
webob_exc.HTTPBadRequest))
|
||||||
|
@ddt.unpack
|
||||||
|
def test_update_security_service_share_api_failure(self, side_effect, exc):
|
||||||
|
security_services = [
|
||||||
|
db_utils.create_security_service() for i in range(2)]
|
||||||
|
share_network = copy.deepcopy(fake_share_network)
|
||||||
|
share_network['security_service_update_support'] = True
|
||||||
|
|
||||||
|
req, context, body = (
|
||||||
|
self._setup_update_sec_services_with_servers_tests(
|
||||||
|
share_network, security_services,
|
||||||
|
share_api_update_services_action=mock.Mock(
|
||||||
|
side_effect=side_effect)))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exc,
|
||||||
|
self.controller.update_security_service,
|
||||||
|
req, share_network['id'], body)
|
||||||
|
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network['id'])
|
||||||
|
db_api.security_service_get.assert_has_calls(
|
||||||
|
[mock.call(context, security_services[0]['id']),
|
||||||
|
mock.call(context, security_services[1]['id'])]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_update_security_service(self):
|
||||||
|
security_services = [
|
||||||
|
db_utils.create_security_service() for i in range(2)]
|
||||||
|
share_network = copy.copy(fake_share_network)
|
||||||
|
share_network['security_service_update_support'] = True
|
||||||
|
|
||||||
|
req, context, body = (
|
||||||
|
self._setup_update_sec_services_with_servers_tests(
|
||||||
|
share_network, security_services))
|
||||||
|
|
||||||
|
self.controller.update_security_service(
|
||||||
|
req, share_network['id'], body)
|
||||||
|
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network['id'])
|
||||||
|
db_api.security_service_get.assert_has_calls(
|
||||||
|
[mock.call(context, security_services[0]['id']),
|
||||||
|
mock.call(context, security_services[1]['id'])]
|
||||||
|
)
|
||||||
|
(self.controller.share_api.update_share_network_security_service.
|
||||||
|
assert_called_once_with(
|
||||||
|
context, share_network, security_services[1],
|
||||||
|
current_security_service=security_services[0]))
|
||||||
|
db_api.share_network_update_security_service.assert_called_once_with(
|
||||||
|
context, share_network['id'], security_services[0]['id'],
|
||||||
|
security_services[1]['id'])
|
||||||
|
|
||||||
@ddt.data(*set(("1.0", "2.25", "2.26", api_version._MAX_API_VERSION)))
|
@ddt.data(*set(("1.0", "2.25", "2.26", api_version._MAX_API_VERSION)))
|
||||||
def test_action_remove_security_service(self, microversion):
|
def test_action_remove_security_service(self, microversion):
|
||||||
@ -933,11 +1168,12 @@ class ShareNetworkAPITest(test.TestCase):
|
|||||||
security_service_id}}
|
security_service_id}}
|
||||||
|
|
||||||
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
|
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
|
||||||
with mock.patch.object(self.controller, '_remove_security_service',
|
with mock.patch.object(self.controller, 'remove_security_service',
|
||||||
mock.Mock()):
|
mock.Mock()):
|
||||||
self.controller.action(req, share_network_id, body)
|
self.controller.remove_security_service(
|
||||||
self.controller._remove_security_service.assert_called_once_with(
|
req, share_network_id, body)
|
||||||
req, share_network_id, body['remove_security_service'])
|
self.controller.remove_security_service.assert_called_once_with(
|
||||||
|
req, share_network_id, body)
|
||||||
|
|
||||||
@mock.patch.object(db_api, 'share_network_get', mock.Mock())
|
@mock.patch.object(db_api, 'share_network_get', mock.Mock())
|
||||||
@mock.patch.object(share_networks.policy, 'check_policy', mock.Mock())
|
@mock.patch.object(share_networks.policy, 'check_policy', mock.Mock())
|
||||||
@ -956,7 +1192,7 @@ class ShareNetworkAPITest(test.TestCase):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
self.assertRaises(webob_exc.HTTPForbidden,
|
self.assertRaises(webob_exc.HTTPForbidden,
|
||||||
self.controller.action,
|
self.controller.remove_security_service,
|
||||||
self.req,
|
self.req,
|
||||||
share_network['id'],
|
share_network['id'],
|
||||||
body)
|
body)
|
||||||
@ -965,23 +1201,17 @@ class ShareNetworkAPITest(test.TestCase):
|
|||||||
share_networks.policy.check_policy.assert_called_once_with(
|
share_networks.policy.check_policy.assert_called_once_with(
|
||||||
self.req.environ['manila.context'],
|
self.req.environ['manila.context'],
|
||||||
share_networks.RESOURCE_NAME,
|
share_networks.RESOURCE_NAME,
|
||||||
'remove_security_service')
|
'remove_security_service', target_obj=share_network)
|
||||||
|
|
||||||
def test_action_bad_request(self):
|
|
||||||
share_network_id = 'fake network id'
|
|
||||||
body = {'bad_action': {}}
|
|
||||||
|
|
||||||
self.assertRaises(webob_exc.HTTPBadRequest,
|
|
||||||
self.controller.action,
|
|
||||||
self.req,
|
|
||||||
share_network_id,
|
|
||||||
body)
|
|
||||||
|
|
||||||
@ddt.data('add_security_service', 'remove_security_service')
|
@ddt.data('add_security_service', 'remove_security_service')
|
||||||
def test_action_security_service_contains_share_servers(self, action):
|
def test_action_security_service_contains_share_servers(self, action):
|
||||||
share_network = fake_share_network.copy()
|
share_network = fake_share_network.copy()
|
||||||
security_service = {'id': ' security_service_2',
|
security_service = {'id': ' security_service_2',
|
||||||
'type': 'ldap'}
|
'type': 'ldap'}
|
||||||
|
method_to_call = (
|
||||||
|
self.controller.add_security_service
|
||||||
|
if action == 'add_security_service'
|
||||||
|
else self.controller.remove_security_service)
|
||||||
body = {
|
body = {
|
||||||
action: {
|
action: {
|
||||||
'security_service_id': security_service['id']
|
'security_service_id': security_service['id']
|
||||||
@ -990,12 +1220,14 @@ class ShareNetworkAPITest(test.TestCase):
|
|||||||
self.mock_object(share_networks.policy, 'check_policy')
|
self.mock_object(share_networks.policy, 'check_policy')
|
||||||
self.mock_object(db_api, 'share_network_get',
|
self.mock_object(db_api, 'share_network_get',
|
||||||
mock.Mock(return_value=share_network))
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(db_api, 'security_service_get',
|
||||||
|
mock.Mock(return_value=security_service))
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
self.controller, '_share_network_subnets_contain_share_servers',
|
self.controller, '_share_network_subnets_contain_share_servers',
|
||||||
mock.Mock(return_value=True))
|
mock.Mock(return_value=True))
|
||||||
|
|
||||||
self.assertRaises(webob_exc.HTTPForbidden,
|
self.assertRaises(webob_exc.HTTPForbidden,
|
||||||
self.controller.action,
|
method_to_call,
|
||||||
self.req,
|
self.req,
|
||||||
share_network['id'],
|
share_network['id'],
|
||||||
body)
|
body)
|
||||||
@ -1003,4 +1235,228 @@ class ShareNetworkAPITest(test.TestCase):
|
|||||||
self.req.environ['manila.context'], share_network['id'])
|
self.req.environ['manila.context'], share_network['id'])
|
||||||
share_networks.policy.check_policy.assert_called_once_with(
|
share_networks.policy.check_policy.assert_called_once_with(
|
||||||
self.req.environ['manila.context'],
|
self.req.environ['manila.context'],
|
||||||
share_networks.RESOURCE_NAME, action)
|
share_networks.RESOURCE_NAME, action, target_obj=share_network)
|
||||||
|
|
||||||
|
def _setup_data_for_check_update_tests(self):
|
||||||
|
security_services = [
|
||||||
|
db_utils.create_security_service() for i in range(2)]
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
body = {
|
||||||
|
'update_security_service_check': {
|
||||||
|
'reset_operation': False,
|
||||||
|
'current_service_id': security_services[0]['id'],
|
||||||
|
'new_service_id': security_services[1]['id'],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request = fakes.HTTPRequest.blank(
|
||||||
|
'/share-networks', use_admin_context=True, version='2.63')
|
||||||
|
return security_services, share_network, body, request
|
||||||
|
|
||||||
|
def test_check_update_security_service_not_found(self):
|
||||||
|
security_services, share_network, body, request = (
|
||||||
|
self._setup_data_for_check_update_tests())
|
||||||
|
|
||||||
|
context = request.environ['manila.context']
|
||||||
|
|
||||||
|
self.mock_object(share_networks.policy, 'check_policy')
|
||||||
|
self.mock_object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(db_api, 'security_service_get',
|
||||||
|
mock.Mock(side_effect=exception.NotFound()))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
webob_exc.HTTPBadRequest,
|
||||||
|
self.controller.check_update_security_service,
|
||||||
|
request,
|
||||||
|
share_network['id'],
|
||||||
|
body)
|
||||||
|
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network['id']
|
||||||
|
)
|
||||||
|
db_api.security_service_get.assert_called_once_with(
|
||||||
|
context, security_services[0]['id'])
|
||||||
|
|
||||||
|
def test_check_update_security_service(self):
|
||||||
|
security_services, share_network, body, request = (
|
||||||
|
self._setup_data_for_check_update_tests())
|
||||||
|
context = request.environ['manila.context']
|
||||||
|
share_api_return = {'fake_key': 'fake_value'}
|
||||||
|
|
||||||
|
self.mock_object(share_networks.policy, 'check_policy')
|
||||||
|
self.mock_object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(
|
||||||
|
db_api, 'security_service_get',
|
||||||
|
mock.Mock(
|
||||||
|
side_effect=[security_services[0], security_services[1]]))
|
||||||
|
self.mock_object(
|
||||||
|
self.controller.share_api,
|
||||||
|
'check_share_network_security_service_update',
|
||||||
|
mock.Mock(return_vale=share_api_return))
|
||||||
|
self.mock_object(
|
||||||
|
self.controller._view_builder,
|
||||||
|
'build_security_service_update_check')
|
||||||
|
|
||||||
|
self.controller.check_update_security_service(
|
||||||
|
request, share_network['id'], body)
|
||||||
|
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network['id'])
|
||||||
|
db_api.security_service_get.assert_has_calls(
|
||||||
|
[mock.call(context, security_services[0]['id']),
|
||||||
|
mock.call(context, security_services[1]['id'])])
|
||||||
|
(self.controller.share_api.check_share_network_security_service_update.
|
||||||
|
assert_called_once_with(
|
||||||
|
context, share_network, security_services[1],
|
||||||
|
current_security_service=security_services[0],
|
||||||
|
reset_operation=False))
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
(exception.ServiceIsDown(message='fake'), webob_exc.HTTPConflict),
|
||||||
|
(exception.InvalidShareNetwork(message='fake'),
|
||||||
|
webob_exc.HTTPBadRequest))
|
||||||
|
@ddt.unpack
|
||||||
|
def test_check_update_security_service_share_api_failed(
|
||||||
|
self, captured_exception, exception_to_be_raised):
|
||||||
|
security_services, share_network, body, request = (
|
||||||
|
self._setup_data_for_check_update_tests())
|
||||||
|
context = request.environ['manila.context']
|
||||||
|
|
||||||
|
self.mock_object(share_networks.policy, 'check_policy')
|
||||||
|
self.mock_object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(
|
||||||
|
db_api, 'security_service_get',
|
||||||
|
mock.Mock(
|
||||||
|
side_effect=[security_services[0], security_services[1]]))
|
||||||
|
self.mock_object(
|
||||||
|
self.controller.share_api,
|
||||||
|
'check_share_network_security_service_update',
|
||||||
|
mock.Mock(side_effect=captured_exception))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception_to_be_raised,
|
||||||
|
self.controller.check_update_security_service,
|
||||||
|
request,
|
||||||
|
share_network['id'],
|
||||||
|
body)
|
||||||
|
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network['id'])
|
||||||
|
db_api.security_service_get.assert_has_calls(
|
||||||
|
[mock.call(context, security_services[0]['id']),
|
||||||
|
mock.call(context, security_services[1]['id'])])
|
||||||
|
(self.controller.share_api.check_share_network_security_service_update.
|
||||||
|
assert_called_once_with(
|
||||||
|
context, share_network, security_services[1],
|
||||||
|
current_security_service=security_services[0],
|
||||||
|
reset_operation=False))
|
||||||
|
|
||||||
|
def _setup_data_for_check_add_tests(self):
|
||||||
|
security_service = db_utils.create_security_service()
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
body = {
|
||||||
|
'add_security_service_check': {
|
||||||
|
'reset_operation': False,
|
||||||
|
'security_service_id': security_service['id'],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
request = fakes.HTTPRequest.blank(
|
||||||
|
'/share-networks', use_admin_context=True, version='2.63')
|
||||||
|
return security_service, share_network, body, request
|
||||||
|
|
||||||
|
def test_check_add_security_service_not_found(self):
|
||||||
|
security_service, share_network, body, request = (
|
||||||
|
self._setup_data_for_check_add_tests())
|
||||||
|
|
||||||
|
context = request.environ['manila.context']
|
||||||
|
|
||||||
|
self.mock_object(share_networks.policy, 'check_policy')
|
||||||
|
self.mock_object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(db_api, 'security_service_get',
|
||||||
|
mock.Mock(side_effect=exception.NotFound()))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
webob_exc.HTTPBadRequest,
|
||||||
|
self.controller.check_add_security_service,
|
||||||
|
request,
|
||||||
|
share_network['id'],
|
||||||
|
body)
|
||||||
|
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network['id']
|
||||||
|
)
|
||||||
|
db_api.security_service_get.assert_called_once_with(
|
||||||
|
context, security_service['id'])
|
||||||
|
|
||||||
|
def test_check_add_security_service(self):
|
||||||
|
security_service, share_network, body, request = (
|
||||||
|
self._setup_data_for_check_add_tests())
|
||||||
|
context = request.environ['manila.context']
|
||||||
|
share_api_return = {'fake_key': 'fake_value'}
|
||||||
|
|
||||||
|
self.mock_object(share_networks.policy, 'check_policy')
|
||||||
|
self.mock_object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(
|
||||||
|
db_api, 'security_service_get',
|
||||||
|
mock.Mock(return_value=security_service))
|
||||||
|
self.mock_object(
|
||||||
|
self.controller.share_api,
|
||||||
|
'check_share_network_security_service_update',
|
||||||
|
mock.Mock(return_vale=share_api_return))
|
||||||
|
self.mock_object(
|
||||||
|
self.controller._view_builder,
|
||||||
|
'build_security_service_update_check')
|
||||||
|
|
||||||
|
self.controller.check_add_security_service(
|
||||||
|
request, share_network['id'], body)
|
||||||
|
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network['id'])
|
||||||
|
db_api.security_service_get.assert_called_once_with(
|
||||||
|
context, security_service['id'])
|
||||||
|
(self.controller.share_api.check_share_network_security_service_update.
|
||||||
|
assert_called_once_with(
|
||||||
|
context, share_network, security_service,
|
||||||
|
reset_operation=False))
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
(exception.ServiceIsDown(message='fake'), webob_exc.HTTPConflict),
|
||||||
|
(exception.InvalidShareNetwork(message='fake'),
|
||||||
|
webob_exc.HTTPBadRequest))
|
||||||
|
@ddt.unpack
|
||||||
|
def test_check_add_security_service_share_api_failed(
|
||||||
|
self, captured_exception, exception_to_be_raised):
|
||||||
|
security_service, share_network, body, request = (
|
||||||
|
self._setup_data_for_check_add_tests())
|
||||||
|
context = request.environ['manila.context']
|
||||||
|
|
||||||
|
self.mock_object(share_networks.policy, 'check_policy')
|
||||||
|
self.mock_object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(
|
||||||
|
db_api, 'security_service_get',
|
||||||
|
mock.Mock(return_value=security_service))
|
||||||
|
self.mock_object(
|
||||||
|
self.controller.share_api,
|
||||||
|
'check_share_network_security_service_update',
|
||||||
|
mock.Mock(side_effect=captured_exception))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception_to_be_raised,
|
||||||
|
self.controller.check_add_security_service,
|
||||||
|
request,
|
||||||
|
share_network['id'],
|
||||||
|
body)
|
||||||
|
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network['id'])
|
||||||
|
db_api.security_service_get.assert_called_once_with(
|
||||||
|
context, security_service['id'])
|
||||||
|
(self.controller.share_api.check_share_network_security_service_update.
|
||||||
|
assert_called_once_with(
|
||||||
|
context, share_network, security_service,
|
||||||
|
reset_operation=False))
|
||||||
|
@ -15,11 +15,13 @@
|
|||||||
|
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
import copy
|
||||||
import ddt
|
import ddt
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
|
from manila.api import common
|
||||||
from manila.api.openstack import api_version_request as api_version
|
from manila.api.openstack import api_version_request as api_version
|
||||||
from manila.api.v2 import share_replicas
|
from manila.api.v2 import share_replicas
|
||||||
from manila.common import constants
|
from manila.common import constants
|
||||||
@ -56,6 +58,17 @@ class ShareReplicasApiTest(test.TestCase):
|
|||||||
experimental=True, use_admin_context=True)
|
experimental=True, use_admin_context=True)
|
||||||
self.admin_context = self.replicas_req_admin.environ['manila.context']
|
self.admin_context = self.replicas_req_admin.environ['manila.context']
|
||||||
self.mock_policy_check = self.mock_object(policy, 'check_policy')
|
self.mock_policy_check = self.mock_object(policy, 'check_policy')
|
||||||
|
self.fake_share_network = {
|
||||||
|
'id': 'fake network id',
|
||||||
|
'project_id': 'fake project',
|
||||||
|
'updated_at': None,
|
||||||
|
'name': 'fake name',
|
||||||
|
'description': 'fake description',
|
||||||
|
'security_services': [],
|
||||||
|
'share_network_subnets': [],
|
||||||
|
'security_service_update_support': True,
|
||||||
|
'status': 'active'
|
||||||
|
}
|
||||||
|
|
||||||
def _get_context(self, role):
|
def _get_context(self, role):
|
||||||
return getattr(self, '%s_context' % role)
|
return getattr(self, '%s_context' % role)
|
||||||
@ -370,6 +383,7 @@ class ShareReplicasApiTest(test.TestCase):
|
|||||||
mock__view_builder_call = self.mock_object(
|
mock__view_builder_call = self.mock_object(
|
||||||
share_replicas.replication_view.ReplicationViewBuilder,
|
share_replicas.replication_view.ReplicationViewBuilder,
|
||||||
'detail_list')
|
'detail_list')
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
body = {
|
body = {
|
||||||
'share_replica': {
|
'share_replica': {
|
||||||
'share_id': 'FAKE_SHAREID',
|
'share_id': 'FAKE_SHAREID',
|
||||||
@ -381,6 +395,10 @@ class ShareReplicasApiTest(test.TestCase):
|
|||||||
mock.Mock(return_value=fake_replica))
|
mock.Mock(return_value=fake_replica))
|
||||||
self.mock_object(share.API, 'create_share_replica',
|
self.mock_object(share.API, 'create_share_replica',
|
||||||
mock.Mock(side_effect=exception_type(**exc_args)))
|
mock.Mock(side_effect=exception_type(**exc_args)))
|
||||||
|
self.mock_object(share_replicas.db, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
|
|
||||||
self.assertRaises(exc.HTTPBadRequest,
|
self.assertRaises(exc.HTTPBadRequest,
|
||||||
self.controller.create,
|
self.controller.create,
|
||||||
@ -388,6 +406,10 @@ class ShareReplicasApiTest(test.TestCase):
|
|||||||
self.assertFalse(mock__view_builder_call.called)
|
self.assertFalse(mock__view_builder_call.called)
|
||||||
self.mock_policy_check.assert_called_once_with(
|
self.mock_policy_check.assert_called_once_with(
|
||||||
self.member_context, self.resource_name, 'create')
|
self.member_context, self.resource_name, 'create')
|
||||||
|
share_replicas.db.share_network_get.assert_called_once_with(
|
||||||
|
self.member_context, fake_replica['share_network_id'])
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
share_network)
|
||||||
|
|
||||||
@ddt.data((True, PRE_GRADUATION_VERSION), (False, GRADUATION_VERSION))
|
@ddt.data((True, PRE_GRADUATION_VERSION), (False, GRADUATION_VERSION))
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
@ -395,6 +417,7 @@ class ShareReplicasApiTest(test.TestCase):
|
|||||||
fake_replica, expected_replica = self._get_fake_replica(
|
fake_replica, expected_replica = self._get_fake_replica(
|
||||||
replication_type='writable', admin=is_admin,
|
replication_type='writable', admin=is_admin,
|
||||||
microversion=microversion)
|
microversion=microversion)
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
body = {
|
body = {
|
||||||
'share_replica': {
|
'share_replica': {
|
||||||
'share_id': 'FAKE_SHAREID',
|
'share_id': 'FAKE_SHAREID',
|
||||||
@ -408,6 +431,10 @@ class ShareReplicasApiTest(test.TestCase):
|
|||||||
self.mock_object(share_replicas.db,
|
self.mock_object(share_replicas.db,
|
||||||
'share_replicas_get_available_active_replica',
|
'share_replicas_get_available_active_replica',
|
||||||
mock.Mock(return_value=[{'id': 'active1'}]))
|
mock.Mock(return_value=[{'id': 'active1'}]))
|
||||||
|
self.mock_object(share_replicas.db, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
|
|
||||||
req = self._get_request(microversion, is_admin)
|
req = self._get_request(microversion, is_admin)
|
||||||
req_context = req.environ['manila.context']
|
req_context = req.environ['manila.context']
|
||||||
@ -417,6 +444,10 @@ class ShareReplicasApiTest(test.TestCase):
|
|||||||
self.assertEqual(expected_replica, res_dict['share_replica'])
|
self.assertEqual(expected_replica, res_dict['share_replica'])
|
||||||
self.mock_policy_check.assert_called_once_with(
|
self.mock_policy_check.assert_called_once_with(
|
||||||
req_context, self.resource_name, 'create')
|
req_context, self.resource_name, 'create')
|
||||||
|
share_replicas.db.share_network_get.assert_called_once_with(
|
||||||
|
req_context, fake_replica['share_network_id'])
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
share_network)
|
||||||
|
|
||||||
def test_delete_invalid_replica(self):
|
def test_delete_invalid_replica(self):
|
||||||
fake_exception = exception.ShareReplicaNotFound(
|
fake_exception = exception.ShareReplicaNotFound(
|
||||||
@ -492,6 +523,8 @@ class ShareReplicasApiTest(test.TestCase):
|
|||||||
replica_state=constants.REPLICA_STATE_ACTIVE)
|
replica_state=constants.REPLICA_STATE_ACTIVE)
|
||||||
self.mock_object(share_replicas.db, 'share_replica_get',
|
self.mock_object(share_replicas.db, 'share_replica_get',
|
||||||
mock.Mock(return_value=replica))
|
mock.Mock(return_value=replica))
|
||||||
|
self.mock_object(share_replicas.db, 'share_network_get',
|
||||||
|
mock.Mock(return_value=self.fake_share_network))
|
||||||
mock_api_promote_replica_call = self.mock_object(
|
mock_api_promote_replica_call = self.mock_object(
|
||||||
share.API, 'promote_share_replica')
|
share.API, 'promote_share_replica')
|
||||||
|
|
||||||
@ -509,6 +542,8 @@ class ShareReplicasApiTest(test.TestCase):
|
|||||||
exception_type = exception.ReplicationException(reason='xyz')
|
exception_type = exception.ReplicationException(reason='xyz')
|
||||||
self.mock_object(share_replicas.db, 'share_replica_get',
|
self.mock_object(share_replicas.db, 'share_replica_get',
|
||||||
mock.Mock(return_value=replica))
|
mock.Mock(return_value=replica))
|
||||||
|
self.mock_object(share_replicas.db, 'share_network_get',
|
||||||
|
mock.Mock(return_value=self.fake_share_network))
|
||||||
mock_api_promote_replica_call = self.mock_object(
|
mock_api_promote_replica_call = self.mock_object(
|
||||||
share.API, 'promote_share_replica',
|
share.API, 'promote_share_replica',
|
||||||
mock.Mock(side_effect=exception_type))
|
mock.Mock(side_effect=exception_type))
|
||||||
@ -522,12 +557,33 @@ class ShareReplicasApiTest(test.TestCase):
|
|||||||
self.mock_policy_check.assert_called_once_with(
|
self.mock_policy_check.assert_called_once_with(
|
||||||
self.member_context, self.resource_name, 'promote')
|
self.member_context, self.resource_name, 'promote')
|
||||||
|
|
||||||
|
def test_promote_share_network_not_active(self):
|
||||||
|
body = {'promote': None}
|
||||||
|
replica, expected_replica = self._get_fake_replica(
|
||||||
|
replica_state=constants.REPLICA_STATE_IN_SYNC)
|
||||||
|
fake_share_network = copy.deepcopy(self.fake_share_network)
|
||||||
|
fake_share_network['status'] = constants.STATUS_NETWORK_CHANGE
|
||||||
|
self.mock_object(share_replicas.db, 'share_replica_get',
|
||||||
|
mock.Mock(return_value=replica))
|
||||||
|
self.mock_object(share_replicas.db, 'share_network_get',
|
||||||
|
mock.Mock(return_value=fake_share_network))
|
||||||
|
|
||||||
|
self.assertRaises(exc.HTTPBadRequest,
|
||||||
|
self.controller.promote,
|
||||||
|
self.replicas_req,
|
||||||
|
replica['id'],
|
||||||
|
body)
|
||||||
|
self.mock_policy_check.assert_called_once_with(
|
||||||
|
self.member_context, self.resource_name, 'promote')
|
||||||
|
|
||||||
def test_promote_admin_required_exception(self):
|
def test_promote_admin_required_exception(self):
|
||||||
body = {'promote': None}
|
body = {'promote': None}
|
||||||
replica, expected_replica = self._get_fake_replica(
|
replica, expected_replica = self._get_fake_replica(
|
||||||
replica_state=constants.REPLICA_STATE_IN_SYNC)
|
replica_state=constants.REPLICA_STATE_IN_SYNC)
|
||||||
self.mock_object(share_replicas.db, 'share_replica_get',
|
self.mock_object(share_replicas.db, 'share_replica_get',
|
||||||
mock.Mock(return_value=replica))
|
mock.Mock(return_value=replica))
|
||||||
|
self.mock_object(share_replicas.db, 'share_network_get',
|
||||||
|
mock.Mock(return_value=self.fake_share_network))
|
||||||
mock_api_promote_replica_call = self.mock_object(
|
mock_api_promote_replica_call = self.mock_object(
|
||||||
share.API, 'promote_share_replica',
|
share.API, 'promote_share_replica',
|
||||||
mock.Mock(side_effect=exception.AdminRequired))
|
mock.Mock(side_effect=exception.AdminRequired))
|
||||||
@ -549,6 +605,8 @@ class ShareReplicasApiTest(test.TestCase):
|
|||||||
microversion=microversion)
|
microversion=microversion)
|
||||||
self.mock_object(share_replicas.db, 'share_replica_get',
|
self.mock_object(share_replicas.db, 'share_replica_get',
|
||||||
mock.Mock(return_value=replica))
|
mock.Mock(return_value=replica))
|
||||||
|
self.mock_object(share_replicas.db, 'share_network_get',
|
||||||
|
mock.Mock(return_value=self.fake_share_network))
|
||||||
mock_api_promote_replica_call = self.mock_object(
|
mock_api_promote_replica_call = self.mock_object(
|
||||||
share.API, 'promote_share_replica',
|
share.API, 'promote_share_replica',
|
||||||
mock.Mock(return_value=replica))
|
mock.Mock(return_value=replica))
|
||||||
|
@ -18,6 +18,7 @@ from unittest import mock
|
|||||||
import ddt
|
import ddt
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
|
from manila.api import common
|
||||||
from manila.api.v2 import share_servers
|
from manila.api.v2 import share_servers
|
||||||
from manila.common import constants
|
from manila.common import constants
|
||||||
from manila import context as ctx_api
|
from manila import context as ctx_api
|
||||||
@ -287,11 +288,40 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
return_value=share_network))
|
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_subnet',
|
||||||
mock.Mock(return_value=share_net_subnet))
|
mock.Mock(return_value=share_net_subnet))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
|
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
exception_to_raise, self.controller.manage, req,
|
exception_to_raise, self.controller.manage, req,
|
||||||
{'share_server': self._setup_manage_test_request_body()})
|
{'share_server': self._setup_manage_test_request_body()})
|
||||||
|
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
share_net_subnet['share_network'])
|
||||||
|
policy.check_policy.assert_called_once_with(
|
||||||
|
context, self.resource_name, 'manage_share_server')
|
||||||
|
|
||||||
|
def test__validate_manage_share_network_not_active(self):
|
||||||
|
req = fakes.HTTPRequest.blank('/manage', 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'])
|
||||||
|
|
||||||
|
self.mock_object(db_api, 'share_network_get', mock.Mock(
|
||||||
|
return_value=share_network))
|
||||||
|
self.mock_object(db_api, 'share_network_subnet_get_default_subnet',
|
||||||
|
mock.Mock(return_value=share_net_subnet))
|
||||||
|
self.mock_object(utils, 'validate_service_host')
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(side_effect=webob.exc.HTTPBadRequest()))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
webob.exc.HTTPBadRequest, self.controller.manage, req,
|
||||||
|
{'share_server': self._setup_manage_test_request_body()})
|
||||||
|
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
share_net_subnet['share_network'])
|
||||||
policy.check_policy.assert_called_once_with(
|
policy.check_policy.assert_called_once_with(
|
||||||
context, self.resource_name, 'manage_share_server')
|
context, self.resource_name, 'manage_share_server')
|
||||||
|
|
||||||
@ -434,8 +464,15 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
def _setup_unmanage_tests(self, status=constants.STATUS_ACTIVE):
|
def _setup_unmanage_tests(self, status=constants.STATUS_ACTIVE):
|
||||||
server = db_utils.create_share_server(
|
server = db_utils.create_share_server(
|
||||||
id='fake_server_id', status=status)
|
id='fake_server_id', status=status)
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
network_subnet = db_utils.create_share_network_subnet(
|
||||||
|
share_network_id=share_network['id'])
|
||||||
self.mock_object(db_api, 'share_server_get',
|
self.mock_object(db_api, 'share_server_get',
|
||||||
mock.Mock(return_value=server))
|
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))
|
||||||
return server
|
return server
|
||||||
|
|
||||||
@ddt.data(exception.ShareServerInUse, exception.PolicyNotAuthorized)
|
@ddt.data(exception.ShareServerInUse, exception.PolicyNotAuthorized)
|
||||||
@ -446,6 +483,8 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
error = mock.Mock(side_effect=exc('foobar'))
|
error = mock.Mock(side_effect=exc('foobar'))
|
||||||
mock_unmanage = self.mock_object(
|
mock_unmanage = self.mock_object(
|
||||||
share_api.API, 'unmanage_share_server', error)
|
share_api.API, 'unmanage_share_server', error)
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
body = {'unmanage': {'force': True}}
|
body = {'unmanage': {'force': True}}
|
||||||
|
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
@ -455,9 +494,44 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
body)
|
body)
|
||||||
|
|
||||||
mock_unmanage.assert_called_once_with(context, server, force=True)
|
mock_unmanage.assert_called_once_with(context, server, force=True)
|
||||||
|
db_api.share_network_get.assert_called()
|
||||||
|
common.check_share_network_is_active.assert_called()
|
||||||
policy.check_policy.assert_called_once_with(
|
policy.check_policy.assert_called_once_with(
|
||||||
context, self.resource_name, 'unmanage_share_server')
|
context, self.resource_name, 'unmanage_share_server')
|
||||||
|
|
||||||
|
def test_unmanage_share_server_network_not_active(self):
|
||||||
|
"""Tests unmanaging share servers"""
|
||||||
|
req = fakes.HTTPRequest.blank(
|
||||||
|
'/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()
|
||||||
|
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))
|
||||||
|
is_active_mock = self.mock_object(
|
||||||
|
common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(side_effect=webob.exc.HTTPBadRequest()))
|
||||||
|
body = {'unmanage': {'force': True}}
|
||||||
|
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
|
self.controller.unmanage,
|
||||||
|
req,
|
||||||
|
'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'])
|
||||||
|
is_active_mock.assert_called_once_with(share_network)
|
||||||
|
|
||||||
def _get_server_migration_request(self, server_id):
|
def _get_server_migration_request(self, server_id):
|
||||||
req = fakes.HTTPRequest.blank(
|
req = fakes.HTTPRequest.blank(
|
||||||
'/share-servers/%s/action' % server_id,
|
'/share-servers/%s/action' % server_id,
|
||||||
@ -478,6 +552,8 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
return_value=share_network))
|
return_value=share_network))
|
||||||
self.mock_object(db_api, 'share_server_get',
|
self.mock_object(db_api, 'share_server_get',
|
||||||
mock.Mock(return_value=server))
|
mock.Mock(return_value=server))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
self.mock_object(share_api.API, 'share_server_migration_start')
|
self.mock_object(share_api.API, 'share_server_migration_start')
|
||||||
|
|
||||||
body = {
|
body = {
|
||||||
@ -499,6 +575,8 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
new_share_network=share_network)
|
new_share_network=share_network)
|
||||||
db_api.share_network_get.assert_called_once_with(
|
db_api.share_network_get.assert_called_once_with(
|
||||||
context, 'fake_net_id')
|
context, 'fake_net_id')
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
share_network)
|
||||||
|
|
||||||
@ddt.data({'api_exception': exception.ServiceIsDown(service='fake_srv'),
|
@ddt.data({'api_exception': exception.ServiceIsDown(service='fake_srv'),
|
||||||
'expected_exception': webob.exc.HTTPBadRequest},
|
'expected_exception': webob.exc.HTTPBadRequest},
|
||||||
@ -507,8 +585,12 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
def test_share_server_migration_start_conflict(self, api_exception,
|
def test_share_server_migration_start_conflict(self, api_exception,
|
||||||
expected_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'])
|
||||||
server = db_utils.create_share_server(
|
server = db_utils.create_share_server(
|
||||||
id='fake_server_id', status=constants.STATUS_ACTIVE)
|
id='fake_server_id', status=constants.STATUS_ACTIVE,
|
||||||
|
share_network_subnet_id=share_network_subnet['id'])
|
||||||
req = self._get_server_migration_request(server['id'])
|
req = self._get_server_migration_request(server['id'])
|
||||||
context = req.environ['manila.context']
|
context = req.environ['manila.context']
|
||||||
body = {
|
body = {
|
||||||
@ -523,6 +605,10 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
mock.Mock(side_effect=api_exception))
|
mock.Mock(side_effect=api_exception))
|
||||||
self.mock_object(db_api, 'share_server_get',
|
self.mock_object(db_api, 'share_server_get',
|
||||||
mock.Mock(return_value=server))
|
mock.Mock(return_value=server))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
|
self.mock_object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
|
||||||
self.assertRaises(expected_exception,
|
self.assertRaises(expected_exception,
|
||||||
self.controller.share_server_migration_start,
|
self.controller.share_server_migration_start,
|
||||||
@ -531,6 +617,10 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
db_api.share_server_get.assert_called_once_with(context,
|
db_api.share_server_get.assert_called_once_with(context,
|
||||||
server['id'])
|
server['id'])
|
||||||
migration_start_params = body['migration_start']
|
migration_start_params = body['migration_start']
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
share_network)
|
||||||
|
db_api.share_network_get.assert_called_once_with(
|
||||||
|
context, share_network['id'])
|
||||||
share_api.API.share_server_migration_start.assert_called_once_with(
|
share_api.API.share_server_migration_start.assert_called_once_with(
|
||||||
context, server, migration_start_params['host'],
|
context, server, migration_start_params['host'],
|
||||||
migration_start_params['writable'],
|
migration_start_params['writable'],
|
||||||
@ -960,6 +1050,8 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
mock_network_get = self.mock_object(
|
mock_network_get = self.mock_object(
|
||||||
db_api, 'share_network_get',
|
db_api, 'share_network_get',
|
||||||
mock.Mock(return_value=fake_share_network))
|
mock.Mock(return_value=fake_share_network))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
mock_migration_check = self.mock_object(
|
mock_migration_check = self.mock_object(
|
||||||
share_api.API, 'share_server_migration_check',
|
share_api.API, 'share_server_migration_check',
|
||||||
mock.Mock(return_value=driver_result))
|
mock.Mock(return_value=driver_result))
|
||||||
@ -974,6 +1066,8 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
context, fake_share_server['id'])
|
context, fake_share_server['id'])
|
||||||
mock_network_get.assert_called_once_with(
|
mock_network_get.assert_called_once_with(
|
||||||
context, fake_share_network['id'])
|
context, fake_share_network['id'])
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
fake_share_network)
|
||||||
mock_migration_check.assert_called_once_with(
|
mock_migration_check.assert_called_once_with(
|
||||||
context, fake_share_server, fake_host, requested_writable,
|
context, fake_share_server, fake_host, requested_writable,
|
||||||
requested_nondisruptive, requested_preserve_snapshots,
|
requested_nondisruptive, requested_preserve_snapshots,
|
||||||
@ -1030,7 +1124,7 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
{'api_exception': exception.ServiceIsDown(service='fake_srv'),
|
{'api_exception': exception.ServiceIsDown(service='fake_srv'),
|
||||||
'expected_exception': webob.exc.HTTPBadRequest},
|
'expected_exception': webob.exc.HTTPBadRequest},
|
||||||
{'api_exception': exception.InvalidShareServer(reason=""),
|
{'api_exception': exception.InvalidShareServer(reason=""),
|
||||||
'expected_exception': webob.exc.HTTPConflict})
|
'expected_exception': webob.exc.HTTPBadRequest})
|
||||||
@ddt.unpack
|
@ddt.unpack
|
||||||
def test_share_server_migration_complete_exceptions_from_api(
|
def test_share_server_migration_complete_exceptions_from_api(
|
||||||
self, api_exception, expected_exception):
|
self, api_exception, expected_exception):
|
||||||
@ -1048,21 +1142,16 @@ class ShareServerControllerTest(test.TestCase):
|
|||||||
self.mock_object(db_api, 'share_server_get',
|
self.mock_object(db_api, 'share_server_get',
|
||||||
mock.Mock(return_value='fake_share_server'))
|
mock.Mock(return_value='fake_share_server'))
|
||||||
|
|
||||||
self.mock_object(share_api.API, 'share_server_migration_check',
|
self.mock_object(share_api.API, 'share_server_migration_complete',
|
||||||
mock.Mock(side_effect=api_exception))
|
mock.Mock(side_effect=api_exception))
|
||||||
|
|
||||||
self.assertRaises(
|
self.assertRaises(
|
||||||
expected_exception,
|
expected_exception,
|
||||||
self.controller.share_server_migration_check,
|
self.controller.share_server_migration_complete,
|
||||||
req, 'fake_id', body
|
req, 'fake_id', body
|
||||||
)
|
)
|
||||||
|
|
||||||
db_api.share_server_get.assert_called_once_with(context,
|
db_api.share_server_get.assert_called_once_with(context,
|
||||||
'fake_id')
|
'fake_id')
|
||||||
migration_check_params = body['migration_check']
|
share_api.API.share_server_migration_complete.assert_called_once_with(
|
||||||
share_api.API.share_server_migration_check.assert_called_once_with(
|
context, 'fake_share_server', )
|
||||||
context, 'fake_share_server', migration_check_params['host'],
|
|
||||||
migration_check_params['writable'],
|
|
||||||
migration_check_params['nondisruptive'],
|
|
||||||
migration_check_params['preserve_snapshots'],
|
|
||||||
new_share_network=None)
|
|
||||||
|
@ -664,6 +664,7 @@ class ShareAPITest(test.TestCase):
|
|||||||
"availability_zone": "zone1:host1",
|
"availability_zone": "zone1:host1",
|
||||||
"share_network_id": "fakenetid"
|
"share_network_id": "fakenetid"
|
||||||
}
|
}
|
||||||
|
fake_network = {'id': 'fakenetid'}
|
||||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||||
display_name=shr['name'],
|
display_name=shr['name'],
|
||||||
display_description=shr['description'],
|
display_description=shr['description'],
|
||||||
@ -673,7 +674,9 @@ class ShareAPITest(test.TestCase):
|
|||||||
share_network_id=shr['share_network_id']))
|
share_network_id=shr['share_network_id']))
|
||||||
self.mock_object(share_api.API, 'create', create_mock)
|
self.mock_object(share_api.API, 'create', create_mock)
|
||||||
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
||||||
return_value={'id': 'fakenetid'}))
|
return_value=fake_network))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||||
|
|
||||||
@ -687,6 +690,8 @@ class ShareAPITest(test.TestCase):
|
|||||||
# pylint: disable=unsubscriptable-object
|
# pylint: disable=unsubscriptable-object
|
||||||
self.assertEqual("fakenetid",
|
self.assertEqual("fakenetid",
|
||||||
create_mock.call_args[1]['share_network_id'])
|
create_mock.call_args[1]['share_network_id'])
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
fake_network)
|
||||||
|
|
||||||
@ddt.data("2.15", "2.16")
|
@ddt.data("2.15", "2.16")
|
||||||
def test_share_create_original_with_user_id(self, microversion):
|
def test_share_create_original_with_user_id(self, microversion):
|
||||||
@ -1268,6 +1273,7 @@ class ShareAPITest(test.TestCase):
|
|||||||
"share_network_id": None,
|
"share_network_id": None,
|
||||||
}
|
}
|
||||||
parent_share_net = 444
|
parent_share_net = 444
|
||||||
|
fake_network = {'id': parent_share_net}
|
||||||
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
create_mock = mock.Mock(return_value=stubs.stub_share('1',
|
||||||
display_name=shr['name'],
|
display_name=shr['name'],
|
||||||
display_description=shr['description'],
|
display_description=shr['description'],
|
||||||
@ -1280,13 +1286,15 @@ class ShareAPITest(test.TestCase):
|
|||||||
self.mock_object(share_api.API, 'create', create_mock)
|
self.mock_object(share_api.API, 'create', create_mock)
|
||||||
self.mock_object(share_api.API, 'get_snapshot',
|
self.mock_object(share_api.API, 'get_snapshot',
|
||||||
stubs.stub_snapshot_get)
|
stubs.stub_snapshot_get)
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
parent_share = stubs.stub_share(
|
parent_share = stubs.stub_share(
|
||||||
'1', instance={'share_network_id': parent_share_net},
|
'1', instance={'share_network_id': parent_share_net},
|
||||||
create_share_from_snapshot_support=True)
|
create_share_from_snapshot_support=True)
|
||||||
self.mock_object(share_api.API, 'get', mock.Mock(
|
self.mock_object(share_api.API, 'get', mock.Mock(
|
||||||
return_value=parent_share))
|
return_value=parent_share))
|
||||||
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
||||||
return_value={'id': parent_share_net}))
|
return_value=fake_network))
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||||
|
|
||||||
@ -1301,6 +1309,8 @@ class ShareAPITest(test.TestCase):
|
|||||||
# pylint: disable=unsubscriptable-object
|
# pylint: disable=unsubscriptable-object
|
||||||
self.assertEqual(parent_share_net,
|
self.assertEqual(parent_share_net,
|
||||||
create_mock.call_args[1]['share_network_id'])
|
create_mock.call_args[1]['share_network_id'])
|
||||||
|
common.check_share_network_is_active.assert_called_once_with(
|
||||||
|
fake_network)
|
||||||
|
|
||||||
def test_share_create_from_snapshot_with_share_net_equals_parent(self):
|
def test_share_create_from_snapshot_with_share_net_equals_parent(self):
|
||||||
parent_share_net = 444
|
parent_share_net = 444
|
||||||
@ -1332,6 +1342,8 @@ class ShareAPITest(test.TestCase):
|
|||||||
return_value=parent_share))
|
return_value=parent_share))
|
||||||
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
self.mock_object(share_api.API, 'get_share_network', mock.Mock(
|
||||||
return_value={'id': parent_share_net}))
|
return_value={'id': parent_share_net}))
|
||||||
|
self.mock_object(common, 'check_share_network_is_active',
|
||||||
|
mock.Mock(return_value=True))
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
db, 'share_network_subnet_get_by_availability_zone_id')
|
db, 'share_network_subnet_get_by_availability_zone_id')
|
||||||
|
|
||||||
|
@ -62,6 +62,9 @@ class ViewBuilderTestCase(test.TestCase):
|
|||||||
<= api_version.APIVersionRequest('2.49'))
|
<= api_version.APIVersionRequest('2.49'))
|
||||||
subnets_support = (api_version.APIVersionRequest(microversion) >
|
subnets_support = (api_version.APIVersionRequest(microversion) >
|
||||||
api_version.APIVersionRequest('2.49'))
|
api_version.APIVersionRequest('2.49'))
|
||||||
|
status_and_sec_serv_update = (
|
||||||
|
api_version.APIVersionRequest(microversion) >=
|
||||||
|
api_version.APIVersionRequest('2.63'))
|
||||||
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
|
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
|
||||||
expected_keys = {
|
expected_keys = {
|
||||||
'id', 'name', 'project_id', 'created_at', 'updated_at',
|
'id', 'name', 'project_id', 'created_at', 'updated_at',
|
||||||
@ -80,6 +83,8 @@ class ViewBuilderTestCase(test.TestCase):
|
|||||||
expected_keys.add('mtu')
|
expected_keys.add('mtu')
|
||||||
if nova_net_support:
|
if nova_net_support:
|
||||||
expected_keys.add('nova_net_id')
|
expected_keys.add('nova_net_id')
|
||||||
|
if status_and_sec_serv_update:
|
||||||
|
expected_keys.update({'status', 'security_service_update_support'})
|
||||||
|
|
||||||
result = self.builder.build_share_network(req, share_network_data)
|
result = self.builder.build_share_network(req, share_network_data)
|
||||||
self.assertEqual(1, len(result))
|
self.assertEqual(1, len(result))
|
||||||
@ -129,6 +134,9 @@ class ViewBuilderTestCase(test.TestCase):
|
|||||||
<= api_version.APIVersionRequest('2.49'))
|
<= api_version.APIVersionRequest('2.49'))
|
||||||
subnets_support = (api_version.APIVersionRequest(microversion) >
|
subnets_support = (api_version.APIVersionRequest(microversion) >
|
||||||
api_version.APIVersionRequest('2.49'))
|
api_version.APIVersionRequest('2.49'))
|
||||||
|
status_and_sec_serv_update = (
|
||||||
|
api_version.APIVersionRequest(microversion) >=
|
||||||
|
api_version.APIVersionRequest('2.63'))
|
||||||
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
|
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
|
||||||
expected_networks_list = []
|
expected_networks_list = []
|
||||||
for share_network in share_networks:
|
for share_network in share_networks:
|
||||||
@ -166,6 +174,13 @@ class ViewBuilderTestCase(test.TestCase):
|
|||||||
if nova_net_support:
|
if nova_net_support:
|
||||||
share_network.update({'nova_net_id': 'fake_nova_net_id'})
|
share_network.update({'nova_net_id': 'fake_nova_net_id'})
|
||||||
expected_data.update({'nova_net_id': None})
|
expected_data.update({'nova_net_id': None})
|
||||||
|
if status_and_sec_serv_update:
|
||||||
|
share_network.update(
|
||||||
|
{'status': 'active',
|
||||||
|
'security_service_update_support': False})
|
||||||
|
expected_data.update(
|
||||||
|
{'status': 'active',
|
||||||
|
'security_service_update_support': False})
|
||||||
expected_networks_list.append(expected_data)
|
expected_networks_list.append(expected_data)
|
||||||
expected = {'share_networks': expected_networks_list}
|
expected = {'share_networks': expected_networks_list}
|
||||||
|
|
||||||
|
@ -2971,3 +2971,76 @@ class ShareServerTaskState(BaseMigrationChecks):
|
|||||||
for ss in engine.execute(ss_table.select()):
|
for ss in engine.execute(ss_table.select()):
|
||||||
self.test_case.assertFalse(hasattr(ss, 'task_state'))
|
self.test_case.assertFalse(hasattr(ss, 'task_state'))
|
||||||
self.test_case.assertFalse(hasattr(ss, 'source_share_server_id'))
|
self.test_case.assertFalse(hasattr(ss, 'source_share_server_id'))
|
||||||
|
|
||||||
|
|
||||||
|
@map_to_migration('478c445d8d3e')
|
||||||
|
class AddUpdateSecurityServiceControlFields(BaseMigrationChecks):
|
||||||
|
|
||||||
|
def setup_upgrade_data(self, engine):
|
||||||
|
user_id = 'user_id'
|
||||||
|
project_id = 'project_id'
|
||||||
|
|
||||||
|
# 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))
|
||||||
|
|
||||||
|
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(),
|
||||||
|
'share_network_subnet_id': share_network_subnet_data['id'],
|
||||||
|
'host': 'fake_host',
|
||||||
|
'status': 'active',
|
||||||
|
}
|
||||||
|
ss_table = utils.load_table('share_servers', engine)
|
||||||
|
engine.execute(ss_table.insert(share_server_data))
|
||||||
|
|
||||||
|
def check_upgrade(self, engine, data):
|
||||||
|
ss_table = utils.load_table('share_servers', engine)
|
||||||
|
for ss in engine.execute(ss_table.select()):
|
||||||
|
self.test_case.assertTrue(
|
||||||
|
hasattr(ss, 'security_service_update_support'))
|
||||||
|
self.test_case.assertEqual(
|
||||||
|
False, ss.security_service_update_support)
|
||||||
|
|
||||||
|
sn_table = utils.load_table('share_networks', engine)
|
||||||
|
for sn in engine.execute(sn_table.select()):
|
||||||
|
self.test_case.assertTrue(hasattr(sn, 'status'))
|
||||||
|
self.test_case.assertEqual(constants.STATUS_NETWORK_ACTIVE,
|
||||||
|
sn.status)
|
||||||
|
async_op_data = {
|
||||||
|
'created_at': datetime.datetime(2021, 3, 12, 17, 40, 34),
|
||||||
|
'updated_at': None,
|
||||||
|
'deleted_at': None,
|
||||||
|
'deleted': 0,
|
||||||
|
'entity_uuid': uuidutils.generate_uuid(),
|
||||||
|
'key': 't' * 255,
|
||||||
|
'value': 'v' * 1023,
|
||||||
|
}
|
||||||
|
async_op_data_table = utils.load_table('async_operation_data', engine)
|
||||||
|
engine.execute(async_op_data_table.insert(async_op_data))
|
||||||
|
|
||||||
|
def check_downgrade(self, engine):
|
||||||
|
ss_table = utils.load_table('share_servers', engine)
|
||||||
|
for ss in engine.execute(ss_table.select()):
|
||||||
|
self.test_case.assertFalse(
|
||||||
|
hasattr(ss, 'security_service_update_support'))
|
||||||
|
sn_table = utils.load_table('share_networks', engine)
|
||||||
|
for sn in engine.execute(sn_table.select()):
|
||||||
|
self.test_case.assertFalse(hasattr(sn, 'status'))
|
||||||
|
|
||||||
|
self.test_case.assertRaises(
|
||||||
|
sa_exc.NoSuchTableError,
|
||||||
|
utils.load_table, 'async_operation_data', engine)
|
||||||
|
@ -2544,6 +2544,45 @@ class ShareNetworkDatabaseAPITestCase(BaseDatabaseAPITestCase):
|
|||||||
|
|
||||||
self.assertEqual(0, len(result['share_instances']))
|
self.assertEqual(0, len(result['share_instances']))
|
||||||
|
|
||||||
|
def test_association_get(self):
|
||||||
|
network = db_api.share_network_create(
|
||||||
|
self.fake_context, self.share_nw_dict)
|
||||||
|
security_service = db_api.security_service_create(
|
||||||
|
self.fake_context, security_service_dict)
|
||||||
|
network_id = network['id']
|
||||||
|
security_service_id = security_service['id']
|
||||||
|
|
||||||
|
db_api.share_network_add_security_service(
|
||||||
|
self.fake_context, network_id, security_service_id)
|
||||||
|
result = db_api.share_network_security_service_association_get(
|
||||||
|
self.fake_context, network_id, security_service_id)
|
||||||
|
|
||||||
|
self.assertEqual(result['share_network_id'], network_id)
|
||||||
|
self.assertEqual(result['security_service_id'], security_service_id)
|
||||||
|
|
||||||
|
def test_share_network_update_security_service(self):
|
||||||
|
new_sec_service = copy.copy(security_service_dict)
|
||||||
|
new_sec_service['id'] = 'fakeid'
|
||||||
|
share_network_id = self.share_nw_dict['id']
|
||||||
|
db_api.share_network_create(
|
||||||
|
self.fake_context, self.share_nw_dict)
|
||||||
|
db_api.security_service_create(
|
||||||
|
self.fake_context, security_service_dict)
|
||||||
|
db_api.security_service_create(self.fake_context, new_sec_service)
|
||||||
|
db_api.share_network_add_security_service(
|
||||||
|
self.fake_context, share_network_id,
|
||||||
|
security_service_dict['id'])
|
||||||
|
db_api.share_network_update_security_service(
|
||||||
|
self.fake_context, share_network_id, security_service_dict['id'],
|
||||||
|
new_sec_service['id'])
|
||||||
|
|
||||||
|
association = db_api.share_network_security_service_association_get(
|
||||||
|
self.fake_context, share_network_id, new_sec_service['id'])
|
||||||
|
|
||||||
|
self.assertEqual(association['share_network_id'], share_network_id)
|
||||||
|
self.assertEqual(
|
||||||
|
association['security_service_id'], new_sec_service['id'])
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class ShareNetworkSubnetDatabaseAPITestCase(BaseDatabaseAPITestCase):
|
class ShareNetworkSubnetDatabaseAPITestCase(BaseDatabaseAPITestCase):
|
||||||
|
@ -251,7 +251,7 @@ def create_share_network(**kwargs):
|
|||||||
net = {
|
net = {
|
||||||
'user_id': 'fake',
|
'user_id': 'fake',
|
||||||
'project_id': 'fake',
|
'project_id': 'fake',
|
||||||
'status': 'new',
|
'status': 'active',
|
||||||
'name': 'whatever',
|
'name': 'whatever',
|
||||||
'description': 'fake description',
|
'description': 'fake description',
|
||||||
}
|
}
|
||||||
|
@ -219,6 +219,7 @@ class HostManagerTestCase(test.TestCase):
|
|||||||
'replication_type': None,
|
'replication_type': None,
|
||||||
'replication_domain': None,
|
'replication_domain': None,
|
||||||
'sg_consistent_snapshot_support': None,
|
'sg_consistent_snapshot_support': None,
|
||||||
|
'security_service_update_support': False,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
'name': 'host2@back1#BBB',
|
'name': 'host2@back1#BBB',
|
||||||
@ -247,6 +248,7 @@ class HostManagerTestCase(test.TestCase):
|
|||||||
'replication_type': None,
|
'replication_type': None,
|
||||||
'replication_domain': None,
|
'replication_domain': None,
|
||||||
'sg_consistent_snapshot_support': None,
|
'sg_consistent_snapshot_support': None,
|
||||||
|
'security_service_update_support': False,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
'name': 'host2@back2#CCC',
|
'name': 'host2@back2#CCC',
|
||||||
@ -275,6 +277,7 @@ class HostManagerTestCase(test.TestCase):
|
|||||||
'replication_type': None,
|
'replication_type': None,
|
||||||
'replication_domain': None,
|
'replication_domain': None,
|
||||||
'sg_consistent_snapshot_support': None,
|
'sg_consistent_snapshot_support': None,
|
||||||
|
'security_service_update_support': False,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -325,6 +328,7 @@ class HostManagerTestCase(test.TestCase):
|
|||||||
'replication_type': None,
|
'replication_type': None,
|
||||||
'replication_domain': None,
|
'replication_domain': None,
|
||||||
'sg_consistent_snapshot_support': None,
|
'sg_consistent_snapshot_support': None,
|
||||||
|
'security_service_update_support': False,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
'name': 'host2@BBB#pool2',
|
'name': 'host2@BBB#pool2',
|
||||||
@ -354,6 +358,7 @@ class HostManagerTestCase(test.TestCase):
|
|||||||
'replication_type': None,
|
'replication_type': None,
|
||||||
'replication_domain': None,
|
'replication_domain': None,
|
||||||
'sg_consistent_snapshot_support': None,
|
'sg_consistent_snapshot_support': None,
|
||||||
|
'security_service_update_support': False,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
'name': 'host3@CCC#pool3',
|
'name': 'host3@CCC#pool3',
|
||||||
@ -383,6 +388,7 @@ class HostManagerTestCase(test.TestCase):
|
|||||||
'replication_type': None,
|
'replication_type': None,
|
||||||
'replication_domain': None,
|
'replication_domain': None,
|
||||||
'sg_consistent_snapshot_support': None,
|
'sg_consistent_snapshot_support': None,
|
||||||
|
'security_service_update_support': False,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
'name': 'host4@DDD#pool4a',
|
'name': 'host4@DDD#pool4a',
|
||||||
@ -412,6 +418,7 @@ class HostManagerTestCase(test.TestCase):
|
|||||||
'replication_type': None,
|
'replication_type': None,
|
||||||
'replication_domain': None,
|
'replication_domain': None,
|
||||||
'sg_consistent_snapshot_support': None,
|
'sg_consistent_snapshot_support': None,
|
||||||
|
'security_service_update_support': False,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
'name': 'host4@DDD#pool4b',
|
'name': 'host4@DDD#pool4b',
|
||||||
@ -441,6 +448,7 @@ class HostManagerTestCase(test.TestCase):
|
|||||||
'replication_type': None,
|
'replication_type': None,
|
||||||
'replication_domain': None,
|
'replication_domain': None,
|
||||||
'sg_consistent_snapshot_support': None,
|
'sg_consistent_snapshot_support': None,
|
||||||
|
'security_service_update_support': False,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -503,6 +511,7 @@ class HostManagerTestCase(test.TestCase):
|
|||||||
'replication_type': None,
|
'replication_type': None,
|
||||||
'replication_domain': None,
|
'replication_domain': None,
|
||||||
'sg_consistent_snapshot_support': None,
|
'sg_consistent_snapshot_support': None,
|
||||||
|
'security_service_update_support': False,
|
||||||
},
|
},
|
||||||
}, {
|
}, {
|
||||||
'name': 'host2@back1#BBB',
|
'name': 'host2@back1#BBB',
|
||||||
@ -531,6 +540,7 @@ class HostManagerTestCase(test.TestCase):
|
|||||||
'replication_type': None,
|
'replication_type': None,
|
||||||
'replication_domain': None,
|
'replication_domain': None,
|
||||||
'sg_consistent_snapshot_support': None,
|
'sg_consistent_snapshot_support': None,
|
||||||
|
'security_service_update_support': False,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
@ -587,6 +597,7 @@ class HostManagerTestCase(test.TestCase):
|
|||||||
'replication_type': None,
|
'replication_type': None,
|
||||||
'replication_domain': None,
|
'replication_domain': None,
|
||||||
'sg_consistent_snapshot_support': None,
|
'sg_consistent_snapshot_support': None,
|
||||||
|
'security_service_update_support': False,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
@ -142,6 +142,7 @@ class EMCShareFrameworkTestCase(test.TestCase):
|
|||||||
data['ipv6_support'] = False
|
data['ipv6_support'] = False
|
||||||
data['max_shares_per_share_server'] = -1
|
data['max_shares_per_share_server'] = -1
|
||||||
data['max_share_server_size'] = -1
|
data['max_share_server_size'] = -1
|
||||||
|
data['security_service_update_support'] = False
|
||||||
self.assertEqual(data, self.driver._stats)
|
self.assertEqual(data, self.driver._stats)
|
||||||
|
|
||||||
def _fake_safe_get(self, value):
|
def _fake_safe_get(self, value):
|
||||||
|
@ -140,6 +140,7 @@ class DummyDriver(driver.ShareDriver):
|
|||||||
self.backend_name = self.configuration.safe_get(
|
self.backend_name = self.configuration.safe_get(
|
||||||
"share_backend_name") or "DummyDriver"
|
"share_backend_name") or "DummyDriver"
|
||||||
self.migration_progress = {}
|
self.migration_progress = {}
|
||||||
|
self.security_service_update_support = True
|
||||||
|
|
||||||
def _verify_configuration(self):
|
def _verify_configuration(self):
|
||||||
allowed_driver_methods = [m for m in dir(self) if m[0] != '_']
|
allowed_driver_methods = [m for m in dir(self) if m[0] != '_']
|
||||||
@ -852,3 +853,34 @@ class DummyDriver(driver.ShareDriver):
|
|||||||
'export_locations': self.private_storage.get(share['id'],
|
'export_locations': self.private_storage.get(share['id'],
|
||||||
key='export_location')
|
key='export_location')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@slow_me_down
|
||||||
|
def update_share_server_security_service(self, context, share_server,
|
||||||
|
network_info, share_instances,
|
||||||
|
share_instance_rules,
|
||||||
|
new_security_service,
|
||||||
|
current_security_service=None):
|
||||||
|
if current_security_service:
|
||||||
|
msg = _("Replacing security service %(cur_sec_serv_id)s by "
|
||||||
|
"security service %(new_sec_serv_id)s on share server "
|
||||||
|
"%(server_id)s."
|
||||||
|
) % {
|
||||||
|
'cur_sec_serv_id': current_security_service['id'],
|
||||||
|
'new_sec_serv_id': new_security_service['id'],
|
||||||
|
'server_id': share_server['id']
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
msg = _("Adding security service %(sec_serv_id)s on share server "
|
||||||
|
"%(server_id)s."
|
||||||
|
) % {
|
||||||
|
'sec_serv_id': new_security_service['id'],
|
||||||
|
'server_id': share_server['id']
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG.debug(msg)
|
||||||
|
|
||||||
|
def check_update_share_server_security_service(
|
||||||
|
self, context, share_server, network_info, share_instances,
|
||||||
|
share_instance_rules, new_security_service,
|
||||||
|
current_security_service=None):
|
||||||
|
return True
|
||||||
|
@ -268,6 +268,7 @@ class GlusterfsNativeShareDriverTestCase(test.TestCase):
|
|||||||
'goodness_function': None,
|
'goodness_function': None,
|
||||||
'ipv4_support': True,
|
'ipv4_support': True,
|
||||||
'ipv6_support': False,
|
'ipv6_support': False,
|
||||||
|
'security_service_update_support': False,
|
||||||
}
|
}
|
||||||
self.assertEqual(test_data, self._driver._stats)
|
self.assertEqual(test_data, self._driver._stats)
|
||||||
|
|
||||||
|
@ -748,6 +748,7 @@ class HPE3ParDriverTestCase(test.TestCase):
|
|||||||
'ipv6_support': False,
|
'ipv6_support': False,
|
||||||
'max_share_server_size': -1,
|
'max_share_server_size': -1,
|
||||||
'max_shares_per_share_server': -1,
|
'max_shares_per_share_server': -1,
|
||||||
|
'security_service_update_support': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
result = self.driver.get_share_stats(refresh=True)
|
result = self.driver.get_share_stats(refresh=True)
|
||||||
@ -801,6 +802,8 @@ class HPE3ParDriverTestCase(test.TestCase):
|
|||||||
'provisioned_capacity_gb': 0,
|
'provisioned_capacity_gb': 0,
|
||||||
'reserved_percentage': 0,
|
'reserved_percentage': 0,
|
||||||
'max_over_subscription_ratio': None,
|
'max_over_subscription_ratio': None,
|
||||||
|
'max_share_server_size': -1,
|
||||||
|
'max_shares_per_share_server': -1,
|
||||||
'qos': False,
|
'qos': False,
|
||||||
'thin_provisioning': True,
|
'thin_provisioning': True,
|
||||||
'pools': [{
|
'pools': [{
|
||||||
@ -816,6 +819,7 @@ class HPE3ParDriverTestCase(test.TestCase):
|
|||||||
'snapshot_support': True,
|
'snapshot_support': True,
|
||||||
'create_share_from_snapshot_support': True,
|
'create_share_from_snapshot_support': True,
|
||||||
'revert_to_snapshot_support': False,
|
'revert_to_snapshot_support': False,
|
||||||
|
'security_service_update_support': False,
|
||||||
'mount_snapshot_support': False,
|
'mount_snapshot_support': False,
|
||||||
'share_group_stats': {
|
'share_group_stats': {
|
||||||
'consistent_snapshot_support': None,
|
'consistent_snapshot_support': None,
|
||||||
@ -825,8 +829,6 @@ class HPE3ParDriverTestCase(test.TestCase):
|
|||||||
'goodness_function': None,
|
'goodness_function': None,
|
||||||
'ipv4_support': True,
|
'ipv4_support': True,
|
||||||
'ipv6_support': False,
|
'ipv6_support': False,
|
||||||
'max_share_server_size': -1,
|
|
||||||
'max_shares_per_share_server': -1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = self.driver.get_share_stats(refresh=True)
|
result = self.driver.get_share_stats(refresh=True)
|
||||||
@ -851,6 +853,8 @@ class HPE3ParDriverTestCase(test.TestCase):
|
|||||||
'driver_version': expected_version,
|
'driver_version': expected_version,
|
||||||
'free_capacity_gb': 0,
|
'free_capacity_gb': 0,
|
||||||
'max_over_subscription_ratio': None,
|
'max_over_subscription_ratio': None,
|
||||||
|
'max_share_server_size': -1,
|
||||||
|
'max_shares_per_share_server': -1,
|
||||||
'pools': None,
|
'pools': None,
|
||||||
'provisioned_capacity_gb': 0,
|
'provisioned_capacity_gb': 0,
|
||||||
'reserved_percentage': 0,
|
'reserved_percentage': 0,
|
||||||
@ -862,6 +866,7 @@ class HPE3ParDriverTestCase(test.TestCase):
|
|||||||
'snapshot_support': True,
|
'snapshot_support': True,
|
||||||
'create_share_from_snapshot_support': True,
|
'create_share_from_snapshot_support': True,
|
||||||
'revert_to_snapshot_support': False,
|
'revert_to_snapshot_support': False,
|
||||||
|
'security_service_update_support': False,
|
||||||
'mount_snapshot_support': False,
|
'mount_snapshot_support': False,
|
||||||
'share_group_stats': {
|
'share_group_stats': {
|
||||||
'consistent_snapshot_support': None,
|
'consistent_snapshot_support': None,
|
||||||
@ -871,8 +876,6 @@ class HPE3ParDriverTestCase(test.TestCase):
|
|||||||
'goodness_function': None,
|
'goodness_function': None,
|
||||||
'ipv4_support': True,
|
'ipv4_support': True,
|
||||||
'ipv6_support': False,
|
'ipv6_support': False,
|
||||||
'max_share_server_size': -1,
|
|
||||||
'max_shares_per_share_server': -1,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = self.driver.get_share_stats(refresh=True)
|
result = self.driver.get_share_stats(refresh=True)
|
||||||
|
@ -2434,6 +2434,7 @@ class HuaweiShareDriverTestCase(test.TestCase):
|
|||||||
"share_group_stats": {"consistent_snapshot_support": None},
|
"share_group_stats": {"consistent_snapshot_support": None},
|
||||||
"ipv4_support": True,
|
"ipv4_support": True,
|
||||||
"ipv6_support": False,
|
"ipv6_support": False,
|
||||||
|
"security_service_update_support": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
if replication_support:
|
if replication_support:
|
||||||
|
@ -446,6 +446,7 @@ class ACCESSShareDriverTestCase(test.TestCase):
|
|||||||
'revert_to_snapshot_support': False,
|
'revert_to_snapshot_support': False,
|
||||||
'share_group_stats': {'consistent_snapshot_support': None},
|
'share_group_stats': {'consistent_snapshot_support': None},
|
||||||
'snapshot_support': True,
|
'snapshot_support': True,
|
||||||
|
'security_service_update_support': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
self.assertEqual(data, self._driver._stats)
|
self.assertEqual(data, self._driver._stats)
|
||||||
|
@ -368,6 +368,7 @@ class ZFSonLinuxShareDriverTestCase(test.TestCase):
|
|||||||
'goodness_function': None,
|
'goodness_function': None,
|
||||||
'ipv4_support': True,
|
'ipv4_support': True,
|
||||||
'ipv6_support': False,
|
'ipv6_support': False,
|
||||||
|
'security_service_update_support': False,
|
||||||
}
|
}
|
||||||
if replication_domain:
|
if replication_domain:
|
||||||
expected['replication_type'] = 'readable'
|
expected['replication_type'] = 'readable'
|
||||||
|
@ -23,6 +23,7 @@ import ddt
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
|
from webob import exc as webob_exc
|
||||||
|
|
||||||
from manila.common import constants
|
from manila.common import constants
|
||||||
from manila import context
|
from manila import context
|
||||||
@ -1098,6 +1099,7 @@ class ShareAPITestCase(test.TestCase):
|
|||||||
share_server = db_utils.create_share_server(
|
share_server = db_utils.create_share_server(
|
||||||
status=constants.STATUS_ACTIVE, id=share_server_id,
|
status=constants.STATUS_ACTIVE, id=share_server_id,
|
||||||
share_network_subnet_id=fake_subnet['id'])
|
share_network_subnet_id=fake_subnet['id'])
|
||||||
|
share_network = db_utils.create_share_network(id='fake')
|
||||||
fake_share_data = {
|
fake_share_data = {
|
||||||
'id': 'fakeid',
|
'id': 'fakeid',
|
||||||
'status': constants.STATUS_CREATING,
|
'status': constants.STATUS_CREATING,
|
||||||
@ -1130,6 +1132,8 @@ class ShareAPITestCase(test.TestCase):
|
|||||||
mock.Mock(return_value=fake_subnet))
|
mock.Mock(return_value=fake_subnet))
|
||||||
self.mock_object(db_api, 'share_instances_get_all',
|
self.mock_object(db_api, 'share_instances_get_all',
|
||||||
mock.Mock(return_value=[]))
|
mock.Mock(return_value=[]))
|
||||||
|
self.mock_object(db_api, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
|
||||||
self.api.manage(self.context, copy.deepcopy(share_data),
|
self.api.manage(self.context, copy.deepcopy(share_data),
|
||||||
driver_options)
|
driver_options)
|
||||||
@ -5664,6 +5668,262 @@ class ShareAPITestCase(test.TestCase):
|
|||||||
self.api.share_rpcapi.migration_get_progress.assert_called_once_with(
|
self.api.share_rpcapi.migration_get_progress.assert_called_once_with(
|
||||||
self.context, instance1, instance2['id'])
|
self.context, instance1, instance2['id'])
|
||||||
|
|
||||||
|
def test__share_network_update_initial_checks_network_not_active(self):
|
||||||
|
share_network = db_utils.create_share_network(
|
||||||
|
status=constants.STATUS_NETWORK_CHANGE)
|
||||||
|
new_sec_service = db_utils.create_security_service(
|
||||||
|
share_network_id=share_network['id'], type='ldap')
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
webob_exc.HTTPBadRequest,
|
||||||
|
self.api._share_network_update_initial_checks,
|
||||||
|
self.context, share_network, new_sec_service
|
||||||
|
)
|
||||||
|
|
||||||
|
def test__share_network_update_initial_checks_server_not_active(self):
|
||||||
|
db_utils.create_share_server(
|
||||||
|
share_network_subnet_id='fakeid', status=constants.STATUS_ERROR,
|
||||||
|
security_service_update_support=True)
|
||||||
|
db_utils.create_share_network_subnet(
|
||||||
|
id='fakeid', share_network_id='fakenetid')
|
||||||
|
share_network = db_utils.create_share_network(id='fakenetid')
|
||||||
|
new_sec_service = db_utils.create_security_service(
|
||||||
|
share_network_id='fakenetid', type='ldap')
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception.InvalidShareNetwork,
|
||||||
|
self.api._share_network_update_initial_checks,
|
||||||
|
self.context, share_network, new_sec_service,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test__share_network_update_initial_checks_shares_not_available(self):
|
||||||
|
db_utils.create_share_server(share_network_subnet_id='fakeid',
|
||||||
|
security_service_update_support=True)
|
||||||
|
db_utils.create_share_network_subnet(
|
||||||
|
id='fakeid', share_network_id='fake_network_id')
|
||||||
|
share_network = db_utils.create_share_network(
|
||||||
|
id='fake_network_id')
|
||||||
|
new_sec_service = db_utils.create_security_service(
|
||||||
|
share_network_id='fake_network_id', type='ldap')
|
||||||
|
shares = [db_utils.create_share(status=constants.STATUS_ERROR)]
|
||||||
|
|
||||||
|
self.mock_object(utils, 'validate_service_host')
|
||||||
|
self.mock_object(
|
||||||
|
self.api, 'get_all', mock.Mock(return_value=shares))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception.InvalidShareNetwork,
|
||||||
|
self.api._share_network_update_initial_checks,
|
||||||
|
self.context, share_network, new_sec_service
|
||||||
|
)
|
||||||
|
utils.validate_service_host.assert_called_once_with(
|
||||||
|
utils.IsAMatcher(context.RequestContext), 'host1')
|
||||||
|
self.api.get_all.assert_called_once_with(
|
||||||
|
self.context,
|
||||||
|
search_opts={'share_network_id': share_network['id']})
|
||||||
|
|
||||||
|
def test__share_network_update_initial_checks_rules_in_error(self):
|
||||||
|
db_utils.create_share_server(share_network_subnet_id='fakeid',
|
||||||
|
security_service_update_support=True)
|
||||||
|
db_utils.create_share_network_subnet(
|
||||||
|
id='fakeid', share_network_id='fake_network_id')
|
||||||
|
share_network = db_utils.create_share_network(
|
||||||
|
id='fake_network_id')
|
||||||
|
new_sec_service = db_utils.create_security_service(
|
||||||
|
share_network_id='fake_network_id', type='ldap')
|
||||||
|
shares = [db_utils.create_share(status=constants.STATUS_AVAILABLE)]
|
||||||
|
shares[0]['instance']['access_rules_status'] = (
|
||||||
|
constants.ACCESS_STATE_ERROR)
|
||||||
|
|
||||||
|
self.mock_object(utils, 'validate_service_host')
|
||||||
|
self.mock_object(
|
||||||
|
self.api, 'get_all', mock.Mock(return_value=shares))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception.InvalidShareNetwork,
|
||||||
|
self.api._share_network_update_initial_checks,
|
||||||
|
self.context, share_network, new_sec_service
|
||||||
|
)
|
||||||
|
utils.validate_service_host.assert_called_once_with(
|
||||||
|
utils.IsAMatcher(context.RequestContext), 'host1')
|
||||||
|
self.api.get_all.assert_called_once_with(
|
||||||
|
self.context,
|
||||||
|
search_opts={'share_network_id': share_network['id']})
|
||||||
|
|
||||||
|
def test__share_network_update_initial_checks_share_is_busy(self):
|
||||||
|
db_utils.create_share_server(share_network_subnet_id='fakeid',
|
||||||
|
security_service_update_support=True)
|
||||||
|
db_utils.create_share_network_subnet(
|
||||||
|
id='fakeid', share_network_id='fake_net_id')
|
||||||
|
share_network = db_utils.create_share_network(id='fake_net_id')
|
||||||
|
new_sec_service = db_utils.create_security_service(
|
||||||
|
share_network_id='fake_net_id', type='ldap')
|
||||||
|
shares = [db_utils.create_share(status=constants.STATUS_AVAILABLE)]
|
||||||
|
|
||||||
|
self.mock_object(utils, 'validate_service_host')
|
||||||
|
self.mock_object(
|
||||||
|
self.api, 'get_all', mock.Mock(return_value=shares))
|
||||||
|
self.mock_object(
|
||||||
|
self.api, '_check_is_share_busy',
|
||||||
|
mock.Mock(side_effect=exception.ShareBusyException(message='fake'))
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception.InvalidShareNetwork,
|
||||||
|
self.api._share_network_update_initial_checks,
|
||||||
|
self.context, share_network, new_sec_service
|
||||||
|
)
|
||||||
|
utils.validate_service_host.assert_called_once_with(
|
||||||
|
utils.IsAMatcher(context.RequestContext), 'host1')
|
||||||
|
self.api.get_all.assert_called_once_with(
|
||||||
|
self.context,
|
||||||
|
search_opts={'share_network_id': share_network['id']})
|
||||||
|
self.api._check_is_share_busy.assert_called_once_with(shares[0])
|
||||||
|
|
||||||
|
def test__share_network_update_initial_checks_unsupported_server(self):
|
||||||
|
db_utils.create_share_server(share_network_subnet_id='fakeid',
|
||||||
|
security_service_update_support=False)
|
||||||
|
db_utils.create_share_network_subnet(
|
||||||
|
id='fakeid', share_network_id='fake_net_id')
|
||||||
|
share_network = db_utils.create_share_network(id='fake_net_id')
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception.InvalidShareNetwork,
|
||||||
|
self.api._share_network_update_initial_checks,
|
||||||
|
self.context, share_network, None
|
||||||
|
)
|
||||||
|
|
||||||
|
def test__share_network_update_initial_checks_update_different_types(self):
|
||||||
|
db_utils.create_share_server(share_network_subnet_id='fakeid',
|
||||||
|
security_service_update_support=True)
|
||||||
|
db_utils.create_share_network_subnet(
|
||||||
|
id='fakeid', share_network_id='fake_net_id')
|
||||||
|
share_network = db_utils.create_share_network(id='fake_net_id')
|
||||||
|
new_sec_service = db_utils.create_security_service(
|
||||||
|
share_network_id='fake_net_id', type='ldap')
|
||||||
|
curr_sec_service = db_utils.create_security_service(
|
||||||
|
share_network_id='fake_net_id', type='kerberos')
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception.InvalidSecurityService,
|
||||||
|
self.api._share_network_update_initial_checks,
|
||||||
|
self.context, share_network, new_sec_service,
|
||||||
|
current_security_service=curr_sec_service
|
||||||
|
)
|
||||||
|
|
||||||
|
def test__share_network_update_initial_checks_add_type_conflict(self):
|
||||||
|
db_utils.create_share_server(share_network_subnet_id='fakeid',
|
||||||
|
security_service_update_support=True)
|
||||||
|
db_utils.create_share_network_subnet(
|
||||||
|
id='fakeid', share_network_id='fake_net_id')
|
||||||
|
share_network = db_utils.create_share_network(id='fake_net_id')
|
||||||
|
db_utils.create_security_service(
|
||||||
|
share_network_id='fake_net_id', type='ldap')
|
||||||
|
share_network = db_api.share_network_get(self.context,
|
||||||
|
share_network['id'])
|
||||||
|
new_sec_service = db_utils.create_security_service(
|
||||||
|
share_network_id='fake_net_id', type='ldap')
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception.InvalidSecurityService,
|
||||||
|
self.api._share_network_update_initial_checks,
|
||||||
|
self.context, share_network, new_sec_service,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_update_share_network_security_service_backend_host_failure(self):
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
security_service = db_utils.create_security_service()
|
||||||
|
backend_host = 'fakehost'
|
||||||
|
|
||||||
|
mock_initial_checks = self.mock_object(
|
||||||
|
self.api, '_share_network_update_initial_checks',
|
||||||
|
mock.Mock(return_value=(['fake_server'], [backend_host])))
|
||||||
|
mock_get_update_key = self.mock_object(
|
||||||
|
self.api, 'get_security_service_update_key',
|
||||||
|
mock.Mock(return_value='fake_key'))
|
||||||
|
mock_db_async_op = self.mock_object(
|
||||||
|
db_api, 'async_operation_data_get',
|
||||||
|
mock.Mock(return_value='fake_update_value'))
|
||||||
|
mock_validate_host = self.mock_object(
|
||||||
|
self.api, '_security_service_update_validate_hosts',
|
||||||
|
mock.Mock(return_value=(False, None)))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
exception.InvalidShareNetwork,
|
||||||
|
self.api.update_share_network_security_service,
|
||||||
|
self.context, share_network, security_service)
|
||||||
|
|
||||||
|
mock_initial_checks.assert_called_once_with(
|
||||||
|
self.context, share_network, security_service,
|
||||||
|
current_security_service=None)
|
||||||
|
mock_db_async_op.assert_called_once_with(
|
||||||
|
self.context, share_network['id'], 'fake_key')
|
||||||
|
mock_get_update_key.assert_called_once_with(
|
||||||
|
'hosts_check', security_service['id'],
|
||||||
|
current_security_service_id=None)
|
||||||
|
mock_validate_host.assert_called_once_with(
|
||||||
|
self.context, share_network, [backend_host], ['fake_server'],
|
||||||
|
new_security_service_id=security_service['id'],
|
||||||
|
current_security_service_id=None)
|
||||||
|
|
||||||
|
def test_update_share_network_security_service(self):
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
security_service = db_utils.create_security_service()
|
||||||
|
backend_hosts = ['fakehost']
|
||||||
|
fake_update_key = 'fake_key'
|
||||||
|
servers = [
|
||||||
|
db_utils.create_share_server() for i in range(2)]
|
||||||
|
server_ids = [server['id'] for server in servers]
|
||||||
|
|
||||||
|
mock_initial_checks = self.mock_object(
|
||||||
|
self.api, '_share_network_update_initial_checks',
|
||||||
|
mock.Mock(return_value=(servers, backend_hosts)))
|
||||||
|
mock_get_update_key = self.mock_object(
|
||||||
|
self.api, 'get_security_service_update_key',
|
||||||
|
mock.Mock(return_value=fake_update_key))
|
||||||
|
mock_db_async_op = self.mock_object(
|
||||||
|
db_api, 'async_operation_data_get',
|
||||||
|
mock.Mock(return_value='fake_update_value'))
|
||||||
|
mock_validate_host = self.mock_object(
|
||||||
|
self.api, '_security_service_update_validate_hosts',
|
||||||
|
mock.Mock(return_value=(True, None)))
|
||||||
|
mock_network_update = self.mock_object(
|
||||||
|
db_api, 'share_network_update')
|
||||||
|
mock_servers_update = self.mock_object(
|
||||||
|
db_api, 'share_servers_update')
|
||||||
|
mock_update_security_services = self.mock_object(
|
||||||
|
self.share_rpcapi, 'update_share_network_security_service')
|
||||||
|
mock_db_async_op_del = self.mock_object(
|
||||||
|
db_api, 'async_operation_data_delete',)
|
||||||
|
|
||||||
|
self.api.update_share_network_security_service(
|
||||||
|
self.context, share_network, security_service)
|
||||||
|
|
||||||
|
mock_initial_checks.assert_called_once_with(
|
||||||
|
self.context, share_network, security_service,
|
||||||
|
current_security_service=None)
|
||||||
|
mock_db_async_op.assert_called_once_with(
|
||||||
|
self.context, share_network['id'], fake_update_key)
|
||||||
|
mock_get_update_key.assert_called_once_with(
|
||||||
|
'hosts_check', security_service['id'],
|
||||||
|
current_security_service_id=None)
|
||||||
|
mock_validate_host.assert_called_once_with(
|
||||||
|
self.context, share_network, backend_hosts, servers,
|
||||||
|
new_security_service_id=security_service['id'],
|
||||||
|
current_security_service_id=None)
|
||||||
|
mock_network_update.assert_called_once_with(
|
||||||
|
self.context, share_network['id'],
|
||||||
|
{'status': constants.STATUS_NETWORK_CHANGE})
|
||||||
|
mock_servers_update.assert_called_once_with(
|
||||||
|
self.context, server_ids,
|
||||||
|
{'status': constants.STATUS_SERVER_NETWORK_CHANGE}
|
||||||
|
)
|
||||||
|
mock_update_security_services.assert_called_once_with(
|
||||||
|
self.context, backend_hosts[0], share_network['id'],
|
||||||
|
security_service['id'], current_security_service_id=None)
|
||||||
|
mock_db_async_op_del.assert_called_once_with(
|
||||||
|
self.context, share_network['id'], fake_update_key)
|
||||||
|
|
||||||
|
|
||||||
class OtherTenantsShareActionsTestCase(test.TestCase):
|
class OtherTenantsShareActionsTestCase(test.TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -945,6 +945,31 @@ class ShareDriverTestCase(test.TestCase):
|
|||||||
self.assertIsNone(share_group_update)
|
self.assertIsNone(share_group_update)
|
||||||
self.assertEqual(expected_share_updates, share_update)
|
self.assertEqual(expected_share_updates, share_update)
|
||||||
|
|
||||||
|
def test_update_share_server_security_service(self):
|
||||||
|
share_driver = self._instantiate_share_driver(None, True)
|
||||||
|
self.assertRaises(NotImplementedError,
|
||||||
|
share_driver.update_share_server_security_service,
|
||||||
|
'fake_context',
|
||||||
|
{'id', 'share_server_id'},
|
||||||
|
{'fake', 'fake_net_info'},
|
||||||
|
[{"id": "fake_instance_id"}],
|
||||||
|
[{"id": "fake_rule_id"}],
|
||||||
|
{'id', 'fake_sec_service_id'},
|
||||||
|
current_security_service=None)
|
||||||
|
|
||||||
|
def test_check_update_share_server_security_service(self):
|
||||||
|
share_driver = self._instantiate_share_driver(None, True)
|
||||||
|
self.assertRaises(
|
||||||
|
NotImplementedError,
|
||||||
|
share_driver.check_update_share_server_security_service,
|
||||||
|
'fake_context',
|
||||||
|
{'id', 'share_server_id'},
|
||||||
|
{'fake', 'fake_net_info'},
|
||||||
|
[{"id": "fake_instance_id"}],
|
||||||
|
[{"id": "fake_rule_id"}],
|
||||||
|
{'id', 'fake_sec_service_id'},
|
||||||
|
current_security_service=None)
|
||||||
|
|
||||||
def test_create_share_group_from_sg_snapshot_with_no_members(self):
|
def test_create_share_group_from_sg_snapshot_with_no_members(self):
|
||||||
share_driver = self._instantiate_share_driver(None, False)
|
share_driver = self._instantiate_share_driver(None, False)
|
||||||
fake_share_group_dict = {}
|
fake_share_group_dict = {}
|
||||||
|
@ -579,6 +579,7 @@ class ShareManagerTestCase(test.TestCase):
|
|||||||
'source_share_group_snapshot_member_id'),
|
'source_share_group_snapshot_member_id'),
|
||||||
'availability_zone': share_instance.get('availability_zone'),
|
'availability_zone': share_instance.get('availability_zone'),
|
||||||
'export_locations': share_instance.get('export_locations') or [],
|
'export_locations': share_instance.get('export_locations') or [],
|
||||||
|
'share_network_status': share_instance.get('share_network_status')
|
||||||
}
|
}
|
||||||
return share_instance_ref
|
return share_instance_ref
|
||||||
|
|
||||||
@ -1115,7 +1116,7 @@ class ShareManagerTestCase(test.TestCase):
|
|||||||
self.mock_object(db, 'share_instance_access_get',
|
self.mock_object(db, 'share_instance_access_get',
|
||||||
mock.Mock(return_value=fake_access_rules[0]))
|
mock.Mock(return_value=fake_access_rules[0]))
|
||||||
mock_share_replica_access_update = self.mock_object(
|
mock_share_replica_access_update = self.mock_object(
|
||||||
self.share_manager, '_update_share_replica_access_rules_state')
|
self.share_manager, '_update_share_instance_access_rules_state')
|
||||||
driver_call = self.mock_object(
|
driver_call = self.mock_object(
|
||||||
self.share_manager.driver, 'create_replica',
|
self.share_manager.driver, 'create_replica',
|
||||||
mock.Mock(return_value=replica))
|
mock.Mock(return_value=replica))
|
||||||
@ -2828,6 +2829,7 @@ class ShareManagerTestCase(test.TestCase):
|
|||||||
'host': self.share_manager.host,
|
'host': self.share_manager.host,
|
||||||
'share_network_subnet_id': fake_data['fake_network_subnet']['id'],
|
'share_network_subnet_id': fake_data['fake_network_subnet']['id'],
|
||||||
'status': constants.STATUS_CREATING,
|
'status': constants.STATUS_CREATING,
|
||||||
|
'security_service_update_support': False,
|
||||||
}
|
}
|
||||||
fake_metadata = {
|
fake_metadata = {
|
||||||
'migration_destination': True,
|
'migration_destination': True,
|
||||||
@ -9034,6 +9036,377 @@ class ShareManagerTestCase(test.TestCase):
|
|||||||
self.context, fake_source_share_server, fake_dest_share_server,
|
self.context, fake_source_share_server, fake_dest_share_server,
|
||||||
fake_share_instances, fake_snapshot_instances)
|
fake_share_instances, fake_snapshot_instances)
|
||||||
|
|
||||||
|
@ddt.data([constants.STATUS_ERROR, constants.STATUS_ACTIVE],
|
||||||
|
[constants.STATUS_ACTIVE, constants.STATUS_ACTIVE])
|
||||||
|
def test__check_share_network_update_finished(self, server_statuses):
|
||||||
|
share_servers = [
|
||||||
|
db_utils.create_share_server(status=status)
|
||||||
|
for status in server_statuses]
|
||||||
|
share_network = db_utils.create_share_network(
|
||||||
|
status=constants.STATUS_SERVER_NETWORK_CHANGE)
|
||||||
|
all_servers_are_active = (
|
||||||
|
all(server_statuses) == constants.STATUS_ACTIVE)
|
||||||
|
|
||||||
|
self.mock_object(db, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(
|
||||||
|
db, 'share_server_get_all_with_filters',
|
||||||
|
mock.Mock(return_value=share_servers))
|
||||||
|
self.mock_object(db, 'share_network_update')
|
||||||
|
|
||||||
|
self.share_manager._check_share_network_update_finished(
|
||||||
|
self.context, share_network['id'])
|
||||||
|
|
||||||
|
db.share_server_get_all_with_filters.assert_called_once_with(
|
||||||
|
self.context, {'share_network_id': share_network['id']})
|
||||||
|
db.share_network_get.assert_called_once_with(
|
||||||
|
self.context, share_network['id'])
|
||||||
|
if all_servers_are_active:
|
||||||
|
db.share_network_update.assert_called_once_with(
|
||||||
|
self.context, share_network['id'],
|
||||||
|
{'status': constants.STATUS_NETWORK_ACTIVE})
|
||||||
|
|
||||||
|
def test__check_share_network_update_finished_already_active(self):
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
|
||||||
|
self.mock_object(db, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(db, 'share_server_get_all_with_filters')
|
||||||
|
|
||||||
|
self.share_manager._check_share_network_update_finished(
|
||||||
|
self.context, share_network['id'])
|
||||||
|
|
||||||
|
db.share_network_get.assert_called_once_with(
|
||||||
|
self.context, share_network['id'])
|
||||||
|
db.share_server_get_all_with_filters.assert_not_called()
|
||||||
|
|
||||||
|
def _setup_mocks_for_sec_service_update(
|
||||||
|
self, service_get_effect, share_network, share_servers, subnet,
|
||||||
|
network_info, share_instances, fake_rules,
|
||||||
|
driver_support_update=True, driver_update_action=mock.Mock()):
|
||||||
|
|
||||||
|
self.mock_object(
|
||||||
|
db, 'security_service_get',
|
||||||
|
mock.Mock(side_effect=service_get_effect))
|
||||||
|
self.mock_object(
|
||||||
|
db, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
self.mock_object(
|
||||||
|
db, 'share_server_get_all_by_host',
|
||||||
|
mock.Mock(return_value=share_servers))
|
||||||
|
self.mock_object(
|
||||||
|
db, 'share_network_subnet_get', mock.Mock(return_value=subnet))
|
||||||
|
self.mock_object(
|
||||||
|
self.share_manager, '_form_server_setup_info',
|
||||||
|
mock.Mock(return_value=network_info))
|
||||||
|
self.mock_object(
|
||||||
|
db, 'share_instances_get_all_by_share_server',
|
||||||
|
mock.Mock(return_value=share_instances))
|
||||||
|
self.mock_object(
|
||||||
|
db, 'share_access_get_all_for_instance',
|
||||||
|
mock.Mock(return_value=fake_rules))
|
||||||
|
self.mock_object(
|
||||||
|
self.share_manager.driver,
|
||||||
|
'check_update_share_server_security_service',
|
||||||
|
mock.Mock(return_value=driver_support_update))
|
||||||
|
self.mock_object(db, 'share_server_backend_details_set')
|
||||||
|
self.mock_object(
|
||||||
|
self.share_manager.driver,
|
||||||
|
'update_share_server_security_service', driver_update_action)
|
||||||
|
self.mock_object(db, 'share_server_update')
|
||||||
|
self.mock_object(
|
||||||
|
self.share_manager, '_check_share_network_update_finished')
|
||||||
|
self.mock_object(
|
||||||
|
self.share_manager.access_helper,
|
||||||
|
'get_and_update_share_instance_access_rules')
|
||||||
|
self.mock_object(
|
||||||
|
self.share_manager.access_helper,
|
||||||
|
'update_share_instances_access_rules_status')
|
||||||
|
self.mock_object(
|
||||||
|
self.share_manager.access_helper, 'process_driver_rule_updates')
|
||||||
|
|
||||||
|
@ddt.data(False, True)
|
||||||
|
def test__update_share_network_security_service(self, is_check_only):
|
||||||
|
security_services = [
|
||||||
|
db_utils.create_security_service() for i in range(2)]
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
share_network_subnet = db_utils.create_share_network_subnet()
|
||||||
|
share_servers = [
|
||||||
|
db_utils.create_share_server(
|
||||||
|
share_network_subnet_id=share_network_subnet['id'])]
|
||||||
|
security_services_effect = mock.Mock(side_effect=security_services)
|
||||||
|
share_network_id = share_network['id']
|
||||||
|
current_security_service_id = security_services[0]['id']
|
||||||
|
new_security_service_id = security_services[1]['id']
|
||||||
|
share_network_subnet_id = share_servers[0]['share_network_subnet_id']
|
||||||
|
share_instances = [db_utils.create_share()['instance']]
|
||||||
|
fake_rules = ['fake_rules']
|
||||||
|
network_info = {'fake': 'fake'}
|
||||||
|
backend_details_keys = [
|
||||||
|
'name', 'ou', 'domain', 'server', 'dns_ip', 'user', 'type',
|
||||||
|
'password']
|
||||||
|
backend_details_data = {}
|
||||||
|
[backend_details_data.update(
|
||||||
|
{key: security_services[0][key]}) for key in backend_details_keys]
|
||||||
|
backend_details_exp_update = {
|
||||||
|
'security_service_' + security_services[0]['type']:
|
||||||
|
jsonutils.dumps(backend_details_data)
|
||||||
|
}
|
||||||
|
expected_instance_rules = [{
|
||||||
|
'share_instance_id': share_instances[0]['id'],
|
||||||
|
'access_rules': fake_rules
|
||||||
|
}]
|
||||||
|
rule_updates = {
|
||||||
|
share_instances[0]['id']: {
|
||||||
|
'access_rule_id': {
|
||||||
|
'access_key': 'fake_access_key',
|
||||||
|
'state': 'active',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
}
|
||||||
|
expected_rule_updates_value = rule_updates[share_instances[0]['id']]
|
||||||
|
driver_return = mock.Mock(return_value=rule_updates)
|
||||||
|
|
||||||
|
self._setup_mocks_for_sec_service_update(
|
||||||
|
security_services_effect, share_network, share_servers,
|
||||||
|
share_network_subnet, network_info, share_instances, fake_rules,
|
||||||
|
driver_update_action=driver_return)
|
||||||
|
|
||||||
|
result = self.share_manager._update_share_network_security_service(
|
||||||
|
self.context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id,
|
||||||
|
check_only=is_check_only)
|
||||||
|
|
||||||
|
db.security_service_get.assert_has_calls(
|
||||||
|
[mock.call(self.context, security_services[1]['id']),
|
||||||
|
mock.call(self.context, security_services[0]['id'])]
|
||||||
|
)
|
||||||
|
db.share_network_get.assert_called_once_with(
|
||||||
|
self.context, share_network_id)
|
||||||
|
db.share_server_get_all_by_host.assert_called_once_with(
|
||||||
|
self.context, self.share_manager.host,
|
||||||
|
filters={'share_network_id': share_network_id})
|
||||||
|
db.share_network_subnet_get.assert_called_once_with(
|
||||||
|
self.context, share_network_subnet_id)
|
||||||
|
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||||
|
self.context, share_servers[0], share_network, share_network_subnet
|
||||||
|
)
|
||||||
|
db.share_instances_get_all_by_share_server.assert_called_once_with(
|
||||||
|
self.context, share_servers[0]['id'], with_share_data=True)
|
||||||
|
db.share_access_get_all_for_instance.assert_called_once_with(
|
||||||
|
self.context, share_instances[0]['id'])
|
||||||
|
if not is_check_only:
|
||||||
|
(self.share_manager.driver.update_share_server_security_service.
|
||||||
|
assert_called_once_with(
|
||||||
|
self.context, share_servers[0], network_info,
|
||||||
|
share_instances,
|
||||||
|
expected_instance_rules,
|
||||||
|
security_services[0],
|
||||||
|
current_security_service=security_services[1]))
|
||||||
|
db.share_server_backend_details_set.assert_called_once_with(
|
||||||
|
self.context, share_servers[0]['id'],
|
||||||
|
backend_details_exp_update)
|
||||||
|
db.share_server_update.assert_called_once_with(
|
||||||
|
self.context, share_servers[0]['id'],
|
||||||
|
{'status': constants.STATUS_ACTIVE})
|
||||||
|
(self.share_manager.access_helper.process_driver_rule_updates.
|
||||||
|
assert_called_once_with(
|
||||||
|
self.context, expected_rule_updates_value,
|
||||||
|
share_instances[0]['id']))
|
||||||
|
else:
|
||||||
|
(self.share_manager.driver.
|
||||||
|
check_update_share_server_security_service.
|
||||||
|
assert_called_once_with(
|
||||||
|
self.context, share_servers[0], network_info,
|
||||||
|
share_instances,
|
||||||
|
expected_instance_rules,
|
||||||
|
security_services[0],
|
||||||
|
current_security_service=security_services[1]))
|
||||||
|
self.assertEqual(result, True)
|
||||||
|
|
||||||
|
def test__update_share_network_security_service_no_support(self):
|
||||||
|
security_services = [
|
||||||
|
db_utils.create_security_service() for i in range(2)]
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
share_network_subnet = db_utils.create_share_network_subnet()
|
||||||
|
share_servers = [
|
||||||
|
db_utils.create_share_server(
|
||||||
|
share_network_subnet_id=share_network_subnet['id'])]
|
||||||
|
security_services_effect = mock.Mock(side_effect=security_services)
|
||||||
|
share_network_id = share_network['id']
|
||||||
|
current_security_service_id = security_services[0]['id']
|
||||||
|
new_security_service_id = security_services[1]['id']
|
||||||
|
share_network_subnet_id = share_servers[0]['share_network_subnet_id']
|
||||||
|
network_info = {'fake': 'fake'}
|
||||||
|
share_instances = [db_utils.create_share()['instance']]
|
||||||
|
fake_rules = ['fake_rules']
|
||||||
|
expected_instance_rules = [{
|
||||||
|
'share_instance_id': share_instances[0]['id'],
|
||||||
|
'access_rules': fake_rules
|
||||||
|
}]
|
||||||
|
|
||||||
|
self._setup_mocks_for_sec_service_update(
|
||||||
|
security_services_effect, share_network, share_servers,
|
||||||
|
share_network_subnet, network_info, share_instances, fake_rules,
|
||||||
|
driver_support_update=False)
|
||||||
|
|
||||||
|
result = self.share_manager._update_share_network_security_service(
|
||||||
|
self.context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id,
|
||||||
|
check_only=True)
|
||||||
|
|
||||||
|
db.security_service_get.assert_has_calls(
|
||||||
|
[mock.call(self.context, security_services[1]['id']),
|
||||||
|
mock.call(self.context, security_services[0]['id'])]
|
||||||
|
)
|
||||||
|
db.share_network_get.assert_called_once_with(
|
||||||
|
self.context, share_network_id)
|
||||||
|
db.share_server_get_all_by_host.assert_called_once_with(
|
||||||
|
self.context, self.share_manager.host,
|
||||||
|
filters={'share_network_id': share_network_id})
|
||||||
|
db.share_network_subnet_get.assert_called_once_with(
|
||||||
|
self.context, share_network_subnet_id)
|
||||||
|
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||||
|
self.context, share_servers[0], share_network, share_network_subnet
|
||||||
|
)
|
||||||
|
db.share_instances_get_all_by_share_server.assert_called_once_with(
|
||||||
|
self.context, share_servers[0]['id'], with_share_data=True)
|
||||||
|
db.share_access_get_all_for_instance.assert_called_once_with(
|
||||||
|
self.context, share_instances[0]['id'])
|
||||||
|
(self.share_manager.driver.check_update_share_server_security_service.
|
||||||
|
assert_called_once_with(
|
||||||
|
self.context, share_servers[0], network_info,
|
||||||
|
share_instances,
|
||||||
|
expected_instance_rules,
|
||||||
|
security_services[0],
|
||||||
|
current_security_service=security_services[1]))
|
||||||
|
self.assertEqual(result, False)
|
||||||
|
|
||||||
|
def test__update_share_network_security_service_exception(self):
|
||||||
|
security_services = [
|
||||||
|
db_utils.create_security_service() for i in range(2)]
|
||||||
|
share_network = db_utils.create_share_network()
|
||||||
|
share_network_subnet = db_utils.create_share_network_subnet()
|
||||||
|
share_servers = [
|
||||||
|
db_utils.create_share_server(
|
||||||
|
share_network_subnet_id=share_network_subnet['id'])]
|
||||||
|
share_instances = [db_utils.create_share_instance(share_id='fake')]
|
||||||
|
share_instance_ids = [instance['id'] for instance in share_instances]
|
||||||
|
security_services_effect = mock.Mock(side_effect=security_services)
|
||||||
|
share_network_id = share_network['id']
|
||||||
|
current_security_service_id = security_services[0]['id']
|
||||||
|
new_security_service_id = security_services[1]['id']
|
||||||
|
share_network_subnet_id = share_servers[0]['share_network_subnet_id']
|
||||||
|
network_info = {'fake': 'fake'}
|
||||||
|
backend_details_keys = [
|
||||||
|
'name', 'ou', 'domain', 'server', 'dns_ip', 'user', 'type',
|
||||||
|
'password']
|
||||||
|
backend_details_data = {}
|
||||||
|
[backend_details_data.update(
|
||||||
|
{key: security_services[0][key]}) for key in backend_details_keys]
|
||||||
|
backend_details_exp_update = {
|
||||||
|
'security_service_' + security_services[0]['type']:
|
||||||
|
jsonutils.dumps(backend_details_data)
|
||||||
|
}
|
||||||
|
driver_exception = mock.Mock(side_effect=Exception())
|
||||||
|
share_instances = [db_utils.create_share()['instance']]
|
||||||
|
fake_rules = ['fake_rules']
|
||||||
|
expected_instance_rules = [{
|
||||||
|
'share_instance_id': share_instances[0]['id'],
|
||||||
|
'access_rules': fake_rules
|
||||||
|
}]
|
||||||
|
|
||||||
|
self._setup_mocks_for_sec_service_update(
|
||||||
|
security_services_effect, share_network, share_servers,
|
||||||
|
share_network_subnet, network_info, share_instances, fake_rules,
|
||||||
|
driver_update_action=driver_exception)
|
||||||
|
|
||||||
|
self.mock_object(
|
||||||
|
self.share_manager.access_helper,
|
||||||
|
'update_share_instances_access_rules_status')
|
||||||
|
self.mock_object(
|
||||||
|
db, 'share_instances_get_all_by_share_server',
|
||||||
|
mock.Mock(return_value=share_instances))
|
||||||
|
|
||||||
|
self.share_manager._update_share_network_security_service(
|
||||||
|
self.context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id)
|
||||||
|
|
||||||
|
db.security_service_get.assert_has_calls(
|
||||||
|
[mock.call(self.context, security_services[1]['id']),
|
||||||
|
mock.call(self.context, security_services[0]['id'])]
|
||||||
|
)
|
||||||
|
db.share_network_get.assert_called_once_with(
|
||||||
|
self.context, share_network_id)
|
||||||
|
db.share_server_get_all_by_host.assert_called_once_with(
|
||||||
|
self.context, self.share_manager.host,
|
||||||
|
filters={'share_network_id': share_network_id})
|
||||||
|
db.share_network_subnet_get.assert_called_once_with(
|
||||||
|
self.context, share_network_subnet_id)
|
||||||
|
self.share_manager._form_server_setup_info.assert_called_once_with(
|
||||||
|
self.context, share_servers[0], share_network, share_network_subnet
|
||||||
|
)
|
||||||
|
(self.share_manager.driver.update_share_server_security_service.
|
||||||
|
assert_called_once_with(
|
||||||
|
self.context, share_servers[0], network_info,
|
||||||
|
share_instances,
|
||||||
|
expected_instance_rules,
|
||||||
|
security_services[0],
|
||||||
|
current_security_service=security_services[1]))
|
||||||
|
db.share_server_backend_details_set.assert_called_once_with(
|
||||||
|
self.context, share_servers[0]['id'],
|
||||||
|
backend_details_exp_update)
|
||||||
|
db.share_server_update.assert_called_once_with(
|
||||||
|
self.context, share_servers[0]['id'],
|
||||||
|
{'status': constants.STATUS_ERROR})
|
||||||
|
db.share_instances_get_all_by_share_server.assert_called_once_with(
|
||||||
|
self.context, share_servers[0]['id'], with_share_data=True)
|
||||||
|
db.share_access_get_all_for_instance.assert_called_once_with(
|
||||||
|
self.context, share_instances[0]['id'])
|
||||||
|
(self.share_manager.access_helper.
|
||||||
|
update_share_instances_access_rules_status(
|
||||||
|
self.context, constants.SHARE_INSTANCE_RULES_ERROR,
|
||||||
|
share_instance_ids))
|
||||||
|
(self.share_manager.access_helper.
|
||||||
|
get_and_update_share_instance_access_rules(
|
||||||
|
self.context, updates={'state': constants.STATUS_ERROR},
|
||||||
|
share_instance_id=share_instances[0]['id']))
|
||||||
|
|
||||||
|
def test_update_share_network_security_service(self):
|
||||||
|
share_network_id = 'fake_sn_id'
|
||||||
|
new_security_service_id = 'new_sec_service_id'
|
||||||
|
current_security_service_id = 'current_sec_service_id'
|
||||||
|
|
||||||
|
self.mock_object(
|
||||||
|
self.share_manager, '_update_share_network_security_service')
|
||||||
|
|
||||||
|
self.share_manager.update_share_network_security_service(
|
||||||
|
self.context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id)
|
||||||
|
(self.share_manager._update_share_network_security_service.
|
||||||
|
assert_called_once_with(
|
||||||
|
self.context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id,
|
||||||
|
check_only=False))
|
||||||
|
|
||||||
|
def test_check_update_share_network_security_service(self):
|
||||||
|
share_network_id = 'fake_sn_id'
|
||||||
|
new_security_service_id = 'new_sec_service_id'
|
||||||
|
current_security_service_id = 'current_sec_service_id'
|
||||||
|
|
||||||
|
self.mock_object(
|
||||||
|
self.share_manager, '_update_share_network_security_service')
|
||||||
|
|
||||||
|
self.share_manager.check_update_share_network_security_service(
|
||||||
|
self.context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id)
|
||||||
|
(self.share_manager._update_share_network_security_service.
|
||||||
|
assert_called_once_with(
|
||||||
|
self.context, share_network_id, new_security_service_id,
|
||||||
|
current_security_service_id=current_security_service_id,
|
||||||
|
check_only=True))
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class HookWrapperTestCase(test.TestCase):
|
class HookWrapperTestCase(test.TestCase):
|
||||||
|
@ -457,3 +457,22 @@ class ShareRpcAPITestCase(test.TestCase):
|
|||||||
dest_host=self.fake_host,
|
dest_host=self.fake_host,
|
||||||
share_instance_ids=[self.fake_share['instance']['id']],
|
share_instance_ids=[self.fake_share['instance']['id']],
|
||||||
share_server_id=self.fake_share_server['id'])
|
share_server_id=self.fake_share_server['id'])
|
||||||
|
|
||||||
|
def test_update_share_network_security_service(self):
|
||||||
|
self._test_share_api(
|
||||||
|
'update_share_network_security_service',
|
||||||
|
rpc_method='cast',
|
||||||
|
version='1.22',
|
||||||
|
dest_host=self.fake_host,
|
||||||
|
share_network_id='fake_net_id',
|
||||||
|
new_security_service_id='fake_sec_service_id',
|
||||||
|
current_security_service_id='fake_sec_service_id')
|
||||||
|
|
||||||
|
def test_check_update_share_network_security_service(self):
|
||||||
|
self._test_share_api('check_update_share_network_security_service',
|
||||||
|
rpc_method='cast',
|
||||||
|
version='1.22',
|
||||||
|
dest_host=self.fake_host,
|
||||||
|
share_network_id='fake_net_id',
|
||||||
|
new_security_service_id='fake_sec_service_id',
|
||||||
|
current_security_service_id='fake_sec_service_id')
|
||||||
|
@ -21,6 +21,7 @@ from unittest import mock
|
|||||||
import ddt
|
import ddt
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_utils import timeutils
|
from oslo_utils import timeutils
|
||||||
|
from webob import exc as webob_exc
|
||||||
|
|
||||||
from manila.common import constants
|
from manila.common import constants
|
||||||
from manila import context
|
from manila import context
|
||||||
@ -460,6 +461,10 @@ class ShareGroupsAPITestCase(test.TestCase):
|
|||||||
host='fake_original_host',
|
host='fake_original_host',
|
||||||
share_network_id='fake_network_id',
|
share_network_id='fake_network_id',
|
||||||
share_server_id='fake_server_id')
|
share_server_id='fake_server_id')
|
||||||
|
share_network = {
|
||||||
|
'id': 'fakeid',
|
||||||
|
'status': constants.STATUS_NETWORK_ACTIVE
|
||||||
|
}
|
||||||
expected_values = share_group.copy()
|
expected_values = share_group.copy()
|
||||||
for name in ('id', 'created_at', 'share_network_id',
|
for name in ('id', 'created_at', 'share_network_id',
|
||||||
'share_server_id'):
|
'share_server_id'):
|
||||||
@ -484,7 +489,8 @@ class ShareGroupsAPITestCase(test.TestCase):
|
|||||||
self.mock_object(
|
self.mock_object(
|
||||||
share_types, 'get_share_type',
|
share_types, 'get_share_type',
|
||||||
mock.Mock(return_value={"id": self.fake_share_type['id']}))
|
mock.Mock(return_value={"id": self.fake_share_type['id']}))
|
||||||
self.mock_object(db_driver, 'share_network_get')
|
self.mock_object(db_driver, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
db_driver, 'share_group_snapshot_members_get_all',
|
db_driver, 'share_group_snapshot_members_get_all',
|
||||||
mock.Mock(return_value=[]))
|
mock.Mock(return_value=[]))
|
||||||
@ -502,6 +508,44 @@ class ShareGroupsAPITestCase(test.TestCase):
|
|||||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||||
|
|
||||||
|
def test_create_share_group_network_not_active(self):
|
||||||
|
fake_share_type_mapping = {'share_type_id': self.fake_share_type['id']}
|
||||||
|
share_group = fake_share_group(
|
||||||
|
'fakeid', user_id=self.context.user_id,
|
||||||
|
project_id=self.context.project_id,
|
||||||
|
share_types=[fake_share_type_mapping],
|
||||||
|
status=constants.STATUS_CREATING,
|
||||||
|
host='fake_original_host',
|
||||||
|
share_network_id='fake_network_id',
|
||||||
|
share_server_id='fake_server_id')
|
||||||
|
network_id = 'fake_sn'
|
||||||
|
share_network = {
|
||||||
|
'id': network_id,
|
||||||
|
'status': constants.STATUS_SERVER_NETWORK_CHANGE
|
||||||
|
}
|
||||||
|
expected_values = share_group.copy()
|
||||||
|
for name in ('id', 'created_at', 'share_network_id',
|
||||||
|
'share_server_id'):
|
||||||
|
expected_values.pop(name, None)
|
||||||
|
expected_values['share_types'] = [self.fake_share_type['id']]
|
||||||
|
expected_values['share_network_id'] = 'fake_network_id'
|
||||||
|
expected_values['share_server_id'] = 'fake_server_id'
|
||||||
|
|
||||||
|
self.mock_object(
|
||||||
|
share_types, 'get_share_type',
|
||||||
|
mock.Mock(return_value={"id": self.fake_share_type['id']}))
|
||||||
|
self.mock_object(db_driver, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
|
|
||||||
|
self.assertRaises(
|
||||||
|
webob_exc.HTTPBadRequest,
|
||||||
|
self.api.create,
|
||||||
|
self.context, share_type_ids=[fake_share_type_mapping],
|
||||||
|
share_network_id="fake_sn")
|
||||||
|
|
||||||
|
db_driver.share_network_get.assert_called_once_with(
|
||||||
|
self.context, network_id)
|
||||||
|
|
||||||
def test_create_with_source_share_group_snapshot_id_with_member(self):
|
def test_create_with_source_share_group_snapshot_id_with_member(self):
|
||||||
snap = fake_share_group_snapshot(
|
snap = fake_share_group_snapshot(
|
||||||
"fake_source_share_group_snapshot_id",
|
"fake_source_share_group_snapshot_id",
|
||||||
@ -524,6 +568,10 @@ class ShareGroupsAPITestCase(test.TestCase):
|
|||||||
share_network_id='fake_network_id',
|
share_network_id='fake_network_id',
|
||||||
share_server_id='fake_server_id')
|
share_server_id='fake_server_id')
|
||||||
expected_values = share_group.copy()
|
expected_values = share_group.copy()
|
||||||
|
share_network = {
|
||||||
|
'id': 'fakeid',
|
||||||
|
'status': constants.STATUS_NETWORK_ACTIVE
|
||||||
|
}
|
||||||
for name in ('id', 'created_at', 'fake_network_id',
|
for name in ('id', 'created_at', 'fake_network_id',
|
||||||
'fake_share_server_id'):
|
'fake_share_server_id'):
|
||||||
expected_values.pop(name, None)
|
expected_values.pop(name, None)
|
||||||
@ -547,7 +595,8 @@ class ShareGroupsAPITestCase(test.TestCase):
|
|||||||
self.mock_object(
|
self.mock_object(
|
||||||
share_types, 'get_share_type',
|
share_types, 'get_share_type',
|
||||||
mock.Mock(return_value={"id": self.fake_share_type['id']}))
|
mock.Mock(return_value={"id": self.fake_share_type['id']}))
|
||||||
self.mock_object(db_driver, 'share_network_get')
|
self.mock_object(db_driver, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
db_driver, 'share_instance_get', mock.Mock(return_value=share))
|
db_driver, 'share_instance_get', mock.Mock(return_value=share))
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
@ -593,6 +642,10 @@ class ShareGroupsAPITestCase(test.TestCase):
|
|||||||
status=constants.STATUS_CREATING,
|
status=constants.STATUS_CREATING,
|
||||||
share_network_id='fake_network_id',
|
share_network_id='fake_network_id',
|
||||||
share_server_id='fake_server_id')
|
share_server_id='fake_server_id')
|
||||||
|
share_network = {
|
||||||
|
'id': 'fakeid',
|
||||||
|
'status': constants.STATUS_NETWORK_ACTIVE
|
||||||
|
}
|
||||||
expected_values = share_group.copy()
|
expected_values = share_group.copy()
|
||||||
for name in ('id', 'created_at', 'share_network_id',
|
for name in ('id', 'created_at', 'share_network_id',
|
||||||
'share_server_id'):
|
'share_server_id'):
|
||||||
@ -606,7 +659,8 @@ class ShareGroupsAPITestCase(test.TestCase):
|
|||||||
mock.Mock(return_value=snap))
|
mock.Mock(return_value=snap))
|
||||||
self.mock_object(db_driver, 'share_group_get',
|
self.mock_object(db_driver, 'share_group_get',
|
||||||
mock.Mock(return_value=orig_share_group))
|
mock.Mock(return_value=orig_share_group))
|
||||||
self.mock_object(db_driver, 'share_network_get')
|
self.mock_object(db_driver, 'share_network_get',
|
||||||
|
mock.Mock(return_value=share_network))
|
||||||
self.mock_object(db_driver, 'share_instance_get',
|
self.mock_object(db_driver, 'share_instance_get',
|
||||||
mock.Mock(return_value=share))
|
mock.Mock(return_value=share))
|
||||||
self.mock_object(db_driver, 'share_group_create',
|
self.mock_object(db_driver, 'share_group_create',
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added the possibility to add and update an entire security service when
|
||||||
|
a share network is already being used.
|
||||||
|
A new field called ``status`` was added to the share network model and its
|
||||||
|
default value is ``active``. Some operations might be blocked depending on
|
||||||
|
the share network status.
|
||||||
|
A boolean field called ``security_service_update_support`` was added to the
|
||||||
|
share server's model. This field defaults to ``False``, and all of the
|
||||||
|
already deployed share servers are going to get the default value even if
|
||||||
|
their backend support it. Administrators will be able to update the field
|
||||||
|
value using ``manila-manage`` commands.
|
||||||
|
The scheduler will filter out backend that does not handle this request
|
||||||
|
during some operations.
|
||||||
|
upgrade:
|
||||||
|
- |
|
||||||
|
``manila-manage`` now supports share server commands, which allow
|
||||||
|
administrators to modify the field value of some share server's
|
||||||
|
capabilities.
|
Loading…
x
Reference in New Issue
Block a user