From 04a123cdee0644e2319e7d50f9f2bf1105199ba7 Mon Sep 17 00:00:00 2001 From: Dan Smith Date: Wed, 19 Feb 2014 08:07:56 -0800 Subject: [PATCH] Add os-server-external-events support This adds support for the os-server-external-events extension in nova, which allows other services to deliver events to nova. It also adds a shell command to trigger the "network-changed" event manually, which will cause nova to refresh its network cache from neutron. Related to blueprint admin-event-callback-api Change-Id: I1a302a43b6b7a6d8bdc03965a8f4c1a151bcab88 --- README.rst | 1 + novaclient/tests/v1_1/contrib/fakes.py | 11 +++++ .../contrib/test_server_external_events.py | 44 +++++++++++++++++++ novaclient/tests/v1_1/fakes.py | 5 +++ novaclient/tests/v1_1/test_shell.py | 6 +++ .../v1_1/contrib/server_external_events.py | 43 ++++++++++++++++++ novaclient/v1_1/shell.py | 10 +++++ 7 files changed, 120 insertions(+) create mode 100644 novaclient/tests/v1_1/contrib/test_server_external_events.py create mode 100644 novaclient/v1_1/contrib/server_external_events.py diff --git a/README.rst b/README.rst index 30131e1cd..b155bf54e 100644 --- a/README.rst +++ b/README.rst @@ -146,6 +146,7 @@ You'll find complete documentation on the shell by running rate-limits Print a list of rate limits for a user reboot Reboot a server. rebuild Shutdown, re-image, and re-boot a server. + refresh-network Refresh server network information. remove-fixed-ip Remove an IP address from a server. remove-floating-ip Remove a floating IP address from a server. rename Rename a server. diff --git a/novaclient/tests/v1_1/contrib/fakes.py b/novaclient/tests/v1_1/contrib/fakes.py index fd25910a5..3b859362e 100644 --- a/novaclient/tests/v1_1/contrib/fakes.py +++ b/novaclient/tests/v1_1/contrib/fakes.py @@ -134,3 +134,14 @@ class FakeHTTPClient(fakes.FakeHTTPClient): def delete_os_assisted_volume_snapshots_x(self, **kw): return (202, {}, {}) + + def post_os_server_external_events(self, **kw): + return (200, {}, {'events': [ + {'name': 'test-event', + 'status': 'completed', + 'tag': 'tag', + 'server_uuid': 'fake-uuid1'}, + {'name': 'test-event', + 'status': 'completed', + 'tag': 'tag', + 'server_uuid': 'fake-uuid2'}]}) diff --git a/novaclient/tests/v1_1/contrib/test_server_external_events.py b/novaclient/tests/v1_1/contrib/test_server_external_events.py new file mode 100644 index 000000000..c92ba34e0 --- /dev/null +++ b/novaclient/tests/v1_1/contrib/test_server_external_events.py @@ -0,0 +1,44 @@ +# Copyright (C) 2014, Red Hat, Inc. +# +# 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. + +""" +External event triggering for servers, not to be used by users. +""" + +from novaclient import extension +from novaclient.tests import utils +from novaclient.tests.v1_1.contrib import fakes +from novaclient.v1_1.contrib import server_external_events as ext_events + + +extensions = [ + extension.Extension(ext_events.__name__.split(".")[-1], + ext_events), +] +cs = fakes.FakeClient(extensions=extensions) + + +class ServerExternalEventsTestCase(utils.TestCase): + def test_external_event(self): + events = [{'server_uuid': 'fake-uuid1', + 'name': 'test-event', + 'status': 'completed', + 'tag': 'tag'}, + {'server_uuid': 'fake-uuid2', + 'name': 'test-event', + 'status': 'completed', + 'tag': 'tag'}] + result = cs.server_external_events.create(events) + self.assertEqual(events, result) + cs.assert_called('POST', '/os-server-external-events') diff --git a/novaclient/tests/v1_1/fakes.py b/novaclient/tests/v1_1/fakes.py index 3604312b3..43caf367e 100644 --- a/novaclient/tests/v1_1/fakes.py +++ b/novaclient/tests/v1_1/fakes.py @@ -1991,3 +1991,8 @@ class FakeHTTPClient(base_client.HTTPClient): "updated_at": "2012-10-29T13:42:02.000000" }]} return (200, {}, migrations) + + def post_os_server_external_events(self, **kw): + return (200, {}, {'events': [ + {'name': 'network-changed', + 'server_uuid': '1234'}]}) diff --git a/novaclient/tests/v1_1/test_shell.py b/novaclient/tests/v1_1/test_shell.py index a4c4ca19c..580d2ed55 100644 --- a/novaclient/tests/v1_1/test_shell.py +++ b/novaclient/tests/v1_1/test_shell.py @@ -946,6 +946,12 @@ class ShellTest(utils.TestCase): self.run_command('diagnostics sample-server') self.assert_called('GET', '/servers/1234/diagnostics') + def test_refresh_network(self): + self.run_command('refresh-network 1234') + self.assert_called('POST', '/os-server-external-events', + {'events': [{'name': 'network-changed', + 'server_uuid': 1234}]}) + def test_set_meta_set(self): self.run_command('meta 1234 set key1=val1 key2=val2') self.assert_called('POST', '/servers/1234/metadata', diff --git a/novaclient/v1_1/contrib/server_external_events.py b/novaclient/v1_1/contrib/server_external_events.py new file mode 100644 index 000000000..a45914b55 --- /dev/null +++ b/novaclient/v1_1/contrib/server_external_events.py @@ -0,0 +1,43 @@ +# Copyright (C) 2014, Red Hat, Inc. +# +# 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. + +""" +External event triggering for servers, not to be used by users. +""" + +from novaclient import base + + +class Event(base.Resource): + def __repr__(self): + return "" % self.name + + +class ServerExternalEventManager(base.Manager): + resource_class = Event + + def create(self, events): + """Create one or more server events. + + :param:events: A list of dictionaries containing 'server_uuid', 'name', + 'status', and 'tag' (which may be absent) + """ + + body = {'events': events} + return self._create('/os-server-external-events', body, 'events', + return_raw=True) + + +manager_class = ServerExternalEventManager +name = 'server_external_events' diff --git a/novaclient/v1_1/shell.py b/novaclient/v1_1/shell.py index 5f0858b55..ea0d4dff9 100644 --- a/novaclient/v1_1/shell.py +++ b/novaclient/v1_1/shell.py @@ -1366,6 +1366,16 @@ def do_diagnostics(cs, args): utils.print_dict(cs.servers.diagnostics(server)[1], wrap=80) +@utils.arg('server', metavar='', + help=_('Name or ID of a server for which the network cache should ' + 'be refreshed from neutron (Admin only).')) +def do_refresh_network(cs, args): + """Refresh server network information.""" + server = _find_server(cs, args.server) + cs.server_external_events.create([{'server_uuid': server.id, + 'name': 'network-changed'}]) + + @utils.arg('server', metavar='', help=_('Name or ID of server.')) def do_root_password(cs, args): """