From 140394fe1fc8acffc5f27ac931c4808bab0d9106 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Thu, 28 Mar 2019 11:41:44 -0400 Subject: [PATCH 1/2] Change credential pattern for openstack inventory plugin See upstream docs https://github.com/ansible/ansible/pull/54532 Previously it was thought that the entry in the inventory config file was necessary, but the upstream docs change allows us to use the same pattern that we used to for the script. --- awx/main/models/inventory.py | 22 +++++++++---------- .../data/inventory/plugins/openstack/env.json | 3 ++- .../{file_reference => OS_CLIENT_CONFIG_FILE} | 0 .../plugins/openstack/files/openstack.yml | 2 -- 4 files changed, 12 insertions(+), 15 deletions(-) rename awx/main/tests/data/inventory/plugins/openstack/files/{file_reference => OS_CLIENT_CONFIG_FILE} (100%) diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index ab2af142b1..1ab7e28ea9 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -2508,26 +2508,25 @@ class openstack(PluginFileInjector): openstack_data['ansible'] = ansible_variables return openstack_data - def build_script_private_data(self, inventory_update, private_data_dir): + def build_script_private_data(self, inventory_update, private_data_dir, mk_cache=True): credential = inventory_update.get_cloud_credential() private_data = {'credentials': {}} - openstack_data = self._get_clouds_dict(inventory_update, credential, private_data_dir) + openstack_data = self._get_clouds_dict(inventory_update, credential, private_data_dir, mk_cache=mk_cache) private_data['credentials'][credential] = yaml.safe_dump( openstack_data, default_flow_style=False, allow_unicode=True ) return private_data + def build_plugin_private_data(self, inventory_update, private_data_dir): + # Credentials can be passed in the same way as the script did + # but do not create the tmp cache file + return self.build_script_private_data(inventory_update, private_data_dir, mk_cache=False) + + def get_plugin_env(self, inventory_update, private_data_dir, private_data_files): + return self.get_script_env(inventory_update, private_data_dir, private_data_files) + def inventory_as_dict(self, inventory_update, private_data_dir): - credential = inventory_update.get_cloud_credential() - - openstack_data = self._get_clouds_dict(inventory_update, credential, private_data_dir, mk_cache=False) - handle, path = tempfile.mkstemp(dir=private_data_dir) - f = os.fdopen(handle, 'w') - yaml.dump(openstack_data, f, default_flow_style=False) - f.close() - os.chmod(path, stat.S_IRUSR | stat.S_IWUSR) - def use_host_name_for_name(a_bool_maybe): if not isinstance(a_bool_maybe, bool): # Could be specified by user via "host" or "uuid" @@ -2542,7 +2541,6 @@ class openstack(PluginFileInjector): fail_on_errors=True, expand_hostvars=True, inventory_hostname=use_host_name_for_name(False), - clouds_yaml_path=[path] # why a list? it just is ) # Note: mucking with defaults will break import integrity # For the plugin, we need to use the same defaults as the old script diff --git a/awx/main/tests/data/inventory/plugins/openstack/env.json b/awx/main/tests/data/inventory/plugins/openstack/env.json index f18da63d1c..88dfb239c3 100644 --- a/awx/main/tests/data/inventory/plugins/openstack/env.json +++ b/awx/main/tests/data/inventory/plugins/openstack/env.json @@ -1,3 +1,4 @@ { - "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never" + "ANSIBLE_TRANSFORM_INVALID_GROUP_CHARS": "never", + "OS_CLIENT_CONFIG_FILE": "{{ file_reference }}" } \ No newline at end of file diff --git a/awx/main/tests/data/inventory/plugins/openstack/files/file_reference b/awx/main/tests/data/inventory/plugins/openstack/files/OS_CLIENT_CONFIG_FILE similarity index 100% rename from awx/main/tests/data/inventory/plugins/openstack/files/file_reference rename to awx/main/tests/data/inventory/plugins/openstack/files/OS_CLIENT_CONFIG_FILE diff --git a/awx/main/tests/data/inventory/plugins/openstack/files/openstack.yml b/awx/main/tests/data/inventory/plugins/openstack/files/openstack.yml index 2356b3c4ed..c2b6ee58f3 100644 --- a/awx/main/tests/data/inventory/plugins/openstack/files/openstack.yml +++ b/awx/main/tests/data/inventory/plugins/openstack/files/openstack.yml @@ -1,5 +1,3 @@ -clouds_yaml_path: -- {{ file_reference }} expand_hostvars: true fail_on_errors: true inventory_hostname: uuid From adfce6edf1d3001dde823f475fddd2ed78c257c7 Mon Sep 17 00:00:00 2001 From: AlanCoding Date: Mon, 22 Apr 2019 14:59:09 -0400 Subject: [PATCH 2/2] Unify openstack inventory injection logic Remove logic specific to job runs to create a "clouds" file for openstack credential type Move that logic into the collection of managed_by_tower injector methods, so it will be used by all job types Modify inventory openstack injector logic to use this data as a base for its logic building the clouds file --- awx/main/models/credential/injectors.py | 30 +++++++++++++++++++++++++ awx/main/models/inventory.py | 22 ++++-------------- awx/main/tasks.py | 21 ----------------- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/awx/main/models/credential/injectors.py b/awx/main/models/credential/injectors.py index 9bf7edc4a9..945077851a 100644 --- a/awx/main/models/credential/injectors.py +++ b/awx/main/models/credential/injectors.py @@ -1,4 +1,5 @@ import json +import yaml import os import stat import tempfile @@ -62,3 +63,32 @@ def vmware(cred, env, private_data_dir): env['VMWARE_PASSWORD'] = cred.get_input('password', default='') env['VMWARE_HOST'] = cred.get_input('host', default='') env['VMWARE_VALIDATE_CERTS'] = str(settings.VMWARE_VALIDATE_CERTS) + + +def _openstack_data(cred): + openstack_auth = dict(auth_url=cred.get_input('host', default=''), + username=cred.get_input('username', default=''), + password=cred.get_input('password', default=''), + project_name=cred.get_input('project', default='')) + if cred.has_input('domain'): + openstack_auth['domain_name'] = cred.get_input('domain', default='') + verify_state = cred.get_input('verify_ssl', default=True) + openstack_data = { + 'clouds': { + 'devstack': { + 'auth': openstack_auth, + 'verify': verify_state, + }, + }, + } + return openstack_data + + +def openstack(cred, env, private_data_dir): + handle, path = tempfile.mkstemp(dir=private_data_dir) + f = os.fdopen(handle, 'w') + openstack_data = _openstack_data(cred) + yaml.safe_dump(openstack_data, f, default_flow_style=False, allow_unicode=True) + f.close() + os.chmod(path, stat.S_IRUSR | stat.S_IWUSR) + env['OS_CLIENT_CONFIG_FILE'] = path diff --git a/awx/main/models/inventory.py b/awx/main/models/inventory.py index 1ab7e28ea9..057c99f325 100644 --- a/awx/main/models/inventory.py +++ b/awx/main/models/inventory.py @@ -59,6 +59,7 @@ from awx.main.models.notifications import ( NotificationTemplate, JobNotificationMixin, ) +from awx.main.models.credential.injectors import _openstack_data from awx.main.utils import _inventory_updates, region_sorting, get_licenser @@ -2463,25 +2464,10 @@ class openstack(PluginFileInjector): def script_name(self): return 'openstack_inventory.py' # exception - def _get_clouds_dict(self, inventory_update, credential, private_data_dir, mk_cache=True): - openstack_auth = dict(auth_url=credential.get_input('host', default=''), - username=credential.get_input('username', default=''), - password=credential.get_input('password', default=''), - project_name=credential.get_input('project', default='')) - if credential.has_input('domain'): - openstack_auth['domain_name'] = credential.get_input('domain', default='') + def _get_clouds_dict(self, inventory_update, cred, private_data_dir, mk_cache=True): + openstack_data = _openstack_data(cred) - private_state = inventory_update.source_vars_dict.get('private', True) - verify_state = credential.get_input('verify_ssl', default=True) - openstack_data = { - 'clouds': { - 'devstack': { - 'private': private_state, - 'verify': verify_state, - 'auth': openstack_auth, - }, - }, - } + openstack_data['clouds']['devstack']['private'] = inventory_update.source_vars_dict.get('private', True) if mk_cache: # Retrieve cache path from inventory update vars if available, # otherwise create a temporary cache path only for this update. diff --git a/awx/main/tasks.py b/awx/main/tasks.py index d7521729b0..52d176e146 100644 --- a/awx/main/tasks.py +++ b/awx/main/tasks.py @@ -1340,24 +1340,6 @@ class RunJob(BaseTask): if credential.has_input('ssh_public_key_data'): private_data.setdefault('certificates', {})[credential] = credential.get_input('ssh_public_key_data', default='') - if credential.kind == 'openstack': - openstack_auth = dict(auth_url=credential.get_input('host', default=''), - username=credential.get_input('username', default=''), - password=credential.get_input('password', default=''), - project_name=credential.get_input('project', default='')) - if credential.has_input('domain'): - openstack_auth['domain_name'] = credential.get_input('domain', default='') - verify_state = credential.get_input('verify_ssl', default=True) - openstack_data = { - 'clouds': { - 'devstack': { - 'auth': openstack_auth, - 'verify': verify_state, - }, - }, - } - private_data['credentials'][credential] = yaml.safe_dump(openstack_data, default_flow_style=False, allow_unicode=True) - return private_data def build_passwords(self, job, runtime_passwords): @@ -1450,9 +1432,6 @@ class RunJob(BaseTask): # Set environment variables for cloud credentials. cred_files = private_data_files.get('credentials', {}) - for cloud_cred in job.cloud_credentials: - if cloud_cred and cloud_cred.kind == 'openstack': - env['OS_CLIENT_CONFIG_FILE'] = cred_files.get(cloud_cred, '') for network_cred in job.network_credentials: env['ANSIBLE_NET_USERNAME'] = network_cred.get_input('username', default='')