Add support for changing metadata of compute instances
Change-Id: I2301e0ab2024c51e7482ce0f05b706e8a395d676
This commit is contained in:
parent
a1ab68cd2b
commit
e67b306c10
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Add new APIs, OpenStackCloud.set_server_metadata() and OpenStackCloud.delete_server_metadata() to manage metadata of existing nova compute instances
|
@ -172,6 +172,16 @@ class ServerRebuild(task_manager.Task):
|
||||
return client.nova_client.servers.rebuild(**self.args)
|
||||
|
||||
|
||||
class ServerSetMetadata(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.nova_client.servers.set_meta(**self.args)
|
||||
|
||||
|
||||
class ServerDeleteMetadata(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.nova_client.servers.delete_meta(**self.args)
|
||||
|
||||
|
||||
class ServerGroupList(task_manager.Task):
|
||||
def main(self, client):
|
||||
return client.nova_client.server_groups.list(**self.args)
|
||||
|
@ -4302,6 +4302,47 @@ class OpenStackCloud(object):
|
||||
extra_data=dict(server=server))
|
||||
return server
|
||||
|
||||
def set_server_metadata(self, name_or_id, metadata):
|
||||
"""Set metadata in a server instance.
|
||||
|
||||
:param str name_or_id: The name or id of the server instance
|
||||
to update.
|
||||
:param dict metadata: A dictionary with the key=value pairs
|
||||
to set in the server instance. It only updates the key=value
|
||||
pairs provided. Existing ones will remain untouched.
|
||||
|
||||
:raises: OpenStackCloudException on operation error.
|
||||
"""
|
||||
try:
|
||||
self.manager.submitTask(
|
||||
_tasks.ServerSetMetadata(server=self.get_server(name_or_id),
|
||||
metadata=metadata))
|
||||
except OpenStackCloudException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise OpenStackCloudException(
|
||||
"Error updating metadata: {0}".format(e))
|
||||
|
||||
def delete_server_metadata(self, name_or_id, metadata_keys):
|
||||
"""Delete metadata from a server instance.
|
||||
|
||||
:param str name_or_id: The name or id of the server instance
|
||||
to update.
|
||||
:param list metadata_keys: A list with the keys to be deleted
|
||||
from the server instance.
|
||||
|
||||
:raises: OpenStackCloudException on operation error.
|
||||
"""
|
||||
try:
|
||||
self.manager.submitTask(
|
||||
_tasks.ServerDeleteMetadata(server=self.get_server(name_or_id),
|
||||
keys=metadata_keys))
|
||||
except OpenStackCloudException:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise OpenStackCloudException(
|
||||
"Error deleting metadata: {0}".format(e))
|
||||
|
||||
def delete_server(
|
||||
self, name_or_id, wait=False, timeout=180, delete_ips=False,
|
||||
delete_ip_retry=1):
|
||||
|
@ -19,6 +19,7 @@ test_compute
|
||||
Functional tests for `shade` compute methods.
|
||||
"""
|
||||
|
||||
from shade import exc
|
||||
from shade.tests.functional import base
|
||||
from shade.tests.functional.util import pick_flavor, pick_image
|
||||
|
||||
@ -215,3 +216,37 @@ class TestCompute(base.BaseFunctionalTestCase):
|
||||
wait=True)
|
||||
self.addCleanup(self.demo_cloud.delete_image, image['id'])
|
||||
self.assertEqual('active', image['status'])
|
||||
|
||||
def test_set_and_delete_metadata(self):
|
||||
self.addCleanup(self._cleanup_servers_and_volumes, self.server_name)
|
||||
self.demo_cloud.create_server(
|
||||
name=self.server_name,
|
||||
image=self.image,
|
||||
flavor=self.flavor,
|
||||
wait=True)
|
||||
self.demo_cloud.set_server_metadata(self.server_name,
|
||||
{'key1': 'value1',
|
||||
'key2': 'value2'})
|
||||
updated_server = self.demo_cloud.get_server(self.server_name)
|
||||
self.assertEqual(set(updated_server.metadata.items()),
|
||||
set({'key1': 'value1', 'key2': 'value2'}.items()))
|
||||
|
||||
self.demo_cloud.set_server_metadata(self.server_name,
|
||||
{'key2': 'value3'})
|
||||
updated_server = self.demo_cloud.get_server(self.server_name)
|
||||
self.assertEqual(set(updated_server.metadata.items()),
|
||||
set({'key1': 'value1', 'key2': 'value3'}.items()))
|
||||
|
||||
self.demo_cloud.delete_server_metadata(self.server_name, ['key2'])
|
||||
updated_server = self.demo_cloud.get_server(self.server_name)
|
||||
self.assertEqual(set(updated_server.metadata.items()),
|
||||
set({'key1': 'value1'}.items()))
|
||||
|
||||
self.demo_cloud.delete_server_metadata(self.server_name, ['key1'])
|
||||
updated_server = self.demo_cloud.get_server(self.server_name)
|
||||
self.assertEqual(set(updated_server.metadata.items()), set([]))
|
||||
|
||||
self.assertRaises(
|
||||
exc.OpenStackCloudException,
|
||||
self.demo_cloud.delete_server_metadata,
|
||||
self.server_name, ['key1'])
|
||||
|
66
shade/tests/unit/test_server_delete_metadata.py
Normal file
66
shade/tests/unit/test_server_delete_metadata.py
Normal file
@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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.
|
||||
|
||||
"""
|
||||
test_server_delete_metadata
|
||||
----------------------------------
|
||||
|
||||
Tests for the `delete_server_metadata` command.
|
||||
"""
|
||||
|
||||
from mock import patch, Mock
|
||||
import os_client_config
|
||||
from shade import OpenStackCloud
|
||||
from shade.exc import OpenStackCloudException
|
||||
from shade.tests import base
|
||||
|
||||
|
||||
class TestServerDeleteMetadata(base.TestCase):
|
||||
def setUp(self):
|
||||
super(TestServerDeleteMetadata, self).setUp()
|
||||
config = os_client_config.OpenStackConfig()
|
||||
self.client = OpenStackCloud(
|
||||
cloud_config=config.get_one_cloud(validate=False))
|
||||
self.client._SERVER_AGE = 0
|
||||
|
||||
def test_server_delete_metadata_with_delete_meta_exception(self):
|
||||
"""
|
||||
Test that a generic exception in the novaclient delete_meta raises
|
||||
an exception in delete_server_metadata.
|
||||
"""
|
||||
with patch("shade.OpenStackCloud"):
|
||||
config = {
|
||||
"servers.delete_meta.side_effect": Exception("exception"),
|
||||
}
|
||||
OpenStackCloud.nova_client = Mock(**config)
|
||||
|
||||
self.assertRaises(
|
||||
OpenStackCloudException, self.client.delete_server_metadata,
|
||||
{'id': 'server-id'}, ['key'])
|
||||
|
||||
def test_server_delete_metadata_with_exception_reraise(self):
|
||||
"""
|
||||
Test that an OpenStackCloudException exception gets re-raised
|
||||
in delete_server_metadata.
|
||||
"""
|
||||
with patch("shade.OpenStackCloud"):
|
||||
config = {
|
||||
"servers.delete_meta.side_effect":
|
||||
OpenStackCloudException("exception"),
|
||||
}
|
||||
OpenStackCloud.nova_client = Mock(**config)
|
||||
|
||||
self.assertRaises(
|
||||
OpenStackCloudException, self.client.delete_server_metadata,
|
||||
'server-id', ['key'])
|
67
shade/tests/unit/test_server_set_metadata.py
Normal file
67
shade/tests/unit/test_server_set_metadata.py
Normal file
@ -0,0 +1,67 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# 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.
|
||||
|
||||
"""
|
||||
test_server_set_metadata
|
||||
----------------------------------
|
||||
|
||||
Tests for the `set_server_metadata` command.
|
||||
"""
|
||||
|
||||
from mock import patch, Mock
|
||||
import os_client_config
|
||||
from shade import OpenStackCloud
|
||||
from shade.exc import OpenStackCloudException
|
||||
from shade.tests import base
|
||||
|
||||
|
||||
class TestServerSetMetadata(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestServerSetMetadata, self).setUp()
|
||||
config = os_client_config.OpenStackConfig()
|
||||
self.client = OpenStackCloud(
|
||||
cloud_config=config.get_one_cloud(validate=False))
|
||||
self.client._SERVER_AGE = 0
|
||||
|
||||
def test_server_set_metadata_with_set_meta_exception(self):
|
||||
"""
|
||||
Test that a generic exception in the novaclient set_meta raises
|
||||
an exception in set_server_metadata.
|
||||
"""
|
||||
with patch("shade.OpenStackCloud"):
|
||||
config = {
|
||||
"servers.set_meta.side_effect": Exception("exception"),
|
||||
}
|
||||
OpenStackCloud.nova_client = Mock(**config)
|
||||
|
||||
self.assertRaises(
|
||||
OpenStackCloudException, self.client.set_server_metadata,
|
||||
{'id': 'server-id'}, {'meta': 'data'})
|
||||
|
||||
def test_server_set_metadata_with_exception_reraise(self):
|
||||
"""
|
||||
Test that an OpenStackCloudException exception gets re-raised
|
||||
in set_server_metadata.
|
||||
"""
|
||||
with patch("shade.OpenStackCloud"):
|
||||
config = {
|
||||
"servers.set_meta.side_effect":
|
||||
OpenStackCloudException("exception"),
|
||||
}
|
||||
OpenStackCloud.nova_client = Mock(**config)
|
||||
|
||||
self.assertRaises(
|
||||
OpenStackCloudException, self.client.set_server_metadata,
|
||||
'server-id', {'meta': 'data'})
|
Loading…
Reference in New Issue
Block a user