Merge "Add tags to image set
"
This commit is contained in:
commit
23e821a86b
@ -238,6 +238,7 @@ Set image properties
|
|||||||
[--checksum <checksum>]
|
[--checksum <checksum>]
|
||||||
[--stdin]
|
[--stdin]
|
||||||
[--property <key=value> [...] ]
|
[--property <key=value> [...] ]
|
||||||
|
[--tag <tag> [...] ]
|
||||||
[--architecture <architecture>]
|
[--architecture <architecture>]
|
||||||
[--instance-id <instance-id>]
|
[--instance-id <instance-id>]
|
||||||
[--kernel-id <kernel-id>]
|
[--kernel-id <kernel-id>]
|
||||||
@ -344,6 +345,14 @@ Set image properties
|
|||||||
|
|
||||||
Set a property on this image (repeat option to set multiple properties)
|
Set a property on this image (repeat option to set multiple properties)
|
||||||
|
|
||||||
|
.. versionadded:: 2
|
||||||
|
|
||||||
|
.. option:: --tag <tag>
|
||||||
|
|
||||||
|
Set a tag on this image (repeat for multiple values)
|
||||||
|
|
||||||
|
.. versionadded:: 2
|
||||||
|
|
||||||
.. option:: --architecture <architecture>
|
.. option:: --architecture <architecture>
|
||||||
|
|
||||||
Operating system architecture
|
Operating system architecture
|
||||||
|
@ -57,8 +57,7 @@ def _format_image(image):
|
|||||||
properties[key] = image.get(key)
|
properties[key] = image.get(key)
|
||||||
|
|
||||||
# format the tags if they are there
|
# format the tags if they are there
|
||||||
if image.get('tags'):
|
info['tags'] = utils.format_list(image.get('tags'))
|
||||||
info['tags'] = utils.format_list(image.get('tags'))
|
|
||||||
|
|
||||||
# add properties back into the dictionary as a top-level key
|
# add properties back into the dictionary as a top-level key
|
||||||
if properties:
|
if properties:
|
||||||
@ -540,7 +539,6 @@ class SetImage(show.ShowOne):
|
|||||||
# --force - needs adding
|
# --force - needs adding
|
||||||
# --checksum - maybe could be done client side
|
# --checksum - maybe could be done client side
|
||||||
# --stdin - could be implemented
|
# --stdin - could be implemented
|
||||||
# --tags - needs adding
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"image",
|
"image",
|
||||||
metavar="<image>",
|
metavar="<image>",
|
||||||
@ -610,6 +608,15 @@ class SetImage(show.ShowOne):
|
|||||||
help="Set a property on this image "
|
help="Set a property on this image "
|
||||||
"(repeat option to set multiple properties)",
|
"(repeat option to set multiple properties)",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--tag",
|
||||||
|
dest="tags",
|
||||||
|
metavar="<tag>",
|
||||||
|
default=[],
|
||||||
|
action='append',
|
||||||
|
help="Set a tag on this image "
|
||||||
|
"(repeat option to set multiple tags)",
|
||||||
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--architecture",
|
"--architecture",
|
||||||
metavar="<architecture>",
|
metavar="<architecture>",
|
||||||
@ -669,7 +676,7 @@ class SetImage(show.ShowOne):
|
|||||||
copy_attrs = ('architecture', 'container_format', 'disk_format',
|
copy_attrs = ('architecture', 'container_format', 'disk_format',
|
||||||
'file', 'instance_id', 'kernel_id', 'locations',
|
'file', 'instance_id', 'kernel_id', 'locations',
|
||||||
'min_disk', 'min_ram', 'name', 'os_distro', 'os_version',
|
'min_disk', 'min_ram', 'name', 'os_distro', 'os_version',
|
||||||
'owner', 'prefix', 'progress', 'ramdisk_id')
|
'owner', 'prefix', 'progress', 'ramdisk_id', 'tags')
|
||||||
for attr in copy_attrs:
|
for attr in copy_attrs:
|
||||||
if attr in parsed_args:
|
if attr in parsed_args:
|
||||||
val = getattr(parsed_args, attr, None)
|
val = getattr(parsed_args, attr, None)
|
||||||
@ -705,6 +712,10 @@ class SetImage(show.ShowOne):
|
|||||||
image = utils.find_resource(
|
image = utils.find_resource(
|
||||||
image_client.images, parsed_args.image)
|
image_client.images, parsed_args.image)
|
||||||
|
|
||||||
|
if parsed_args.tags:
|
||||||
|
# Tags should be extended, but duplicates removed
|
||||||
|
kwargs['tags'] = list(set(image.tags).union(set(parsed_args.tags)))
|
||||||
|
|
||||||
image = image_client.images.update(image.id, **kwargs)
|
image = image_client.images.update(image.id, **kwargs)
|
||||||
info = {}
|
info = {}
|
||||||
info.update(image)
|
info.update(image)
|
||||||
|
@ -410,13 +410,14 @@ class TestServerImageCreate(TestServer):
|
|||||||
compute_fakes.server_name,
|
compute_fakes.server_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
collist = ('id', 'name', 'owner', 'protected', 'visibility')
|
collist = ('id', 'name', 'owner', 'protected', 'tags', 'visibility')
|
||||||
self.assertEqual(collist, columns)
|
self.assertEqual(collist, columns)
|
||||||
datalist = (
|
datalist = (
|
||||||
image_fakes.image_id,
|
image_fakes.image_id,
|
||||||
image_fakes.image_name,
|
image_fakes.image_name,
|
||||||
image_fakes.image_owner,
|
image_fakes.image_owner,
|
||||||
image_fakes.image_protected,
|
image_fakes.image_protected,
|
||||||
|
image_fakes.image_tags,
|
||||||
image_fakes.image_visibility,
|
image_fakes.image_visibility,
|
||||||
)
|
)
|
||||||
self.assertEqual(datalist, data)
|
self.assertEqual(datalist, data)
|
||||||
@ -441,13 +442,14 @@ class TestServerImageCreate(TestServer):
|
|||||||
'img-nam',
|
'img-nam',
|
||||||
)
|
)
|
||||||
|
|
||||||
collist = ('id', 'name', 'owner', 'protected', 'visibility')
|
collist = ('id', 'name', 'owner', 'protected', 'tags', 'visibility')
|
||||||
self.assertEqual(collist, columns)
|
self.assertEqual(collist, columns)
|
||||||
datalist = (
|
datalist = (
|
||||||
image_fakes.image_id,
|
image_fakes.image_id,
|
||||||
image_fakes.image_name,
|
image_fakes.image_name,
|
||||||
image_fakes.image_owner,
|
image_fakes.image_owner,
|
||||||
image_fakes.image_protected,
|
image_fakes.image_protected,
|
||||||
|
image_fakes.image_tags,
|
||||||
image_fakes.image_visibility,
|
image_fakes.image_visibility,
|
||||||
)
|
)
|
||||||
self.assertEqual(datalist, data)
|
self.assertEqual(datalist, data)
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import copy
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from openstackclient.tests import fakes
|
from openstackclient.tests import fakes
|
||||||
@ -25,6 +26,7 @@ image_name = 'graven'
|
|||||||
image_owner = 'baal'
|
image_owner = 'baal'
|
||||||
image_protected = False
|
image_protected = False
|
||||||
image_visibility = 'public'
|
image_visibility = 'public'
|
||||||
|
image_tags = []
|
||||||
|
|
||||||
IMAGE = {
|
IMAGE = {
|
||||||
'id': image_id,
|
'id': image_id,
|
||||||
@ -32,11 +34,16 @@ IMAGE = {
|
|||||||
'owner': image_owner,
|
'owner': image_owner,
|
||||||
'protected': image_protected,
|
'protected': image_protected,
|
||||||
'visibility': image_visibility,
|
'visibility': image_visibility,
|
||||||
|
'tags': image_tags
|
||||||
}
|
}
|
||||||
|
|
||||||
IMAGE_columns = tuple(sorted(IMAGE))
|
IMAGE_columns = tuple(sorted(IMAGE))
|
||||||
IMAGE_data = tuple((IMAGE[x] for x in sorted(IMAGE)))
|
IMAGE_data = tuple((IMAGE[x] for x in sorted(IMAGE)))
|
||||||
|
|
||||||
|
IMAGE_SHOW = copy.copy(IMAGE)
|
||||||
|
IMAGE_SHOW['tags'] = ''
|
||||||
|
IMAGE_SHOW_data = tuple((IMAGE_SHOW[x] for x in sorted(IMAGE_SHOW)))
|
||||||
|
|
||||||
member_status = 'pending'
|
member_status = 'pending'
|
||||||
MEMBER = {
|
MEMBER = {
|
||||||
'member_id': identity_fakes.project_id,
|
'member_id': identity_fakes.project_id,
|
||||||
@ -117,6 +124,14 @@ IMAGE_schema = {
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Status of the image (READ-ONLY)"
|
"description": "Status of the image (READ-ONLY)"
|
||||||
},
|
},
|
||||||
|
"tags": {
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"maxLength": 255
|
||||||
|
},
|
||||||
|
"type": "array",
|
||||||
|
"description": "List of strings related to the image"
|
||||||
|
},
|
||||||
"visibility": {
|
"visibility": {
|
||||||
"enum": [
|
"enum": [
|
||||||
"public",
|
"public",
|
||||||
|
@ -96,7 +96,7 @@ class TestImageCreate(TestImage):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(image_fakes.IMAGE_columns, columns)
|
self.assertEqual(image_fakes.IMAGE_columns, columns)
|
||||||
self.assertEqual(image_fakes.IMAGE_data, data)
|
self.assertEqual(image_fakes.IMAGE_SHOW_data, data)
|
||||||
|
|
||||||
@mock.patch('glanceclient.common.utils.get_data_file', name='Open')
|
@mock.patch('glanceclient.common.utils.get_data_file', name='Open')
|
||||||
def test_image_reserve_options(self, mock_open):
|
def test_image_reserve_options(self, mock_open):
|
||||||
@ -151,7 +151,7 @@ class TestImageCreate(TestImage):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(image_fakes.IMAGE_columns, columns)
|
self.assertEqual(image_fakes.IMAGE_columns, columns)
|
||||||
self.assertEqual(image_fakes.IMAGE_data, data)
|
self.assertEqual(image_fakes.IMAGE_SHOW_data, data)
|
||||||
|
|
||||||
@mock.patch('glanceclient.common.utils.get_data_file', name='Open')
|
@mock.patch('glanceclient.common.utils.get_data_file', name='Open')
|
||||||
def test_image_create_file(self, mock_open):
|
def test_image_create_file(self, mock_open):
|
||||||
@ -208,7 +208,7 @@ class TestImageCreate(TestImage):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(image_fakes.IMAGE_columns, columns)
|
self.assertEqual(image_fakes.IMAGE_columns, columns)
|
||||||
self.assertEqual(image_fakes.IMAGE_data, data)
|
self.assertEqual(image_fakes.IMAGE_SHOW_data, data)
|
||||||
|
|
||||||
def test_image_create_dead_options(self):
|
def test_image_create_dead_options(self):
|
||||||
|
|
||||||
@ -812,6 +812,81 @@ class TestImageSet(TestImage):
|
|||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_image_set_tag(self):
|
||||||
|
arglist = [
|
||||||
|
'--tag', 'test-tag',
|
||||||
|
image_fakes.image_name,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('tags', ['test-tag']),
|
||||||
|
('image', image_fakes.image_name),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
# DisplayCommandBase.take_action() returns two tuples
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
'tags': ['test-tag'],
|
||||||
|
}
|
||||||
|
# ImageManager.update(image, **kwargs)
|
||||||
|
self.images_mock.update.assert_called_with(
|
||||||
|
image_fakes.image_id,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_image_set_tag_merge(self):
|
||||||
|
old_image = copy.copy(image_fakes.IMAGE)
|
||||||
|
old_image['tags'] = ['old1', 'new2']
|
||||||
|
self.images_mock.get.return_value = self.model(**old_image)
|
||||||
|
arglist = [
|
||||||
|
'--tag', 'test-tag',
|
||||||
|
image_fakes.image_name,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('tags', ['test-tag']),
|
||||||
|
('image', image_fakes.image_name),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
# DisplayCommandBase.take_action() returns two tuples
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
'tags': ['old1', 'new2', 'test-tag'],
|
||||||
|
}
|
||||||
|
# ImageManager.update(image, **kwargs)
|
||||||
|
a, k = self.images_mock.update.call_args
|
||||||
|
self.assertEqual(image_fakes.image_id, a[0])
|
||||||
|
self.assertTrue('tags' in k)
|
||||||
|
self.assertEqual(set(kwargs['tags']), set(k['tags']))
|
||||||
|
|
||||||
|
def test_image_set_tag_merge_dupe(self):
|
||||||
|
old_image = copy.copy(image_fakes.IMAGE)
|
||||||
|
old_image['tags'] = ['old1', 'new2']
|
||||||
|
self.images_mock.get.return_value = self.model(**old_image)
|
||||||
|
arglist = [
|
||||||
|
'--tag', 'old1',
|
||||||
|
image_fakes.image_name,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('tags', ['old1']),
|
||||||
|
('image', image_fakes.image_name),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
# DisplayCommandBase.take_action() returns two tuples
|
||||||
|
self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
'tags': ['new2', 'old1'],
|
||||||
|
}
|
||||||
|
# ImageManager.update(image, **kwargs)
|
||||||
|
a, k = self.images_mock.update.call_args
|
||||||
|
self.assertEqual(image_fakes.image_id, a[0])
|
||||||
|
self.assertTrue('tags' in k)
|
||||||
|
self.assertEqual(set(kwargs['tags']), set(k['tags']))
|
||||||
|
|
||||||
def test_image_set_dead_options(self):
|
def test_image_set_dead_options(self):
|
||||||
|
|
||||||
arglist = [
|
arglist = [
|
||||||
@ -861,4 +936,4 @@ class TestImageShow(TestImage):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(image_fakes.IMAGE_columns, columns)
|
self.assertEqual(image_fakes.IMAGE_columns, columns)
|
||||||
self.assertEqual(image_fakes.IMAGE_data, data)
|
self.assertEqual(image_fakes.IMAGE_SHOW_data, data)
|
||||||
|
Loading…
Reference in New Issue
Block a user