From 91c138c51fff43779a4fe4a9f12cd1e2c38c689c Mon Sep 17 00:00:00 2001 From: shihanzhang Date: Sun, 9 Mar 2014 16:19:17 +0800 Subject: [PATCH] Support IPv6 when booting instances When nova uses neutron, IPv6 addresses may be allocated. This ensures those addresses are supported.the patch to modify nova is https://review.openstack.org/#/c/74252/ Change-Id: I2468d3bcaca9122e5d3f9c98044d57f623630dc3 Closes-bug: #1267685 --- novaclient/tests/v1_1/test_servers.py | 22 +++++++++++++ novaclient/tests/v1_1/test_shell.py | 26 ++++++++++++++++ novaclient/tests/v3/test_servers.py | 45 +++++++++++++++++++++++++++ novaclient/tests/v3/test_shell.py | 26 ++++++++++++++++ novaclient/v1_1/servers.py | 10 +++++- novaclient/v1_1/shell.py | 11 ++++--- novaclient/v3/servers.py | 10 +++++- novaclient/v3/shell.py | 11 ++++--- 8 files changed, 151 insertions(+), 10 deletions(-) diff --git a/novaclient/tests/v1_1/test_servers.py b/novaclient/tests/v1_1/test_servers.py index a48204c19..521cca832 100644 --- a/novaclient/tests/v1_1/test_servers.py +++ b/novaclient/tests/v1_1/test_servers.py @@ -104,6 +104,28 @@ class ServersTest(utils.TestCase): test_create_server_from_volume() + def test_create_server_boot_with_nics_ipv6(self): + old_boot = cs.servers._boot + nics = [{'net-id': '11111111-1111-1111-1111-111111111111', + 'v6-fixed-ip': '2001:db9:0:1::10'}] + + def wrapped_boot(url, key, *boot_args, **boot_kwargs): + self.assertEqual(boot_kwargs['nics'], nics) + return old_boot(url, key, *boot_args, **boot_kwargs) + + with mock.patch.object(cs.servers, '_boot', wrapped_boot): + s = cs.servers.create( + name="My server", + image=1, + flavor=1, + meta={'foo': 'bar'}, + userdata="hello moto", + key_name="fakekey", + nics=nics + ) + cs.assert_called('POST', '/servers') + self.assertIsInstance(s, servers.Server) + def test_create_server_userdata_file_object(self): s = cs.servers.create( name="My server", diff --git a/novaclient/tests/v1_1/test_shell.py b/novaclient/tests/v1_1/test_shell.py index 58c50b64d..adac6c096 100644 --- a/novaclient/tests/v1_1/test_shell.py +++ b/novaclient/tests/v1_1/test_shell.py @@ -497,6 +497,32 @@ class ShellTest(utils.TestCase): }, ) + def test_boot_nics_ipv6(self): + cmd = ('boot --image 1 --flavor 1 ' + '--nic net-id=a=c,v6-fixed-ip=2001:db9:0:1::10 some-server') + self.run_command(cmd) + self.assert_called_anytime( + 'POST', '/servers', + { + 'server': { + 'flavorRef': '1', + 'name': 'some-server', + 'imageRef': '1', + 'min_count': 1, + 'max_count': 1, + 'networks': [ + {'uuid': 'a=c', 'fixed_ip': '2001:db9:0:1::10'}, + ], + }, + }, + ) + + def test_boot_nics_both_ipv4_and_ipv6(self): + cmd = ('boot --image 1 --flavor 1 ' + '--nic net-id=a=c,v4-fixed-ip=10.0.0.1,' + 'v6-fixed-ip=2001:db9:0:1::10 some-server') + self.assertRaises(exceptions.CommandError, self.run_command, cmd) + def test_boot_nics_no_value(self): cmd = ('boot --image 1 --flavor 1 ' '--nic net-id some-server') diff --git a/novaclient/tests/v3/test_servers.py b/novaclient/tests/v3/test_servers.py index 9d0abcd62..bde6893ca 100644 --- a/novaclient/tests/v3/test_servers.py +++ b/novaclient/tests/v3/test_servers.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +import mock import six from novaclient import exceptions @@ -74,6 +75,50 @@ class ServersTest(utils.TestCase): cs.assert_called('POST', '/servers') self.assertIsInstance(s, servers.Server) + def test_create_server_boot_with_nics_ipv4(self): + old_boot = cs.servers._boot + nics = [{'net-id': '11111111-1111-1111-1111-111111111111', + 'v4-fixed-ip': '10.10.0.7'}] + + def wrapped_boot(url, key, *boot_args, **boot_kwargs): + self.assertEqual(boot_kwargs['nics'], nics) + return old_boot(url, key, *boot_args, **boot_kwargs) + + with mock.patch.object(cs.servers, '_boot', wrapped_boot): + s = cs.servers.create( + name="My server", + image=1, + flavor=1, + meta={'foo': 'bar'}, + userdata="hello moto", + key_name="fakekey", + nics=nics + ) + cs.assert_called('POST', '/servers') + self.assertIsInstance(s, servers.Server) + + def test_create_server_boot_with_nics_ipv6(self): + old_boot = cs.servers._boot + nics = [{'net-id': '11111111-1111-1111-1111-111111111111', + 'v6-fixed-ip': '2001:db9:0:1::10'}] + + def wrapped_boot(url, key, *boot_args, **boot_kwargs): + self.assertEqual(boot_kwargs['nics'], nics) + return old_boot(url, key, *boot_args, **boot_kwargs) + + with mock.patch.object(cs.servers, '_boot', wrapped_boot): + s = cs.servers.create( + name="My server", + image=1, + flavor=1, + meta={'foo': 'bar'}, + userdata="hello moto", + key_name="fakekey", + nics=nics + ) + cs.assert_called('POST', '/servers') + self.assertIsInstance(s, servers.Server) + def test_create_server_userdata_file_object(self): s = cs.servers.create( name="My server", diff --git a/novaclient/tests/v3/test_shell.py b/novaclient/tests/v3/test_shell.py index d3300bf70..e0c28ac74 100644 --- a/novaclient/tests/v3/test_shell.py +++ b/novaclient/tests/v3/test_shell.py @@ -428,6 +428,32 @@ class ShellTest(utils.TestCase): }, ) + def test_boot_nics_ipv6(self): + cmd = ('boot --image 1 --flavor 1 ' + '--nic net-id=a=c,v6-fixed-ip=2001:db9:0:1::10 some-server') + self.run_command(cmd) + self.assert_called_anytime( + 'POST', '/servers', + { + 'server': { + 'flavor_ref': '1', + 'name': 'some-server', + 'image_ref': '1', + 'os-multiple-create:min_count': 1, + 'os-multiple-create:max_count': 1, + 'networks': [ + {'uuid': 'a=c', 'fixed_ip': '2001:db9:0:1::10'}, + ], + }, + }, + ) + + def test_boot_nics_both_ipv4_and_ipv6(self): + cmd = ('boot --image 1 --flavor 1 ' + '--nic net-id=a=c,v4-fixed-ip=10.0.0.1,' + 'v6-fixed-ip=2001:db9:0:1::10 some-server') + self.assertRaises(exceptions.CommandError, self.run_command, cmd) + def test_boot_nics_no_value(self): cmd = ('boot --image 1 --flavor 1 ' '--nic net-id some-server') diff --git a/novaclient/v1_1/servers.py b/novaclient/v1_1/servers.py index cf284d94b..e5778b2ad 100644 --- a/novaclient/v1_1/servers.py +++ b/novaclient/v1_1/servers.py @@ -26,6 +26,7 @@ from six.moves.urllib import parse from novaclient import base from novaclient import crypto +from novaclient.openstack.common.gettextutils import _ from novaclient.openstack.common import strutils from novaclient.v1_1.security_groups import SecurityGroup @@ -520,8 +521,15 @@ class ServerManager(base.BootingManagerWithFind): # if value is empty string, do not send value in body if nic_info.get('net-id'): net_data['uuid'] = nic_info['net-id'] - if nic_info.get('v4-fixed-ip'): + if (nic_info.get('v4-fixed-ip') and + nic_info.get('v6-fixed-ip')): + raise base.exceptions.CommandError(_( + "Only one of 'v4-fixed-ip' and 'v6-fixed-ip' may be" + " provided.")) + elif nic_info.get('v4-fixed-ip'): net_data['fixed_ip'] = nic_info['v4-fixed-ip'] + elif nic_info.get('v6-fixed-ip'): + net_data['fixed_ip'] = nic_info['v6-fixed-ip'] if nic_info.get('port-id'): net_data['port'] = nic_info['port-id'] all_net_data.append(net_data) diff --git a/novaclient/v1_1/shell.py b/novaclient/v1_1/shell.py index c1754c986..3e3d6ec45 100644 --- a/novaclient/v1_1/shell.py +++ b/novaclient/v1_1/shell.py @@ -235,9 +235,10 @@ def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): for nic_str in args.nics: err_msg = (_("Invalid nic argument '%s'. Nic arguments must be of " "the form --nic , with at minimum net-id or port-id " - "specified.") % nic_str) - nic_info = {"net-id": "", "v4-fixed-ip": "", "port-id": ""} + "v6-fixed-ip=ip-addr,port-id=port-uuid>, with at minimum " + "net-id or port-id specified.") % nic_str) + nic_info = {"net-id": "", "v4-fixed-ip": "", "v6-fixed-ip": "", + "port-id": ""} for kv_str in nic_str.split(","): try: @@ -402,7 +403,8 @@ def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): help=_("Send arbitrary key/value pairs to the scheduler for custom " "use.")) @utils.arg('--nic', - metavar="", + metavar="", action='append', dest='nics', default=[], @@ -411,6 +413,7 @@ def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): "net-id: attach NIC to network with this UUID " "(required if no port-id), " "v4-fixed-ip: IPv4 fixed address for NIC (optional), " + "v6-fixed-ip: IPv6 fixed address for NIC (optional), " "port-id: attach NIC to port with this UUID " "(required if no net-id)")) @utils.arg('--config-drive', diff --git a/novaclient/v3/servers.py b/novaclient/v3/servers.py index d8ebd0a13..75e0d6990 100644 --- a/novaclient/v3/servers.py +++ b/novaclient/v3/servers.py @@ -26,6 +26,7 @@ from six.moves.urllib import parse from novaclient import base from novaclient import crypto +from novaclient.openstack.common.gettextutils import _ from novaclient.openstack.common import strutils REBOOT_SOFT, REBOOT_HARD = 'SOFT', 'HARD' @@ -457,8 +458,15 @@ class ServerManager(base.BootingManagerWithFind): # if value is empty string, do not send value in body if nic_info.get('net-id'): net_data['uuid'] = nic_info['net-id'] - if nic_info.get('v4-fixed-ip'): + if (nic_info.get('v4-fixed-ip') and + nic_info.get('v6-fixed-ip')): + raise base.exceptions.CommandError(_( + "Only one of 'v4-fixed-ip' and 'v6-fixed-ip' may be" + " provided.")) + elif nic_info.get('v4-fixed-ip'): net_data['fixed_ip'] = nic_info['v4-fixed-ip'] + elif nic_info.get('v6-fixed-ip'): + net_data['fixed_ip'] = nic_info['v6-fixed-ip'] if nic_info.get('port-id'): net_data['port'] = nic_info['port-id'] all_net_data.append(net_data) diff --git a/novaclient/v3/shell.py b/novaclient/v3/shell.py index 10a6975d8..61c9a8cb5 100644 --- a/novaclient/v3/shell.py +++ b/novaclient/v3/shell.py @@ -146,9 +146,10 @@ def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): for nic_str in args.nics: err_msg = ("Invalid nic argument '%s'. Nic arguments must be of the " "form --nic , with at minimum net-id or port-id " - "specified." % nic_str) - nic_info = {"net-id": "", "v4-fixed-ip": "", "port-id": ""} + "v6-fixed-ip=ip-addr,port-id=port-uuid>, with at minimum " + "net-id or port-id specified." % nic_str) + nic_info = {"net-id": "", "v4-fixed-ip": "", "v6-fixed-ip": "", + "port-id": ""} for kv_str in nic_str.split(","): try: @@ -278,7 +279,8 @@ def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): metavar='', help="Send arbitrary key/value pairs to the scheduler for custom use.") @utils.arg('--nic', - metavar="", + metavar="", action='append', dest='nics', default=[], @@ -287,6 +289,7 @@ def _boot(cs, args, reservation_id=None, min_count=None, max_count=None): "net-id: attach NIC to network with this UUID " "(required if no port-id), " "v4-fixed-ip: IPv4 fixed address for NIC (optional), " + "v6-fixed-ip: IPv6 fixed address for NIC (optional), " "port-id: attach NIC to port with this UUID " "(required if no net-id)") @utils.arg('--config-drive',