From a737663ddea2d42526e5d7308c4a4d99dd0d56fc Mon Sep 17 00:00:00 2001 From: Richard Bywater Date: Thu, 1 Feb 2018 14:11:51 +1300 Subject: [PATCH 1/4] Add ability to select to prefer IPv4 addresses for ansible_ssh_host Currently Cloudforms can return a mix of IPv4 and IPv6 addresses in the ipaddresses field and this mix comes in a "random" order (that is the first entry may be IPv4 sometimes but IPv6 other times). If you wish to always use IPv4 for the ansible_ssh_host value then this is problematic. This change adds a new prefer_ipv4 flag which will look for the first IPv4 address in the ipaddresses list and uses that instead of just the first entry. --- awx/plugins/inventory/cloudforms.ini.example | 3 +++ awx/plugins/inventory/cloudforms.py | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/awx/plugins/inventory/cloudforms.ini.example b/awx/plugins/inventory/cloudforms.ini.example index dc055c1fb7..30b9aa609e 100644 --- a/awx/plugins/inventory/cloudforms.ini.example +++ b/awx/plugins/inventory/cloudforms.ini.example @@ -31,6 +31,9 @@ nest_tags = False # Note: This suffix *must* include the leading '.' as it is appended to the hostname as is # suffix = .example.org +# If true, will try and use an IPv4 address for the ansible_ssh_host rather than just the first IP address in the list +prefer_ipv4 = False + [cache] # Maximum time to trust the cache in seconds diff --git a/awx/plugins/inventory/cloudforms.py b/awx/plugins/inventory/cloudforms.py index 25b8d23159..0cdefc93c9 100755 --- a/awx/plugins/inventory/cloudforms.py +++ b/awx/plugins/inventory/cloudforms.py @@ -182,6 +182,11 @@ class CloudFormsInventory(object): else: self.cloudforms_suffix = None + if config.has_option('cloudforms', 'prefer_ipv4'): + self.cloudforms_prefer_ipv4 = config.getboolean('cloudforms', 'prefer_ipv4') + else: + self.cloudforms_prefer_ipv4 = False + # Ansible related try: group_patterns = config.get('ansible', 'group_patterns') @@ -362,7 +367,15 @@ class CloudFormsInventory(object): # Set ansible_ssh_host to the first available ip address if 'ipaddresses' in host and host['ipaddresses'] and isinstance(host['ipaddresses'], list): - host['ansible_ssh_host'] = host['ipaddresses'][0] + # If no preference for IPv4, just use the first entry + if not self.cloudforms_prefer_ipv4: + host['ansible_ssh_host'] = host['ipaddresses'][0] + else: + # Before we search for an IPv4 address, set using the first entry in case we don't find any + host['ansible_ssh_host'] = host['ipaddresses'][0] + for currenthost in host['ipaddresses']: + if '.' in currenthost: + host['ansible_ssh_host'] = currenthost # Create additional groups for key in ('location', 'type', 'vendor'): From 6d69087db8a02d9a690c8767a186249a7d9f729e Mon Sep 17 00:00:00 2001 From: Richard Bywater Date: Fri, 2 Feb 2018 08:54:54 +1300 Subject: [PATCH 2/4] Add prefer_ipv4 to whitelist and add unit test for config value --- awx/main/tasks.py | 2 +- awx/main/tests/unit/test_tasks.py | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/awx/main/tasks.py b/awx/main/tasks.py index d41f21b087..374f9f9f22 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -1822,7 +1822,7 @@ class RunInventoryUpdate(BaseTask): cp.set(section, 'ssl_verify', "false") cloudforms_opts = dict(inventory_update.source_vars_dict.items()) - for opt in ['version', 'purge_actions', 'clean_group_keys', 'nest_tags', 'suffix']: + for opt in ['version', 'purge_actions', 'clean_group_keys', 'nest_tags', 'suffix', 'prefer_ipv4']: if opt in cloudforms_opts: cp.set(section, opt, cloudforms_opts[opt]) diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index c80dbda6f9..8c4698b004 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -1757,6 +1757,8 @@ class TestInventoryUpdateCredentials(TestJobExecution): self.instance.credential, 'password' ) + self.instance.source_vars_dict['prefer_ipv4'] = True + def run_pexpect_side_effect(*args, **kwargs): args, cwd, env, stdout = args config = ConfigParser.ConfigParser() @@ -1765,6 +1767,7 @@ class TestInventoryUpdateCredentials(TestJobExecution): assert config.get('cloudforms', 'username') == 'bob' assert config.get('cloudforms', 'password') == 'secret' assert config.get('cloudforms', 'ssl_verify') == 'false' + assert config.get('cloudforms', 'prefer_ipv4') == 'true' cache_path = config.get('cache', 'path') assert cache_path.startswith(env['AWX_PRIVATE_DATA_DIR']) From 9f8b9b8d7f367e940193493feb7c2bece473968d Mon Sep 17 00:00:00 2001 From: Richard Bywater Date: Fri, 2 Feb 2018 09:17:14 +1300 Subject: [PATCH 3/4] Fix unit test --- awx/main/tests/unit/test_tasks.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index 8c4698b004..ba8c7dde75 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -1757,7 +1757,7 @@ class TestInventoryUpdateCredentials(TestJobExecution): self.instance.credential, 'password' ) - self.instance.source_vars_dict['prefer_ipv4'] = True + self.instance.source_vars['prefer_ipv4'] = True def run_pexpect_side_effect(*args, **kwargs): args, cwd, env, stdout = args From 5e5790e7d10b0ddb67f6c0d56cec54bd2f332fc8 Mon Sep 17 00:00:00 2001 From: Richard Bywater Date: Mon, 5 Feb 2018 12:45:07 +1300 Subject: [PATCH 4/4] Use correct source_vars syntax --- awx/main/tests/unit/test_tasks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/awx/main/tests/unit/test_tasks.py b/awx/main/tests/unit/test_tasks.py index ba8c7dde75..d83dea71dd 100644 --- a/awx/main/tests/unit/test_tasks.py +++ b/awx/main/tests/unit/test_tasks.py @@ -1757,7 +1757,7 @@ class TestInventoryUpdateCredentials(TestJobExecution): self.instance.credential, 'password' ) - self.instance.source_vars['prefer_ipv4'] = True + self.instance.source_vars = '{"prefer_ipv4": True}' def run_pexpect_side_effect(*args, **kwargs): args, cwd, env, stdout = args @@ -1767,7 +1767,7 @@ class TestInventoryUpdateCredentials(TestJobExecution): assert config.get('cloudforms', 'username') == 'bob' assert config.get('cloudforms', 'password') == 'secret' assert config.get('cloudforms', 'ssl_verify') == 'false' - assert config.get('cloudforms', 'prefer_ipv4') == 'true' + assert config.get('cloudforms', 'prefer_ipv4') == 'True' cache_path = config.get('cache', 'path') assert cache_path.startswith(env['AWX_PRIVATE_DATA_DIR'])