From 9d757b3a9a89bdd63f56ce171b7c878ded9a4cd8 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Thu, 18 Aug 2016 11:35:50 -0500 Subject: Add support for configuring split-stack networks Some clouds, like OSIC and v1 of DreamCompute, have a split stack network. This means that a single Neutron Network has both an IPv4 and an IPv6 subnet, but that the IPv4 subnet is a private/RFC-1918 and the IPv6 subnet is a Global network. As any inferrance information is attached to the Network, it's impossible to properly categorize IP addresses that are on the Server in such a scenario. Add support for ipv4 and ipv6 versions of the current routes_externally config value, with each of them defaulting to the value of the un-specialized routes_externally. Change-Id: I1e87a1423d20eac31175f44f5f7b38dfcf3a11cb --- doc/source/network-config.rst | 13 ++++++++++++- os_client_config/cloud_config.py | 24 ++++++++++++++++++++++++ os_client_config/config.py | 8 ++++++++ os_client_config/tests/base.py | 8 ++++++++ os_client_config/tests/test_config.py | 16 +++++++++++++--- 5 files changed, 65 insertions(+), 4 deletions(-) diff --git a/doc/source/network-config.rst b/doc/source/network-config.rst index 5a27b8e..0957180 100644 --- a/doc/source/network-config.rst +++ b/doc/source/network-config.rst @@ -19,9 +19,15 @@ allows configuring a list of network metadata. default_interface: true - name: green routes_externally: false - - name: purple + - name: yellow routes_externally: false nat_destination: true + - name: chartreuse + routes_externally: false + routes_ipv6_externally: true + - name: aubergine + routes_ipv4_externally: false + routes_ipv6_externally: true Every entry must have a name field, which can hold either the name or the id of the network. @@ -33,6 +39,11 @@ be an RFC1918 address. In either case, it's provides IPs to servers that things not on the cloud can use. This value defaults to `false`, which indicates only servers on the same network can talk to it. +`routes_ipv4_externally` and `routes_ipv6_externally` are boolean fields to +help handle `routes_externally` in the case where a network has a split stack +with different values for IPv4 and IPv6. Either entry, if not given, defaults +to the value of `routes_externally`. + `default_interface` is a boolean field that indicates that the network is the one that programs should use. It defaults to false. An example of needing to use this value is a cloud with two private networks, and where a user is diff --git a/os_client_config/cloud_config.py b/os_client_config/cloud_config.py index 08c739a..1846f54 100644 --- a/os_client_config/cloud_config.py +++ b/os_client_config/cloud_config.py @@ -452,12 +452,36 @@ class CloudConfig(object): net['name'] for net in self.config['networks'] if net['routes_externally']] + def get_external_ipv4_networks(self): + """Get list of network names for external IPv4 networks.""" + return [ + net['name'] for net in self.config['networks'] + if net['routes_ipv4_externally']] + + def get_external_ipv6_networks(self): + """Get list of network names for external IPv6 networks.""" + return [ + net['name'] for net in self.config['networks'] + if net['routes_ipv6_externally']] + def get_internal_networks(self): """Get list of network names for internal networks.""" return [ net['name'] for net in self.config['networks'] if not net['routes_externally']] + def get_internal_ipv4_networks(self): + """Get list of network names for internal IPv4 networks.""" + return [ + net['name'] for net in self.config['networks'] + if not net['routes_ipv4_externally']] + + def get_internal_ipv6_networks(self): + """Get list of network names for internal IPv6 networks.""" + return [ + net['name'] for net in self.config['networks'] + if not net['routes_ipv6_externally']] + def get_default_network(self): """Get network used for default interactions.""" for net in self.config['networks']: diff --git a/os_client_config/config.py b/os_client_config/config.py index 7fa670f..a518932 100644 --- a/os_client_config/config.py +++ b/os_client_config/config.py @@ -520,6 +520,14 @@ class OpenStackConfig(object): nat_destination=get_boolean(net.get('nat_destination')), default_interface=get_boolean(net.get('default_interface')), ) + # routes_ipv4_externally defaults to the value of routes_externally + network['routes_ipv4_externally'] = get_boolean( + net.get( + 'routes_ipv4_externally', network['routes_externally'])) + # routes_ipv6_externally defaults to the value of routes_externally + network['routes_ipv6_externally'] = get_boolean( + net.get( + 'routes_ipv6_externally', network['routes_externally'])) networks.append(network) for key in ('external_network', 'internal_network'): diff --git a/os_client_config/tests/base.py b/os_client_config/tests/base.py index d046a94..85a42c5 100644 --- a/os_client_config/tests/base.py +++ b/os_client_config/tests/base.py @@ -113,6 +113,14 @@ USER_CONF = { 'name': 'another-private', 'routes_externally': False, 'nat_destination': True, + }, { + 'name': 'split-default', + 'routes_externally': True, + 'routes_ipv4_externally': False, + }, { + 'name': 'split-no-default', + 'routes_ipv6_externally': False, + 'routes_ipv4_externally': True, }], 'region_name': 'test-region', }, diff --git a/os_client_config/tests/test_config.py b/os_client_config/tests/test_config.py index baa35cd..b9dcb21 100644 --- a/os_client_config/tests/test_config.py +++ b/os_client_config/tests/test_config.py @@ -194,11 +194,19 @@ class TestConfig(base.TestCase): vendor_files=[self.vendor_yaml]) cc = c.get_one_cloud('_test-cloud-networks_') self.assertEqual( - ['a-public', 'another-public'], cc.get_external_networks()) + ['a-public', 'another-public', 'split-default'], + cc.get_external_networks()) self.assertEqual( - ['a-private', 'another-private'], cc.get_internal_networks()) + ['a-private', 'another-private', 'split-no-default'], + cc.get_internal_networks()) self.assertEqual('another-private', cc.get_nat_destination()) self.assertEqual('another-public', cc.get_default_network()) + self.assertEqual( + ['a-public', 'another-public', 'split-no-default'], + cc.get_external_ipv4_networks()) + self.assertEqual( + ['a-public', 'another-public', 'split-default'], + cc.get_external_ipv6_networks()) def test_get_one_cloud_no_networks(self): c = config.OpenStackConfig(config_files=[self.cloud_yaml], @@ -875,7 +883,9 @@ class TestBackwardsCompatibility(base.TestCase): expected = { 'networks': [ {'name': 'private', 'routes_externally': False, - 'nat_destination': False, 'default_interface': False}, + 'nat_destination': False, 'default_interface': False, + 'routes_ipv4_externally': False, + 'routes_ipv6_externally': False}, ] } self.assertEqual(expected, result) -- cgit v1.2.1