Merge "Metadata for Share Network Subnet Resource"
This commit is contained in:
commit
cf86b23896
@ -614,7 +614,7 @@ def validate_subnet_create(context, share_network_id, data,
|
||||
return share_network, existing_subnets
|
||||
|
||||
|
||||
def _check_metadata_properties(metadata=None):
|
||||
def check_metadata_properties(metadata=None):
|
||||
if not metadata:
|
||||
metadata = {}
|
||||
|
||||
|
@ -194,6 +194,7 @@ REST_API_VERSION_HISTORY = """
|
||||
promote API.
|
||||
* 2.76 - Added 'default_ad_site' field in security service object.
|
||||
* 2.77 - Added support for share transfer between different projects.
|
||||
* 2.78 - Added Share Network Subnet Metadata to Metadata API.
|
||||
|
||||
"""
|
||||
|
||||
@ -201,7 +202,7 @@ REST_API_VERSION_HISTORY = """
|
||||
# The default api version request is defined to be the
|
||||
# minimum version of the API supported.
|
||||
_MIN_API_VERSION = "2.0"
|
||||
_MAX_API_VERSION = "2.77"
|
||||
_MAX_API_VERSION = "2.78"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
|
||||
|
@ -422,3 +422,8 @@ ____
|
||||
2.77
|
||||
----
|
||||
Added support for share transfer between different projects.
|
||||
|
||||
2.78
|
||||
----
|
||||
Added Metadata API methods (GET, PUT, POST, DELETE)
|
||||
to Share Network Subnets.
|
||||
|
@ -134,7 +134,7 @@ class ShareMetadataController(object):
|
||||
_metadata = orig_meta.copy()
|
||||
_metadata.update(metadata_copy)
|
||||
|
||||
api_common._check_metadata_properties(_metadata)
|
||||
api_common.check_metadata_properties(_metadata)
|
||||
db.share_metadata_update(context, share['id'],
|
||||
_metadata, delete)
|
||||
|
||||
|
@ -27,36 +27,43 @@ class MetadataController(object):
|
||||
resource_get = {
|
||||
"share": "share_get",
|
||||
"share_snapshot": "share_snapshot_get",
|
||||
"share_network_subnet": "share_network_subnet_get",
|
||||
}
|
||||
|
||||
resource_metadata_get = {
|
||||
"share": "share_metadata_get",
|
||||
"share_snapshot": "share_snapshot_metadata_get",
|
||||
"share_network_subnet": "share_network_subnet_metadata_get",
|
||||
}
|
||||
|
||||
resource_metadata_get_item = {
|
||||
"share": "share_metadata_get_item",
|
||||
"share_snapshot": "share_snapshot_metadata_get_item",
|
||||
"share_network_subnet": "share_network_subnet_metadata_get_item",
|
||||
}
|
||||
|
||||
resource_metadata_update = {
|
||||
"share": "share_metadata_update",
|
||||
"share_snapshot": "share_snapshot_metadata_update",
|
||||
"share_network_subnet": "share_network_subnet_metadata_update",
|
||||
}
|
||||
|
||||
resource_metadata_update_item = {
|
||||
"share": "share_metadata_update_item",
|
||||
"share_snapshot": "share_snapshot_metadata_update_item",
|
||||
"share_network_subnet": "share_network_subnet_metadata_update_item",
|
||||
}
|
||||
|
||||
resource_metadata_delete = {
|
||||
"share": "share_metadata_delete",
|
||||
"share_snapshot": "share_snapshot_metadata_delete",
|
||||
"share_network_subnet": "share_network_subnet_metadata_delete",
|
||||
}
|
||||
|
||||
resource_policy_get = {
|
||||
'share': 'get',
|
||||
'share_snapshot': 'get_snapshot',
|
||||
'share_network_subnet': 'show',
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
@ -65,7 +72,7 @@ class MetadataController(object):
|
||||
|
||||
def _get_resource(self, context, resource_id,
|
||||
for_modification=False, parent_id=None):
|
||||
if self.resource_name in ['share']:
|
||||
if self.resource_name in ['share', 'share_network_subnet']:
|
||||
# we would allow retrieving some "public" resources
|
||||
# across project namespaces excpet share snaphots,
|
||||
# project_only=True is hard coded
|
||||
@ -114,7 +121,7 @@ class MetadataController(object):
|
||||
context = req.environ['manila.context']
|
||||
try:
|
||||
metadata = body['metadata']
|
||||
common._check_metadata_properties(metadata)
|
||||
common.check_metadata_properties(metadata)
|
||||
except (KeyError, TypeError):
|
||||
msg = _("Malformed request body")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
@ -140,7 +147,7 @@ class MetadataController(object):
|
||||
context = req.environ['manila.context']
|
||||
try:
|
||||
meta_item = body['metadata']
|
||||
common._check_metadata_properties(meta_item)
|
||||
common.check_metadata_properties(meta_item)
|
||||
except (TypeError, KeyError):
|
||||
expl = _('Malformed request body')
|
||||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
@ -171,7 +178,7 @@ class MetadataController(object):
|
||||
context = req.environ['manila.context']
|
||||
try:
|
||||
metadata = body['metadata']
|
||||
common._check_metadata_properties(metadata)
|
||||
common.check_metadata_properties(metadata)
|
||||
except (TypeError, KeyError):
|
||||
expl = _('Malformed request body')
|
||||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
|
@ -403,6 +403,48 @@ class APIRouter(manila.api.openstack.APIRouter):
|
||||
action="index",
|
||||
conditions={"method": ["GET"]})
|
||||
|
||||
for path_prefix in ['/{project_id}', '']:
|
||||
# project_id is optional
|
||||
mapper.connect("subnets_metadata",
|
||||
"%s/share-networks/{share_network_id}"
|
||||
"/subnets/{resource_id}/metadata" % path_prefix,
|
||||
controller=self.resources["share_network_subnets"],
|
||||
action="create_metadata",
|
||||
conditions={"method": ["POST"]})
|
||||
mapper.connect("subnets_metadata",
|
||||
"%s/share-networks/{share_network_id}"
|
||||
"/subnets/{resource_id}/metadata" % path_prefix,
|
||||
controller=self.resources["share_network_subnets"],
|
||||
action="update_all_metadata",
|
||||
conditions={"method": ["PUT"]})
|
||||
mapper.connect("subnets_metadata",
|
||||
"%s/share-networks/{share_network_id}"
|
||||
"/subnets/{resource_id}"
|
||||
"/metadata/{key}" % path_prefix,
|
||||
controller=self.resources["share_network_subnets"],
|
||||
action="update_metadata_item",
|
||||
conditions={"method": ["POST"]})
|
||||
mapper.connect("subnets_metadata",
|
||||
"%s/share-networks/{share_network_id}"
|
||||
"/subnets/{resource_id}/metadata" % path_prefix,
|
||||
controller=self.resources["share_network_subnets"],
|
||||
action="index_metadata",
|
||||
conditions={"method": ["GET"]})
|
||||
mapper.connect("subnets_metadata",
|
||||
"%s/share-networks/{share_network_id}"
|
||||
"/subnets/{resource_id}"
|
||||
"/metadata/{key}" % path_prefix,
|
||||
controller=self.resources["share_network_subnets"],
|
||||
action="show_metadata",
|
||||
conditions={"method": ["GET"]})
|
||||
mapper.connect("subnets_metadata",
|
||||
"%s/share-networks/{share_network_id}"
|
||||
"/subnets/{resource_id}"
|
||||
"/metadata/{key}" % path_prefix,
|
||||
controller=self.resources["share_network_subnets"],
|
||||
action="delete_metadata",
|
||||
conditions={"method": ["DELETE"]})
|
||||
|
||||
self.resources["share_servers"] = share_servers.create_resource()
|
||||
mapper.resource("share_server",
|
||||
"share-servers",
|
||||
|
@ -21,8 +21,10 @@ from oslo_log import log
|
||||
import webob
|
||||
from webob import exc
|
||||
|
||||
from manila.api import common as api_common
|
||||
from manila.api.openstack import api_version_request as api_version
|
||||
from manila.api.openstack import wsgi
|
||||
from manila.api.v2 import metadata as metadata_controller
|
||||
from manila.api.views import share_network_subnets as subnet_views
|
||||
from manila.db import api as db_api
|
||||
from manila import exception
|
||||
@ -33,7 +35,8 @@ from manila.share import rpcapi as share_rpcapi
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class ShareNetworkSubnetController(wsgi.Controller):
|
||||
class ShareNetworkSubnetController(wsgi.Controller,
|
||||
metadata_controller.MetadataController):
|
||||
"""The Share Network Subnet API controller for the OpenStack API."""
|
||||
|
||||
resource_name = 'share_network_subnet'
|
||||
@ -116,6 +119,12 @@ class ShareNetworkSubnetController(wsgi.Controller):
|
||||
msg = _("Share Network Subnet is missing from the request body.")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
data = body['share-network-subnet']
|
||||
|
||||
if req.api_version_request >= api_version.APIVersionRequest("2.78"):
|
||||
api_common.check_metadata_properties(data.get('metadata'))
|
||||
else:
|
||||
data.pop('metadata', None)
|
||||
|
||||
data['share_network_id'] = share_network_id
|
||||
multiple_subnet_support = (req.api_version_request >=
|
||||
api_version.APIVersionRequest("2.70"))
|
||||
@ -181,6 +190,49 @@ class ShareNetworkSubnetController(wsgi.Controller):
|
||||
return self._view_builder.build_share_network_subnet(
|
||||
req, share_network_subnet)
|
||||
|
||||
@wsgi.Controller.api_version("2.78")
|
||||
@wsgi.Controller.authorize("get_metadata")
|
||||
def index_metadata(self, req, share_network_id, resource_id):
|
||||
"""Returns the list of metadata for a given share network subnet."""
|
||||
return self._index_metadata(req, resource_id,
|
||||
parent_id=share_network_id)
|
||||
|
||||
@wsgi.Controller.api_version("2.78")
|
||||
@wsgi.Controller.authorize("update_metadata")
|
||||
def create_metadata(self, req, share_network_id, resource_id, body):
|
||||
"""Create metadata for a given share network subnet."""
|
||||
return self._create_metadata(req, resource_id, body,
|
||||
parent_id=share_network_id)
|
||||
|
||||
@wsgi.Controller.api_version("2.78")
|
||||
@wsgi.Controller.authorize("update_metadata")
|
||||
def update_all_metadata(self, req, share_network_id, resource_id, body):
|
||||
"""Update entire metadata for a given share network subnet."""
|
||||
return self._update_all_metadata(req, resource_id, body,
|
||||
parent_id=share_network_id)
|
||||
|
||||
@wsgi.Controller.api_version("2.78")
|
||||
@wsgi.Controller.authorize("update_metadata")
|
||||
def update_metadata_item(self, req, share_network_id, resource_id, body,
|
||||
key):
|
||||
"""Update metadata item for a given share network subnet."""
|
||||
return self._update_metadata_item(req, resource_id, body, key,
|
||||
parent_id=share_network_id)
|
||||
|
||||
@wsgi.Controller.api_version("2.78")
|
||||
@wsgi.Controller.authorize("get_metadata")
|
||||
def show_metadata(self, req, share_network_id, resource_id, key):
|
||||
"""Show metadata for a given share network subnet."""
|
||||
return self._show_metadata(req, resource_id, key,
|
||||
parent_id=share_network_id)
|
||||
|
||||
@wsgi.Controller.api_version("2.78")
|
||||
@wsgi.Controller.authorize("delete_metadata")
|
||||
def delete_metadata(self, req, share_network_id, resource_id, key):
|
||||
"""Delete metadata for a given share network subnet."""
|
||||
return self._delete_metadata(req, resource_id, key,
|
||||
parent_id=share_network_id)
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(ShareNetworkSubnetController())
|
||||
|
@ -20,6 +20,9 @@ class ViewBuilder(common.ViewBuilder):
|
||||
"""Model a server API response as a python dictionary."""
|
||||
|
||||
_collection_name = 'share_network_subnets'
|
||||
_detail_version_modifiers = [
|
||||
"add_metadata"
|
||||
]
|
||||
|
||||
def build_share_network_subnet(self, request, share_network_subnet):
|
||||
return {
|
||||
@ -51,3 +54,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
}
|
||||
self.update_versioned_resource_dict(request, sns, share_network_subnet)
|
||||
return sns
|
||||
|
||||
@common.ViewBuilder.versioned_method("2.78")
|
||||
def add_metadata(self, context, share_network_subnet_dict, sns):
|
||||
share_network_subnet_dict['metadata'] = sns.get('subnet_metadata')
|
||||
|
@ -23,7 +23,8 @@ class ViewBuilder(common.ViewBuilder):
|
||||
_detail_version_modifiers = ["add_gateway", "add_mtu", "add_nova_net_id",
|
||||
"add_subnets",
|
||||
"add_status_and_sec_service_update_fields",
|
||||
"add_network_allocation_update_support_field"]
|
||||
"add_network_allocation_update_support_field",
|
||||
"add_subnet_with_metadata"]
|
||||
|
||||
def build_share_network(self, request, share_network):
|
||||
"""View of a share network."""
|
||||
@ -104,7 +105,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
self.update_versioned_resource_dict(request, sn, share_network)
|
||||
return sn
|
||||
|
||||
@common.ViewBuilder.versioned_method("2.51")
|
||||
@common.ViewBuilder.versioned_method("2.51", "2.77")
|
||||
def add_subnets(self, context, network_dict, network):
|
||||
subnets = [{
|
||||
'id': sns.get('id'),
|
||||
@ -152,3 +153,28 @@ class ViewBuilder(common.ViewBuilder):
|
||||
self, context, network_dict, network):
|
||||
network_dict['network_allocation_update_support'] = network.get(
|
||||
'network_allocation_update_support')
|
||||
|
||||
@common.ViewBuilder.versioned_method("2.78")
|
||||
def add_subnet_with_metadata(self, context, network_dict, network):
|
||||
subnets = [{
|
||||
'id': sns.get('id'),
|
||||
'availability_zone': sns.get('availability_zone'),
|
||||
'created_at': sns.get('created_at'),
|
||||
'updated_at': sns.get('updated_at'),
|
||||
'segmentation_id': sns.get('segmentation_id'),
|
||||
'neutron_net_id': sns.get('neutron_net_id'),
|
||||
'neutron_subnet_id': sns.get('neutron_subnet_id'),
|
||||
'ip_version': sns.get('ip_version'),
|
||||
'cidr': sns.get('cidr'),
|
||||
'network_type': sns.get('network_type'),
|
||||
'mtu': sns.get('mtu'),
|
||||
'gateway': sns.get('gateway'),
|
||||
'metadata': sns.get('subnet_metadata'),
|
||||
} for sns in network.get('share_network_subnets')]
|
||||
|
||||
network_dict['share_network_subnets'] = subnets
|
||||
attr_to_remove = [
|
||||
'neutron_net_id', 'neutron_subnet_id', 'network_type',
|
||||
'segmentation_id', 'cidr', 'ip_version', 'gateway', 'mtu']
|
||||
for attr in attr_to_remove:
|
||||
network_dict.pop(attr)
|
||||
|
@ -1072,10 +1072,11 @@ def share_network_subnet_update(context, network_subnet_id, values):
|
||||
return IMPL.share_network_subnet_update(context, network_subnet_id, values)
|
||||
|
||||
|
||||
def share_network_subnet_get(context, network_subnet_id, session=None):
|
||||
def share_network_subnet_get(context, network_subnet_id, session=None,
|
||||
parent_id=None):
|
||||
"""Get requested share network subnet DB record."""
|
||||
return IMPL.share_network_subnet_get(context, network_subnet_id,
|
||||
session=session)
|
||||
session=session, parent_id=parent_id)
|
||||
|
||||
|
||||
def share_network_subnet_get_all_with_same_az(context, network_subnet_id,
|
||||
@ -1118,8 +1119,47 @@ def share_network_subnet_get_all_by_share_server_id(context, share_server_id):
|
||||
return IMPL.share_network_subnet_get_all_by_share_server_id(
|
||||
context, share_server_id)
|
||||
|
||||
####################
|
||||
|
||||
##################
|
||||
|
||||
def share_network_subnet_metadata_get(context, share_network_subnet_id,
|
||||
**kwargs):
|
||||
"""Get all metadata for a share network subnet."""
|
||||
return IMPL.share_network_subnet_metadata_get(context,
|
||||
share_network_subnet_id,
|
||||
**kwargs)
|
||||
|
||||
|
||||
def share_network_subnet_metadata_get_item(context, share_network_subnet_id,
|
||||
key):
|
||||
"""Get metadata item for a share network subnet."""
|
||||
return IMPL.share_network_subnet_metadata_get_item(context,
|
||||
share_network_subnet_id,
|
||||
key)
|
||||
|
||||
|
||||
def share_network_subnet_metadata_delete(context, share_network_subnet_id,
|
||||
key):
|
||||
"""Delete the given metadata item."""
|
||||
IMPL.share_network_subnet_metadata_delete(context, share_network_subnet_id,
|
||||
key)
|
||||
|
||||
|
||||
def share_network_subnet_metadata_update(context, share_network_subnet_id,
|
||||
metadata, delete):
|
||||
"""Update metadata if it exists, otherwise create it."""
|
||||
return IMPL.share_network_subnet_metadata_update(context,
|
||||
share_network_subnet_id,
|
||||
metadata, delete)
|
||||
|
||||
|
||||
def share_network_subnet_metadata_update_item(context, share_network_subnet_id,
|
||||
metadata):
|
||||
"""Update metadata item if it exists, otherwise create it."""
|
||||
return IMPL.share_network_subnet_metadata_update_item(
|
||||
context, share_network_subnet_id, metadata)
|
||||
|
||||
###################
|
||||
|
||||
|
||||
def network_allocation_create(context, values):
|
||||
|
@ -0,0 +1,67 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Add share network subnet metadata
|
||||
|
||||
Revision ID: ac0620cbe74d
|
||||
Revises: 1e2d600bf972
|
||||
Create Date: 2023-01-07 14:13:25.525968
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'ac0620cbe74d'
|
||||
down_revision = '1e2d600bf972'
|
||||
|
||||
from alembic import op
|
||||
from oslo_log import log
|
||||
import sqlalchemy as sql
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
share_network_subnet_metadata_table_name = 'share_network_subnet_metadata'
|
||||
|
||||
|
||||
def upgrade():
|
||||
context = op.get_context()
|
||||
mysql_dl = context.bind.dialect.name == 'mysql'
|
||||
datetime_type = (sql.dialects.mysql.DATETIME(fsp=6)
|
||||
if mysql_dl else sql.DateTime)
|
||||
try:
|
||||
op.create_table(
|
||||
share_network_subnet_metadata_table_name,
|
||||
sql.Column('deleted', sql.String(36), default='False'),
|
||||
sql.Column('created_at', datetime_type),
|
||||
sql.Column('updated_at', datetime_type),
|
||||
sql.Column('deleted_at', datetime_type),
|
||||
sql.Column('share_network_subnet_id', sql.String(36),
|
||||
sql.ForeignKey('share_network_subnets.id'),
|
||||
nullable=False),
|
||||
sql.Column('key', sql.String(255), nullable=False),
|
||||
sql.Column('value', sql.String(1023), nullable=False),
|
||||
sql.Column('id', sql.Integer, primary_key=True, nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
except Exception:
|
||||
LOG.error("Table |%s| not created!",
|
||||
share_network_subnet_metadata_table_name)
|
||||
raise
|
||||
|
||||
|
||||
def downgrade():
|
||||
try:
|
||||
op.drop_table(share_network_subnet_metadata_table_name)
|
||||
except Exception:
|
||||
LOG.error("Table |%s| not dropped!",
|
||||
share_network_subnet_metadata_table_name)
|
||||
raise
|
@ -201,6 +201,20 @@ def require_share_snapshot_exists(f):
|
||||
return wrapper
|
||||
|
||||
|
||||
def require_share_network_subnet_exists(f):
|
||||
"""Decorator to require the specified share network subnet to exist.
|
||||
|
||||
Requires the wrapped function to use context and share_network_subnet_id
|
||||
as their first two arguments.
|
||||
"""
|
||||
@wraps(f)
|
||||
def wrapper(context, share_network_subnet_id, *args, **kwargs):
|
||||
share_network_subnet_get(context, share_network_subnet_id)
|
||||
return f(context, share_network_subnet_id, *args, **kwargs)
|
||||
wrapper.__name__ = f.__name__
|
||||
return wrapper
|
||||
|
||||
|
||||
def require_share_instance_exists(f):
|
||||
"""Decorator to require the specified share instance to exist.
|
||||
|
||||
@ -4611,12 +4625,16 @@ def _network_subnet_get_query(context, session=None):
|
||||
if session is None:
|
||||
session = get_session()
|
||||
return (model_query(context, models.ShareNetworkSubnet, session=session).
|
||||
options(joinedload('share_servers'), joinedload('share_network')))
|
||||
options(joinedload('share_servers'),
|
||||
joinedload('share_network'),
|
||||
joinedload('share_network_subnet_metadata')))
|
||||
|
||||
|
||||
@require_context
|
||||
def share_network_subnet_create(context, values):
|
||||
values = ensure_model_dict_has_id(values)
|
||||
values['share_network_subnet_metadata'] = _metadata_refs(
|
||||
values.pop('metadata', {}), models.ShareNetworkSubnetMetadata)
|
||||
|
||||
network_subnet_ref = models.ShareNetworkSubnet()
|
||||
network_subnet_ref.update(values)
|
||||
@ -4635,6 +4653,8 @@ def share_network_subnet_delete(context, network_subnet_id):
|
||||
network_subnet_ref = share_network_subnet_get(context,
|
||||
network_subnet_id,
|
||||
session=session)
|
||||
session.query(models.ShareNetworkSubnetMetadata).filter_by(
|
||||
share_network_subnet_id=network_subnet_id).soft_delete()
|
||||
network_subnet_ref.soft_delete(session=session, update_status=True)
|
||||
|
||||
|
||||
@ -4652,9 +4672,13 @@ def share_network_subnet_update(context, network_subnet_id, values):
|
||||
|
||||
|
||||
@require_context
|
||||
def share_network_subnet_get(context, network_subnet_id, session=None):
|
||||
def share_network_subnet_get(context, network_subnet_id, session=None,
|
||||
parent_id=None):
|
||||
kwargs = {'id': network_subnet_id}
|
||||
if parent_id:
|
||||
kwargs['share_network_id'] = parent_id
|
||||
result = (_network_subnet_get_query(context, session)
|
||||
.filter_by(id=network_subnet_id)
|
||||
.filter_by(**kwargs)
|
||||
.first())
|
||||
if result is None:
|
||||
raise exception.ShareNetworkSubnetNotFound(
|
||||
@ -4740,10 +4764,126 @@ def share_network_subnet_get_all_by_share_server_id(context, share_server_id):
|
||||
|
||||
return result
|
||||
|
||||
|
||||
###################
|
||||
|
||||
|
||||
@require_context
|
||||
@require_share_network_subnet_exists
|
||||
def share_network_subnet_metadata_get(context, share_network_subnet_id):
|
||||
session = get_session()
|
||||
return _share_network_subnet_metadata_get(context, share_network_subnet_id,
|
||||
session=session)
|
||||
|
||||
|
||||
@require_context
|
||||
@require_share_network_subnet_exists
|
||||
def share_network_subnet_metadata_delete(context, share_network_subnet_id,
|
||||
key):
|
||||
session = get_session()
|
||||
meta_ref = _share_network_subnet_metadata_get_item(
|
||||
context, share_network_subnet_id, key, session=session)
|
||||
meta_ref.soft_delete(session=session)
|
||||
|
||||
|
||||
@require_context
|
||||
@require_share_network_subnet_exists
|
||||
def share_network_subnet_metadata_update(context, share_network_subnet_id,
|
||||
metadata, delete):
|
||||
session = get_session()
|
||||
return _share_network_subnet_metadata_update(
|
||||
context, share_network_subnet_id, metadata, delete, session=session)
|
||||
|
||||
|
||||
def share_network_subnet_metadata_update_item(context, share_network_subnet_id,
|
||||
item):
|
||||
session = get_session()
|
||||
return _share_network_subnet_metadata_update(
|
||||
context, share_network_subnet_id, item, delete=False, session=session)
|
||||
|
||||
|
||||
def share_network_subnet_metadata_get_item(context, share_network_subnet_id,
|
||||
key):
|
||||
|
||||
session = get_session()
|
||||
row = _share_network_subnet_metadata_get_item(
|
||||
context, share_network_subnet_id, key, session=session)
|
||||
|
||||
result = {row['key']: row['value']}
|
||||
return result
|
||||
|
||||
|
||||
def _share_network_subnet_metadata_get_query(context, share_network_subnet_id,
|
||||
session=None):
|
||||
session = session or get_session()
|
||||
return (model_query(context, models.ShareNetworkSubnetMetadata,
|
||||
session=session,
|
||||
read_deleted="no").
|
||||
filter_by(share_network_subnet_id=share_network_subnet_id).
|
||||
options(joinedload('share_network_subnet')))
|
||||
|
||||
|
||||
def _share_network_subnet_metadata_get(context, share_network_subnet_id,
|
||||
session=None):
|
||||
session = session or get_session()
|
||||
rows = _share_network_subnet_metadata_get_query(
|
||||
context, share_network_subnet_id, session=session).all()
|
||||
|
||||
result = {}
|
||||
for row in rows:
|
||||
result[row['key']] = row['value']
|
||||
return result
|
||||
|
||||
|
||||
def _share_network_subnet_metadata_get_item(context, share_network_subnet_id,
|
||||
key, session=None):
|
||||
session = session or get_session()
|
||||
result = (_share_network_subnet_metadata_get_query(
|
||||
context, share_network_subnet_id, session=session).
|
||||
filter_by(key=key).first())
|
||||
if not result:
|
||||
raise exception.MetadataItemNotFound
|
||||
return result
|
||||
|
||||
|
||||
@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
|
||||
def _share_network_subnet_metadata_update(context, share_network_subnet_id,
|
||||
metadata, delete, session=None):
|
||||
session = session or get_session()
|
||||
delete = strutils.bool_from_string(delete)
|
||||
with session.begin():
|
||||
if delete:
|
||||
original_metadata = _share_network_subnet_metadata_get(
|
||||
context, share_network_subnet_id, session=session)
|
||||
for meta_key, meta_value in original_metadata.items():
|
||||
if meta_key not in metadata:
|
||||
meta_ref = _share_network_subnet_metadata_get_item(
|
||||
context, share_network_subnet_id, meta_key,
|
||||
session=session)
|
||||
meta_ref.soft_delete(session=session)
|
||||
meta_ref = None
|
||||
# Now update all existing items with new values, or create new meta
|
||||
# objects.
|
||||
for meta_key, meta_value in metadata.items():
|
||||
|
||||
# update the value whether it exists or not.
|
||||
item = {"value": meta_value}
|
||||
meta_ref = _share_network_subnet_metadata_get_query(
|
||||
context, share_network_subnet_id,
|
||||
session=session).filter_by(
|
||||
key=meta_key).first()
|
||||
if not meta_ref:
|
||||
meta_ref = models.ShareNetworkSubnetMetadata()
|
||||
item.update(
|
||||
{"key": meta_key,
|
||||
"share_network_subnet_id": share_network_subnet_id})
|
||||
meta_ref.update(item)
|
||||
meta_ref.save(session=session)
|
||||
|
||||
return metadata
|
||||
|
||||
#################################
|
||||
|
||||
|
||||
def _server_get_query(context, session=None):
|
||||
if session is None:
|
||||
session = get_session()
|
||||
|
@ -1001,7 +1001,7 @@ class ShareNetwork(BASE, ManilaBase):
|
||||
class ShareNetworkSubnet(BASE, ManilaBase):
|
||||
"""Represents a share network subnet used by some resources."""
|
||||
|
||||
_extra_keys = ['availability_zone']
|
||||
_extra_keys = ['availability_zone', 'subnet_metadata']
|
||||
|
||||
__tablename__ = 'share_network_subnets'
|
||||
id = Column(String(36), primary_key=True, nullable=False)
|
||||
@ -1056,6 +1056,35 @@ class ShareNetworkSubnet(BASE, ManilaBase):
|
||||
def share_network_name(self):
|
||||
return self.share_network['name']
|
||||
|
||||
@property
|
||||
def subnet_metadata(self):
|
||||
metadata_dict = {}
|
||||
metadata_list = (
|
||||
self.share_network_subnet_metadata) # pylint: disable=no-member
|
||||
for meta in metadata_list:
|
||||
metadata_dict[meta['key']] = meta['value']
|
||||
return metadata_dict
|
||||
|
||||
|
||||
class ShareNetworkSubnetMetadata(BASE, ManilaBase):
|
||||
"""Represents a metadata key/value pair for a subnet."""
|
||||
__tablename__ = 'share_network_subnet_metadata'
|
||||
id = Column(Integer, primary_key=True)
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
deleted = Column(String(36), default='False')
|
||||
share_network_subnet_id = Column(String(36), ForeignKey(
|
||||
'share_network_subnets.id'), nullable=False)
|
||||
|
||||
share_network_subnet = orm.relationship(
|
||||
ShareNetworkSubnet,
|
||||
backref=orm.backref('share_network_subnet_metadata', lazy='immediate'),
|
||||
foreign_keys=share_network_subnet_id,
|
||||
primaryjoin='and_('
|
||||
'ShareNetworkSubnetMetadata.share_network_subnet_id == '
|
||||
'ShareNetworkSubnet.id,'
|
||||
'ShareNetworkSubnetMetadata.deleted == "False")')
|
||||
|
||||
|
||||
class ShareServer(BASE, ManilaBase):
|
||||
"""Represents share server used by share."""
|
||||
|
@ -48,6 +48,24 @@ deprecated_subnet_index = policy.DeprecatedRule(
|
||||
deprecated_reason=DEPRECATED_REASON,
|
||||
deprecated_since=versionutils.deprecated.WALLABY
|
||||
)
|
||||
deprecated_update_subnet_metadata = policy.DeprecatedRule(
|
||||
name=BASE_POLICY_NAME % 'update_metadata',
|
||||
check_str=base.RULE_DEFAULT,
|
||||
deprecated_reason=DEPRECATED_REASON,
|
||||
deprecated_since='ANTELOPE'
|
||||
)
|
||||
deprecated_delete_subnet_metadata = policy.DeprecatedRule(
|
||||
name=BASE_POLICY_NAME % 'delete_metadata',
|
||||
check_str=base.RULE_DEFAULT,
|
||||
deprecated_reason=DEPRECATED_REASON,
|
||||
deprecated_since='ANTELOPE'
|
||||
)
|
||||
deprecated_get_subnet_metadata = policy.DeprecatedRule(
|
||||
name=BASE_POLICY_NAME % 'get_metadata',
|
||||
check_str=base.RULE_DEFAULT,
|
||||
deprecated_reason=DEPRECATED_REASON,
|
||||
deprecated_since='ANTELOPE'
|
||||
)
|
||||
|
||||
|
||||
share_network_subnet_policies = [
|
||||
@ -105,6 +123,63 @@ share_network_subnet_policies = [
|
||||
],
|
||||
deprecated_rule=deprecated_subnet_index
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=BASE_POLICY_NAME % 'update_metadata',
|
||||
check_str=base.ADMIN_OR_PROJECT_MEMBER,
|
||||
scope_types=['system', 'project'],
|
||||
description="Update share network subnet metadata.",
|
||||
operations=[
|
||||
{
|
||||
'method': 'PUT',
|
||||
'path': '/share-networks/{share_network_id}/subnets/'
|
||||
'{share_network_subnet_id}/metadata',
|
||||
},
|
||||
{
|
||||
'method': 'POST',
|
||||
'path': '/share-networks/{share_network_id}/subnets/'
|
||||
'{share_network_subnet_id}/metadata/{key}',
|
||||
},
|
||||
{
|
||||
'method': 'POST',
|
||||
'path': '/share-networks/{share_network_id}/subnets/'
|
||||
'{share_network_subnet_id}/metadata',
|
||||
},
|
||||
],
|
||||
deprecated_rule=deprecated_update_subnet_metadata
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=BASE_POLICY_NAME % 'delete_metadata',
|
||||
check_str=base.ADMIN_OR_PROJECT_MEMBER,
|
||||
scope_types=['system', 'project'],
|
||||
description="Delete share network subnet metadata.",
|
||||
operations=[
|
||||
{
|
||||
'method': 'DELETE',
|
||||
'path': '/share-networks/{share_network_id}/subnets/'
|
||||
'{share_network_subnet_id}/metadata/{key}',
|
||||
}
|
||||
],
|
||||
deprecated_rule=deprecated_delete_subnet_metadata
|
||||
),
|
||||
policy.DocumentedRuleDefault(
|
||||
name=BASE_POLICY_NAME % 'get_metadata',
|
||||
check_str=base.ADMIN_OR_PROJECT_READER,
|
||||
scope_types=['system', 'project'],
|
||||
description="Get share network subnet metadata.",
|
||||
operations=[
|
||||
{
|
||||
'method': 'GET',
|
||||
'path': '/share-networks/{share_network_id}/subnets/'
|
||||
'{share_network_subnet_id}/metadata',
|
||||
},
|
||||
{
|
||||
'method': 'GET',
|
||||
'path': '/share-networks/{share_network_id}/subnets/'
|
||||
'{share_network_subnet_id}/metadata/{key}',
|
||||
}
|
||||
],
|
||||
deprecated_rule=deprecated_get_subnet_metadata
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -223,7 +223,7 @@ class API(base.Base):
|
||||
az_request_multiple_subnet_support_map=None):
|
||||
"""Create new share."""
|
||||
|
||||
api_common._check_metadata_properties(metadata)
|
||||
api_common.check_metadata_properties(metadata)
|
||||
|
||||
if snapshot_id is not None:
|
||||
snapshot = self.get_snapshot(context, snapshot_id)
|
||||
@ -1449,7 +1449,7 @@ class API(base.Base):
|
||||
force=False, metadata=None):
|
||||
policy.check_policy(context, 'share', 'create_snapshot', share)
|
||||
if metadata:
|
||||
api_common._check_metadata_properties(metadata)
|
||||
api_common.check_metadata_properties(metadata)
|
||||
|
||||
if ((not force) and (share['status'] != constants.STATUS_AVAILABLE)):
|
||||
msg = _("Source share status must be "
|
||||
@ -2231,7 +2231,7 @@ class API(base.Base):
|
||||
msg = _("Invalid share access level: %s.") % access_level
|
||||
raise exception.InvalidShareAccess(reason=msg)
|
||||
|
||||
api_common._check_metadata_properties(metadata)
|
||||
api_common.check_metadata_properties(metadata)
|
||||
access_exists = self.db.share_access_check_for_existing_access(
|
||||
ctx, share['id'], access_type, access_to)
|
||||
|
||||
@ -2413,7 +2413,7 @@ class API(base.Base):
|
||||
def update_share_access_metadata(self, context, access_id, metadata):
|
||||
"""Updates share access metadata."""
|
||||
try:
|
||||
api_common._check_metadata_properties(metadata)
|
||||
api_common.check_metadata_properties(metadata)
|
||||
except exception.InvalidMetadata:
|
||||
raise exception.InvalidMetadata()
|
||||
except exception.InvalidMetadataSize:
|
||||
|
@ -4209,6 +4209,7 @@ class ShareManager(manager.SchedulerDependentManager):
|
||||
'admin_network_allocations': admin_network_allocations,
|
||||
'backend_details': share_server.get('backend_details'),
|
||||
'network_type': share_network_subnet['network_type'],
|
||||
'subnet_metadata': share_network_subnet['subnet_metadata']
|
||||
})
|
||||
return network_info
|
||||
|
||||
|
@ -62,8 +62,10 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
mock.Mock(return_value=fake_az))
|
||||
self.share_network = db_utils.create_share_network(
|
||||
name='fake_network', id='fake_sn_id')
|
||||
self.subnet_metadata = {'fake_key': 'fake_value'}
|
||||
self.subnet = db_utils.create_share_network_subnet(
|
||||
share_network_id=self.share_network['id'])
|
||||
share_network_id=self.share_network['id'],
|
||||
metadata=self.subnet_metadata)
|
||||
self.share_server = db_utils.create_share_server(
|
||||
share_network_subnets=[self.subnet])
|
||||
self.share = db_utils.create_share()
|
||||
@ -212,27 +214,35 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
context, self.resource_name, 'delete')
|
||||
|
||||
def _setup_create_test_request_body(self):
|
||||
def _setup_create_test_request_body(self, metadata=False):
|
||||
body = {
|
||||
'share_network_id': self.share_network['id'],
|
||||
'availability_zone': fake_az['name'],
|
||||
'neutron_net_id': 'fake_nn_id',
|
||||
'neutron_subnet_id': 'fake_nsn_id'
|
||||
}
|
||||
if metadata:
|
||||
body['metadata'] = self.subnet_metadata
|
||||
return body
|
||||
|
||||
@ddt.data({'version': "2.51", 'has_share_servers': False},
|
||||
{'version': "2.70", 'has_share_servers': False},
|
||||
{'version': "2.70", 'has_share_servers': True})
|
||||
{'version': "2.70", 'has_share_servers': True},
|
||||
{'version': "2.78", 'has_share_servers': False})
|
||||
@ddt.unpack
|
||||
def test_subnet_create(self, version, has_share_servers):
|
||||
req = fakes.HTTPRequest.blank('/subnets', version=version)
|
||||
multiple_subnet_support = (req.api_version_request >=
|
||||
api_version.APIVersionRequest("2.70"))
|
||||
metadata_support = (req.api_version_request >=
|
||||
api_version.APIVersionRequest("2.78"))
|
||||
|
||||
context = req.environ['manila.context']
|
||||
body = {
|
||||
'share-network-subnet': self._setup_create_test_request_body()
|
||||
'share-network-subnet': self._setup_create_test_request_body(
|
||||
metadata=metadata_support)
|
||||
}
|
||||
|
||||
sn_id = body['share-network-subnet']['share_network_id']
|
||||
expected_subnet = copy.deepcopy(self.subnet)
|
||||
if has_share_servers:
|
||||
@ -251,6 +261,8 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
mock_share_network_subnet_get = self.mock_object(
|
||||
db_api, 'share_network_subnet_get',
|
||||
mock.Mock(return_value=expected_subnet))
|
||||
mock_check_metadata_properties = self.mock_object(
|
||||
common, 'check_metadata_properties')
|
||||
|
||||
fake_data = body['share-network-subnet']
|
||||
fake_data['share_network_id'] = self.share_network['id']
|
||||
@ -273,6 +285,8 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
'mtu': expected_subnet.get('mtu'),
|
||||
'gateway': expected_subnet.get('gateway')
|
||||
}
|
||||
if metadata_support:
|
||||
view_subnet['metadata'] = self.subnet_metadata
|
||||
self.assertEqual(view_subnet, res['share_network_subnet'])
|
||||
mock_share_network_subnet_get.assert_called_once_with(
|
||||
context, expected_subnet['id'])
|
||||
@ -285,6 +299,8 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
else:
|
||||
mock_subnet_create.assert_called_once_with(
|
||||
context, fake_data)
|
||||
self.assertEqual(metadata_support,
|
||||
mock_check_metadata_properties.called)
|
||||
|
||||
@ddt.data({'exception1': exception.ServiceIsDown(service='fake_srv'),
|
||||
'exc_raise': exc.HTTPInternalServerError},
|
||||
@ -475,3 +491,87 @@ class ShareNetworkSubnetControllerTest(test.TestCase):
|
||||
req,
|
||||
self.share_network['id'])
|
||||
mock_sn_get.assert_called_once_with(context, self.share_network['id'])
|
||||
|
||||
def test_index_metadata(self):
|
||||
req = fakes.HTTPRequest.blank('/subnets/', version="2.78")
|
||||
mock_index = self.mock_object(
|
||||
self.controller, '_index_metadata',
|
||||
mock.Mock(return_value='fake_metadata'))
|
||||
|
||||
result = self.controller.index_metadata(req, self.share_network['id'],
|
||||
self.subnet['id'])
|
||||
|
||||
self.assertEqual('fake_metadata', result)
|
||||
mock_index.assert_called_once_with(req, self.subnet['id'],
|
||||
parent_id=self.share_network['id'])
|
||||
|
||||
def test_create_metadata(self):
|
||||
req = fakes.HTTPRequest.blank('/subnets/', version="2.78")
|
||||
mock_index = self.mock_object(
|
||||
self.controller, '_create_metadata',
|
||||
mock.Mock(return_value='fake_metadata'))
|
||||
|
||||
body = 'fake_metadata_body'
|
||||
result = self.controller.create_metadata(req, self.share_network['id'],
|
||||
self.subnet['id'], body)
|
||||
|
||||
self.assertEqual('fake_metadata', result)
|
||||
mock_index.assert_called_once_with(req, self.subnet['id'], body,
|
||||
parent_id=self.share_network['id'])
|
||||
|
||||
def test_update_all_metadata(self):
|
||||
req = fakes.HTTPRequest.blank('/subnets/', version="2.78")
|
||||
mock_index = self.mock_object(
|
||||
self.controller, '_update_all_metadata',
|
||||
mock.Mock(return_value='fake_metadata'))
|
||||
|
||||
body = 'fake_metadata_body'
|
||||
result = self.controller.update_all_metadata(
|
||||
req, self.share_network['id'], self.subnet['id'], body)
|
||||
|
||||
self.assertEqual('fake_metadata', result)
|
||||
mock_index.assert_called_once_with(req, self.subnet['id'], body,
|
||||
parent_id=self.share_network['id'])
|
||||
|
||||
def test_update_metadata_item(self):
|
||||
req = fakes.HTTPRequest.blank('/subnets/', version="2.78")
|
||||
mock_index = self.mock_object(
|
||||
self.controller, '_update_metadata_item',
|
||||
mock.Mock(return_value='fake_metadata'))
|
||||
|
||||
body = 'fake_metadata_body'
|
||||
key = 'fake_key'
|
||||
result = self.controller.update_metadata_item(
|
||||
req, self.share_network['id'], self.subnet['id'], body, key)
|
||||
|
||||
self.assertEqual('fake_metadata', result)
|
||||
mock_index.assert_called_once_with(req, self.subnet['id'], body, key,
|
||||
parent_id=self.share_network['id'])
|
||||
|
||||
def test_show_metadata(self):
|
||||
req = fakes.HTTPRequest.blank('/subnets/', version="2.78")
|
||||
mock_index = self.mock_object(
|
||||
self.controller, '_show_metadata',
|
||||
mock.Mock(return_value='fake_metadata'))
|
||||
|
||||
key = 'fake_key'
|
||||
result = self.controller.show_metadata(
|
||||
req, self.share_network['id'], self.subnet['id'], key)
|
||||
|
||||
self.assertEqual('fake_metadata', result)
|
||||
mock_index.assert_called_once_with(req, self.subnet['id'], key,
|
||||
parent_id=self.share_network['id'])
|
||||
|
||||
def test_delete_metadata(self):
|
||||
req = fakes.HTTPRequest.blank('/subnets/', version="2.78")
|
||||
mock_index = self.mock_object(
|
||||
self.controller, '_delete_metadata',
|
||||
mock.Mock(return_value='fake_metadata'))
|
||||
|
||||
key = 'fake_key'
|
||||
result = self.controller.delete_metadata(
|
||||
req, self.share_network['id'], self.subnet['id'], key)
|
||||
|
||||
self.assertEqual('fake_metadata', result)
|
||||
mock_index.assert_called_once_with(req, self.subnet['id'], key,
|
||||
parent_id=self.share_network['id'])
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
import ddt
|
||||
|
||||
from manila.api.openstack import api_version_request as api_version
|
||||
from manila.api.views import share_network_subnets
|
||||
from manila import test
|
||||
from manila.tests.api import fakes
|
||||
@ -31,11 +32,13 @@ class ViewBuilderTestCase(test.TestCase):
|
||||
self.share_network = db_utils.create_share_network(
|
||||
name='fake_network', id='fake_sn_id')
|
||||
|
||||
def _validate_is_detail_return(self, result):
|
||||
def _validate_is_detail_return(self, result, metadata_support=False):
|
||||
expected_keys = ['id', 'created_at', 'updated_at', 'neutron_net_id',
|
||||
'neutron_subnet_id', 'network_type', 'cidr',
|
||||
'segmentation_id', 'ip_version', 'share_network_id',
|
||||
'availability_zone', 'gateway', 'mtu']
|
||||
if metadata_support:
|
||||
expected_keys.append('metadata')
|
||||
|
||||
for key in expected_keys:
|
||||
self.assertIn(key, result)
|
||||
@ -58,13 +61,19 @@ class ViewBuilderTestCase(test.TestCase):
|
||||
result['share_network_subnet']['availability_zone'])
|
||||
self._validate_is_detail_return(result['share_network_subnet'])
|
||||
|
||||
def test_build_share_network_subnets(self):
|
||||
req = fakes.HTTPRequest.blank('/subnets', version='2.51')
|
||||
@ddt.data("2.51", "2.78")
|
||||
def test_build_share_network_subnets(self, microversion):
|
||||
metadata_support = (api_version.APIVersionRequest(microversion) >=
|
||||
api_version.APIVersionRequest('2.78'))
|
||||
|
||||
req = fakes.HTTPRequest.blank('/subnets', version=microversion)
|
||||
|
||||
share_network = db_utils.create_share_network(
|
||||
name='fake_network', id='fake_sn_id_1')
|
||||
|
||||
expected_metadata = {'fake_key': 'fake_value'}
|
||||
subnet = db_utils.create_share_network_subnet(
|
||||
share_network_id=share_network['id'])
|
||||
share_network_id=share_network['id'], metadata=expected_metadata)
|
||||
|
||||
result = self.builder.build_share_network_subnets(req, [subnet])
|
||||
|
||||
@ -72,4 +81,7 @@ class ViewBuilderTestCase(test.TestCase):
|
||||
self.assertEqual(1, len(result['share_network_subnets']))
|
||||
subnet_list = result['share_network_subnets']
|
||||
for subnet in subnet_list:
|
||||
self._validate_is_detail_return(subnet)
|
||||
self._validate_is_detail_return(subnet,
|
||||
metadata_support=metadata_support)
|
||||
if metadata_support:
|
||||
self.assertEqual(expected_metadata, subnet['metadata'])
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
import ddt
|
||||
import itertools
|
||||
|
||||
@ -145,6 +146,9 @@ class ViewBuilderTestCase(test.TestCase):
|
||||
network_allocation_update_support = (
|
||||
api_version.APIVersionRequest(microversion) >=
|
||||
api_version.APIVersionRequest('2.69'))
|
||||
subnet_metadata_support = (
|
||||
api_version.APIVersionRequest(microversion) >=
|
||||
api_version.APIVersionRequest('2.78'))
|
||||
|
||||
req = fakes.HTTPRequest.blank('/share-networks', version=microversion)
|
||||
expected_networks_list = []
|
||||
@ -158,8 +162,30 @@ class ViewBuilderTestCase(test.TestCase):
|
||||
'description': share_network.get('description'),
|
||||
}
|
||||
if subnets_support:
|
||||
share_network.update({'share_network_subnets': []})
|
||||
expected_data.update({'share_network_subnets': []})
|
||||
expected_subnet = {
|
||||
'id': 'fake_subnet_id',
|
||||
'availability_zone': 'fake_az',
|
||||
'created_at': share_network.get('created_at'),
|
||||
'updated_at': share_network.get('updated_at'),
|
||||
'segmentation_id': share_network.get('segmentation_id'),
|
||||
'neutron_net_id': share_network.get('neutron_net_id'),
|
||||
'neutron_subnet_id': share_network.get(
|
||||
'neutron_subnet_id'),
|
||||
'ip_version': share_network.get('ip_version'),
|
||||
'cidr': share_network.get('cidr'),
|
||||
'network_type': share_network.get('network_type'),
|
||||
'mtu': share_network.get('mtu'),
|
||||
'gateway': share_network.get('gateway'),
|
||||
}
|
||||
subnet = expected_subnet
|
||||
if subnet_metadata_support:
|
||||
subnet = copy.deepcopy(expected_subnet)
|
||||
expected_subnet['metadata'] = {'fake_key': 'fake_value'}
|
||||
subnet['subnet_metadata'] = expected_subnet['metadata']
|
||||
|
||||
expected_data.update(
|
||||
{'share_network_subnets': [expected_subnet]})
|
||||
share_network.update({'share_network_subnets': [subnet]})
|
||||
else:
|
||||
if default_net_info_support:
|
||||
network_data = {
|
||||
|
@ -3253,3 +3253,58 @@ class AddSnapshotMetadata(BaseMigrationChecks):
|
||||
def check_downgrade(self, engine):
|
||||
self.test_case.assertRaises(sa_exc.NoSuchTableError, utils.load_table,
|
||||
self.new_table_name, engine)
|
||||
|
||||
|
||||
@map_to_migration('ac0620cbe74d')
|
||||
class AddSubnetMetadata(BaseMigrationChecks):
|
||||
share_subnet_id = uuidutils.generate_uuid()
|
||||
new_table_name = 'share_network_subnet_metadata'
|
||||
|
||||
def setup_upgrade_data(self, engine):
|
||||
# Setup Share network.
|
||||
share_network_data = {
|
||||
'id': uuidutils.generate_uuid(),
|
||||
'user_id': 'fake',
|
||||
'project_id': 'fake'
|
||||
}
|
||||
network_table = utils.load_table('share_networks', engine)
|
||||
engine.execute(network_table.insert(share_network_data))
|
||||
|
||||
# Setup share network subnet.
|
||||
share_network_subnet_data = {
|
||||
'id': self.share_subnet_id,
|
||||
'share_network_id': share_network_data['id']
|
||||
}
|
||||
network_table = utils.load_table('share_network_subnets', engine)
|
||||
engine.execute(network_table.insert(share_network_subnet_data))
|
||||
|
||||
def check_upgrade(self, engine, data):
|
||||
data = {
|
||||
'id': 1,
|
||||
'key': 't' * 255,
|
||||
'value': 'v' * 1023,
|
||||
'share_network_subnet_id': self.share_subnet_id,
|
||||
'deleted': 'False',
|
||||
}
|
||||
|
||||
new_table = utils.load_table(self.new_table_name, engine)
|
||||
engine.execute(new_table.insert(data))
|
||||
|
||||
item = engine.execute(
|
||||
new_table.select().where(new_table.c.id == data['id'])).first()
|
||||
self.test_case.assertTrue(hasattr(item, 'id'))
|
||||
self.test_case.assertEqual(data['id'], item['id'])
|
||||
self.test_case.assertTrue(hasattr(item, 'key'))
|
||||
self.test_case.assertEqual(data['key'], item['key'])
|
||||
self.test_case.assertTrue(hasattr(item, 'value'))
|
||||
self.test_case.assertEqual(data['value'], item['value'])
|
||||
self.test_case.assertTrue(hasattr(item, 'share_network_subnet_id'))
|
||||
self.test_case.assertEqual(self.share_subnet_id,
|
||||
item['share_network_subnet_id'])
|
||||
self.test_case.assertTrue(hasattr(item, 'deleted'))
|
||||
self.test_case.assertEqual('False', item['deleted'])
|
||||
|
||||
def check_downgrade(self, engine):
|
||||
self.test_case.assertRaises(sa_exc.NoSuchTableError,
|
||||
utils.load_table,
|
||||
self.new_table_name, engine)
|
||||
|
@ -3149,6 +3149,64 @@ class ShareNetworkSubnetDatabaseAPITestCase(BaseDatabaseAPITestCase):
|
||||
db_api.share_network_subnet_get_all_by_share_server_id,
|
||||
self.fake_context, 'share_server_id')
|
||||
|
||||
def test_share_network_subnet_metadata_get(self):
|
||||
metadata = {'a': 'b', 'c': 'd'}
|
||||
|
||||
subnet_1 = db_api.share_network_subnet_create(
|
||||
self.fake_context, self.subnet_dict)
|
||||
db_api.share_network_subnet_metadata_update(
|
||||
self.fake_context, share_network_subnet_id=subnet_1['id'],
|
||||
metadata=metadata, delete=False)
|
||||
self.assertEqual(
|
||||
metadata, db_api.share_network_subnet_metadata_get(
|
||||
self.fake_context, share_network_subnet_id=subnet_1['id']))
|
||||
|
||||
def test_share_network_subnet_metadata_get_item(self):
|
||||
metadata = {'a': 'b', 'c': 'd'}
|
||||
key = 'a'
|
||||
shouldbe = {'a': 'b'}
|
||||
subnet_1 = db_api.share_network_subnet_create(
|
||||
self.fake_context, self.subnet_dict)
|
||||
db_api.share_network_subnet_metadata_update(
|
||||
self.fake_context, share_network_subnet_id=subnet_1['id'],
|
||||
metadata=metadata, delete=False)
|
||||
self.assertEqual(
|
||||
shouldbe, db_api.share_network_subnet_metadata_get_item(
|
||||
self.fake_context, share_network_subnet_id=subnet_1['id'],
|
||||
key=key))
|
||||
|
||||
def test_share_network_subnet_metadata_update(self):
|
||||
metadata1 = {'a': '1', 'c': '2'}
|
||||
metadata2 = {'a': '3', 'd': '5'}
|
||||
should_be = {'a': '3', 'c': '2', 'd': '5'}
|
||||
subnet_1 = db_api.share_network_subnet_create(
|
||||
self.fake_context, self.subnet_dict)
|
||||
db_api.share_network_subnet_metadata_update(
|
||||
self.fake_context, share_network_subnet_id=subnet_1['id'],
|
||||
metadata=metadata1, delete=False)
|
||||
db_api.share_network_subnet_metadata_update(
|
||||
self.fake_context, share_network_subnet_id=subnet_1['id'],
|
||||
metadata=metadata2, delete=False)
|
||||
self.assertEqual(
|
||||
should_be, db_api.share_network_subnet_metadata_get(
|
||||
self.fake_context, share_network_subnet_id=subnet_1['id']))
|
||||
|
||||
def test_share_network_subnet_metadata_delete(self):
|
||||
key = 'a'
|
||||
metadata = {'a': '1', 'c': '2'}
|
||||
should_be = {'c': '2'}
|
||||
subnet_1 = db_api.share_network_subnet_create(
|
||||
self.fake_context, self.subnet_dict)
|
||||
db_api.share_network_subnet_metadata_update(
|
||||
self.fake_context, share_network_subnet_id=subnet_1['id'],
|
||||
metadata=metadata, delete=False)
|
||||
db_api.share_network_subnet_metadata_delete(
|
||||
self.fake_context, share_network_subnet_id=subnet_1['id'],
|
||||
key=key)
|
||||
self.assertEqual(
|
||||
should_be, db_api.share_network_subnet_metadata_get(
|
||||
self.fake_context, share_network_subnet_id=subnet_1['id']))
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SecurityServiceDatabaseAPITestCase(BaseDatabaseAPITestCase):
|
||||
|
@ -3861,7 +3861,8 @@ class ShareManagerTestCase(test.TestCase):
|
||||
cidr='fake_cidr',
|
||||
neutron_net_id='fake_neutron_net_id',
|
||||
neutron_subnet_id='fake_neutron_subnet_id',
|
||||
network_type='fake_network_type')
|
||||
network_type='fake_network_type',
|
||||
subnet_metadata={'fake_key': 'fake_value'})
|
||||
expected = [dict(
|
||||
server_id=fake_share_server['id'],
|
||||
segmentation_id=fake_share_network_subnet['segmentation_id'],
|
||||
@ -3874,7 +3875,8 @@ class ShareManagerTestCase(test.TestCase):
|
||||
admin_network_allocations=(
|
||||
fake_network_allocations_get_for_share_server(label='admin')),
|
||||
backend_details=fake_share_server['backend_details'],
|
||||
network_type=fake_share_network_subnet['network_type'])]
|
||||
network_type=fake_share_network_subnet['network_type'],
|
||||
subnet_metadata=fake_share_network_subnet['subnet_metadata'])]
|
||||
|
||||
network_info = self.share_manager._form_server_setup_info(
|
||||
self.context, fake_share_server, fake_share_network,
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Adds share network subnet metadata capabilities including
|
||||
create, update all, update single, show and delete metadata.
|
Loading…
Reference in New Issue
Block a user