diff --git a/awx/main/fields.py b/awx/main/fields.py index 777836ebf3..893051492f 100644 --- a/awx/main/fields.py +++ b/awx/main/fields.py @@ -695,11 +695,10 @@ class CredentialTypeInjectorField(JSONSchemaField): 'properties': { 'file': { 'type': 'object', - 'properties': { - 'template': {'type': 'string'}, + 'patternProperties': { + '^template\.[a-zA-Z_]+$': {'type': 'string'}, }, 'additionalProperties': False, - 'required': ['template'], }, 'env': { 'type': 'object', diff --git a/awx/main/models/credential/__init__.py b/awx/main/models/credential/__init__.py index face2befdb..5f82c79a91 100644 --- a/awx/main/models/credential/__init__.py +++ b/awx/main/models/credential/__init__.py @@ -594,9 +594,11 @@ class CredentialType(CommonModelNameNotUnique): return class TowerNamespace: - filename = None + pass tower_namespace = TowerNamespace() + filename_namespace = TowerNamespace() + tower_namespace.filename = filename_namespace # maintain a normal namespace for building the ansible-playbook arguments (env and args) namespace = {'tower': tower_namespace} @@ -622,17 +624,18 @@ class CredentialType(CommonModelNameNotUnique): if len(value): namespace[field_name] = value - file_tmpl = self.injectors.get('file', {}).get('template') - if file_tmpl is not None: - # If a file template is provided, render the file and update the - # special `tower` template namespace so the filename can be - # referenced in other injectors + file_tmpls = self.injectors.get('file', {}) + # If any file templates are provided, render the files and update the + # special `tower` template namespace so the filename can be + # referenced in other injectors + for file_label, file_tmpl in file_tmpls.items(): data = Template(file_tmpl).render(**namespace) _, path = tempfile.mkstemp(dir=private_data_dir) with open(path, 'w') as f: f.write(data) os.chmod(path, stat.S_IRUSR | stat.S_IWUSR) - namespace['tower'].filename = path + file_label = file_label.split('.')[1] + setattr(namespace['tower'].filename, file_label, path) for env_var, tmpl in self.injectors.get('env', {}).items(): if env_var.startswith('ANSIBLE_') or env_var in self.ENV_BLACKLIST: diff --git a/awx/main/tests/functional/test_credential.py b/awx/main/tests/functional/test_credential.py index 1fe909c092..2bf15b3f8e 100644 --- a/awx/main/tests/functional/test_credential.py +++ b/awx/main/tests/functional/test_credential.py @@ -109,6 +109,8 @@ def test_cred_type_input_schema_validity(input_, valid): ({'file': 123}, False), ({'file': {}}, False), ({'file': {'template': '{{username}}'}}, True), + ({'file': {'template.username': '{{username}}'}}, True), + ({'file': {'template.username': '{{username}}', 'template.password': '{{pass}}'}}, True), ({'file': {'foo': 'bar'}}, False), ({'env': 123}, False), ({'env': {}}, True),