diff --git a/releasenotes/notes/add_update_server-8761059d6de7e68b.yaml b/releasenotes/notes/add_update_server-8761059d6de7e68b.yaml new file mode 100644 index 000000000..5bbe898d4 --- /dev/null +++ b/releasenotes/notes/add_update_server-8761059d6de7e68b.yaml @@ -0,0 +1,3 @@ +--- +features: + - Add update_server method to update name or description of a server. diff --git a/shade/_tasks.py b/shade/_tasks.py index eaa7c007a..6947cb0e1 100644 --- a/shade/_tasks.py +++ b/shade/_tasks.py @@ -167,6 +167,11 @@ class ServerDelete(task_manager.Task): return client.nova_client.servers.delete(**self.args) +class ServerUpdate(task_manager.Task): + def main(self, client): + return client.nova_client.servers.update(**self.args) + + class ServerRebuild(task_manager.Task): def main(self, client): return client.nova_client.servers.rebuild(**self.args) diff --git a/shade/openstackcloud.py b/shade/openstackcloud.py index 401f4df39..6b965b47b 100644 --- a/shade/openstackcloud.py +++ b/shade/openstackcloud.py @@ -4471,6 +4471,30 @@ class OpenStackCloud(object): self._servers_time = self._servers_time - self._SERVER_AGE return True + @_utils.valid_kwargs( + 'name', 'description') + def update_server(self, name_or_id, **kwargs): + """Update a server. + + :param name_or_id: Name of the server to be updated. + :name: New name for the server + :description: New description for the server + + :returns: a dictionary representing the updated server. + + :raises: OpenStackCloudException on operation error. + """ + server = self.get_server(name_or_id=name_or_id) + if server is None: + raise OpenStackCloudException( + "failed to find server '{server}'".format(server=name_or_id)) + + with _utils.shade_exceptions( + "Error updating server {0}".format(name_or_id)): + return self.manager.submitTask( + _tasks.ServerUpdate( + server=server['id'], **kwargs)) + def create_server_group(self, name, policies): """Create a new server group. diff --git a/shade/tests/functional/test_compute.py b/shade/tests/functional/test_compute.py index 287806685..d17ebfaa1 100644 --- a/shade/tests/functional/test_compute.py +++ b/shade/tests/functional/test_compute.py @@ -250,3 +250,16 @@ class TestCompute(base.BaseFunctionalTestCase): exc.OpenStackCloudException, self.demo_cloud.delete_server_metadata, self.server_name, ['key1']) + + def test_update_server(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) + server_updated = self.demo_cloud.update_server( + self.server_name, + name='new_name' + ) + self.assertEqual('new_name', server_updated['name']) diff --git a/shade/tests/unit/test_update_server.py b/shade/tests/unit/test_update_server.py new file mode 100644 index 000000000..b18f2cb77 --- /dev/null +++ b/shade/tests/unit/test_update_server.py @@ -0,0 +1,72 @@ +# -*- 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_update_server +---------------------------------- + +Tests for the `update_server` command. +""" + +from mock import patch, Mock +import os_client_config +from shade import OpenStackCloud +from shade.exc import OpenStackCloudException +from shade.tests import base, fakes + + +class TestUpdateServer(base.TestCase): + + def setUp(self): + super(TestUpdateServer, 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_update_server_with_update_exception(self): + """ + Test that an exception in the novaclient update raises an exception in + update_server. + """ + with patch("shade.OpenStackCloud"): + config = { + "servers.update.side_effect": Exception("exception"), + } + OpenStackCloud.nova_client = Mock(**config) + self.assertRaises( + OpenStackCloudException, self.client.update_server, + 'server-name') + + def test_update_server_name(self): + """ + Test that update_server updates the name without raising any exception + """ + with patch("shade.OpenStackCloud"): + fake_server = fakes.FakeServer('1234', 'server-name', 'ACTIVE') + fake_update_server = fakes.FakeServer('1234', 'server-name2', + 'ACTIVE') + fake_floating_ip = fakes.FakeFloatingIP('1234', 'ippool', + '1.1.1.1', '2.2.2.2', + '5678') + config = { + "servers.list.return_value": [fake_server], + "servers.update.return_value": fake_update_server, + "floating_ips.list.return_value": [fake_floating_ip] + } + OpenStackCloud.nova_client = Mock(**config) + self.assertEqual( + 'server-name2', + self.client.update_server( + 'server-name', name='server-name2')['name'])