Merge "Add image metadef resource type association commands 'create', 'list', 'delete'"
This commit is contained in:
commit
a79cb608b0
@ -28,7 +28,7 @@ md-namespace-import,,Import a metadata definitions namespace from file or standa
|
||||
md-namespace-list,image metadef namespace list,List metadata definitions namespaces.
|
||||
md-namespace-objects-delete,,Delete all metadata definitions objects inside a specific namespace.
|
||||
md-namespace-properties-delete,,Delete all metadata definitions property inside a specific namespace.
|
||||
md-namespace-resource-type-list,image metadef resource type list,List resource types associated to specific namespace.
|
||||
md-namespace-resource-type-list,image metadef resource type association list,List resource types associated to specific namespace.
|
||||
md-namespace-show,image metadef namespace show,Describe a specific metadata definitions namespace.
|
||||
md-namespace-tags-delete,,Delete all metadata definitions tags inside a specific namespace.
|
||||
md-namespace-update,,Update an existing metadata definitions namespace.
|
||||
@ -43,9 +43,9 @@ md-property-delete,image metadef property delete,Delete a specific metadata defi
|
||||
md-property-list,image metadef property list,List metadata definitions properties inside a specific namespace.
|
||||
md-property-show,image metadef property show,Describe a specific metadata definitions property inside a namespace.
|
||||
md-property-update,image metadef property set,Update metadata definitions property inside a namespace.
|
||||
md-resource-type-associate,,Associate resource type with a metadata definitions namespace.
|
||||
md-resource-type-deassociate,,Deassociate resource type with a metadata definitions namespace.
|
||||
md-resource-type-list,,List available resource type names.
|
||||
md-resource-type-associate,image metadef resource type association create,Associate resource type with a metadata definitions namespace.
|
||||
md-resource-type-deassociate,image metadef resource type association delete,Deassociate resource type with a metadata definitions namespace.
|
||||
md-resource-type-list,image metadef resource type list,List available resource type names.
|
||||
md-tag-create,,Add a new metadata definitions tag inside a namespace.
|
||||
md-tag-create-multiple,,Create new metadata definitions tags inside a namespace.
|
||||
md-tag-delete,,Delete a specific metadata definitions tag inside a namespace.
|
||||
|
|
189
openstackclient/image/v2/metadef_resource_type_association.py
Normal file
189
openstackclient/image/v2/metadef_resource_type_association.py
Normal file
@ -0,0 +1,189 @@
|
||||
# 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.
|
||||
|
||||
import logging
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import exceptions
|
||||
from osc_lib import utils
|
||||
|
||||
from openstackclient.i18n import _
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_columns(item):
|
||||
column_map = {}
|
||||
hidden_columns = ['location']
|
||||
return utils.get_osc_show_columns_for_sdk_resource(
|
||||
item, column_map, hidden_columns
|
||||
)
|
||||
|
||||
|
||||
class CreateMetadefResourceTypeAssociation(command.ShowOne):
|
||||
_description = _("Create metadef resource type association")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super().get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"namespace",
|
||||
metavar="<namespace>",
|
||||
help=_(
|
||||
"The name of the namespace you want to create the "
|
||||
"resource type association in"
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"name",
|
||||
metavar="<name>",
|
||||
help=_("A name of the new resource type"),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--properties-target",
|
||||
metavar="<properties_target>",
|
||||
help=_(
|
||||
"Some resource types allow more than one "
|
||||
"key/value pair per instance."
|
||||
),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
image_client = self.app.client_manager.image
|
||||
kwargs = {}
|
||||
|
||||
kwargs['namespace'] = parsed_args.namespace
|
||||
kwargs['name'] = parsed_args.name
|
||||
|
||||
if parsed_args.properties_target:
|
||||
kwargs['properties_target'] = parsed_args.properties_target
|
||||
|
||||
obj = image_client.create_metadef_resource_type_association(
|
||||
parsed_args.namespace, **kwargs
|
||||
)
|
||||
|
||||
display_columns, columns = _get_columns(obj)
|
||||
data = utils.get_item_properties(obj, columns, formatters={})
|
||||
|
||||
return (display_columns, data)
|
||||
|
||||
|
||||
class DeleteMetadefResourceTypeAssociation(command.Command):
|
||||
_description = _("Delete metadef resource type association")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super().get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"metadef_namespace",
|
||||
metavar="<metadef_namespace>",
|
||||
help=_("The name of the namespace whose details you want to see"),
|
||||
)
|
||||
parser.add_argument(
|
||||
"name",
|
||||
metavar="<name>",
|
||||
nargs="+",
|
||||
help=_(
|
||||
"The name of the resource type(s) (repeat option to delete"
|
||||
"multiple metadef resource type associations)"
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--force",
|
||||
dest='force',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_(
|
||||
"Force delete the resource type association if the"
|
||||
"namespace is protected"
|
||||
),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
image_client = self.app.client_manager.image
|
||||
|
||||
result = 0
|
||||
for resource_type in parsed_args.name:
|
||||
try:
|
||||
metadef_namespace = image_client.get_metadef_namespace(
|
||||
parsed_args.metadef_namespace
|
||||
)
|
||||
|
||||
kwargs = {}
|
||||
is_initially_protected = (
|
||||
True if metadef_namespace.is_protected else False
|
||||
)
|
||||
if is_initially_protected and parsed_args.force:
|
||||
kwargs['is_protected'] = False
|
||||
|
||||
image_client.update_metadef_namespace(
|
||||
metadef_namespace.namespace, **kwargs
|
||||
)
|
||||
|
||||
try:
|
||||
image_client.delete_metadef_resource_type_association(
|
||||
resource_type, metadef_namespace, ignore_missing=False
|
||||
)
|
||||
finally:
|
||||
if is_initially_protected:
|
||||
kwargs['is_protected'] = True
|
||||
image_client.update_metadef_namespace(
|
||||
metadef_namespace.namespace, **kwargs
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
result += 1
|
||||
LOG.error(
|
||||
_(
|
||||
"Failed to delete resource type with name or "
|
||||
"ID '%(resource_type)s': %(e)s"
|
||||
),
|
||||
{'resource_type': resource_type, 'e': e},
|
||||
)
|
||||
|
||||
if result > 0:
|
||||
total = len(parsed_args.metadef_namespace)
|
||||
msg = _(
|
||||
"%(result)s of %(total)s resource type failed to delete."
|
||||
) % {'result': result, 'total': total}
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
|
||||
class ListMetadefResourceTypeAssociations(command.Lister):
|
||||
_description = _("List metadef resource type associations")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super().get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
"metadef_namespace",
|
||||
metavar="<metadef_namespace>",
|
||||
help=_("The name of the namespace whose details you want to see"),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
image_client = self.app.client_manager.image
|
||||
data = image_client.metadef_resource_type_associations(
|
||||
parsed_args.metadef_namespace,
|
||||
)
|
||||
columns = ['Name']
|
||||
column_headers = columns
|
||||
return (
|
||||
column_headers,
|
||||
(
|
||||
utils.get_item_properties(
|
||||
s,
|
||||
columns,
|
||||
)
|
||||
for s in data
|
||||
),
|
||||
)
|
@ -378,3 +378,44 @@ def create_one_metadef_object(attrs=None):
|
||||
# Overwrite default attributes if there are some attributes set
|
||||
metadef_objects_list.update(attrs)
|
||||
return metadef_object.MetadefObject(**metadef_objects_list)
|
||||
|
||||
|
||||
def create_one_resource_type_association(attrs=None):
|
||||
"""Create a fake MetadefResourceTypeAssociation.
|
||||
|
||||
:param attrs: A dictionary with all attributes of
|
||||
metadef_resource_type_association member
|
||||
:type attrs: dict
|
||||
:return: A fake MetadefResourceTypeAssociation object
|
||||
:rtype: A `metadef_resource_type_association.
|
||||
MetadefResourceTypeAssociation`
|
||||
"""
|
||||
attrs = attrs or {}
|
||||
|
||||
metadef_resource_type_association_info = {
|
||||
'namespace_name': 'OS::Compute::Quota',
|
||||
'name': 'OS::Nova::Flavor',
|
||||
}
|
||||
|
||||
metadef_resource_type_association_info.update(attrs)
|
||||
return metadef_resource_type.MetadefResourceTypeAssociation(
|
||||
**metadef_resource_type_association_info
|
||||
)
|
||||
|
||||
|
||||
def create_resource_type_associations(attrs=None, count=2):
|
||||
"""Create mutiple fake resource type associations/
|
||||
|
||||
:param attrs: A dictionary with all attributes of
|
||||
metadef_resource_type_association member
|
||||
:type attrs: dict
|
||||
:return: A list of fake MetadefResourceTypeAssociation objects
|
||||
:rtype: list
|
||||
"""
|
||||
resource_type_associations = []
|
||||
for n in range(0, count):
|
||||
resource_type_associations.append(
|
||||
create_one_resource_type_association(attrs)
|
||||
)
|
||||
|
||||
return resource_type_associations
|
||||
|
@ -0,0 +1,131 @@
|
||||
# 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 openstackclient.image.v2 import metadef_resource_type_association
|
||||
from openstackclient.tests.unit.image.v2 import fakes as resource_type_fakes
|
||||
|
||||
|
||||
class TestMetadefResourceTypeAssociationCreate(
|
||||
resource_type_fakes.TestImagev2
|
||||
):
|
||||
resource_type_association = (
|
||||
resource_type_fakes.create_one_resource_type_association()
|
||||
)
|
||||
|
||||
columns = (
|
||||
'created_at',
|
||||
'id',
|
||||
'name',
|
||||
'prefix',
|
||||
'properties_target',
|
||||
'updated_at',
|
||||
)
|
||||
|
||||
data = (
|
||||
resource_type_association.created_at,
|
||||
resource_type_association.id,
|
||||
resource_type_association.name,
|
||||
resource_type_association.prefix,
|
||||
resource_type_association.properties_target,
|
||||
resource_type_association.updated_at,
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.image_client.create_metadef_resource_type_association.return_value = (
|
||||
self.resource_type_association
|
||||
)
|
||||
self.cmd = metadef_resource_type_association.CreateMetadefResourceTypeAssociation(
|
||||
self.app, None
|
||||
)
|
||||
|
||||
def test_resource_type_association_create(self):
|
||||
arglist = [
|
||||
self.resource_type_association.namespace_name,
|
||||
self.resource_type_association.name,
|
||||
]
|
||||
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertEqual(self.data, data)
|
||||
|
||||
|
||||
class TestMetadefResourceTypeAssociationDelete(
|
||||
resource_type_fakes.TestImagev2
|
||||
):
|
||||
resource_type_association = (
|
||||
resource_type_fakes.create_one_resource_type_association()
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.image_client.delete_metadef_resource_type_association.return_value = (
|
||||
self.resource_type_association
|
||||
)
|
||||
self.cmd = metadef_resource_type_association.DeleteMetadefResourceTypeAssociation(
|
||||
self.app, None
|
||||
)
|
||||
|
||||
def test_resource_type_association_delete(self):
|
||||
arglist = [
|
||||
self.resource_type_association.namespace_name,
|
||||
self.resource_type_association.name,
|
||||
]
|
||||
|
||||
verifylist = []
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertIsNone(result)
|
||||
|
||||
|
||||
class TestMetadefResourceTypeAssociationList(resource_type_fakes.TestImagev2):
|
||||
resource_type_associations = (
|
||||
resource_type_fakes.create_resource_type_associations()
|
||||
)
|
||||
|
||||
columns = ['Name']
|
||||
|
||||
datalist = [
|
||||
(resource_type_association.name,)
|
||||
for resource_type_association in resource_type_associations
|
||||
]
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
|
||||
self.image_client.metadef_resource_type_associations.side_effect = [
|
||||
self.resource_type_associations,
|
||||
[],
|
||||
]
|
||||
|
||||
self.cmd = metadef_resource_type_association.ListMetadefResourceTypeAssociations(
|
||||
self.app, None
|
||||
)
|
||||
|
||||
def test_resource_type_association_list(self):
|
||||
arglist = [
|
||||
self.resource_type_associations[0].namespace_name,
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, [])
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertCountEqual(self.datalist, data)
|
@ -0,0 +1,17 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added ``image metadef resource type association list``
|
||||
to list resource type associations for the image service.
|
||||
This is equivalent to the
|
||||
``md-namespace-resource-type-list`` command in glance.
|
||||
- |
|
||||
Added ``image metadef resource type association create``
|
||||
to create a resource type association for the image service.
|
||||
This is equivalent to the
|
||||
``md-resource-type-associate`` command in glance.
|
||||
- |
|
||||
Added ``image metadef resource type association delete``
|
||||
to delete a resource type association for the image service.
|
||||
This is equivalent to the
|
||||
``md-resource-type-deassociate`` command in glance.
|
@ -413,6 +413,9 @@ openstack.image.v2 =
|
||||
image_metadef_property_show = openstackclient.image.v2.metadef_properties:ShowMetadefProperty
|
||||
|
||||
image_metadef_resource_type_list = openstackclient.image.v2.metadef_resource_types:ListMetadefResourceTypes
|
||||
image_metadef_resource_type_association_create = openstackclient.image.v2.metadef_resource_type_association:CreateMetadefResourceTypeAssociation
|
||||
image_metadef_resource_type_association_delete = openstackclient.image.v2.metadef_resource_type_association:DeleteMetadefResourceTypeAssociation
|
||||
image_metadef_resource_type_association_list = openstackclient.image.v2.metadef_resource_type_association:ListMetadefResourceTypeAssociations
|
||||
|
||||
cached_image_list = openstackclient.image.v2.cache:ListCachedImage
|
||||
cached_image_queue = openstackclient.image.v2.cache:QueueCachedImage
|
||||
|
Loading…
Reference in New Issue
Block a user