WIP:Add Share Snapshot Metadata Resource
Adds a share snapshot metadata resource including: New share snapshot metadata database table Accompanying share snapshot metadata table model Accompanying database methods to access and manipulate metadata Accomapnying API methods to access and manipulate metadata Additional exception This code will be abstracted to include more user-facing resources. Can be used with curl commands This change adds resource metadata tables to the migration including: Share Share Instance Share Instance Export location Share Access Rules Snapshots Snapshots Instance Export location Snapshots Access Rules Share Groups Share Group Snapshots Security Services Share Networks Share Network Subnets Change-Id: I2e7d6edafc929e1c63425f6f4be02335fc263a34
This commit is contained in:
parent
1a39505039
commit
ef0fce81af
|
@ -51,6 +51,7 @@ from manila.api.v2 import share_servers
|
|||
from manila.api.v2 import share_snapshot_export_locations
|
||||
from manila.api.v2 import share_snapshot_instance_export_locations
|
||||
from manila.api.v2 import share_snapshot_instances
|
||||
from manila.api.v2 import share_snapshot_metadata
|
||||
from manila.api.v2 import share_snapshots
|
||||
from manila.api.v2 import share_types
|
||||
from manila.api.v2 import shares
|
||||
|
@ -296,6 +297,49 @@ class APIRouter(manila.api.openstack.APIRouter):
|
|||
action="update_all",
|
||||
conditions={"method": ["PUT"]})
|
||||
|
||||
self.resources["share_snapshot_metadata"] = (
|
||||
share_snapshot_metadata.create_resource())
|
||||
share_snapshot_metadata_controller = (
|
||||
self.resources["share_snapshot_metadata"])
|
||||
|
||||
mapper.resource("share_snapshot_metadata", "metadata",
|
||||
controller=share_snapshot_metadata_controller,
|
||||
parent_resource=dict(member_name="share_snapshot",
|
||||
collection_name="share_snapshots"
|
||||
))
|
||||
for path_prefix in ['/{project_id}', '']:
|
||||
# project_id is optional
|
||||
mapper.connect("metadata",
|
||||
"%s/snapshots/{share_snapshot_id}/metadata"
|
||||
% path_prefix,
|
||||
controller=share_snapshot_metadata_controller,
|
||||
action="create",
|
||||
conditions={"method": ["POST"]})
|
||||
mapper.connect("metadata",
|
||||
"%s/snapshots/{share_snapshot_id}/metadata"
|
||||
% path_prefix,
|
||||
controller=share_snapshot_metadata_controller,
|
||||
action="update_all",
|
||||
conditions={"method": ["PUT"]})
|
||||
mapper.connect("metadata",
|
||||
"%s/snapshots/{share_snapshot_id}/metadata"
|
||||
% path_prefix,
|
||||
controller=share_snapshot_metadata_controller,
|
||||
action="index",
|
||||
conditions={"method": ["GET"]})
|
||||
mapper.connect("metadata",
|
||||
"%s/snapshots/{share_snapshot_id}/metadata/{key}"
|
||||
% path_prefix,
|
||||
controller=share_snapshot_metadata_controller,
|
||||
action="show",
|
||||
conditions={"method": ["GET"]})
|
||||
mapper.connect("metadata",
|
||||
"%s/snapshots/{share_snapshot_id}/metadata/{key}"
|
||||
% path_prefix,
|
||||
controller=share_snapshot_metadata_controller,
|
||||
action="delete",
|
||||
conditions={"method": ["DELETE"]})
|
||||
|
||||
self.resources["limits"] = limits.create_resource()
|
||||
mapper.resource("limit", "limits",
|
||||
controller=self.resources["limits"])
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
# 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.
|
||||
|
||||
from six.moves import http_client
|
||||
import webob
|
||||
from webob import exc
|
||||
|
||||
from manila.api.openstack import wsgi
|
||||
from manila import db
|
||||
from manila import exception
|
||||
from manila.i18n import _
|
||||
from manila import share
|
||||
|
||||
|
||||
class ShareSnapshotMetadataController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
"""The share metadata API V2 controller for the OpenStack API."""
|
||||
|
||||
resource_name = 'share_snapshot_metadata'
|
||||
|
||||
def __init__(self):
|
||||
self.share_api = share.API()
|
||||
super(ShareSnapshotMetadataController, self).__init__()
|
||||
|
||||
def _get_metadata(self, context, share_snapshot_id):
|
||||
try:
|
||||
db.share_snapshot_get(context, share_snapshot_id)
|
||||
metadata = db.share_snapshot_metadata_get(context,
|
||||
share_snapshot_id)
|
||||
except exception.ShareSnapshotNotFound as e:
|
||||
raise exc.HTTPNotFound(explanation=e)
|
||||
return metadata
|
||||
|
||||
def _index(self, req, share_snapshot_id):
|
||||
context = req.environ['manila.context']
|
||||
self._get_metadata(context, share_snapshot_id)
|
||||
metadata = db.share_snapshot_metadata_get(
|
||||
context, share_snapshot_id)
|
||||
return {'metadata': metadata}
|
||||
|
||||
def index(self, req, share_snapshot_id):
|
||||
"""Returns the list of metadata for a given share snapshot."""
|
||||
return self._index(req, share_snapshot_id)
|
||||
|
||||
def create(self, req, share_snapshot_id, body):
|
||||
"""Returns the new metadata item created."""
|
||||
try:
|
||||
metadata = body['metadata']
|
||||
except (KeyError, TypeError):
|
||||
msg = _("Malformed request body")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
context = req.environ['manila.context']
|
||||
new_metadata = db.share_snapshot_metadata_update(
|
||||
context, share_snapshot_id, metadata)
|
||||
return {'metadata': new_metadata}
|
||||
|
||||
def update(self, req, share_snapshot_id, body):
|
||||
"""Returns the updated metadata items."""
|
||||
try:
|
||||
metadata = body['metadata']
|
||||
except (TypeError, KeyError):
|
||||
expl = _('Malformed request body')
|
||||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
|
||||
context = req.environ['manila.context']
|
||||
new_metadata = db.share_snapshot_metadata_update(
|
||||
context, share_snapshot_id, metadata)
|
||||
return {'metadata': new_metadata}
|
||||
|
||||
def update_all(self, req, share_snapshot_id, body):
|
||||
"""Deletes existing metadata, and returns the updated metadata."""
|
||||
try:
|
||||
metadata = body['metadata']
|
||||
except (TypeError, KeyError):
|
||||
expl = _('Malformed request body')
|
||||
raise exc.HTTPBadRequest(explanation=expl)
|
||||
|
||||
context = req.environ['manila.context']
|
||||
metaref = self._get_metadata(context, share_snapshot_id)
|
||||
for key in metaref:
|
||||
db.share_snapshot_metadata_delete(
|
||||
context, share_snapshot_id, key)
|
||||
new_metadata = db.share_snapshot_metadata_update(
|
||||
context, share_snapshot_id, metadata)
|
||||
return {'metadata': new_metadata}
|
||||
|
||||
def show(self, req, share_snapshot_id, key):
|
||||
"""Return metadata item."""
|
||||
|
||||
context = req.environ['manila.context']
|
||||
|
||||
item = db.share_snapshot_metadata_get_item(
|
||||
context, share_snapshot_id, key)
|
||||
|
||||
return {'metadata': {key: item}}
|
||||
|
||||
def delete(self, req, share_snapshot_id, key):
|
||||
"""Deletes existing metadata items."""
|
||||
|
||||
|
||||
context = req.environ['manila.context']
|
||||
|
||||
db.share_snapshot_metadata_delete(
|
||||
context, share_snapshot_id, key)
|
||||
|
||||
return webob.Response(status_int=http_client.OK)
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(ShareSnapshotMetadataController())
|
|
@ -734,7 +734,32 @@ def share_snapshot_instance_export_location_delete(context, el_id):
|
|||
return IMPL.share_snapshot_instance_export_location_delete(context, el_id)
|
||||
|
||||
|
||||
####################
|
||||
|
||||
def share_snapshot_metadata_get(context, share_snapshot_id):
|
||||
"""Get all metadata for a share snapshot."""
|
||||
return IMPL.share_snapshot_metadata_get(context, share_snapshot_id)
|
||||
|
||||
|
||||
def share_snapshot_metadata_get_item(context, share_snapshot_id, key):
|
||||
"""Get all metadata for a share snapshot."""
|
||||
return IMPL.share_snapshot_metadata_get_item(context,
|
||||
share_snapshot_id, key)
|
||||
|
||||
|
||||
def share_snapshot_metadata_delete(context, share_snapshot_id, key):
|
||||
"""Delete the given metadata item."""
|
||||
IMPL.share_snapshot_metadata_delete(context, share_snapshot_id, key)
|
||||
|
||||
|
||||
def share_snapshot_metadata_update(context, share_snapshot_id, metadata):
|
||||
"""Update metadata if it exists, otherwise create it."""
|
||||
return IMPL.share_snapshot_metadata_update(context,
|
||||
share_snapshot_id, metadata)
|
||||
|
||||
|
||||
###################
|
||||
|
||||
def security_service_create(context, values):
|
||||
"""Create security service DB record."""
|
||||
return IMPL.security_service_create(context, values)
|
||||
|
|
|
@ -0,0 +1,423 @@
|
|||
# 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_snapshot_metadata
|
||||
|
||||
Revision ID: aa53865c45d3
|
||||
Revises: fbdfabcba377
|
||||
Create Date: 2021-07-19 15:22:25.274494
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'aa53865c45d3'
|
||||
down_revision = 'fbdfabcba377'
|
||||
|
||||
from alembic import op
|
||||
from manila.db.migrations import utils
|
||||
from oslo_log import log
|
||||
import sqlalchemy as sql
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
# Existing Tables
|
||||
# share_metadata_table_name = 'share_metadata'
|
||||
# share_access_rules_metadata_table_name = 'share_access_rules_metadata'
|
||||
# share_instance_export_locations_metadata_table_name = (
|
||||
# 'share_instance_export_locations_metadata')
|
||||
|
||||
# New Tables
|
||||
share_instance_metadata_table_name = 'share_instance_metadata'
|
||||
share_snapshot_metadata_table_name = 'share_snapshot_metadata'
|
||||
share_snapshot_instance_export_locations_metadata_table_name = (
|
||||
'share_snapshot_instance_export_locations_metadata')
|
||||
share_snapshot_access_rules_metadata_table_name = (
|
||||
'share_snapshot_access_rules_metadata')
|
||||
share_group_metadata_table_name = 'share_group_metadata'
|
||||
share_group_snapshots_metadata_table_name = 'share_group_snapshots_metadata'
|
||||
security_service_metadata_table_name = 'security_service_metadata'
|
||||
share_networks_metadata_table_name = 'share_networks_metadata'
|
||||
share_network_subnets_metadata_table_name = 'share_network_subnets_metadata'
|
||||
|
||||
|
||||
def upgrade():
|
||||
connection = op.get_bind()
|
||||
try:
|
||||
op.create_table(
|
||||
share_snapshot_metadata_table_name,
|
||||
sql.Column('created_at', sql.DateTime),
|
||||
sql.Column('updated_at', sql.DateTime),
|
||||
sql.Column('deleted_at', sql.DateTime),
|
||||
sql.Column('deleted', sql.Integer, default=0),
|
||||
sql.Column('share_snapshot_id', sql.String(36),
|
||||
sql.ForeignKey('share_snapshots.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),
|
||||
sql.Column('user_modifiable', sql.Boolean, default=True,
|
||||
nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
except Exception:
|
||||
LOG.error("Table |%s| not created!",
|
||||
share_snapshot_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.create_table(
|
||||
share_snapshot_instance_export_locations_metadata_table_name,
|
||||
sql.Column('created_at', sql.DateTime),
|
||||
sql.Column('updated_at', sql.DateTime),
|
||||
sql.Column('deleted_at', sql.DateTime),
|
||||
sql.Column('deleted', sql.Integer, default=0),
|
||||
sql.Column(
|
||||
'share_snapshot_instance_export_locations_id',
|
||||
sql.String(36), sql.ForeignKey(
|
||||
'share_snapshot_instance_export_locations.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),
|
||||
sql.Column('user_modifiable', sql.Boolean, default=True,
|
||||
nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
except Exception:
|
||||
LOG.error("Table |%s| not created!",
|
||||
share_snapshot_instance_export_locations_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.create_table(
|
||||
share_instance_metadata_table_name,
|
||||
sql.Column('created_at', sql.DateTime),
|
||||
sql.Column('updated_at', sql.DateTime),
|
||||
sql.Column('deleted_at', sql.DateTime),
|
||||
sql.Column('deleted', sql.Integer, default=0),
|
||||
sql.Column('share_instance_id', sql.String(36), sql.ForeignKey(
|
||||
'share_instances.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),
|
||||
sql.Column('user_modifiable', sql.Boolean, default=True,
|
||||
nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
except Exception:
|
||||
LOG.error("Table |%s| not created!",
|
||||
share_instance_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.create_table(
|
||||
share_snapshot_access_rules_metadata_table_name,
|
||||
sql.Column('created_at', sql.DateTime),
|
||||
sql.Column('updated_at', sql.DateTime),
|
||||
sql.Column('deleted_at', sql.DateTime),
|
||||
sql.Column('deleted', sql.Integer, default=0),
|
||||
sql.Column(
|
||||
'access_id', sql.String(36), sql.ForeignKey(
|
||||
'share_snapshot_access_map.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),
|
||||
sql.Column('user_modifiable', sql.Boolean, default=True,
|
||||
nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
except Exception:
|
||||
LOG.error("Table |%s| not created!",
|
||||
share_snapshot_access_rules_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.create_table(
|
||||
share_group_metadata_table_name,
|
||||
sql.Column('created_at', sql.DateTime),
|
||||
sql.Column('updated_at', sql.DateTime),
|
||||
sql.Column('deleted_at', sql.DateTime),
|
||||
sql.Column('deleted', sql.Integer, default=0),
|
||||
sql.Column(
|
||||
'share_group_id',
|
||||
sql.String(36), sql.ForeignKey(
|
||||
'share_groups.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),
|
||||
sql.Column('user_modifiable', sql.Boolean, default=True,
|
||||
nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
except Exception:
|
||||
LOG.error("Table |%s| not created!",
|
||||
share_group_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.create_table(
|
||||
share_group_snapshots_metadata_table_name,
|
||||
sql.Column('created_at', sql.DateTime),
|
||||
sql.Column('updated_at', sql.DateTime),
|
||||
sql.Column('deleted_at', sql.DateTime),
|
||||
sql.Column('deleted', sql.Integer, default=0),
|
||||
sql.Column(
|
||||
'share_group_snapshot_id', sql.String(36),
|
||||
sql.ForeignKey(
|
||||
'share_group_snapshots.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),
|
||||
sql.Column('user_modifiable', sql.Boolean, default=True,
|
||||
nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
except Exception:
|
||||
LOG.error("Table |%s| not created!",
|
||||
share_group_snapshots_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.create_table(
|
||||
security_service_metadata_table_name,
|
||||
sql.Column('created_at', sql.DateTime),
|
||||
sql.Column('updated_at', sql.DateTime),
|
||||
sql.Column('deleted_at', sql.DateTime),
|
||||
sql.Column('deleted', sql.Integer, default=0),
|
||||
sql.Column(
|
||||
'security_service_id', sql.String(36),
|
||||
sql.ForeignKey('security_services.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),
|
||||
sql.Column('user_modifiable', sql.Boolean, default=True,
|
||||
nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
except Exception:
|
||||
LOG.error("Table |%s| not created!",
|
||||
security_service_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.create_table(
|
||||
share_networks_metadata_table_name,
|
||||
sql.Column('created_at', sql.DateTime),
|
||||
sql.Column('updated_at', sql.DateTime),
|
||||
sql.Column('deleted_at', sql.DateTime),
|
||||
sql.Column('deleted', sql.Integer, default=0),
|
||||
sql.Column(
|
||||
'share_network_id', sql.String(36),
|
||||
sql.ForeignKey('share_networks.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),
|
||||
sql.Column('user_modifiable', sql.Boolean, default=True,
|
||||
nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
except Exception:
|
||||
LOG.error("Table |%s| not created!",
|
||||
share_networks_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.create_table(
|
||||
share_network_subnets_metadata_table_name,
|
||||
sql.Column('created_at', sql.DateTime),
|
||||
sql.Column('updated_at', sql.DateTime),
|
||||
sql.Column('deleted_at', sql.DateTime),
|
||||
sql.Column('deleted', sql.Integer, default=0),
|
||||
sql.Column(
|
||||
'share_network_subnets_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),
|
||||
sql.Column('user_modifiable', sql.Boolean, default=True,
|
||||
nullable=False),
|
||||
mysql_engine='InnoDB',
|
||||
mysql_charset='utf8'
|
||||
)
|
||||
except Exception:
|
||||
LOG.error("Table |%s| not created!",
|
||||
share_network_subnets_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
user_modifiable = sql.Column(
|
||||
'user_modifiable', sql.Boolean, default=True, nullable=False)
|
||||
|
||||
op.add_column(
|
||||
'share_instance_export_locations_metadata', user_modifiable)
|
||||
|
||||
share_instance_export_locations_metadata_table_name = utils.load_table(
|
||||
'share_instance_export_locations_metadata', connection)
|
||||
op.execute(
|
||||
share_instance_export_locations_metadata_table_name.update(
|
||||
).values({'user_modifiable': True}))
|
||||
|
||||
except Exception:
|
||||
LOG.error("Column user_modifiable not created on |%s|!",
|
||||
share_instance_export_locations_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
user_modifiable = sql.Column(
|
||||
'user_modifiable', sql.Boolean, default=True, nullable=False)
|
||||
|
||||
op.add_column('share_access_rules_metadata', user_modifiable)
|
||||
|
||||
share_access_rules_metadata_table_name = utils.load_table(
|
||||
'share_access_rules_metadata', connection)
|
||||
op.execute(
|
||||
share_access_rules_metadata_table_name.update().values({
|
||||
'user_modifiable': True,
|
||||
}))
|
||||
|
||||
except Exception:
|
||||
LOG.error("Column user_modifiable not created on |%s|!",
|
||||
share_access_rules_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
user_modifiable = sql.Column(
|
||||
'user_modifiable', sql.Boolean, default=True, nullable=False)
|
||||
|
||||
op.add_column('share_metadata', user_modifiable)
|
||||
|
||||
share_metadata_table_name = utils.load_table(
|
||||
'share_metadata', connection)
|
||||
op.execute(
|
||||
share_metadata_table_name.update().values({
|
||||
'user_modifiable': True,
|
||||
}))
|
||||
|
||||
except Exception:
|
||||
LOG.error("Column user_modifiable not created on |%s|!",
|
||||
share_metadata_table_name)
|
||||
raise
|
||||
|
||||
|
||||
def downgrade():
|
||||
|
||||
try:
|
||||
op.drop_column(
|
||||
'share_metadata', 'user_modifiable')
|
||||
except Exception:
|
||||
LOG.error(
|
||||
"Column user_modifiable not dropped from %s",
|
||||
'share_metadata')
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_column(
|
||||
'share_access_rules_metadata', 'user_modifiable')
|
||||
except Exception:
|
||||
LOG.error(
|
||||
"Column user_modifiable not dropped from %s",
|
||||
'share_access_rules_metadata')
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_column(
|
||||
'share_instance_export_locations_metadata',
|
||||
'user_modifiable')
|
||||
except Exception:
|
||||
LOG.error(
|
||||
"Column user_modifiable not dropped from %s",
|
||||
'share_instance_export_locations_metadata')
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_table(
|
||||
share_network_subnets_metadata_table_name)
|
||||
except Exception:
|
||||
LOG.error(
|
||||
"%s table not dropped",
|
||||
share_network_subnets_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_table(
|
||||
share_networks_metadata_table_name)
|
||||
except Exception:
|
||||
LOG.error(
|
||||
"%s table not dropped",
|
||||
share_networks_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_table(
|
||||
security_service_metadata_table_name)
|
||||
except Exception:
|
||||
LOG.error(
|
||||
"%s table not dropped",
|
||||
security_service_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_table(
|
||||
share_group_snapshots_metadata_table_name)
|
||||
except Exception:
|
||||
LOG.error(
|
||||
"%s table not dropped",
|
||||
share_group_snapshots_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_table(
|
||||
share_group_metadata_table_name)
|
||||
except Exception:
|
||||
LOG.error(
|
||||
"%s table not dropped",
|
||||
share_group_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_table(share_snapshot_access_rules_metadata_table_name)
|
||||
except Exception:
|
||||
LOG.error(
|
||||
"%s table not dropped",
|
||||
share_snapshot_access_rules_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_table(share_instance_metadata_table_name)
|
||||
except Exception:
|
||||
LOG.error(
|
||||
"%s table not dropped",
|
||||
share_instance_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_table(
|
||||
share_snapshot_instance_export_locations_metadata_table_name)
|
||||
except Exception:
|
||||
LOG.error(
|
||||
"%s table not dropped",
|
||||
share_snapshot_instance_export_locations_metadata_table_name)
|
||||
raise
|
||||
|
||||
try:
|
||||
op.drop_table(share_snapshot_metadata_table_name)
|
||||
except Exception:
|
||||
LOG.error("%s table not dropped", share_snapshot_metadata_table_name)
|
||||
raise
|
|
@ -201,6 +201,20 @@ def require_share_exists(f):
|
|||
return wrapper
|
||||
|
||||
|
||||
def require_share_snapshot_exists(f):
|
||||
"""Decorator to require the specified share snapshot to exist.
|
||||
|
||||
Requires the wrapped function to use context and share_snapshot_id as
|
||||
their first two arguments.
|
||||
"""
|
||||
@wraps(f)
|
||||
def wrapper(context, share_snapshot_id, *args, **kwargs):
|
||||
_share_snapshot_metadata_get(context, share_snapshot_id)
|
||||
return f(context, share_snapshot_id, *args, **kwargs)
|
||||
wrapper.__name__ = f.__name__
|
||||
return wrapper
|
||||
|
||||
|
||||
def require_share_instance_exists(f):
|
||||
"""Decorator to require the specified share instance to exist.
|
||||
|
||||
|
@ -2707,6 +2721,8 @@ def share_snapshot_instance_delete(context, snapshot_instance_id,
|
|||
snapshot = share_snapshot_get(
|
||||
context, snapshot_instance_ref['snapshot_id'], session=session)
|
||||
if len(snapshot.instances) == 0:
|
||||
session.query(models.ShareSnapshotMetadata).filter_by(
|
||||
share_snapshot_id=snapshot['id']).soft_delete()
|
||||
snapshot.soft_delete(session=session)
|
||||
|
||||
|
||||
|
@ -2807,6 +2823,8 @@ def share_snapshot_create(context, create_values,
|
|||
create_snapshot_instance=True):
|
||||
values = copy.deepcopy(create_values)
|
||||
values = ensure_model_dict_has_id(values)
|
||||
values['share_snapshot_metadata'] = _metadata_refs(
|
||||
values.get('metadata'), models.ShareSnapshotMetadata)
|
||||
|
||||
snapshot_ref = models.ShareSnapshot()
|
||||
snapshot_instance_values, snapshot_values = (
|
||||
|
@ -2862,6 +2880,7 @@ def share_snapshot_get(context, snapshot_id, session=None):
|
|||
filter_by(id=snapshot_id).
|
||||
options(joinedload('share')).
|
||||
options(joinedload('instances')).
|
||||
options(joinedload('share_snapshot_metadata')).
|
||||
first())
|
||||
|
||||
if not result:
|
||||
|
@ -2903,7 +2922,12 @@ def _share_snapshot_get_all_with_filters(context, project_id=None,
|
|||
'key': filters['usage'],
|
||||
'ek': usage_filter_keys}
|
||||
raise exception.InvalidInput(reason=msg)
|
||||
|
||||
if 'metadata' in filters:
|
||||
for k, v in filters['metadata'].items():
|
||||
# pylint: disable=no-member
|
||||
query = query.filter(
|
||||
or_(models.ShareSnapshot.share_snapshot_metadata.any(
|
||||
key=k, value=v)))
|
||||
# Apply sorting
|
||||
try:
|
||||
attr = getattr(models.ShareSnapshot, sort_key)
|
||||
|
@ -3356,8 +3380,13 @@ def share_metadata_get(context, share_id):
|
|||
@require_context
|
||||
@require_share_exists
|
||||
def share_metadata_delete(context, share_id, key):
|
||||
(_share_metadata_get_query(context, share_id).
|
||||
filter_by(key=key).soft_delete())
|
||||
session = get_session()
|
||||
meta_ref = _share_metadata_get_query(
|
||||
context, share_id, session=session
|
||||
).filter_by(key=key).first()
|
||||
if not meta_ref:
|
||||
raise exception.ShareMetadataNotFound()
|
||||
meta_ref.soft_delete(session=session)
|
||||
|
||||
|
||||
@require_context
|
||||
|
@ -3434,6 +3463,102 @@ def _share_metadata_get_item(context, share_id, key, session=None):
|
|||
return result
|
||||
|
||||
|
||||
############################
|
||||
# Share Snapshot Metadata functions
|
||||
############################
|
||||
|
||||
@require_context
|
||||
@require_share_snapshot_exists
|
||||
def share_snapshot_metadata_get(context, share_snapshot_id):
|
||||
session = get_session()
|
||||
return _share_snapshot_metadata_get(context,
|
||||
share_snapshot_id, session=session)
|
||||
|
||||
|
||||
@require_context
|
||||
@require_share_snapshot_exists
|
||||
def share_snapshot_metadata_delete(context, share_snapshot_id, key):
|
||||
session = get_session()
|
||||
meta_ref = _share_snapshot_metadata_get_query(
|
||||
context, share_snapshot_id, session=session
|
||||
).filter_by(key=key).first()
|
||||
if not meta_ref:
|
||||
raise exception.ShareSnapshotMetadataNotFound()
|
||||
meta_ref.soft_delete(session=session)
|
||||
|
||||
|
||||
@require_context
|
||||
@require_share_snapshot_exists
|
||||
def share_snapshot_metadata_update(context, share_snapshot_id,
|
||||
metadata):
|
||||
session = get_session()
|
||||
return _share_snapshot_metadata_update(context, share_snapshot_id,
|
||||
metadata, session=session)
|
||||
|
||||
|
||||
def share_snapshot_metadata_get_item(context, share_snapshot_id,
|
||||
key, session=None):
|
||||
session = get_session()
|
||||
row = _share_snapshot_metadata_get_query(
|
||||
context, share_snapshot_id, session=session
|
||||
).filter_by(key=key).first()
|
||||
|
||||
result = {}
|
||||
result[row['key']] = row['value']
|
||||
|
||||
if not result:
|
||||
raise exception.ShareSnapshotMetadataNotFound()
|
||||
return result
|
||||
|
||||
|
||||
def _share_snapshot_metadata_get_query(context, share_snapshot_id,
|
||||
session=None):
|
||||
session = session or get_session()
|
||||
return (model_query(context, models.ShareSnapshotMetadata,
|
||||
session=session,
|
||||
read_deleted="no").
|
||||
filter_by(share_snapshot_id=share_snapshot_id).
|
||||
options(joinedload('share_snapshot')))
|
||||
|
||||
|
||||
def _share_snapshot_metadata_get(context, share_snapshot_id, session=None):
|
||||
session = session or get_session()
|
||||
rows = _share_snapshot_metadata_get_query(context, share_snapshot_id,
|
||||
session=session).all()
|
||||
result = {}
|
||||
for row in rows:
|
||||
result[row['key']] = row['value']
|
||||
return result
|
||||
|
||||
|
||||
@oslo_db_api.wrap_db_retry(max_retries=5, retry_on_deadlock=True)
|
||||
def _share_snapshot_metadata_update(context, share_snapshot_id,
|
||||
metadata, session=None):
|
||||
if not session:
|
||||
session = get_session()
|
||||
|
||||
with session.begin():
|
||||
meta_ref = None
|
||||
# LOG.warning("dict for _update: %s", dict(metadata))
|
||||
# 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_snapshot_metadata_get_query(
|
||||
context, share_snapshot_id,
|
||||
session=session).filter_by(key=meta_key).first()
|
||||
if not meta_ref:
|
||||
meta_ref = models.ShareSnapshotMetadata()
|
||||
item.update({"key": meta_key,
|
||||
"share_snapshot_id": share_snapshot_id})
|
||||
meta_ref.update(item)
|
||||
meta_ref.save(session=session)
|
||||
|
||||
return metadata
|
||||
|
||||
|
||||
############################
|
||||
# Export locations functions
|
||||
############################
|
||||
|
|
|
@ -459,16 +459,16 @@ class ShareInstanceExportLocationsMetadata(BASE, ManilaBase):
|
|||
ForeignKey("share_instance_export_locations.id"), nullable=False)
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
deleted = Column(String(36), default='False')
|
||||
user_modifiable = Column(Boolean, default=True, nullable=False)
|
||||
export_location = orm.relationship(
|
||||
ShareInstanceExportLocations,
|
||||
backref="_el_metadata_bare",
|
||||
foreign_keys=export_location_id,
|
||||
lazy='immediate',
|
||||
primaryjoin="and_("
|
||||
"%(cls_name)s.export_location_id == "
|
||||
"ShareInstanceExportLocations.id,"
|
||||
"%(cls_name)s.deleted == 0)" % {
|
||||
"cls_name": "ShareInstanceExportLocationsMetadata"})
|
||||
"ShareInstanceExportLocationsMetadata.export_location_id"
|
||||
" == ShareInstanceExportLocations.id,"
|
||||
"ShareInstanceExportLocationsMetadata.deleted == 0)")
|
||||
|
||||
@property
|
||||
def export_location_uuid(self):
|
||||
|
@ -531,11 +531,11 @@ class ShareMetadata(BASE, ManilaBase):
|
|||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
share_id = Column(String(36), ForeignKey('shares.id'), nullable=False)
|
||||
user_modifiable = Column(Boolean, default=True, nullable=False)
|
||||
share = orm.relationship(Share, backref="share_metadata",
|
||||
foreign_keys=share_id,
|
||||
primaryjoin='and_('
|
||||
'ShareMetadata.share_id == Share.id,'
|
||||
'ShareMetadata.deleted == 0)')
|
||||
'ShareMetadata.share_id == Share.id)')
|
||||
|
||||
|
||||
class ShareAccessMapping(BASE, ManilaBase):
|
||||
|
@ -580,8 +580,10 @@ class ShareAccessRulesMetadata(BASE, ManilaBase):
|
|||
deleted = Column(String(36), default='False')
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
deleted = Column(String(36), default='False')
|
||||
access_id = Column(String(36), ForeignKey('share_access_map.id'),
|
||||
nullable=False)
|
||||
user_modifiable = Column(Boolean, default=True, nullable=False)
|
||||
access = orm.relationship(
|
||||
ShareAccessMapping, backref="share_access_rules_metadata",
|
||||
foreign_keys=access_id,
|
||||
|
@ -734,6 +736,25 @@ class ShareSnapshot(BASE, ManilaBase):
|
|||
'ShareSnapshot.deleted == "False")')
|
||||
|
||||
|
||||
class ShareSnapshotMetadata(BASE, ManilaBase):
|
||||
"""Represents a metadata key/value pair for a snapshot."""
|
||||
__tablename__ = 'share_snapshot_metadata'
|
||||
id = Column(Integer, primary_key=True)
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
deleted = Column(Integer, default=0)
|
||||
share_snapshot_id = Column(String(36), ForeignKey(
|
||||
'share_snapshots.id'), nullable=False)
|
||||
user_modifiable = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
share_snapshot = orm.relationship(
|
||||
ShareSnapshot, backref="share_snapshot_metadata",
|
||||
foreign_keys=share_snapshot_id,
|
||||
primaryjoin='and_('
|
||||
'ShareSnapshotMetadata.share_snapshot_id == ShareSnapshot.id,'
|
||||
'ShareSnapshotMetadata.deleted == 0)')
|
||||
|
||||
|
||||
class ShareSnapshotInstance(BASE, ManilaBase):
|
||||
"""Represents a snapshot of a share."""
|
||||
__tablename__ = 'share_snapshot_instances'
|
||||
|
@ -850,6 +871,27 @@ class ShareSnapshotAccessMapping(BASE, ManilaBase):
|
|||
)
|
||||
|
||||
|
||||
class ShareSnapshotAccessRulesMetadata(BASE, ManilaBase):
|
||||
"""Represents a metadata key/value pair for a share access rule."""
|
||||
__tablename__ = 'share_snapshot_access_rules_metadata'
|
||||
id = Column(Integer, primary_key=True)
|
||||
deleted = Column(String(36), default='False')
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
deleted = Column(Integer, default=0)
|
||||
access_id = Column(String(36), ForeignKey('share_snapshot_access_map.id'),
|
||||
nullable=False)
|
||||
user_modifiable = Column(Boolean, default=True, nullable=False)
|
||||
access = orm.relationship(
|
||||
ShareSnapshotAccessMapping,
|
||||
backref="share_snapshot_access_rules_metadata",
|
||||
foreign_keys=access_id,
|
||||
primaryjoin='and_('
|
||||
'ShareSnapshotAccessRulesMetadata.access_id == '
|
||||
'ShareSnapshotAccessMapping.id,'
|
||||
'ShareSnapshotAccessRulesMetadata.deleted == "False")')
|
||||
|
||||
|
||||
class ShareSnapshotInstanceAccessMapping(BASE, ManilaBase):
|
||||
"""Represents access to individual share snapshot instances."""
|
||||
|
||||
|
@ -893,6 +935,31 @@ class ShareSnapshotInstanceExportLocation(BASE, ManilaBase):
|
|||
deleted = Column(String(36), default='False')
|
||||
|
||||
|
||||
class ShareSnapshotInstanceExportLocationMetadata(BASE, ManilaBase):
|
||||
"""Represents a metadata key/value pair for snapshot export locations."""
|
||||
|
||||
__tablename__ = 'share_snapshot_instance_export_locations_metadata'
|
||||
|
||||
id = Column(Integer, primary_key=True)
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
deleted = Column(Integer, default=0)
|
||||
share_snapshot_instance_export_locations_id = (
|
||||
Column(String(36), ForeignKey(
|
||||
'share_snapshot_instance_export_locations.id'), nullable=False))
|
||||
user_modifiable = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
share_snapshot_instance_export_locations = orm.relationship(
|
||||
ShareSnapshotInstanceExportLocation,
|
||||
backref="share_snapshot_instance_export_locations_metadata",
|
||||
foreign_keys=share_snapshot_instance_export_locations_id,
|
||||
primaryjoin='and_('
|
||||
'ShareSnapshotInstanceExportLocationMetadata.'
|
||||
'share_snapshot_instance_export_locations_id =='
|
||||
'ShareSnapshotInstanceExportLocation.id,'
|
||||
'ShareSnapshotInstanceExportLocationMetadata.deleted == 0)')
|
||||
|
||||
|
||||
class SecurityService(BASE, ManilaBase):
|
||||
"""Security service information for manila shares."""
|
||||
|
||||
|
@ -911,6 +978,25 @@ class SecurityService(BASE, ManilaBase):
|
|||
ou = Column(String(255), nullable=True)
|
||||
|
||||
|
||||
class SecurityServiceMetadata(BASE, ManilaBase):
|
||||
"""Represents a metadata key/value pair for a security service."""
|
||||
__tablename__ = 'security_service_metadata'
|
||||
id = Column(Integer, primary_key=True)
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
deleted = Column(Integer, default=0)
|
||||
security_service_id = Column(String(36), ForeignKey(
|
||||
'security_services.id'), nullable=False)
|
||||
user_modifiable = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
security_service = orm.relationship(
|
||||
SecurityService, backref="security_service_metadata",
|
||||
foreign_keys=security_service_id,
|
||||
primaryjoin='and_('
|
||||
'SecurityServiceMetadata.security_service_id == SecurityService.id,'
|
||||
'SecurityServiceMetadata.deleted == 0)')
|
||||
|
||||
|
||||
class ShareNetwork(BASE, ManilaBase):
|
||||
"""Represents network data used by share."""
|
||||
__tablename__ = 'share_networks'
|
||||
|
@ -964,6 +1050,25 @@ class ShareNetwork(BASE, ManilaBase):
|
|||
return all(share_servers_support_updating)
|
||||
|
||||
|
||||
class ShareNetworkMetadata(BASE, ManilaBase):
|
||||
"""Represents a metadata key/value pair for a share network."""
|
||||
__tablename__ = 'share_networks_metadata'
|
||||
id = Column(Integer, primary_key=True)
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
deleted = Column(Integer, default=0)
|
||||
share_network_id = Column(String(36), ForeignKey(
|
||||
'share_networks.id'), nullable=False)
|
||||
user_modifiable = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
share_network = orm.relationship(
|
||||
ShareNetwork, backref="share_networks_metadata",
|
||||
foreign_keys=share_network_id,
|
||||
primaryjoin='and_('
|
||||
'ShareNetworkMetadata.share_network_id == ShareNetwork.id,'
|
||||
'ShareNetworkMetadata.deleted == 0)')
|
||||
|
||||
|
||||
class ShareNetworkSubnet(BASE, ManilaBase):
|
||||
"""Represents a share network subnet used by some resources."""
|
||||
|
||||
|
@ -1015,8 +1120,29 @@ class ShareNetworkSubnet(BASE, ManilaBase):
|
|||
return self.share_network['name']
|
||||
|
||||
|
||||
class ShareNetworkSubnetMetadata(BASE, ManilaBase):
|
||||
"""Represents a metadata key/value pair for a share network subnet."""
|
||||
__tablename__ = 'share_network_subnets_metadata'
|
||||
id = Column(Integer, primary_key=True)
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
deleted = Column(Integer, default=0)
|
||||
share_network_subnets_id = Column(String(36), ForeignKey(
|
||||
'share_network_subnets.id'), nullable=False)
|
||||
user_modifiable = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
share_network_subnet = orm.relationship(
|
||||
ShareNetworkSubnet, backref="share_network_subnets_metadata",
|
||||
foreign_keys=share_network_subnets_id,
|
||||
primaryjoin='and_('
|
||||
'ShareNetworkSubnetMetadata.share_network_subnets_id == '
|
||||
'ShareNetworkSubnet.id,'
|
||||
'ShareNetworkSubnetMetadata.deleted == 0)')
|
||||
|
||||
|
||||
class ShareServer(BASE, ManilaBase):
|
||||
"""Represents share server used by share."""
|
||||
|
||||
__tablename__ = 'share_servers'
|
||||
id = Column(String(36), primary_key=True, nullable=False)
|
||||
deleted = Column(String(36), default='False')
|
||||
|
@ -1195,6 +1321,25 @@ class ShareGroup(BASE, ManilaBase):
|
|||
return self._availability_zone['name']
|
||||
|
||||
|
||||
class ShareGroupsMetadata(BASE, ManilaBase):
|
||||
"""Represents a metadata key/value pair for a share group."""
|
||||
__tablename__ = 'share_groups_metadata'
|
||||
id = Column(Integer, primary_key=True)
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
deleted = Column(Integer, default=0)
|
||||
share_group_id = Column(String(36), ForeignKey(
|
||||
'share_groups.id'), nullable=False)
|
||||
user_modifiable = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
share_group = orm.relationship(
|
||||
ShareGroup, backref="share_groups_metadata",
|
||||
foreign_keys=share_group_id,
|
||||
primaryjoin='and_('
|
||||
'ShareGroupsMetadata.share_group_id == ShareGroup.id,'
|
||||
'ShareGroupsMetadata.deleted == 0)')
|
||||
|
||||
|
||||
class ShareGroupTypeProjects(BASE, ManilaBase):
|
||||
"""Represent projects associated share group types."""
|
||||
__tablename__ = "share_group_type_projects"
|
||||
|
@ -1256,6 +1401,26 @@ class ShareGroupSnapshot(BASE, ManilaBase):
|
|||
)
|
||||
|
||||
|
||||
class ShareGroupSnapshotsMetadata(BASE, ManilaBase):
|
||||
"""Represents a metadata key/value pair for a share group snapshot."""
|
||||
__tablename__ = 'share_group_snapshots_metadata'
|
||||
id = Column(Integer, primary_key=True)
|
||||
key = Column(String(255), nullable=False)
|
||||
value = Column(String(1023), nullable=False)
|
||||
deleted = Column(Integer, default=0)
|
||||
share_group_snapshot_id = Column(String(36), ForeignKey(
|
||||
'share_group_snapshots.id'), nullable=False)
|
||||
user_modifiable = Column(Boolean, default=True, nullable=False)
|
||||
|
||||
share_group_snapshot = orm.relationship(
|
||||
ShareGroupSnapshot, backref="share_groups_metadata",
|
||||
foreign_keys=share_group_snapshot_id,
|
||||
primaryjoin='and_('
|
||||
'ShareGroupSnapshotsMetadata.share_group_snapshot_id == '
|
||||
'ShareGroupSnapshot.id,'
|
||||
'ShareGroupSnapshotsMetadata.deleted == 0)')
|
||||
|
||||
|
||||
class ShareGroupTypeShareTypeMapping(BASE, ManilaBase):
|
||||
"""Represents the share types supported by a share group type."""
|
||||
__tablename__ = 'share_group_type_share_type_mappings'
|
||||
|
|
|
@ -554,6 +554,10 @@ class ShareSnapshotInstanceNotFound(NotFound):
|
|||
message = _("Snapshot instance %(instance_id)s could not be found.")
|
||||
|
||||
|
||||
class ShareSnapshotMetadataNotFound(NotFound):
|
||||
message = _("Metadata could not be found.")
|
||||
|
||||
|
||||
class ShareSnapshotNotSupported(ManilaException):
|
||||
message = _("Share %(share_name)s does not support snapshots.")
|
||||
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
# 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.
|
||||
|
||||
from unittest import mock
|
||||
|
||||
import ddt
|
||||
import webob
|
||||
|
||||
from manila.api.v2 import share_snapshot_metadata
|
||||
from manila.api.v2 import share_snapshots
|
||||
from manila import context
|
||||
from manila import policy
|
||||
from manila import test
|
||||
from manila.tests.api import fakes
|
||||
from manila.tests import db_utils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareSnapshotMetadataAPITest(test.TestCase):
|
||||
|
||||
def _get_request(self, version="2.45", use_admin_context=True):
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/v2/share-access-rules',
|
||||
version=version, use_admin_context=use_admin_context)
|
||||
return req
|
||||
|
||||
def setUp(self):
|
||||
super(ShareSnapshotMetadataAPITest, self).setUp()
|
||||
self.controller = (
|
||||
share_snapshot_metadata.ShareSnapshotMetadataController())
|
||||
self.snapshot_controller = (
|
||||
share_snapshots.ShareSnapshotsController())
|
||||
self.resource_name = self.controller.resource_name
|
||||
self.admin_context = context.RequestContext('admin', 'fake', True)
|
||||
self.member_context = context.RequestContext('fake', 'fake')
|
||||
self.mock_policy_check = self.mock_object(
|
||||
policy, 'check_policy', mock.Mock(return_value=True))
|
||||
self.share = db_utils.create_share()
|
||||
self.snapshot = db_utils.create_snapshot(
|
||||
id=uuidutils.generate_uuid(),
|
||||
share_id=self.share['id'])
|
||||
|
||||
@ddt.data({'body': {'metadata': {'key1': 'v1'}}},
|
||||
{'body': {'metadata': {'test_key1': 'test_v1'}}},
|
||||
{'body': {'metadata': {'key1': 'v2'}}})
|
||||
@ddt.unpack
|
||||
def test_update_metadata(self, body):
|
||||
url = self._get_request()
|
||||
update = self.controller.update(url, self.snapshot['id'], body=body)
|
||||
self.assertEqual(body, update)
|
||||
|
||||
show_result = self.snapshot_controller.show(url, self.snapshot['id'])
|
||||
|
||||
self.assertEqual(1, len(show_result))
|
||||
self.assertIn(self.snapshot['id'], show_result['snapshot']['id'])
|
||||
self.assertEqual(body['metadata'], show_result['snapshot']['metadata'])
|
||||
|
||||
def test_delete_metadata(self):
|
||||
body = {'metadata': {'test_key3': 'test_v3'}}
|
||||
url = self._get_request()
|
||||
self.controller.update(url, self.snapshot['id'], body=body)
|
||||
|
||||
self.controller.delete(url, self.snapshot['id'], 'test_key3')
|
||||
show_result = self.snapshot_controller.show(url, self.snapshot['id'])
|
||||
|
||||
self.assertEqual(1, len(show_result))
|
||||
self.assertIn(self.snapshot['id'], show_result['snapshot']['id'])
|
||||
self.assertNotIn('test_key3', show_result['snapshot']['metadata'])
|
||||
|
||||
def test_update_snapshot_metadata_with_snapshot_id_not_found(self):
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPNotFound,
|
||||
self.controller.update,
|
||||
self._get_request(), 'not_exist_snapshot_id',
|
||||
{'metadata': {'key1': 'v1'}})
|
||||
|
||||
def test_update_snapshot_metadata_with_body_error(self):
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPBadRequest,
|
||||
self.controller.update,
|
||||
self._get_request(), self.snapshot['id'],
|
||||
{'metadata_error': {'key1': 'v1'}})
|
||||
|
||||
@ddt.data({'metadata': {'key1': 'v1', 'key2': None}},
|
||||
{'metadata': {None: 'v1', 'key2': 'v2'}},
|
||||
{'metadata': {'k' * 256: 'v2'}},
|
||||
{'metadata': {'key1': 'v' * 1024}})
|
||||
@ddt.unpack
|
||||
def test_update_metadata_with_invalid_metadata(self, metadata):
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPBadRequest,
|
||||
self.controller.update,
|
||||
self._get_request(), self.snapshot['id'],
|
||||
{'metadata': metadata})
|
||||
|
||||
def test_delete_snapshot_metadata_not_found(self):
|
||||
body = {'metadata': {'test_key_exist': 'test_v_exist'}}
|
||||
update = self.controller.update(
|
||||
self._get_request(), self.snapshot['id'], body=body)
|
||||
self.assertEqual(body, update)
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPNotFound,
|
||||
self.controller.delete,
|
||||
self._get_request(), self.snapshot['id'], 'key1')
|
|
@ -2841,6 +2841,69 @@ class ShareAPITestCase(test.TestCase):
|
|||
self.assertEqual(should_be,
|
||||
db_api.share_metadata_get(self.context, share_id))
|
||||
|
||||
def test_share_snapshot_metadata_get(self):
|
||||
metadata = {'a': 'b', 'c': 'd'}
|
||||
|
||||
self.share_1 = db_utils.create_share(
|
||||
id='fake_share_id_1')
|
||||
self.snapshot_1 = db_utils.create_snapshot(
|
||||
id='fake_snapshot_id_1', share_id=self.share_1['id'])
|
||||
self.assertEqual(
|
||||
metadata, db_api.share_snapshot_metadata_get(
|
||||
self.context, share_snapshot_id=self.snapshot_1['id']))
|
||||
|
||||
def test_share_snapshot_metadata_get_item(self):
|
||||
metadata = {'a': 'b', 'c': 'd'}
|
||||
key = {'a'}
|
||||
shouldbe = {'a': 'b'}
|
||||
self.share_1 = db_utils.create_share(
|
||||
id='fake_share_id_1')
|
||||
self.snapshot_1 = db_utils.create_snapshot(
|
||||
id='fake_snapshot_id_1', share_id=self.share_1['id'])
|
||||
db_api.share_snapshot_metadata_update(
|
||||
self.context, share_snapshot_id=self.snapshot_1['id'],
|
||||
metadata=metadata)
|
||||
self.assertEqual(
|
||||
shouldbe, db_api.share_snapshot_metadata_get_item(
|
||||
self.context, share_snapshot_id=self.snapshot_1['id'],
|
||||
key=key))
|
||||
|
||||
def test_share_snapshot_metadata_update(self):
|
||||
metadata1 = {'a': '1', 'c': '2'}
|
||||
metadata2 = {'a': '3', 'd': '5'}
|
||||
should_be = {'a': '3', 'c': '2', 'd': '5'}
|
||||
self.share_1 = db_utils.create_share(
|
||||
id='fake_share_id_1')
|
||||
self.snapshot_1 = db_utils.create_snapshot(
|
||||
id='fake_snapshot_id_1', share_id=self.share_1['id'])
|
||||
db_api.share_snapshot_metadata_update(
|
||||
self.context, share_snapshot_id=self.snapshot_1['id'],
|
||||
metadata=metadata1)
|
||||
db_api.share_snapshot_metadata_update(
|
||||
self.context, share_snapshot_id=self.snapshot_1['id'],
|
||||
metadata=metadata2)
|
||||
self.assertEqual(
|
||||
should_be, db_api.share_metadata_get(
|
||||
self.context, share_snapshot_id=self.snapshot_1['id']))
|
||||
|
||||
def test_share_snapshot_metadata_delete(self):
|
||||
key = {'a'}
|
||||
metadata = {'a': '1', 'c': '2'}
|
||||
should_be = {'c': '2'}
|
||||
self.share_1 = db_utils.create_share(
|
||||
id='fake_share_id_1')
|
||||
self.snapshot_1 = db_utils.create_snapshot(
|
||||
id='fake_snapshot_id_1', share_id=self.share_1['id'])
|
||||
db_api.share_snapshot_metadata_update(
|
||||
self.context, share_snapshot_id=self.snapshot_1['id'],
|
||||
metadata=metadata)
|
||||
db_api.share_metadata_delete(
|
||||
self.context, share_snapshot_id=self.snapshot_1['id'],
|
||||
key=key)
|
||||
self.assertEqual(
|
||||
should_be, db_api.share_metadata_get(
|
||||
self.context, share_snapshot_id=self.snapshot_1['id']))
|
||||
|
||||
def test_extend_invalid_status(self):
|
||||
invalid_status = 'fake'
|
||||
share = db_utils.create_share(status=invalid_status)
|
||||
|
|
Loading…
Reference in New Issue