Add support for indicating preference for IPv6

People, such as Infra, would like to use IPv6 when it's there, but don't
want to need to write the "if ipv6, awesome, else, ipv4" code all the
time.

Change-Id: I870955863f1e8851c684dc604584c1ef3e20dd6b
This commit is contained in:
Monty Taylor 2015-06-26 10:58:37 -04:00
parent b631da86fe
commit 65dd84515b
7 changed files with 82 additions and 2 deletions

View File

@ -185,6 +185,37 @@ are connecting to OpenStack can share a cache should you desire.
dns_service_type: hpext:dns
IPv6
----
IPv6 may be a thing you would prefer to use not only if the cloud supports it,
but also if your local machine support it. A simple boolean flag is settable
either in an environment variable, `OS_PREFER_IPV6`, or in the client section
of the clouds.yaml.
::
client:
prefer_ipv6: true
clouds:
mordred:
profile: hp
auth:
username: mordred@inaugust.com
password: XXXXXXXXX
project_name: mordred@inaugust.com
region_name: region-b.geo-1
monty:
profile: rax
auth:
username: mordred@inaugust.com
password: XXXXXXXXX
project_name: mordred@inaugust.com
region_name: DFW
The above snippet will tell client programs to prefer returning an IPv6
address. This will result in calls to, for instance, `shade`'s `get_public_ip`
to return an IPv4 address on HP, and an IPv6 address on Rackspace.
Usage
-----

View File

@ -16,10 +16,11 @@ import warnings
class CloudConfig(object):
def __init__(self, name, region, config):
def __init__(self, name, region, config, prefer_ipv6=False):
self.name = name
self.region = region
self.config = config
self._prefer_ipv6 = prefer_ipv6
def __getattr__(self, key):
"""Return arbitrary attributes."""
@ -96,3 +97,7 @@ class CloudConfig(object):
def get_service_name(self, service_type):
key = '{service_type}_service_name'.format(service_type=service_type)
return self.config.get(key, service_type)
@property
def prefer_ipv6(self):
return self._prefer_ipv6

View File

@ -68,6 +68,8 @@ def set_default(key, value):
def get_boolean(value):
if type(value) is bool:
return value
if value.lower() == 'true':
return True
return False
@ -116,6 +118,14 @@ class OpenStackConfig(object):
if 'clouds' not in self.cloud_config:
self.cloud_config['clouds'] = {}
# Grab ipv6 preference settings from env
client_config = self.cloud_config.get('client', {})
self.prefer_ipv6 = get_boolean(
os.environ.pop(
'OS_PREFER_IPV6', client_config.get(
'prefer_ipv6', client_config.get(
'prefer-ipv6', False))))
# Next, process environment variables and add them to the mix
self.envvar_key = os.environ.pop('OS_CLOUD_NAME', 'envvars')
if self.envvar_key in self.cloud_config['clouds']:
@ -427,13 +437,16 @@ class OpenStackConfig(object):
if hasattr(value, 'format'):
config[key] = value.format(**config)
prefer_ipv6 = config.pop('prefer_ipv6', self.prefer_ipv6)
if cloud is None:
cloud_name = ''
else:
cloud_name = str(cloud)
return cloud_config.CloudConfig(
name=cloud_name, region=config['region_name'],
config=self._normalize_keys(config))
config=self._normalize_keys(config),
prefer_ipv6=prefer_ipv6)
@staticmethod
def set_one_cloud(config_file, cloud, set_config=None):

View File

@ -38,6 +38,9 @@ VENDOR_CONF = {
}
}
USER_CONF = {
'client': {
'prefer_ipv6': True,
},
'clouds': {
'_test-cloud_': {
'profile': '_test_cloud_in_our_cloud',

View File

@ -39,6 +39,9 @@ class TestCloudConfig(base.TestCase):
# Lookup mystery attribute
self.assertIsNone(cc.x)
# Test default ipv6
self.assertFalse(cc.prefer_ipv6)
def test_iteration(self):
cc = cloud_config.CloudConfig("test1", "region-al", fake_config_dict)
self.assertTrue('a' in cc)
@ -100,3 +103,8 @@ class TestCloudConfig(base.TestCase):
cc = cloud_config.CloudConfig("test1", "region-xx", config_dict)
(verify, cert) = cc.get_requests_verify_args()
self.assertEqual(("cert", "key"), cert)
def test_ipv6(self):
cc = cloud_config.CloudConfig(
"test1", "region-al", fake_config_dict, prefer_ipv6=True)
self.assertTrue(cc.prefer_ipv6)

View File

@ -107,6 +107,18 @@ class TestConfig(base.TestCase):
self.useFixture(fixtures.EnvironmentVariable(k))
c.get_one_cloud(cloud='defaults')
def test_prefer_ipv6_true(self):
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
vendor_files=[self.vendor_yaml])
cc = c.get_one_cloud(cloud='_test-cloud_')
self.assertTrue(cc.prefer_ipv6)
def test_prefer_ipv6_false(self):
c = config.OpenStackConfig(config_files=[self.no_yaml],
vendor_files=[self.no_yaml])
cc = c.get_one_cloud(cloud='defaults')
self.assertFalse(cc.prefer_ipv6)
def test_get_one_cloud_auth_merge(self):
c = config.OpenStackConfig(config_files=[self.cloud_yaml])
cc = c.get_one_cloud(cloud='_test-cloud_', auth={'username': 'user'})

View File

@ -51,6 +51,14 @@ class TestEnviron(base.TestCase):
cc = c.get_one_cloud('override')
self._assert_cloud_details(cc)
def test_envvar_prefer_ipv6_override(self):
self.useFixture(
fixtures.EnvironmentVariable('OS_PREFER_IPV6', 'false'))
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
vendor_files=[self.vendor_yaml])
cc = c.get_one_cloud('_test-cloud_')
self.assertFalse(cc.prefer_ipv6)
def test_environ_exists(self):
c = config.OpenStackConfig(config_files=[self.cloud_yaml],
vendor_files=[self.vendor_yaml])