Flesh out netowrk config list
Add support for indicating default_interface. Also, add some validation and normalization code, some interface methods and, shockingly, documentation. Change-Id: Ib45b68894585ac02821d5d2376510fd7a8e8ee40
This commit is contained in:
parent
278a761df6
commit
7c439073f3
@ -277,7 +277,7 @@ To support this, the region list can actually be a list of dicts, and any
|
||||
setting that can be set at the cloud level can be overridden for that
|
||||
region.
|
||||
|
||||
::
|
||||
.. code-block:: yaml
|
||||
|
||||
clouds:
|
||||
internap:
|
||||
|
@ -6,6 +6,7 @@
|
||||
vendor-support
|
||||
contributing
|
||||
installation
|
||||
network-config
|
||||
api-reference
|
||||
releasenotes
|
||||
|
||||
|
47
doc/source/network-config.rst
Normal file
47
doc/source/network-config.rst
Normal file
@ -0,0 +1,47 @@
|
||||
==============
|
||||
Network Config
|
||||
==============
|
||||
|
||||
There are several different qualities that networks in OpenStack might have
|
||||
that might not be able to be automatically inferred from the available
|
||||
metadata. To help users navigate more complex setups, `os-client-config`
|
||||
allows configuring a list of network metadata.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
clouds:
|
||||
amazing:
|
||||
networks:
|
||||
- name: blue
|
||||
routes_externally: true
|
||||
- name: purple
|
||||
routes_externally: true
|
||||
default_interface: true
|
||||
- name: green
|
||||
routes_externally: false
|
||||
- name: purple
|
||||
routes_externally: false
|
||||
nat_destination: true
|
||||
|
||||
Every entry must have a name field, which can hold either the name or the id
|
||||
of the network.
|
||||
|
||||
`routes_externally` is a boolean field that labels the network as handling
|
||||
north/south traffic off of the cloud. In a public cloud this might be thought
|
||||
of as the "public" network, but in private clouds it's possible it might
|
||||
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.
|
||||
|
||||
`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
|
||||
running ansible in one of the servers to talk to other servers on the private
|
||||
network. Because both networks are private, there would otherwise be no way
|
||||
to determine which one should be used for the traffic.
|
||||
|
||||
`nat_destination` is a boolean field that indicates which network floating
|
||||
ips should be attached to. It defaults to false. Normally this can be inferred
|
||||
by looking for a network that has subnets that have a gateway_ip. But it's
|
||||
possible to have more than one network that satisfies that condition, so the
|
||||
user might want to tell programs which one to pick.
|
@ -438,3 +438,27 @@ class CloudConfig(object):
|
||||
if resource not in expiration:
|
||||
return default
|
||||
return float(expiration[resource])
|
||||
|
||||
def get_external_networks(self):
|
||||
"""Get list of network names for external networks."""
|
||||
return [
|
||||
net['name'] for net in self._openstack_config['networks']
|
||||
if net['routes_externally']]
|
||||
|
||||
def get_internal_networks(self):
|
||||
"""Get list of network names for internal networks."""
|
||||
return [
|
||||
net['name'] for net in self._openstack_config['networks']
|
||||
if not net['routes_externally']]
|
||||
|
||||
def get_default_network(self):
|
||||
"""Get network used for default interactions."""
|
||||
for net in self._openstack_config['networks']:
|
||||
if net['default_interface']:
|
||||
return net
|
||||
|
||||
def get_nat_destination(self):
|
||||
"""Get network used for NAT destination."""
|
||||
for net in self._openstack_config['networks']:
|
||||
if net['nat_destination']:
|
||||
return net
|
||||
|
@ -83,6 +83,8 @@ def set_default(key, value):
|
||||
|
||||
|
||||
def get_boolean(value):
|
||||
if value is None:
|
||||
return False
|
||||
if type(value) is bool:
|
||||
return value
|
||||
if value.lower() == 'true':
|
||||
@ -486,10 +488,37 @@ class OpenStackConfig(object):
|
||||
or 'project_id' in cloud['auth']
|
||||
or 'project_name' in cloud['auth'])
|
||||
|
||||
def _validate_networks(self, networks, key):
|
||||
value = None
|
||||
for net in networks:
|
||||
if value and net[key]:
|
||||
raise exceptions.OpenStackConfigException(
|
||||
"Duplicate network entries for {key}: {net1} and {net2}."
|
||||
" Only one network can be flagged with {key}".format(
|
||||
key=key,
|
||||
net1=value['name'],
|
||||
net2=net['name']))
|
||||
if not value and net[key]:
|
||||
value = net
|
||||
|
||||
def _fix_backwards_networks(self, cloud):
|
||||
# Leave the external_network and internal_network keys in the
|
||||
# dict because consuming code might be expecting them.
|
||||
networks = cloud.get('networks', [])
|
||||
networks = []
|
||||
# Normalize existing network entries
|
||||
for net in cloud.get('networks', []):
|
||||
name = net.get('name')
|
||||
if not name:
|
||||
raise exceptions.OpenStackConfigException(
|
||||
'Entry in network list is missing required field "name".')
|
||||
network = dict(
|
||||
name=name,
|
||||
routes_externally=get_boolean(net.get('routes_externally')),
|
||||
nat_destination=get_boolean(net.get('nat_destination')),
|
||||
default_interface=get_boolean(net.get('default_interface')),
|
||||
)
|
||||
networks.append(network)
|
||||
|
||||
for key in ('external_network', 'internal_network'):
|
||||
external = key.startswith('external')
|
||||
if key in cloud and 'networks' in cloud:
|
||||
@ -505,7 +534,14 @@ class OpenStackConfig(object):
|
||||
key=key, name=cloud[key], external=external))
|
||||
networks.append(dict(
|
||||
name=cloud[key],
|
||||
routes_externally=external))
|
||||
routes_externally=external,
|
||||
nat_destination=not external,
|
||||
default_interface=external))
|
||||
|
||||
# Validate that we don't have duplicates
|
||||
self._validate_networks(networks, 'nat_destination')
|
||||
self._validate_networks(networks, 'default_interface')
|
||||
|
||||
cloud['networks'] = networks
|
||||
return cloud
|
||||
|
||||
|
@ -779,8 +779,40 @@ class TestBackwardsCompatibility(base.TestCase):
|
||||
'external_network': 'public',
|
||||
'internal_network': 'private',
|
||||
'networks': [
|
||||
{'name': 'public', 'routes_externally': True},
|
||||
{'name': 'private', 'routes_externally': False},
|
||||
{'name': 'public', 'routes_externally': True,
|
||||
'nat_destination': False, 'default_interface': True},
|
||||
{'name': 'private', 'routes_externally': False,
|
||||
'nat_destination': True, 'default_interface': False},
|
||||
]
|
||||
}
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_normalize_network(self):
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml])
|
||||
cloud = {
|
||||
'networks': [
|
||||
{'name': 'private'}
|
||||
]
|
||||
}
|
||||
result = c._fix_backwards_networks(cloud)
|
||||
expected = {
|
||||
'networks': [
|
||||
{'name': 'private', 'routes_externally': False,
|
||||
'nat_destination': False, 'default_interface': False},
|
||||
]
|
||||
}
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_single_default_interface(self):
|
||||
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
|
||||
vendor_files=[self.vendor_yaml])
|
||||
cloud = {
|
||||
'networks': [
|
||||
{'name': 'blue', 'default_interface': True},
|
||||
{'name': 'purple', 'default_interface': True},
|
||||
]
|
||||
}
|
||||
self.assertRaises(
|
||||
exceptions.OpenStackConfigException,
|
||||
c._fix_backwards_networks, cloud)
|
||||
|
@ -3,9 +3,8 @@ features:
|
||||
- Support added for configuring metadata about networks
|
||||
for a cloud in a list of dicts, rather than in the
|
||||
external_network and internal_network entries. The dicts
|
||||
support a name and a routes_externally field, as well as
|
||||
any other arbitrary metadata needed by consuming
|
||||
applications.
|
||||
support a name, a routes_externally field, a nat_destination
|
||||
field and a default_interface field.
|
||||
deprecations:
|
||||
- external_network and internal_network are deprecated and
|
||||
should be replaced with the list of network dicts.
|
||||
|
Loading…
x
Reference in New Issue
Block a user