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
|
setting that can be set at the cloud level can be overridden for that
|
||||||
region.
|
region.
|
||||||
|
|
||||||
::
|
.. code-block:: yaml
|
||||||
|
|
||||||
clouds:
|
clouds:
|
||||||
internap:
|
internap:
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
vendor-support
|
vendor-support
|
||||||
contributing
|
contributing
|
||||||
installation
|
installation
|
||||||
|
network-config
|
||||||
api-reference
|
api-reference
|
||||||
releasenotes
|
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:
|
if resource not in expiration:
|
||||||
return default
|
return default
|
||||||
return float(expiration[resource])
|
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):
|
def get_boolean(value):
|
||||||
|
if value is None:
|
||||||
|
return False
|
||||||
if type(value) is bool:
|
if type(value) is bool:
|
||||||
return value
|
return value
|
||||||
if value.lower() == 'true':
|
if value.lower() == 'true':
|
||||||
@ -486,10 +488,37 @@ class OpenStackConfig(object):
|
|||||||
or 'project_id' in cloud['auth']
|
or 'project_id' in cloud['auth']
|
||||||
or 'project_name' 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):
|
def _fix_backwards_networks(self, cloud):
|
||||||
# Leave the external_network and internal_network keys in the
|
# Leave the external_network and internal_network keys in the
|
||||||
# dict because consuming code might be expecting them.
|
# 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'):
|
for key in ('external_network', 'internal_network'):
|
||||||
external = key.startswith('external')
|
external = key.startswith('external')
|
||||||
if key in cloud and 'networks' in cloud:
|
if key in cloud and 'networks' in cloud:
|
||||||
@ -505,7 +534,14 @@ class OpenStackConfig(object):
|
|||||||
key=key, name=cloud[key], external=external))
|
key=key, name=cloud[key], external=external))
|
||||||
networks.append(dict(
|
networks.append(dict(
|
||||||
name=cloud[key],
|
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
|
cloud['networks'] = networks
|
||||||
return cloud
|
return cloud
|
||||||
|
|
||||||
|
@ -779,8 +779,40 @@ class TestBackwardsCompatibility(base.TestCase):
|
|||||||
'external_network': 'public',
|
'external_network': 'public',
|
||||||
'internal_network': 'private',
|
'internal_network': 'private',
|
||||||
'networks': [
|
'networks': [
|
||||||
{'name': 'public', 'routes_externally': True},
|
{'name': 'public', 'routes_externally': True,
|
||||||
{'name': 'private', 'routes_externally': False},
|
'nat_destination': False, 'default_interface': True},
|
||||||
|
{'name': 'private', 'routes_externally': False,
|
||||||
|
'nat_destination': True, 'default_interface': False},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
self.assertEqual(expected, result)
|
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
|
- Support added for configuring metadata about networks
|
||||||
for a cloud in a list of dicts, rather than in the
|
for a cloud in a list of dicts, rather than in the
|
||||||
external_network and internal_network entries. The dicts
|
external_network and internal_network entries. The dicts
|
||||||
support a name and a routes_externally field, as well as
|
support a name, a routes_externally field, a nat_destination
|
||||||
any other arbitrary metadata needed by consuming
|
field and a default_interface field.
|
||||||
applications.
|
|
||||||
deprecations:
|
deprecations:
|
||||||
- external_network and internal_network are deprecated and
|
- external_network and internal_network are deprecated and
|
||||||
should be replaced with the list of network dicts.
|
should be replaced with the list of network dicts.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user