Metadata for Share Network Subnet Resource
This change adds metadata controller for Share Network Subnets resource. Bumps microversion to 2.78. The subnet metadata is passed down to the driver together with the network_info object. APIImpact Partially-implements: bp/metadata-for-share-resources Change-Id: I8d5a03eb127941a84eea5e6e9bdf76b3489f17a8
This commit is contained in:
parent
b4a0fd9af0
commit
43de2e8fb5
@ -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