move code linting to a stricter pep8-esque auto-formatting tool, black

This commit is contained in:
Ryan Petrello
2021-03-19 12:44:51 -04:00
parent 9b702e46fe
commit c2ef0a6500
671 changed files with 20538 additions and 21924 deletions

View File

@@ -3,7 +3,8 @@
# Copyright: (c) 2017, Wayne Witzel III <wayne@riotousliving.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type

View File

@@ -3,7 +3,8 @@
# Copyright: (c) 2017, Wayne Witzel III <wayne@riotousliving.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type

View File

@@ -3,7 +3,8 @@
# Copyright: (c) 2020, Ansible by Red Hat, Inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type

View File

@@ -1,7 +1,7 @@
# Copyright (c) 2018 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
@@ -109,10 +109,7 @@ class InventoryModule(BaseInventoryPlugin):
if opt_val is not None:
module_params[module_param] = opt_val
module = TowerAPIModule(
argument_spec={}, direct_params=module_params,
error_callback=handle_error, warn_callback=self.warn_callback
)
module = TowerAPIModule(argument_spec={}, direct_params=module_params, error_callback=handle_error, warn_callback=self.warn_callback)
# validate type of inventory_id because we allow two types as special case
inventory_id = self.get_option('inventory_id')
@@ -123,15 +120,12 @@ class InventoryModule(BaseInventoryPlugin):
inventory_id = ensure_type(inventory_id, 'str')
except ValueError as e:
raise AnsibleOptionsError(
'Invalid type for configuration option inventory_id, '
'not integer, and cannot convert to string: {err}'.format(err=to_native(e))
'Invalid type for configuration option inventory_id, ' 'not integer, and cannot convert to string: {err}'.format(err=to_native(e))
)
inventory_id = inventory_id.replace('/', '')
inventory_url = '/api/v2/inventories/{inv_id}/script/'.format(inv_id=inventory_id)
inventory = module.get_endpoint(
inventory_url, data={'hostvars': '1', 'towervars': '1', 'all': '1'}
)['json']
inventory = module.get_endpoint(inventory_url, data={'hostvars': '1', 'towervars': '1', 'all': '1'})['json']
# To start with, create all the groups.
for group_name in inventory:

View File

@@ -1,6 +1,7 @@
# (c) 2020 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = """
@@ -145,10 +146,7 @@ class LookupModule(LookupBase):
module_params[module_param] = opt_val
# Create our module
module = TowerAPIModule(
argument_spec={}, direct_params=module_params,
error_callback=self.handle_error, warn_callback=self.warn_callback
)
module = TowerAPIModule(argument_spec={}, direct_params=module_params, error_callback=self.handle_error, warn_callback=self.warn_callback)
response = module.get_endpoint(terms[0], data=self.get_option('query_params', {}))
@@ -162,17 +160,11 @@ class LookupModule(LookupBase):
if self.get_option('expect_objects') or self.get_option('expect_one'):
if ('id' not in return_data) and ('results' not in return_data):
raise AnsibleError(
'Did not obtain a list or detail view at {0}, and '
'expect_objects or expect_one is set to True'.format(terms[0])
)
raise AnsibleError('Did not obtain a list or detail view at {0}, and ' 'expect_objects or expect_one is set to True'.format(terms[0]))
if self.get_option('expect_one'):
if 'results' in return_data and len(return_data['results']) != 1:
raise AnsibleError(
'Expected one object from endpoint {0}, '
'but obtained {1} from API'.format(terms[0], len(return_data['results']))
)
raise AnsibleError('Expected one object from endpoint {0}, ' 'but obtained {1} from API'.format(terms[0], len(return_data['results'])))
if self.get_option('return_all') and 'results' in return_data:
if return_data['count'] > self.get_option('max_objects'):

View File

@@ -1,6 +1,7 @@
# (c) 2020 Ansible Project
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
DOCUMENTATION = """
@@ -104,6 +105,7 @@ except ImportError:
# Validate the version of python.dateutil
try:
import dateutil
if LooseVersion(dateutil.__version__) < LooseVersion("2.7.0"):
raise Exception
except Exception:

View File

@@ -1,7 +1,8 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from . tower_module import TowerModule
from .tower_module import TowerModule
from ansible.module_utils.urls import Request, SSLValidationError, ConnectionError
from ansible.module_utils.six import PY2
from ansible.module_utils.six.moves.urllib.error import HTTPError
@@ -22,18 +23,15 @@ class TowerAPIModule(TowerModule):
'tower': 'Red Hat Ansible Tower',
}
session = None
IDENTITY_FIELDS = {
'users': 'username',
'workflow_job_template_nodes': 'identifier',
'instances': 'hostname'
}
IDENTITY_FIELDS = {'users': 'username', 'workflow_job_template_nodes': 'identifier', 'instances': 'hostname'}
ENCRYPTED_STRING = "$encrypted$"
def __init__(self, argument_spec, direct_params=None, error_callback=None, warn_callback=None, **kwargs):
kwargs['supports_check_mode'] = True
super(TowerAPIModule, self).__init__(argument_spec=argument_spec, direct_params=direct_params,
error_callback=error_callback, warn_callback=warn_callback, **kwargs)
super(TowerAPIModule, self).__init__(
argument_spec=argument_spec, direct_params=direct_params, error_callback=error_callback, warn_callback=warn_callback, **kwargs
)
self.session = Request(cookies=CookieJar(), validate_certs=self.verify_ssl)
if 'update_secrets' in self.params:
@@ -43,11 +41,7 @@ class TowerAPIModule(TowerModule):
@staticmethod
def param_to_endpoint(name):
exceptions = {
'inventory': 'inventories',
'target_team': 'teams',
'workflow': 'workflow_job_templates'
}
exceptions = {'inventory': 'inventories', 'target_team': 'teams', 'workflow': 'workflow_job_templates'}
return exceptions.get(name, '{0}s'.format(name))
@staticmethod
@@ -168,14 +162,12 @@ class TowerAPIModule(TowerModule):
if len(sample['json']['results']) > 1:
sample['json']['results'] = sample['json']['results'][:2] + ['...more results snipped...']
url = self.build_url(endpoint, query_params)
display_endpoint = url.geturl()[len(self.host):] # truncate to not include the base URL
display_endpoint = url.geturl()[len(self.host) :] # truncate to not include the base URL
self.fail_json(
msg="Request to {0} returned {1} items, expected 1".format(
display_endpoint, response['json']['count']
),
msg="Request to {0} returned {1} items, expected 1".format(display_endpoint, response['json']['count']),
query=query_params,
response=sample,
total_results=response['json']['count']
total_results=response['json']['count'],
)
def get_exactly_one(self, endpoint, name_or_id=None, **kwargs):
@@ -215,11 +207,11 @@ class TowerAPIModule(TowerModule):
try:
response = self.session.open(method, url.geturl(), headers=headers, validate_certs=self.verify_ssl, follow_redirects=True, data=data)
except(SSLValidationError) as ssl_err:
except (SSLValidationError) as ssl_err:
self.fail_json(msg="Could not establish a secure connection to your host ({1}): {0}.".format(url.netloc, ssl_err))
except(ConnectionError) as con_err:
except (ConnectionError) as con_err:
self.fail_json(msg="There was a network error of some kind trying to connect to your host ({1}): {0}.".format(url.netloc, con_err))
except(HTTPError) as he:
except (HTTPError) as he:
# Sanity check: Did the server send back some kind of internal error?
if he.code >= 500:
self.fail_json(msg='The host sent back a server error ({1}): {0}. Please check the logs and try again later'.format(url.path, he))
@@ -254,7 +246,7 @@ class TowerAPIModule(TowerModule):
pass
else:
self.fail_json(msg="Unexpected return code when calling {0}: {1}".format(url.geturl(), he))
except(Exception) as e:
except (Exception) as e:
self.fail_json(msg="There was an unknown error when trying to connect to {2}: {0} {1}".format(type(e).__name__, e, url.geturl()))
if not self.version_checked:
@@ -268,26 +260,22 @@ class TowerAPIModule(TowerModule):
tower_version = response.info().getheader('X-API-Product-Version', None)
if self._COLLECTION_TYPE not in self.collection_to_version or self.collection_to_version[self._COLLECTION_TYPE] != tower_type:
self.warn("You are using the {0} version of this collection but connecting to {1}".format(
self._COLLECTION_TYPE, tower_type
))
self.warn("You are using the {0} version of this collection but connecting to {1}".format(self._COLLECTION_TYPE, tower_type))
elif self._COLLECTION_VERSION != tower_version:
self.warn("You are running collection version {0} but connecting to tower version {1}".format(
self._COLLECTION_VERSION, tower_version
))
self.warn("You are running collection version {0} but connecting to tower version {1}".format(self._COLLECTION_VERSION, tower_version))
self.version_checked = True
response_body = ''
try:
response_body = response.read()
except(Exception) as e:
except (Exception) as e:
self.fail_json(msg="Failed to read response body: {0}".format(e))
response_json = {}
if response_body and response_body != '':
try:
response_json = loads(response_body)
except(Exception) as e:
except (Exception) as e:
self.fail_json(msg="Failed to parse the response json: {0}".format(e))
if PY2:
@@ -310,10 +298,15 @@ class TowerAPIModule(TowerModule):
try:
response = self.session.open(
'POST', api_token_url,
validate_certs=self.verify_ssl, follow_redirects=True,
force_basic_auth=True, url_username=self.username, url_password=self.password,
data=dumps(login_data), headers={'Content-Type': 'application/json'}
'POST',
api_token_url,
validate_certs=self.verify_ssl,
follow_redirects=True,
force_basic_auth=True,
url_username=self.username,
url_password=self.password,
data=dumps(login_data),
headers={'Content-Type': 'application/json'},
)
except HTTPError as he:
try:
@@ -321,7 +314,7 @@ class TowerAPIModule(TowerModule):
except Exception as e:
resp = 'unknown {0}'.format(e)
self.fail_json(msg='Failed to get token: {0}'.format(he), response=resp)
except(Exception) as e:
except (Exception) as e:
# Sanity check: Did the server send back some kind of internal error?
self.fail_json(msg='Failed to get token: {0}'.format(e))
@@ -331,7 +324,7 @@ class TowerAPIModule(TowerModule):
response_json = loads(token_response)
self.oauth_token_id = response_json['id']
self.oauth_token = response_json['token']
except(Exception) as e:
except (Exception) as e:
self.fail_json(msg="Failed to extract token information from login response: {0}".format(e), **{'response': token_response})
# If we have neither of these, then we can try un-authenticated access
@@ -429,9 +422,13 @@ class TowerAPIModule(TowerModule):
if item_type == 'workflow_job_template':
copy_get_check = self.get_endpoint(copy_from_lookup['related']['copy'])
if copy_get_check['status_code'] in [200]:
if (copy_get_check['json']['can_copy'] and copy_get_check['json']['can_copy_without_user_input'] and not
copy_get_check['json']['templates_unable_to_copy'] and not copy_get_check['json']['credentials_unable_to_copy'] and not
copy_get_check['json']['inventories_unable_to_copy']):
if (
copy_get_check['json']['can_copy']
and copy_get_check['json']['can_copy_without_user_input']
and not copy_get_check['json']['templates_unable_to_copy']
and not copy_get_check['json']['credentials_unable_to_copy']
and not copy_get_check['json']['inventories_unable_to_copy']
):
# Because checks have passed
self.json_output['copy_checks'] = 'passed'
else:
@@ -521,7 +518,8 @@ class TowerAPIModule(TowerModule):
self.warn(
'The field {0} of {1} {2} has encrypted data and may inaccurately report task is changed.'.format(
field, old.get('type', 'unknown'), old.get('id', 'unknown')
))
)
)
@staticmethod
def has_encrypted_values(obj):
@@ -612,8 +610,7 @@ class TowerAPIModule(TowerModule):
if response['status_code'] == 200:
# compare apples-to-apples, old API data to new API data
# but do so considering the fields given in parameters
self.json_output['changed'] = self.objects_could_be_different(
existing_item, response['json'], field_set=new_item.keys(), warning=True)
self.json_output['changed'] = self.objects_could_be_different(existing_item, response['json'], field_set=new_item.keys(), warning=True)
elif 'json' in response and '__all__' in response['json']:
self.fail_json(msg=response['json']['__all__'])
else:
@@ -651,7 +648,8 @@ class TowerAPIModule(TowerModule):
return self.update_if_needed(existing_item, new_item, on_update=on_update, auto_exit=auto_exit, associations=associations)
else:
return self.create_if_needed(
existing_item, new_item, endpoint, on_create=on_create, item_type=item_type, auto_exit=auto_exit, associations=associations)
existing_item, new_item, endpoint, on_create=on_create, item_type=item_type, auto_exit=auto_exit, associations=associations
)
def logout(self):
if self.authenticated and self.oauth_token_id:
@@ -659,8 +657,7 @@ class TowerAPIModule(TowerModule):
# Post to the tokens endpoint with baisc auth to try and get a token
api_token_url = (
self.url._replace(
path='/api/v2/tokens/{0}/'.format(self.oauth_token_id),
query=None # in error cases, fail_json exists before exception handling
path='/api/v2/tokens/{0}/'.format(self.oauth_token_id), query=None # in error cases, fail_json exists before exception handling
)
).geturl()
@@ -672,7 +669,7 @@ class TowerAPIModule(TowerModule):
follow_redirects=True,
force_basic_auth=True,
url_username=self.username,
url_password=self.password
url_password=self.password,
)
self.oauth_token_id = None
self.authenticated = False
@@ -682,7 +679,7 @@ class TowerAPIModule(TowerModule):
except Exception as e:
resp = 'unknown {0}'.format(e)
self.warn('Failed to release tower token: {0}, response: {1}'.format(he, resp))
except(Exception) as e:
except (Exception) as e:
# Sanity check: Did the server send back some kind of internal error?
self.warn('Failed to release tower token {0}: {1}'.format(self.oauth_token_id, e))

View File

@@ -1,13 +1,15 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from . tower_module import TowerModule
from .tower_module import TowerModule
from ansible.module_utils.basic import missing_required_lib
try:
from awxkit.api.client import Connection
from awxkit.api.pages.api import ApiV2
from awxkit.api import get_registered_page
HAS_AWX_KIT = True
except ImportError:
HAS_AWX_KIT = False

View File

@@ -26,7 +26,8 @@
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import os
@@ -47,13 +48,13 @@ from ansible.module_utils.basic import AnsibleModule, missing_required_lib
def tower_auth_config(module):
'''
"""
`tower_auth_config` attempts to load the tower-cli.cfg file
specified from the `tower_config_file` parameter. If found,
if returns the contents of the file as a dictionary, else
it will attempt to fetch values from the module params and
only pass those values that have been set.
'''
"""
config_file = module.params.pop('tower_config_file', None)
if config_file:
if not os.path.exists(config_file):
@@ -103,15 +104,16 @@ class TowerLegacyModule(AnsibleModule):
args.update(argument_spec)
kwargs.setdefault('mutually_exclusive', [])
kwargs['mutually_exclusive'].extend((
('tower_config_file', 'tower_host'),
('tower_config_file', 'tower_username'),
('tower_config_file', 'tower_password'),
('tower_config_file', 'validate_certs'),
))
kwargs['mutually_exclusive'].extend(
(
('tower_config_file', 'tower_host'),
('tower_config_file', 'tower_username'),
('tower_config_file', 'tower_password'),
('tower_config_file', 'validate_certs'),
)
)
super(TowerLegacyModule, self).__init__(argument_spec=args, **kwargs)
if not HAS_TOWER_CLI:
self.fail_json(msg=missing_required_lib('ansible-tower-cli'),
exception=TOWER_CLI_IMP_ERR)
self.fail_json(msg=missing_required_lib('ansible-tower-cli'), exception=TOWER_CLI_IMP_ERR)

View File

@@ -1,4 +1,5 @@
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.basic import AnsibleModule, env_fallback
@@ -14,6 +15,7 @@ from distutils.util import strtobool
try:
import yaml
HAS_YAML = True
except ImportError:
HAS_YAML = False
@@ -139,15 +141,14 @@ class TowerModule(AnsibleModule):
# If we have a specified tower config, load it
if self.params.get('tower_config_file'):
duplicated_params = [
fn for fn in self.AUTH_ARGSPEC
if fn != 'tower_config_file' and self.params.get(fn) is not None
]
duplicated_params = [fn for fn in self.AUTH_ARGSPEC if fn != 'tower_config_file' and self.params.get(fn) is not None]
if duplicated_params:
self.warn((
'The parameter(s) {0} were provided at the same time as tower_config_file. '
'Precedence may be unstable, we suggest either using config file or params.'
).format(', '.join(duplicated_params)))
self.warn(
(
'The parameter(s) {0} were provided at the same time as tower_config_file. '
'Precedence may be unstable, we suggest either using config file or params.'
).format(', '.join(duplicated_params))
)
try:
# TODO: warn if there are conflicts with other params
self.load_config(self.params.get('tower_config_file'))
@@ -186,7 +187,7 @@ class TowerModule(AnsibleModule):
raise AssertionError("The yaml config file is not properly formatted as a dict.")
try_config_parsing = False
except(AttributeError, yaml.YAMLError, AssertionError):
except (AttributeError, yaml.YAMLError, AssertionError):
try_config_parsing = True
if try_config_parsing:

View File

@@ -6,12 +6,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
---
@@ -168,26 +167,25 @@ def main():
module.fail_json(msg="Failed to launch command, see response for details", **{'response': results})
if not wait:
module.exit_json(**{
module.exit_json(
**{
'changed': True,
'id': results['json']['id'],
'status': results['json']['status'],
}
)
# Invoke wait function
results = module.wait_on_url(url=results['json']['url'], object_name=module_name, object_type='Ad Hoc Command', timeout=timeout, interval=interval)
module.exit_json(
**{
'changed': True,
'id': results['json']['id'],
'status': results['json']['status'],
})
# Invoke wait function
results = module.wait_on_url(
url=results['json']['url'],
object_name=module_name,
object_type='Ad Hoc Command',
timeout=timeout, interval=interval
}
)
module.exit_json(**{
'changed': True,
'id': results['json']['id'],
'status': results['json']['status'],
})
if __name__ == '__main__':
main()

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -85,11 +84,14 @@ def main():
timeout = module.params.get('timeout')
# Attempt to look up the command based on the provided name
command = module.get_one('ad_hoc_commands', **{
'data': {
'id': command_id,
command = module.get_one(
'ad_hoc_commands',
**{
'data': {
'id': command_id,
}
}
})
)
if command is None:
module.fail_json(msg="Unable to find command with id {0}".format(command_id))

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -103,22 +102,20 @@ def main():
interval = module.params.get('interval')
# Attempt to look up command based on the provided id
command = module.get_one('ad_hoc_commands', **{
'data': {
'id': command_id,
command = module.get_one(
'ad_hoc_commands',
**{
'data': {
'id': command_id,
}
}
})
)
if command is None:
module.fail_json(msg='Unable to wait on ad hoc command {0}; that ID does not exist in Tower.'.format(command_id))
# Invoke wait function
module.wait_on_url(
url=command['url'],
object_name=command_id,
object_type='ad hoc command',
timeout=timeout, interval=interval
)
module.wait_on_url(url=command['url'], object_name=command_id, object_type='ad hoc command', timeout=timeout, interval=interval)
module.exit_json(**module.json_output)

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -105,7 +104,7 @@ def main():
organization=dict(required=True),
redirect_uris=dict(type="list", elements='str'),
state=dict(choices=['present', 'absent'], default='present'),
skip_authorization=dict(type='bool')
skip_authorization=dict(type='bool'),
)
# Create a module for ourselves
@@ -124,11 +123,7 @@ def main():
org_id = module.resolve_name_to_id('organizations', organization)
# Attempt to look up application based on the provided name and org ID
application = module.get_one('applications', name_or_id=name, **{
'data': {
'organization': org_id
}
})
application = module.get_one('applications', name_or_id=name, **{'data': {'organization': org_id}})
if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this
@@ -152,10 +147,7 @@ def main():
application_fields['redirect_uris'] = ' '.join(redirect_uris)
# If the state was present and we can let the module build or update the existing application, this will return on its own
module.create_or_update_if_needed(
application, application_fields,
endpoint='applications', item_type='application'
)
module.create_or_update_if_needed(application, application_fields, endpoint='applications', item_type='application')
if __name__ == '__main__':

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -318,12 +317,25 @@ KIND_CHOICES = {
OLD_INPUT_NAMES = (
'authorize', 'authorize_password', 'client',
'security_token', 'secret', 'tenant', 'subscription',
'domain', 'become_method', 'become_username',
'become_password', 'vault_password', 'project', 'host',
'username', 'password', 'ssh_key_data', 'vault_id',
'ssh_key_unlock'
'authorize',
'authorize_password',
'client',
'security_token',
'secret',
'tenant',
'subscription',
'domain',
'become_method',
'become_username',
'become_password',
'vault_password',
'project',
'host',
'username',
'password',
'ssh_key_data',
'vault_id',
'ssh_key_unlock',
)
@@ -409,8 +421,11 @@ def main():
if copy_from:
# a new existing item is formed when copying and is returned.
credential = module.copy_item(
credential, copy_from, name,
endpoint='credentials', item_type='credential',
credential,
copy_from,
name,
endpoint='credentials',
item_type='credential',
copy_lookup_data=copy_lookup_data,
)
@@ -459,9 +474,7 @@ def main():
credential_fields['team'] = team_id
# If the state was present we can let the module build or update the existing group, this will return on its own
module.create_or_update_if_needed(
credential, credential_fields, endpoint='credentials', item_type='credential'
)
module.create_or_update_if_needed(credential, credential_fields, endpoint='credentials', item_type='credential')
if __name__ == '__main__':

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''

View File

@@ -6,12 +6,11 @@
# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'status': ['preview'],
'supported_by': 'community',
'metadata_version': '1.1'}
ANSIBLE_METADATA = {'status': ['preview'], 'supported_by': 'community', 'metadata_version': '1.1'}
DOCUMENTATION = '''
@@ -83,14 +82,7 @@ RETURN = ''' # '''
from ..module_utils.tower_api import TowerAPIModule
KIND_CHOICES = {
'ssh': 'Machine',
'vault': 'Ansible Vault',
'net': 'Network',
'scm': 'Source Control',
'cloud': 'Lots of others',
'insights': 'Insights'
}
KIND_CHOICES = {'ssh': 'Machine', 'vault': 'Ansible Vault', 'net': 'Network', 'scm': 'Source Control', 'cloud': 'Lots of others', 'insights': 'Insights'}
def main():

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -81,7 +80,7 @@ def main():
organization=dict(),
credential=dict(default=''),
state=dict(choices=['present', 'absent'], default='present'),
pull=dict(choices=['always', 'missing', 'never'], default='missing')
pull=dict(choices=['always', 'missing', 'never'], default='missing'),
)
# Create a module for ourselves
@@ -118,11 +117,7 @@ def main():
if credential:
new_fields['credential'] = module.resolve_name_to_id('credentials', credential)
module.create_or_update_if_needed(
existing_item, new_fields,
endpoint='execution_environments',
item_type='execution_environment'
)
module.create_or_update_if_needed(existing_item, new_fields, endpoint='execution_environments', item_type='execution_environment')
if __name__ == '__main__':

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -104,6 +103,7 @@ from ..module_utils.tower_awxkit import TowerAWXKitModule
try:
from awxkit.api.pages.api import EXPORTABLE_RESOURCES
HAS_EXPORTABLE_RESOURCES = True
except ImportError:
HAS_EXPORTABLE_RESOURCES = False

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -136,11 +135,7 @@ def main():
inventory_id = module.resolve_name_to_id('inventories', inventory)
# Attempt to look up the object based on the provided name and inventory ID
group = module.get_one('groups', name_or_id=name, **{
'data': {
'inventory': inventory_id
}
})
group = module.get_one('groups', name_or_id=name, **{'data': {'inventory': inventory_id}})
if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this
@@ -163,9 +158,13 @@ def main():
continue
id_list = []
for sub_name in name_list:
sub_obj = module.get_one(resource, name_or_id=sub_name, **{
'data': {'inventory': inventory_id},
})
sub_obj = module.get_one(
resource,
name_or_id=sub_name,
**{
'data': {'inventory': inventory_id},
}
)
if sub_obj is None:
module.fail_json(msg='Could not find {0} with name {1}'.format(resource, sub_name))
id_list.append(sub_obj['id'])
@@ -178,10 +177,7 @@ def main():
association_fields[relationship] = id_list
# If the state was present we can let the module build or update the existing group, this will return on its own
module.create_or_update_if_needed(
group, group_fields, endpoint='groups', item_type='group',
associations=association_fields
)
module.create_or_update_if_needed(group, group_fields, endpoint='groups', item_type='group', associations=association_fields)
if __name__ == '__main__':

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -104,11 +103,7 @@ def main():
inventory_id = module.resolve_name_to_id('inventories', inventory)
# Attempt to look up host based on the provided name and inventory ID
host = module.get_one('hosts', name_or_id=name, **{
'data': {
'inventory': inventory_id
}
})
host = module.get_one('hosts', name_or_id=name, **{'data': {'inventory': inventory_id}})
if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -58,15 +57,14 @@ import logging
# In this module we don't use EXPORTABLE_RESOURCES, we just want to validate that our installed awxkit has import/export
try:
from awxkit.api.pages.api import EXPORTABLE_RESOURCES
HAS_EXPORTABLE_RESOURCES = True
except ImportError:
HAS_EXPORTABLE_RESOURCES = False
def main():
argument_spec = dict(
assets=dict(type='dict', required=True)
)
argument_spec = dict(assets=dict(type='dict', required=True))
module = TowerAWXKitModule(argument_spec=argument_spec, supports_check_mode=False)

View File

@@ -6,12 +6,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
---
@@ -149,11 +148,13 @@ def main():
# If the state was present and we can let the module build or update the existing item, this will return on its own
module.create_or_update_if_needed(
existing_item, new_fields,
endpoint='instance_groups', item_type='instance_group',
existing_item,
new_fields,
endpoint='instance_groups',
item_type='instance_group',
associations={
'instances': instances_ids,
}
},
)

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -127,18 +126,17 @@ def main():
org_id = module.resolve_name_to_id('organizations', organization)
# Attempt to look up inventory based on the provided name and org ID
inventory = module.get_one('inventories', name_or_id=name, **{
'data': {
'organization': org_id
}
})
inventory = module.get_one('inventories', name_or_id=name, **{'data': {'organization': org_id}})
# Attempt to look up credential to copy based on the provided name
if copy_from:
# a new existing item is formed when copying and is returned.
inventory = module.copy_item(
inventory, copy_from, name,
endpoint='inventories', item_type='inventory',
inventory,
copy_from,
name,
endpoint='inventories',
item_type='inventory',
copy_lookup_data={},
)

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -163,9 +162,7 @@ def main():
#
# How do we handle manual and file? Tower does not seem to be able to activate them
#
source=dict(choices=["scm", "ec2", "gce",
"azure_rm", "vmware", "satellite6",
"openstack", "rhv", "tower", "custom"]),
source=dict(choices=["scm", "ec2", "gce", "azure_rm", "vmware", "satellite6", "openstack", "rhv", "tower", "custom"]),
source_path=dict(),
source_script=dict(),
source_vars=dict(type='dict'),
@@ -211,11 +208,15 @@ def main():
if not inventory_object:
module.fail_json(msg='The specified inventory, {0}, was not found.'.format(lookup_data))
inventory_source_object = module.get_one('inventory_sources', name_or_id=name, **{
'data': {
'inventory': inventory_object['id'],
inventory_source_object = module.get_one(
'inventory_sources',
name_or_id=name,
**{
'data': {
'inventory': inventory_object['id'],
}
}
})
)
if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this
@@ -259,10 +260,20 @@ def main():
inventory_source_fields['source_script'] = module.resolve_name_to_id('inventory_scripts', source_script)
OPTIONAL_VARS = (
'description', 'source', 'source_path', 'source_vars',
'overwrite', 'overwrite_vars',
'timeout', 'verbosity', 'update_on_launch', 'update_cache_timeout',
'update_on_project_update', 'enabled_var', 'enabled_value', 'host_filter',
'description',
'source',
'source_path',
'source_vars',
'overwrite',
'overwrite_vars',
'timeout',
'verbosity',
'update_on_launch',
'update_cache_timeout',
'update_on_project_update',
'enabled_var',
'enabled_value',
'host_filter',
)
# Layer in all remaining optional information
@@ -281,9 +292,7 @@ def main():
# If the state was present we can let the module build or update the existing inventory_source_object, this will return on its own
module.create_or_update_if_needed(
inventory_source_object, inventory_source_fields,
endpoint='inventory_sources', item_type='inventory source',
associations=association_fields
inventory_source_object, inventory_source_fields, endpoint='inventory_sources', item_type='inventory source', associations=association_fields
)

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -117,9 +116,7 @@ def main():
if not inventory_object:
module.fail_json(msg='The specified inventory, {0}, was not found.'.format(lookup_data))
inventory_source_object = module.get_one('inventory_sources',
name_or_id=name,
data={'inventory': inventory_object['id']})
inventory_source_object = module.get_one('inventory_sources', name_or_id=name, data={'inventory': inventory_object['id']})
if not inventory_source_object:
module.fail_json(msg='The specified inventory source was not found.')
@@ -139,10 +136,7 @@ def main():
# Invoke wait function
module.wait_on_url(
url=inventory_source_update_results['json']['url'],
object_name=inventory_object,
object_type='inventory_update',
timeout=timeout, interval=interval
url=inventory_source_update_results['json']['url'], object_name=inventory_object, object_type='inventory_update', timeout=timeout, interval=interval
)
module.exit_json(**module.json_output)

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -68,11 +67,14 @@ def main():
fail_if_not_running = module.params.get('fail_if_not_running')
# Attempt to look up the job based on the provided name
job = module.get_one('jobs', **{
'data': {
'id': job_id,
job = module.get_one(
'jobs',
**{
'data': {
'id': job_id,
}
}
})
)
if job is None:
module.fail_json(msg="Unable to find job with id {0}".format(job_id))

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -248,26 +247,25 @@ def main():
module.fail_json(msg="Failed to launch job, see response for details", **{'response': results})
if not wait:
module.exit_json(**{
module.exit_json(
**{
'changed': True,
'id': results['json']['id'],
'status': results['json']['status'],
}
)
# Invoke wait function
results = module.wait_on_url(url=results['json']['url'], object_name=name, object_type='Job', timeout=timeout, interval=interval)
module.exit_json(
**{
'changed': True,
'id': results['json']['id'],
'status': results['json']['status'],
})
# Invoke wait function
results = module.wait_on_url(
url=results['json']['url'],
object_name=name,
object_type='Job',
timeout=timeout, interval=interval
}
)
module.exit_json(**{
'changed': True,
'id': results['json']['id'],
'status': results['json']['status'],
})
if __name__ == '__main__':
main()

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -97,7 +96,7 @@ def main():
argument_spec=argument_spec,
mutually_exclusive=[
('page', 'all_pages'),
]
],
)
# Extract our parameters

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -447,8 +446,11 @@ def main():
if copy_from:
# a new existing item is formed when copying and is returned.
existing_item = module.copy_item(
existing_item, copy_from, name,
endpoint='job_templates', item_type='job_template',
existing_item,
copy_from,
name,
endpoint='job_templates',
item_type='job_template',
copy_lookup_data={},
)
@@ -459,12 +461,36 @@ def main():
# Create the data that gets sent for create and update
new_fields['name'] = new_name if new_name else (module.get_item_name(existing_item) if existing_item else name)
for field_name in (
'description', 'job_type', 'playbook', 'scm_branch', 'forks', 'limit', 'verbosity',
'job_tags', 'force_handlers', 'skip_tags', 'start_at_task', 'timeout', 'use_fact_cache',
'host_config_key', 'ask_scm_branch_on_launch', 'ask_diff_mode_on_launch', 'ask_variables_on_launch',
'ask_limit_on_launch', 'ask_tags_on_launch', 'ask_skip_tags_on_launch', 'ask_job_type_on_launch',
'ask_verbosity_on_launch', 'ask_inventory_on_launch', 'ask_credential_on_launch', 'survey_enabled',
'become_enabled', 'diff_mode', 'allow_simultaneous', 'job_slice_count', 'webhook_service',
'description',
'job_type',
'playbook',
'scm_branch',
'forks',
'limit',
'verbosity',
'job_tags',
'force_handlers',
'skip_tags',
'start_at_task',
'timeout',
'use_fact_cache',
'host_config_key',
'ask_scm_branch_on_launch',
'ask_diff_mode_on_launch',
'ask_variables_on_launch',
'ask_limit_on_launch',
'ask_tags_on_launch',
'ask_skip_tags_on_launch',
'ask_job_type_on_launch',
'ask_verbosity_on_launch',
'ask_inventory_on_launch',
'ask_credential_on_launch',
'survey_enabled',
'become_enabled',
'diff_mode',
'allow_simultaneous',
'job_slice_count',
'webhook_service',
):
field_val = module.params.get(field_name)
if field_val is not None:
@@ -484,15 +510,17 @@ def main():
new_fields['inventory'] = module.resolve_name_to_id('inventories', inventory)
if project is not None:
if organization_id is not None:
project_data = module.get_one('projects', name_or_id=project, **{
'data': {
'organization': organization_id,
project_data = module.get_one(
'projects',
name_or_id=project,
**{
'data': {
'organization': organization_id,
}
}
})
)
if project_data is None:
module.fail_json(msg="The project {0} in organization {1} was not found on the Tower server".format(
project, organization
))
module.fail_json(msg="The project {0} in organization {1} was not found on the Tower server".format(project, organization))
new_fields['project'] = project_data['id']
else:
new_fields['project'] = module.resolve_name_to_id('projects', project)
@@ -511,12 +539,12 @@ def main():
association_fields['labels'] = []
for item in labels:
association_fields['labels'].append(module.resolve_name_to_id('labels', item))
# Code to use once Issue #7567 is resolved
# search_fields = {'name': item}
# if organization:
# search_fields['organization'] = organization_id
# label_id = module.get_one('labels', **{'data': search_fields})
# association_fields['labels'].append(label_id)
# Code to use once Issue #7567 is resolved
# search_fields = {'name': item}
# if organization:
# search_fields['organization'] = organization_id
# label_id = module.get_one('labels', **{'data': search_fields})
# association_fields['labels'].append(label_id)
notifications_start = module.params.get('notification_templates_started')
if notifications_start is not None:
@@ -551,10 +579,13 @@ def main():
# If the state was present and we can let the module build or update the existing item, this will return on its own
module.create_or_update_if_needed(
existing_item, new_fields,
endpoint='job_templates', item_type='job_template',
existing_item,
new_fields,
endpoint='job_templates',
item_type='job_template',
associations=association_fields,
on_create=on_change, on_update=on_change,
on_create=on_change,
on_update=on_change,
)

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -134,26 +133,24 @@ def main():
interval = abs((min_interval + max_interval) / 2)
module.deprecate(
msg="Min and max interval have been deprecated, please use interval instead; interval will be set to {0}".format(interval),
version="ansible.tower:4.0.0"
version="ansible.tower:4.0.0",
)
# Attempt to look up job based on the provided id
job = module.get_one(job_type, **{
'data': {
'id': job_id,
job = module.get_one(
job_type,
**{
'data': {
'id': job_id,
}
}
})
)
if job is None:
module.fail_json(msg='Unable to wait on ' + job_type.rstrip("s") + ' {0}; that ID does not exist in Tower.'.format(job_id))
# Invoke wait function
result = module.wait_on_url(
url=job['url'],
object_name=job_id,
object_type='legacy_job_wait',
timeout=timeout, interval=interval
)
result = module.wait_on_url(url=job['url'], object_name=job_id, object_type='legacy_job_wait', timeout=timeout, interval=interval)
module.exit_json(**module.json_output)

View File

@@ -6,12 +6,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
---
@@ -80,11 +79,15 @@ def main():
organization_id = module.resolve_name_to_id('organizations', organization)
# Attempt to look up an existing item based on the provided data
existing_item = module.get_one('labels', name_or_id=name, **{
'data': {
'organization': organization_id,
existing_item = module.get_one(
'labels',
name_or_id=name,
**{
'data': {
'organization': organization_id,
}
}
})
)
# Create the data that gets sent for create and update
new_fields = {}
@@ -92,12 +95,7 @@ def main():
if organization:
new_fields['organization'] = organization_id
module.create_or_update_if_needed(
existing_item, new_fields,
endpoint='labels', item_type='label',
associations={
}
)
module.create_or_update_if_needed(existing_item, new_fields, endpoint='labels', item_type='label', associations={})
if __name__ == '__main__':

View File

@@ -5,11 +5,10 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -62,9 +61,7 @@ def main():
module.fail_json(msg='You must accept the EULA by passing in the param eula_accepted as True')
try:
manifest = base64.b64encode(
open(module.params.get('manifest'), 'rb').read()
)
manifest = base64.b64encode(open(module.params.get('manifest'), 'rb').read())
except OSError as e:
module.fail_json(msg=str(e))
@@ -72,10 +69,7 @@ def main():
if module.check_mode:
module.exit_json(**json_output)
module.post_endpoint('config', data={
'eula_accepted': True,
'manifest': manifest.decode()
})
module.post_endpoint('config', data={'eula_accepted': True, 'manifest': manifest.decode()})
module.exit_json(**json_output)

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
---
@@ -67,17 +66,9 @@ from ..module_utils.tower_api import TowerAPIModule
def main():
module = TowerAPIModule(argument_spec={})
namespace = {
'awx': 'awx',
'tower': 'ansible'
}.get(module._COLLECTION_TYPE, 'unknown')
namespace = {'awx': 'awx', 'tower': 'ansible'}.get(module._COLLECTION_TYPE, 'unknown')
namespace_name = '{0}.{1}'.format(namespace, module._COLLECTION_TYPE)
module.exit_json(
prefix=namespace_name,
name=module._COLLECTION_TYPE,
namespace=namespace,
version=module._COLLECTION_VERSION
)
module.exit_json(prefix=namespace_name, name=module._COLLECTION_TYPE, namespace=namespace, version=module._COLLECTION_VERSION)
if __name__ == '__main__':

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -317,13 +316,31 @@ RETURN = ''' # '''
from ..module_utils.tower_api import TowerAPIModule
OLD_INPUT_NAMES = (
'username', 'sender', 'recipients', 'use_tls',
'host', 'use_ssl', 'password', 'port',
'channels', 'token', 'account_token', 'from_number',
'to_numbers', 'account_sid', 'subdomain', 'service_key',
'client_name', 'message_from', 'color',
'notify', 'url', 'headers', 'server',
'nickname', 'targets',
'username',
'sender',
'recipients',
'use_tls',
'host',
'use_ssl',
'password',
'port',
'channels',
'token',
'account_token',
'from_number',
'to_numbers',
'account_sid',
'subdomain',
'service_key',
'client_name',
'message_from',
'color',
'notify',
'url',
'headers',
'server',
'nickname',
'targets',
)
@@ -335,10 +352,7 @@ def main():
copy_from=dict(),
description=dict(),
organization=dict(),
notification_type=dict(choices=[
'email', 'grafana', 'irc', 'mattermost',
'pagerduty', 'rocketchat', 'slack', 'twilio', 'webhook'
]),
notification_type=dict(choices=['email', 'grafana', 'irc', 'mattermost', 'pagerduty', 'rocketchat', 'slack', 'twilio', 'webhook']),
notification_configuration=dict(type='dict'),
messages=dict(type='dict'),
username=dict(),
@@ -387,8 +401,8 @@ def main():
for legacy_input in OLD_INPUT_NAMES:
if module.params.get(legacy_input) is not None:
module.deprecate(
msg='{0} parameter has been deprecated, please use notification_configuration instead'.format(legacy_input),
version="ansible.tower:4.0.0")
msg='{0} parameter has been deprecated, please use notification_configuration instead'.format(legacy_input), version="ansible.tower:4.0.0"
)
# Attempt to look up the related items the user specified (these will fail the module if not found)
organization_id = None
@@ -396,18 +410,25 @@ def main():
organization_id = module.resolve_name_to_id('organizations', organization)
# Attempt to look up an existing item based on the provided data
existing_item = module.get_one('notification_templates', name_or_id=name, **{
'data': {
'organization': organization_id,
existing_item = module.get_one(
'notification_templates',
name_or_id=name,
**{
'data': {
'organization': organization_id,
}
}
})
)
# Attempt to look up credential to copy based on the provided name
if copy_from:
# a new existing item is formed when copying and is returned.
existing_item = module.copy_item(
existing_item, copy_from, name,
endpoint='notification_templates', item_type='notification_template',
existing_item,
copy_from,
name,
endpoint='notification_templates',
item_type='notification_template',
copy_lookup_data={},
)
@@ -439,12 +460,7 @@ def main():
new_fields['messages'] = messages
# If the state was present and we can let the module build or update the existing item, this will return on its own
module.create_or_update_if_needed(
existing_item, new_fields,
endpoint='notification_templates', item_type='notification_template',
associations={
}
)
module.create_or_update_if_needed(existing_item, new_fields, endpoint='notification_templates', item_type='notification_template', associations={})
if __name__ == '__main__':

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -178,8 +177,10 @@ def main():
# If the state was present and we can let the module build or update the existing organization, this will return on its own
module.create_or_update_if_needed(
organization, org_fields,
endpoint='organizations', item_type='organization',
organization,
org_fields,
endpoint='organizations',
item_type='organization',
associations=association_fields,
)

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -226,10 +225,7 @@ def wait_for_project_update(module, last_request):
# Invoke wait function
module.wait_on_url(
url=result['json']['url'],
object_name=module.get_item_name(last_request),
object_type='Project Update',
timeout=timeout, interval=interval
url=result['json']['url'], object_name=module.get_item_name(last_request), object_type='Project Update', timeout=timeout, interval=interval
)
module.exit_json(**module.json_output)
@@ -298,8 +294,11 @@ def main():
if copy_from:
# a new existing item is formed when copying and is returned.
project = module.copy_item(
project, copy_from, name,
endpoint='projects', item_type='project',
project,
copy_from,
name,
endpoint='projects',
item_type='project',
copy_lookup_data={},
)
@@ -341,9 +340,16 @@ def main():
}
for field_name in (
'scm_url', 'scm_branch', 'scm_refspec', 'scm_clean', 'scm_delete_on_update',
'timeout', 'scm_update_cache_timeout', 'custom_virtualenv',
'description', 'allow_override',
'scm_url',
'scm_branch',
'scm_refspec',
'scm_clean',
'scm_delete_on_update',
'timeout',
'scm_update_cache_timeout',
'custom_virtualenv',
'description',
'allow_override',
):
field_val = module.params.get(field_name)
if field_val is not None:
@@ -368,10 +374,7 @@ def main():
# If the state was present and we can let the module build or update the existing project, this will return on its own
module.create_or_update_if_needed(
project, project_fields,
endpoint='projects', item_type='project',
associations=association_fields,
on_create=on_change, on_update=on_change
project, project_fields, endpoint='projects', item_type='project', associations=association_fields, on_create=on_change, on_update=on_change
)

View File

@@ -4,11 +4,10 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.0',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.0', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
---
@@ -127,12 +126,7 @@ def main():
start = time.time()
# Invoke wait function
module.wait_on_url(
url=result['json']['url'],
object_name=module.get_item_name(project),
object_type='Project Update',
timeout=timeout, interval=interval
)
module.wait_on_url(url=result['json']['url'], object_name=module.get_item_name(project), object_type='Project Update', timeout=timeout, interval=interval)
module.exit_json(**module.json_output)

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['deprecated'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['deprecated'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -142,6 +141,7 @@ try:
from tower_cli.utils.exceptions import TowerCLIError
from tower_cli.conf import settings
TOWER_CLI_HAS_EXPORT = True
except ImportError:
TOWER_CLI_HAS_EXPORT = False

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -157,9 +156,26 @@ def main():
argument_spec = dict(
user=dict(),
team=dict(),
role=dict(choices=["admin", "read", "member", "execute", "adhoc", "update", "use", "approval",
"auditor", "project_admin", "inventory_admin", "credential_admin",
"workflow_admin", "notification_admin", "job_template_admin"], required=True),
role=dict(
choices=[
"admin",
"read",
"member",
"execute",
"adhoc",
"update",
"use",
"approval",
"auditor",
"project_admin",
"inventory_admin",
"credential_admin",
"workflow_admin",
"notification_admin",
"job_template_admin",
],
required=True,
),
target_team=dict(),
target_teams=dict(type='list', elements='str'),
inventory=dict(),
@@ -194,12 +210,10 @@ def main():
'organizations': 'organization',
'projects': 'project',
'target_teams': 'target_team',
'workflows': 'workflow'
'workflows': 'workflow',
}
# Singular parameters
resource_param_keys = (
'user', 'team', 'lookup_organization'
)
resource_param_keys = ('user', 'team', 'lookup_organization')
resources = {}
for resource_group in resource_list_param_keys:
@@ -256,9 +270,9 @@ def main():
resource_roles = resource['summary_fields']['object_roles']
if role_field not in resource_roles:
available_roles = ', '.join(list(resource_roles.keys()))
module.fail_json(msg='Resource {0} has no role {1}, available roles: {2}'.format(
resource['url'], role_field, available_roles
), changed=False)
module.fail_json(
msg='Resource {0} has no role {1}, available roles: {2}'.format(resource['url'], role_field, available_roles), changed=False
)
role_data = resource_roles[role_field]
endpoint = '/roles/{0}/{1}/'.format(role_data['id'], module.param_to_endpoint(actor_type))
associations.setdefault(endpoint, [])

View File

@@ -6,12 +6,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
---
@@ -227,12 +226,7 @@ def main():
module.delete_if_needed(existing_item)
elif state == 'present':
# If the state was present and we can let the module build or update the existing item, this will return on its own
module.create_or_update_if_needed(
existing_item, new_fields,
endpoint='schedules', item_type='schedule',
associations={
}
)
module.create_or_update_if_needed(existing_item, new_fields, endpoint='schedules', item_type='schedule', associations={})
if __name__ == '__main__':

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['deprecated'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['deprecated'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -90,6 +89,7 @@ try:
from tower_cli.utils.exceptions import TowerCLIError
from tower_cli.conf import settings
TOWER_CLI_HAS_EXPORT = True
except ImportError:
TOWER_CLI_HAS_EXPORT = False

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -74,6 +73,7 @@ from ..module_utils.tower_api import TowerAPIModule
try:
import yaml
HAS_YAML = True
except ImportError:
HAS_YAML = False
@@ -84,11 +84,7 @@ def coerce_type(module, value):
if value is None:
return value
yaml_ish = bool((
value.startswith('{') and value.endswith('}')
) or (
value.startswith('[') and value.endswith(']'))
)
yaml_ish = bool((value.startswith('{') and value.endswith('}')) or (value.startswith('[') and value.endswith(']')))
if yaml_ish:
if not HAS_YAML:
module.fail_json(msg="yaml is not installed, try 'pip install pyyaml'")
@@ -115,7 +111,7 @@ def main():
argument_spec=argument_spec,
required_one_of=[['name', 'settings']],
mutually_exclusive=[['name', 'settings']],
required_if=[['name', 'present', ['value']]]
required_if=[['name', 'present', ['value']]],
)
# Extract our parameters
@@ -145,10 +141,7 @@ def main():
json_output['new_values'][a_setting] = new_settings[a_setting]
if module._diff:
json_output['diff'] = {
'before': json_output['old_values'],
'after': json_output['new_values']
}
json_output['diff'] = {'before': json_output['old_values'], 'after': json_output['new_values']}
# If nothing needs an update we can simply exit with the response (as not changed)
if not needs_update:

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
@@ -87,21 +86,14 @@ def main():
org_id = module.resolve_name_to_id('organizations', organization)
# Attempt to look up team based on the provided name and org ID
team = module.get_one('teams', name_or_id=name, **{
'data': {
'organization': org_id
}
})
team = module.get_one('teams', name_or_id=name, **{'data': {'organization': org_id}})
if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this
module.delete_if_needed(team)
# Create the data that gets sent for create and update
team_fields = {
'name': new_name if new_name else (module.get_item_name(team) if team else name),
'organization': org_id
}
team_fields = {'name': new_name if new_name else (module.get_item_name(team) if team else name), 'organization': org_id}
if description is not None:
team_fields['description'] = description

View File

@@ -6,12 +6,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
---
@@ -150,7 +149,12 @@ def main():
],
# If we are state absent make sure one of existing_token or existing_token_id are present
required_if=[
['state', 'absent', ('existing_token', 'existing_token_id'), True, ],
[
'state',
'absent',
('existing_token', 'existing_token_id'),
True,
],
],
)
@@ -164,11 +168,14 @@ def main():
if state == 'absent':
if not existing_token:
existing_token = module.get_one('tokens', **{
'data': {
'id': existing_token_id,
existing_token = module.get_one(
'tokens',
**{
'data': {
'id': existing_token_id,
}
}
})
)
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this
module.delete_if_needed(existing_token)
@@ -189,10 +196,11 @@ def main():
# If the state was present and we can let the module build or update the existing item, this will return on its own
module.create_or_update_if_needed(
None, new_fields,
endpoint='tokens', item_type='token',
associations={
},
None,
new_fields,
endpoint='tokens',
item_type='token',
associations={},
on_create=return_token,
)

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''

View File

@@ -6,12 +6,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
---
@@ -240,8 +239,11 @@ def main():
if copy_from:
# a new existing item is formed when copying and is returned.
existing_item = module.copy_item(
existing_item, copy_from, name,
endpoint='workflow_job_templates', item_type='workflow_job_template',
existing_item,
copy_from,
name,
endpoint='workflow_job_templates',
item_type='workflow_job_template',
copy_lookup_data={},
)
@@ -260,10 +262,18 @@ def main():
# Create the data that gets sent for create and update
new_fields['name'] = new_name if new_name else (module.get_item_name(existing_item) if existing_item else name)
for field_name in (
'description', 'survey_enabled', 'allow_simultaneous',
'limit', 'scm_branch', 'extra_vars',
'ask_inventory_on_launch', 'ask_scm_branch_on_launch', 'ask_limit_on_launch', 'ask_variables_on_launch',
'webhook_service',):
'description',
'survey_enabled',
'allow_simultaneous',
'limit',
'scm_branch',
'extra_vars',
'ask_inventory_on_launch',
'ask_scm_branch_on_launch',
'ask_limit_on_launch',
'ask_variables_on_launch',
'webhook_service',
):
field_val = module.params.get(field_name)
if field_val:
new_fields[field_name] = field_val
@@ -302,12 +312,12 @@ def main():
association_fields['labels'] = []
for item in labels:
association_fields['labels'].append(module.resolve_name_to_id('labels', item))
# Code to use once Issue #7567 is resolved
# search_fields = {'name': item}
# if organization:
# search_fields['organization'] = organization_id
# label_id = module.get_one('labels', **{'data': search_fields})
# association_fields['labels'].append(label_id)
# Code to use once Issue #7567 is resolved
# search_fields = {'name': item}
# if organization:
# search_fields['organization'] = organization_id
# label_id = module.get_one('labels', **{'data': search_fields})
# association_fields['labels'].append(label_id)
on_change = None
new_spec = module.params.get('survey_spec')
@@ -324,10 +334,13 @@ def main():
# If the state was present and we can let the module build or update the existing item, this will return on its own
module.create_or_update_if_needed(
existing_item, new_fields,
endpoint='workflow_job_templates', item_type='workflow_job_template',
existing_item,
new_fields,
endpoint='workflow_job_templates',
item_type='workflow_job_template',
associations=association_fields,
on_create=on_change, on_update=on_change
on_create=on_change,
on_update=on_change,
)

View File

@@ -6,12 +6,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
---
@@ -234,13 +233,9 @@ def main():
if organization:
organization_id = module.resolve_name_to_id('organizations', organization)
wfjt_search_fields['organization'] = organization_id
wfjt_data = module.get_one('workflow_job_templates', name_or_id=workflow_job_template, **{
'data': wfjt_search_fields
})
wfjt_data = module.get_one('workflow_job_templates', name_or_id=workflow_job_template, **{'data': wfjt_search_fields})
if wfjt_data is None:
module.fail_json(msg="The workflow {0} in organization {1} was not found on the Tower server".format(
workflow_job_template, organization
))
module.fail_json(msg="The workflow {0} in organization {1} was not found on the Tower server".format(workflow_job_template, organization))
workflow_job_template_id = wfjt_data['id']
search_fields['workflow_job_template'] = new_fields['workflow_job_template'] = workflow_job_template_id
@@ -261,8 +256,17 @@ def main():
# Create the data that gets sent for create and update
for field_name in (
'identifier', 'extra_data', 'scm_branch', 'job_type', 'job_tags', 'skip_tags',
'limit', 'diff_mode', 'verbosity', 'all_parents_must_converge',):
'identifier',
'extra_data',
'scm_branch',
'job_type',
'job_tags',
'skip_tags',
'limit',
'diff_mode',
'verbosity',
'all_parents_must_converge',
):
field_val = module.params.get(field_name)
if field_val:
new_fields[field_name] = field_val
@@ -294,9 +298,12 @@ def main():
# If the state was present and we can let the module build or update the existing item, this will return on its own
module.create_or_update_if_needed(
existing_item, new_fields,
endpoint='workflow_job_template_nodes', item_type='workflow_job_template_node', auto_exit=not approval_node,
associations=association_fields
existing_item,
new_fields,
endpoint='workflow_job_template_nodes',
item_type='workflow_job_template_node',
auto_exit=not approval_node,
associations=association_fields,
)
# Create approval node unified template or update existing
@@ -326,9 +333,7 @@ def main():
existing_item = module.get_endpoint(workflow_job_template_node['related']['unified_job_template'])['json']
approval_endpoint = 'workflow_job_template_nodes/{0}/create_approval_template/'.format(workflow_job_template_node_id)
module.create_or_update_if_needed(
existing_item, new_fields,
endpoint=approval_endpoint, item_type='workflow_job_template_approval_node',
associations=association_fields
existing_item, new_fields, endpoint=approval_endpoint, item_type='workflow_job_template_approval_node', associations=association_fields
)
module.exit_json(**module.json_output)

View File

@@ -4,11 +4,10 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
ANSIBLE_METADATA = {'metadata_version': '1.1', 'status': ['preview'], 'supported_by': 'community'}
DOCUMENTATION = '''
---
@@ -180,12 +179,7 @@ def main():
module.exit_json(**module.json_output)
# Invoke wait function
module.wait_on_url(
url=result['json']['url'],
object_name=name,
object_type='Workflow Job',
timeout=timeout, interval=interval
)
module.wait_on_url(url=result['json']['url'], object_name=name, object_type='Workflow Job', timeout=timeout, interval=interval)
module.exit_json(**module.json_output)

View File

@@ -5,12 +5,11 @@
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'status': ['deprecated'],
'supported_by': 'community',
'metadata_version': '1.1'}
ANSIBLE_METADATA = {'status': ['deprecated'], 'supported_by': 'community', 'metadata_version': '1.1'}
DOCUMENTATION = '''
@@ -108,11 +107,7 @@ EXAMPLES = '''
RETURN = ''' # '''
from ..module_utils.tower_legacy import (
TowerLegacyModule,
tower_auth_config,
tower_check_mode
)
from ..module_utils.tower_legacy import TowerLegacyModule, tower_auth_config, tower_check_mode
import json
@@ -140,16 +135,16 @@ def main():
state=dict(choices=['present', 'absent'], default='present'),
)
module = TowerLegacyModule(
argument_spec=argument_spec,
supports_check_mode=False
)
module = TowerLegacyModule(argument_spec=argument_spec, supports_check_mode=False)
module.deprecate(msg=(
"This module is replaced by the combination of tower_workflow_job_template and "
"tower_workflow_job_template_node. This uses the old tower-cli and wll be "
"removed in 2022."
), version='awx.awx:14.0.0')
module.deprecate(
msg=(
"This module is replaced by the combination of tower_workflow_job_template and "
"tower_workflow_job_template_node. This uses the old tower-cli and wll be "
"removed in 2022."
),
version='awx.awx:14.0.0',
)
name = module.params.get('name')
state = module.params.get('state')
@@ -159,10 +154,7 @@ def main():
schema = module.params.get('schema')
if schema and state == 'absent':
module.fail_json(
msg='Setting schema when state is absent is not allowed',
changed=False
)
module.fail_json(msg='Setting schema when state is absent is not allowed', changed=False)
json_output = {'workflow_template': name, 'state': state}
@@ -179,15 +171,10 @@ def main():
if module.params.get('organization'):
organization_res = tower_cli.get_resource('organization')
try:
organization = organization_res.get(
name=module.params.get('organization'))
organization = organization_res.get(name=module.params.get('organization'))
params['organization'] = organization['id']
except exc.NotFound as excinfo:
module.fail_json(
msg='Failed to update organization source,'
'organization not found: {0}'.format(excinfo),
changed=False
)
module.fail_json(msg='Failed to update organization source,' 'organization not found: {0}'.format(excinfo), changed=False)
if module.params.get('survey'):
params['survey_spec'] = module.params.get('survey')
@@ -198,8 +185,7 @@ def main():
if module.params.get('ask_inventory'):
params['ask_inventory_on_launch'] = module.params.get('ask_inventory')
for key in ('allow_simultaneous', 'inventory',
'survey_enabled', 'description'):
for key in ('allow_simultaneous', 'inventory', 'survey_enabled', 'description'):
if module.params.get(key):
params[key] = module.params.get(key)
@@ -219,8 +205,13 @@ def main():
params['fail_on_missing'] = False
result = wfjt_res.delete(**params)
except (exc.ConnectionError, exc.BadRequest, exc.AuthError) as excinfo:
module.fail_json(msg='Failed to update workflow template: \
{0}'.format(excinfo), changed=False)
module.fail_json(
msg='Failed to update workflow template: \
{0}'.format(
excinfo
),
changed=False,
)
json_output['changed'] = result['changed']
module.exit_json(**json_output)

View File

@@ -1,3 +0,0 @@
[flake8]
max-line-length=160
ignore=E402

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import io
@@ -21,6 +22,7 @@ from django.db import transaction
try:
import tower_cli # noqa
HAS_TOWER_CLI = True
except ImportError:
HAS_TOWER_CLI = False
@@ -30,6 +32,7 @@ try:
# However, awxkit will not contain api whih causes a stack failure down on line 170 when we try to mock it.
# So here we are importing awxkit.api to prevent that. Then you only get an error on tests for awxkit functionality.
import awxkit.api
HAS_AWX_KIT = True
except ImportError:
HAS_AWX_KIT = False
@@ -38,9 +41,9 @@ logger = logging.getLogger('awx.main.tests')
def sanitize_dict(din):
'''Sanitize Django response data to purge it of internal types
"""Sanitize Django response data to purge it of internal types
so it may be used to cast a requests response object
'''
"""
if isinstance(din, (int, str, type(None), bool)):
return din # native JSON types, no problem
elif isinstance(din, datetime.datetime):
@@ -62,9 +65,7 @@ def collection_path_set(monkeypatch):
"""Monkey patch sys.path, insert the root of the collection folder
so that content can be imported without being fully packaged
"""
base_folder = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
)
base_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
monkeypatch.syspath_prepend(base_folder)
@@ -76,15 +77,16 @@ def collection_import():
go through this fixture so that can be changed if needed.
For instance, we could switch to fully-qualified import paths.
"""
def rf(path):
return importlib.import_module(path)
return rf
@pytest.fixture
def run_module(request, collection_import):
def rf(module_name, module_params, request_user):
def new_request(self, method, url, **kwargs):
kwargs_copy = kwargs.copy()
if 'data' in kwargs:
@@ -95,8 +97,7 @@ def run_module(request, collection_import):
elif isinstance(kwargs['data'], str):
kwargs_copy['data'] = json.loads(kwargs['data'])
else:
raise RuntimeError('Expected data to be dict or str, got {0}, data: {1}'.format(
type(kwargs['data']), kwargs['data']))
raise RuntimeError('Expected data to be dict or str, got {0}, data: {1}'.format(type(kwargs['data']), kwargs['data']))
if 'params' in kwargs and method == 'GET':
# query params for GET are handled a bit differently by
# tower-cli and python requests as opposed to REST framework APIRequestFactory
@@ -123,11 +124,7 @@ def run_module(request, collection_import):
resp.headers = {'X-API-Product-Name': 'AWX', 'X-API-Product-Version': '0.0.1-devel'}
if request.config.getoption('verbose') > 0:
logger.info(
'%s %s by %s, code:%s',
method, '/api/' + url.split('/api/')[1],
request_user.username, resp.status_code
)
logger.info('%s %s by %s, code:%s', method, '/api/' + url.split('/api/')[1], request_user.username, resp.status_code)
resp.request = PreparedRequest()
resp.request.prepare(method=method, url=url)
@@ -135,10 +132,7 @@ def run_module(request, collection_import):
def new_open(self, method, url, **kwargs):
r = new_request(self, method, url, **kwargs)
m = mock.MagicMock(read=mock.MagicMock(return_value=r._content),
status=r.status_code,
getheader=mock.MagicMock(side_effect=r.headers.get)
)
m = mock.MagicMock(read=mock.MagicMock(return_value=r._content), status=r.status_code, getheader=mock.MagicMock(side_effect=r.headers.get))
return m
stdout_buffer = io.StringIO()
@@ -163,7 +157,7 @@ def run_module(request, collection_import):
elif getattr(resource_module, 'TowerLegacyModule', None):
resource_class = resource_module.TowerLegacyModule
else:
raise("The module has neither a TowerLegacyModule, TowerAWXKitModule or a TowerAPIModule")
raise ("The module has neither a TowerLegacyModule, TowerAWXKitModule or a TowerAPIModule")
with mock.patch.object(resource_class, '_load_params', new=mock_load_params):
# Call the test utility (like a mock server) instead of issuing HTTP requests
@@ -204,18 +198,9 @@ def run_module(request, collection_import):
@pytest.fixture
def survey_spec():
return {
"spec": [
{
"index": 0,
"question_name": "my question?",
"default": "mydef",
"variable": "myvar",
"type": "text",
"required": False
}
],
"spec": [{"index": 0, "question_name": "my question?", "default": "mydef", "variable": "myvar", "type": "text", "required": False}],
"description": "test",
"name": "test"
"name": "test",
}
@@ -234,46 +219,32 @@ def project(organization):
local_path='_92__test_proj',
scm_revision='1234567890123456789012345678901234567890',
scm_url='localhost',
scm_type='git'
scm_type='git',
)
@pytest.fixture
def inventory(organization):
return Inventory.objects.create(
name='test-inv',
organization=organization
)
return Inventory.objects.create(name='test-inv', organization=organization)
@pytest.fixture
def job_template(project, inventory):
return JobTemplate.objects.create(
name='test-jt',
project=project,
inventory=inventory,
playbook='helloworld.yml'
)
return JobTemplate.objects.create(name='test-jt', project=project, inventory=inventory, playbook='helloworld.yml')
@pytest.fixture
def machine_credential(organization):
ssh_type = CredentialType.defaults['ssh']()
ssh_type.save()
return Credential.objects.create(
credential_type=ssh_type, name='machine-cred',
inputs={'username': 'test_user', 'password': 'pas4word'}
)
return Credential.objects.create(credential_type=ssh_type, name='machine-cred', inputs={'username': 'test_user', 'password': 'pas4word'})
@pytest.fixture
def vault_credential(organization):
ct = CredentialType.defaults['vault']()
ct.save()
return Credential.objects.create(
credential_type=ct, name='vault-cred',
inputs={'vault_id': 'foo', 'vault_password': 'pas4word'}
)
return Credential.objects.create(credential_type=ct, name='vault-cred', inputs={'vault_id': 'foo', 'vault_password': 'pas4word'})
@pytest.fixture

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -10,26 +11,17 @@ from awx.main.models.ad_hoc_commands import AdHocCommand
@pytest.mark.django_db
def test_ad_hoc_command_wait_successful(run_module, admin_user):
command = AdHocCommand.objects.create(status='successful', started=now(), finished=now())
result = run_module('tower_ad_hoc_command_wait', dict(
command_id=command.id
), admin_user)
result = run_module('tower_ad_hoc_command_wait', dict(command_id=command.id), admin_user)
result.pop('invocation', None)
assert result.pop('finished', '')[:10] == str(command.finished)[:10]
assert result.pop('started', '')[:10] == str(command.started)[:10]
assert result == {
"status": "successful",
"changed": False,
"elapsed": str(command.elapsed),
"id": command.id
}
assert result == {"status": "successful", "changed": False, "elapsed": str(command.elapsed), "id": command.id}
@pytest.mark.django_db
def test_ad_hoc_command_wait_failed(run_module, admin_user):
command = AdHocCommand.objects.create(status='failed', started=now(), finished=now())
result = run_module('tower_ad_hoc_command_wait', dict(
command_id=command.id
), admin_user)
result = run_module('tower_ad_hoc_command_wait', dict(command_id=command.id), admin_user)
result.pop('invocation', None)
assert result.pop('finished', '')[:10] == str(command.finished)[:10]
assert result.pop('started', '')[:10] == str(command.started)[:10]
@@ -39,17 +31,12 @@ def test_ad_hoc_command_wait_failed(run_module, admin_user):
"changed": False,
"elapsed": str(command.elapsed),
"id": command.id,
"msg": "The ad hoc command - 1, failed"
"msg": "The ad hoc command - 1, failed",
}
@pytest.mark.django_db
def test_ad_hoc_command_wait_not_found(run_module, admin_user):
result = run_module('tower_ad_hoc_command_wait', dict(
command_id=42
), admin_user)
result = run_module('tower_ad_hoc_command_wait', dict(command_id=42), admin_user)
result.pop('invocation', None)
assert result == {
"failed": True,
"msg": "Unable to wait on ad hoc command 42; that ID does not exist in Tower."
}
assert result == {"failed": True, "msg": "Unable to wait on ad hoc command 42; that ID does not exist in Tower."}

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -23,15 +24,26 @@ no_module_for_endpoint = []
# Some modules work on the related fields of an endpoint. These modules will not have an auto-associated endpoint
no_endpoint_for_module = [
'tower_import', 'tower_meta', 'tower_export', 'tower_inventory_source_update', 'tower_job_launch', 'tower_job_wait',
'tower_job_list', 'tower_license', 'tower_ping', 'tower_receive', 'tower_send', 'tower_workflow_launch',
'tower_job_cancel', 'tower_workflow_template', 'tower_ad_hoc_command_wait', 'tower_ad_hoc_command_cancel',
'tower_import',
'tower_meta',
'tower_export',
'tower_inventory_source_update',
'tower_job_launch',
'tower_job_wait',
'tower_job_list',
'tower_license',
'tower_ping',
'tower_receive',
'tower_send',
'tower_workflow_launch',
'tower_job_cancel',
'tower_workflow_template',
'tower_ad_hoc_command_wait',
'tower_ad_hoc_command_cancel',
]
# Global module parameters we can ignore
ignore_parameters = [
'state', 'new_name', 'update_secrets', 'copy_from'
]
ignore_parameters = ['state', 'new_name', 'update_secrets', 'copy_from']
# Some modules take additional parameters that do not appear in the API
# Add the module name as the key with the value being the list of params to ignore
@@ -57,9 +69,7 @@ no_api_parameter_ok = {
# When this tool was created we were not feature complete. Adding something in here indicates a module
# that needs to be developed. If the module is found on the file system it will auto-detect that the
# work is being done and will bypass this check. At some point this module should be removed from this list.
needs_development = [
'tower_inventory_script', 'tower_workflow_approval'
]
needs_development = ['tower_inventory_script', 'tower_workflow_approval']
needs_param_development = {
'tower_host': ['instance_id'],
}
@@ -150,9 +160,7 @@ def determine_state(module_id, endpoint, module, parameter, api_option, module_o
def test_completeness(collection_import, request, admin_user, job_template):
option_comparison = {}
# Load a list of existing module files from disk
base_folder = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.pardir, os.pardir)
)
base_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), os.pardir, os.pardir))
module_directory = os.path.join(base_folder, 'plugins', 'modules')
for root, dirs, files in os.walk(module_directory):
if root == module_directory:
@@ -166,10 +174,7 @@ def test_completeness(collection_import, request, admin_user, job_template):
'module_name': module_name,
}
resource_module = collection_import('plugins.modules.{0}'.format(module_name))
option_comparison[module_name]['module_options'] = yaml.load(
resource_module.DOCUMENTATION,
Loader=yaml.SafeLoader
)['options']
option_comparison[module_name]['module_options'] = yaml.load(resource_module.DOCUMENTATION, Loader=yaml.SafeLoader)['options']
endpoint_response = _request('get')(
url='/api/v2/',
@@ -222,51 +227,86 @@ def test_completeness(collection_import, request, admin_user, job_template):
longest_option_name = len(option)
# Print out some headers
print("".join([
"End Point", " " * (longest_endpoint - len("End Point")),
" | Module Name", " " * (longest_module_name - len("Module Name")),
" | Option", " " * (longest_option_name - len("Option")),
" | API | Module | State",
]))
print("-|-".join([
"-" * longest_endpoint,
"-" * longest_module_name,
"-" * longest_option_name,
"---",
"------",
"---------------------------------------------",
]))
print(
"".join(
[
"End Point",
" " * (longest_endpoint - len("End Point")),
" | Module Name",
" " * (longest_module_name - len("Module Name")),
" | Option",
" " * (longest_option_name - len("Option")),
" | API | Module | State",
]
)
)
print(
"-|-".join(
[
"-" * longest_endpoint,
"-" * longest_module_name,
"-" * longest_option_name,
"---",
"------",
"---------------------------------------------",
]
)
)
# Print out all of our data
for module in sorted(option_comparison):
module_data = option_comparison[module]
all_param_names = list(set(module_data['api_options']) | set(module_data['module_options']))
for parameter in sorted(all_param_names):
print("".join([
module_data['endpoint'], " " * (longest_endpoint - len(module_data['endpoint'])), " | ",
module_data['module_name'], " " * (longest_module_name - len(module_data['module_name'])), " | ",
parameter, " " * (longest_option_name - len(parameter)), " | ",
" X " if (parameter in module_data['api_options']) else ' ', " | ",
' X ' if (parameter in module_data['module_options']) else ' ', " | ",
determine_state(
module,
module_data['endpoint'],
module_data['module_name'],
parameter,
module_data['api_options'][parameter] if (parameter in module_data['api_options']) else None,
module_data['module_options'][parameter] if (parameter in module_data['module_options']) else None,
),
]))
print(
"".join(
[
module_data['endpoint'],
" " * (longest_endpoint - len(module_data['endpoint'])),
" | ",
module_data['module_name'],
" " * (longest_module_name - len(module_data['module_name'])),
" | ",
parameter,
" " * (longest_option_name - len(parameter)),
" | ",
" X " if (parameter in module_data['api_options']) else ' ',
" | ",
' X ' if (parameter in module_data['module_options']) else ' ',
" | ",
determine_state(
module,
module_data['endpoint'],
module_data['module_name'],
parameter,
module_data['api_options'][parameter] if (parameter in module_data['api_options']) else None,
module_data['module_options'][parameter] if (parameter in module_data['module_options']) else None,
),
]
)
)
# This handles cases were we got no params from the options page nor from the modules
if len(all_param_names) == 0:
print("".join([
module_data['endpoint'], " " * (longest_endpoint - len(module_data['endpoint'])), " | ",
module_data['module_name'], " " * (longest_module_name - len(module_data['module_name'])), " | ",
"N/A", " " * (longest_option_name - len("N/A")), " | ",
' ', " | ",
' ', " | ",
determine_state(module, module_data['endpoint'], module_data['module_name'], 'N/A', None, None),
]))
print(
"".join(
[
module_data['endpoint'],
" " * (longest_endpoint - len(module_data['endpoint'])),
" | ",
module_data['module_name'],
" " * (longest_module_name - len(module_data['module_name'])),
" | ",
"N/A",
" " * (longest_option_name - len("N/A")),
" | ",
' ',
" | ",
' ',
" | ",
determine_state(module, module_data['endpoint'], module_data['module_name'], 'N/A', None, None),
]
)
)
if return_value != 0:
raise Exception("One or more failures caused issues")

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -11,22 +12,12 @@ def cred_type():
# Make a credential type which will be used by the credential
ct = CredentialType.objects.create(
name='Ansible Galaxy Token',
inputs={
"fields": [
{
"id": "token",
"type": "string",
"secret": True,
"label": "Ansible Galaxy Secret Token Value"
}
],
"required": ["token"]
},
inputs={"fields": [{"id": "token", "type": "string", "secret": True, "label": "Ansible Galaxy Secret Token Value"}], "required": ["token"]},
injectors={
"extra_vars": {
"galaxy_token": "{{token}}",
}
}
},
)
return ct
@@ -38,12 +29,7 @@ def test_create_machine_credential(run_module, admin_user, organization, silence
ct = CredentialType.defaults['ssh']()
ct.save()
# Example from docs
result = run_module('tower_credential', dict(
name='Test Machine Credential',
organization=organization.name,
kind='ssh',
state='present'
), admin_user)
result = run_module('tower_credential', dict(name='Test Machine Credential', organization=organization.name, kind='ssh', state='present'), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -61,14 +47,11 @@ def test_create_vault_credential(run_module, admin_user, organization, silence_d
ct = CredentialType.defaults['vault']()
ct.save()
result = run_module('tower_credential', dict(
name='Test Vault Credential',
organization=organization.name,
kind='vault',
vault_id='bar',
vault_password='foobar',
state='present'
), admin_user)
result = run_module(
'tower_credential',
dict(name='Test Vault Credential', organization=organization.name, kind='vault', vault_id='bar', vault_password='foobar', state='present'),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -83,13 +66,9 @@ def test_create_vault_credential(run_module, admin_user, organization, silence_d
@pytest.mark.django_db
def test_ct_precedence_over_kind(run_module, admin_user, organization, cred_type, silence_deprecation):
result = run_module('tower_credential', dict(
name='A credential',
organization=organization.name,
kind='ssh',
credential_type=cred_type.name,
state='present'
), admin_user)
result = run_module(
'tower_credential', dict(name='A credential', organization=organization.name, kind='ssh', credential_type=cred_type.name, state='present'), admin_user
)
assert not result.get('failed', False), result.get('msg', result)
cred = Credential.objects.get(name='A credential')
@@ -102,14 +81,18 @@ def test_input_overrides_old_fields(run_module, admin_user, organization, silenc
# create the vault credential type
ct = CredentialType.defaults['vault']()
ct.save()
result = run_module('tower_credential', dict(
name='A Vault credential',
organization=organization.name,
kind='vault',
vault_id='1234',
inputs={'vault_id': 'asdf'},
state='present',
), admin_user)
result = run_module(
'tower_credential',
dict(
name='A Vault credential',
organization=organization.name,
kind='vault',
vault_id='1234',
inputs={'vault_id': 'asdf'},
state='present',
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
cred = Credential.objects.get(name='A Vault credential')
@@ -120,12 +103,7 @@ def test_input_overrides_old_fields(run_module, admin_user, organization, silenc
@pytest.mark.django_db
def test_missing_credential_type(run_module, admin_user, organization):
Organization.objects.create(name='test-org')
result = run_module('tower_credential', dict(
name='A credential',
organization=organization.name,
credential_type='foobar',
state='present'
), admin_user)
result = run_module('tower_credential', dict(name='A credential', organization=organization.name, credential_type='foobar', state='present'), admin_user)
assert result.get('failed', False), result
assert 'credential_type' in result['msg']
assert 'foobar' in result['msg']
@@ -134,12 +112,11 @@ def test_missing_credential_type(run_module, admin_user, organization):
@pytest.mark.django_db
def test_make_use_of_custom_credential_type(run_module, organization, admin_user, cred_type):
result = run_module('tower_credential', dict(
name='Galaxy Token for Steve',
organization=organization.name,
credential_type=cred_type.name,
inputs={'token': '7rEZK38DJl58A7RxA6EC7lLvUHbBQ1'}
), admin_user)
result = run_module(
'tower_credential',
dict(name='Galaxy Token for Steve', organization=organization.name, credential_type=cred_type.name, inputs={'token': '7rEZK38DJl58A7RxA6EC7lLvUHbBQ1'}),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', False), result
@@ -159,13 +136,17 @@ def test_secret_field_write_twice(run_module, organization, admin_user, cred_typ
val1 = '7rEZK38DJl58A7RxA6EC7lLvUHbBQ1'
val2 = '7rEZ238DJl5837rxA6xxxlLvUHbBQ1'
for val in (val1, val2):
result = run_module('tower_credential', dict(
name='Galaxy Token for Steve',
organization=organization.name,
credential_type=cred_type.name,
inputs={'token': val},
update_secrets=update_secrets
), admin_user)
result = run_module(
'tower_credential',
dict(
name='Galaxy Token for Steve',
organization=organization.name,
credential_type=cred_type.name,
inputs={'token': val},
update_secrets=update_secrets,
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
if update_secrets:

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -17,13 +18,7 @@ def aim_cred_type():
@pytest.fixture
def source_cred_aim(aim_cred_type):
return Credential.objects.create(
name='CyberArk AIM Cred',
credential_type=aim_cred_type,
inputs={
"url": "https://cyberark.example.com",
"app_id": "myAppID",
"verify": "false"
}
name='CyberArk AIM Cred', credential_type=aim_cred_type, inputs={"url": "https://cyberark.example.com", "app_id": "myAppID", "verify": "false"}
)
@@ -31,20 +26,19 @@ def source_cred_aim(aim_cred_type):
def test_aim_credential_source(run_module, admin_user, organization, source_cred_aim, silence_deprecation):
ct = CredentialType.defaults['ssh']()
ct.save()
tgt_cred = Credential.objects.create(
name='Test Machine Credential',
organization=organization,
credential_type=ct,
inputs={'username': 'bob'}
)
tgt_cred = Credential.objects.create(name='Test Machine Credential', organization=organization, credential_type=ct, inputs={'username': 'bob'})
result = run_module('tower_credential_input_source', dict(
source_credential=source_cred_aim.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"object_query": "Safe=SUPERSAFE;Object=MyAccount"},
state='present'
), admin_user)
result = run_module(
'tower_credential_input_source',
dict(
source_credential=source_cred_aim.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"object_query": "Safe=SUPERSAFE;Object=MyAccount"},
state='present',
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -68,12 +62,7 @@ def source_cred_conjur(organization):
return Credential.objects.create(
name='CyberArk CONJUR Cred',
credential_type=ct,
inputs={
"url": "https://cyberark.example.com",
"api_key": "myApiKey",
"account": "account",
"username": "username"
}
inputs={"url": "https://cyberark.example.com", "api_key": "myApiKey", "account": "account", "username": "username"},
)
@@ -81,20 +70,19 @@ def source_cred_conjur(organization):
def test_conjur_credential_source(run_module, admin_user, organization, source_cred_conjur, silence_deprecation):
ct = CredentialType.defaults['ssh']()
ct.save()
tgt_cred = Credential.objects.create(
name='Test Machine Credential',
organization=organization,
credential_type=ct,
inputs={'username': 'bob'}
)
tgt_cred = Credential.objects.create(name='Test Machine Credential', organization=organization, credential_type=ct, inputs={'username': 'bob'})
result = run_module('tower_credential_input_source', dict(
source_credential=source_cred_conjur.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"secret_path": "/path/to/secret"},
state='present'
), admin_user)
result = run_module(
'tower_credential_input_source',
dict(
source_credential=source_cred_conjur.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"secret_path": "/path/to/secret"},
state='present',
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -123,8 +111,8 @@ def source_cred_hashi_secret(organization):
"token": "myApiKey",
"role_id": "role",
"secret_id": "secret",
"default_auth_path": "path-to-approle"
}
"default_auth_path": "path-to-approle",
},
)
@@ -132,20 +120,19 @@ def source_cred_hashi_secret(organization):
def test_hashi_secret_credential_source(run_module, admin_user, organization, source_cred_hashi_secret, silence_deprecation):
ct = CredentialType.defaults['ssh']()
ct.save()
tgt_cred = Credential.objects.create(
name='Test Machine Credential',
organization=organization,
credential_type=ct,
inputs={'username': 'bob'}
)
tgt_cred = Credential.objects.create(name='Test Machine Credential', organization=organization, credential_type=ct, inputs={'username': 'bob'})
result = run_module('tower_credential_input_source', dict(
source_credential=source_cred_hashi_secret.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"secret_path": "/path/to/secret", "auth_path": "/path/to/auth", "secret_backend": "backend", "secret_key": "a_key"},
state='present'
), admin_user)
result = run_module(
'tower_credential_input_source',
dict(
source_credential=source_cred_hashi_secret.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"secret_path": "/path/to/secret", "auth_path": "/path/to/auth", "secret_backend": "backend", "secret_key": "a_key"},
state='present',
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -172,12 +159,7 @@ def source_cred_hashi_ssh(organization):
return Credential.objects.create(
name='HashiCorp ssh Cred',
credential_type=ct,
inputs={
"url": "https://ssh.hash.example.com",
"token": "myApiKey",
"role_id": "role",
"secret_id": "secret"
}
inputs={"url": "https://ssh.hash.example.com", "token": "myApiKey", "role_id": "role", "secret_id": "secret"},
)
@@ -185,20 +167,19 @@ def source_cred_hashi_ssh(organization):
def test_hashi_ssh_credential_source(run_module, admin_user, organization, source_cred_hashi_ssh, silence_deprecation):
ct = CredentialType.defaults['ssh']()
ct.save()
tgt_cred = Credential.objects.create(
name='Test Machine Credential',
organization=organization,
credential_type=ct,
inputs={'username': 'bob'}
)
tgt_cred = Credential.objects.create(name='Test Machine Credential', organization=organization, credential_type=ct, inputs={'username': 'bob'})
result = run_module('tower_credential_input_source', dict(
source_credential=source_cred_hashi_ssh.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"secret_path": "/path/to/secret", "auth_path": "/path/to/auth", "role": "role", "public_key": "a_key", "valid_principals": "some_value"},
state='present'
), admin_user)
result = run_module(
'tower_credential_input_source',
dict(
source_credential=source_cred_hashi_ssh.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"secret_path": "/path/to/secret", "auth_path": "/path/to/auth", "role": "role", "public_key": "a_key", "valid_principals": "some_value"},
state='present',
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -232,7 +213,7 @@ def source_cred_azure_kv(organization):
"secret": "secret",
"tenant": "tenant",
"cloud_name": "the_cloud",
}
},
)
@@ -240,20 +221,19 @@ def source_cred_azure_kv(organization):
def test_azure_kv_credential_source(run_module, admin_user, organization, source_cred_azure_kv, silence_deprecation):
ct = CredentialType.defaults['ssh']()
ct.save()
tgt_cred = Credential.objects.create(
name='Test Machine Credential',
organization=organization,
credential_type=ct,
inputs={'username': 'bob'}
)
tgt_cred = Credential.objects.create(name='Test Machine Credential', organization=organization, credential_type=ct, inputs={'username': 'bob'})
result = run_module('tower_credential_input_source', dict(
source_credential=source_cred_azure_kv.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"secret_field": "my_pass"},
state='present'
), admin_user)
result = run_module(
'tower_credential_input_source',
dict(
source_credential=source_cred_azure_kv.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"secret_field": "my_pass"},
state='present',
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -274,11 +254,7 @@ def source_cred_aim_alt(aim_cred_type):
return Credential.objects.create(
name='Alternate CyberArk AIM Cred',
credential_type=aim_cred_type,
inputs={
"url": "https://cyberark-alt.example.com",
"app_id": "myAltID",
"verify": "false"
}
inputs={"url": "https://cyberark-alt.example.com", "app_id": "myAltID", "verify": "false"},
)
@@ -286,41 +262,43 @@ def source_cred_aim_alt(aim_cred_type):
def test_aim_credential_source(run_module, admin_user, organization, source_cred_aim, source_cred_aim_alt, silence_deprecation):
ct = CredentialType.defaults['ssh']()
ct.save()
tgt_cred = Credential.objects.create(
name='Test Machine Credential',
organization=organization,
credential_type=ct,
inputs={'username': 'bob'}
)
tgt_cred = Credential.objects.create(name='Test Machine Credential', organization=organization, credential_type=ct, inputs={'username': 'bob'})
result = run_module('tower_credential_input_source', dict(
source_credential=source_cred_aim.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"object_query": "Safe=SUPERSAFE;Object=MyAccount"},
state='present'
), admin_user)
result = run_module(
'tower_credential_input_source',
dict(
source_credential=source_cred_aim.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"object_query": "Safe=SUPERSAFE;Object=MyAccount"},
state='present',
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
unchangedResult = run_module('tower_credential_input_source', dict(
source_credential=source_cred_aim.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"object_query": "Safe=SUPERSAFE;Object=MyAccount"},
state='present'
), admin_user)
unchangedResult = run_module(
'tower_credential_input_source',
dict(
source_credential=source_cred_aim.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"object_query": "Safe=SUPERSAFE;Object=MyAccount"},
state='present',
),
admin_user,
)
assert not unchangedResult.get('failed', False), result.get('msg', result)
assert not unchangedResult.get('changed'), result
changedResult = run_module('tower_credential_input_source', dict(
source_credential=source_cred_aim_alt.name,
target_credential=tgt_cred.name,
input_field_name='password',
state='present'
), admin_user)
changedResult = run_module(
'tower_credential_input_source',
dict(source_credential=source_cred_aim_alt.name, target_credential=tgt_cred.name, input_field_name='password', state='present'),
admin_user,
)
assert not changedResult.get('failed', False), changedResult.get('msg', result)
assert changedResult.get('changed'), result
@@ -347,7 +325,7 @@ def source_cred_centrify_secret(organization):
"url": "https://tenant_id.my.centrify-dev.net",
"client_id": "secretuser@tenant",
"client_password": "secretuserpassword",
}
},
)
@@ -355,20 +333,19 @@ def source_cred_centrify_secret(organization):
def test_centrify_vault_credential_source(run_module, admin_user, organization, source_cred_centrify_secret, silence_deprecation):
ct = CredentialType.defaults['ssh']()
ct.save()
tgt_cred = Credential.objects.create(
name='Test Machine Credential',
organization=organization,
credential_type=ct,
inputs={'username': 'bob'}
)
tgt_cred = Credential.objects.create(name='Test Machine Credential', organization=organization, credential_type=ct, inputs={'username': 'bob'})
result = run_module('tower_credential_input_source', dict(
source_credential=source_cred_centrify_secret.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"system-name": "systemname", "account-name": "accountname"},
state='present'
), admin_user)
result = run_module(
'tower_credential_input_source',
dict(
source_credential=source_cred_centrify_secret.name,
target_credential=tgt_cred.name,
input_field_name='password',
metadata={"system-name": "systemname", "account-name": "accountname"},
state='present',
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -9,14 +10,18 @@ from awx.main.models import CredentialType
@pytest.mark.django_db
def test_create_custom_credential_type(run_module, admin_user, silence_deprecation):
# Example from docs
result = run_module('tower_credential_type', dict(
name='Nexus',
description='Credentials type for Nexus',
kind='cloud',
inputs={"fields": [{"id": "server", "type": "string", "default": "", "label": ""}], "required": []},
injectors={'extra_vars': {'nexus_credential': 'test'}},
state='present',
), admin_user)
result = run_module(
'tower_credential_type',
dict(
name='Nexus',
description='Credentials type for Nexus',
kind='cloud',
inputs={"fields": [{"id": "server", "type": "string", "default": "", "label": ""}], "required": []},
injectors={'extra_vars': {'nexus_credential': 'test'}},
state='present',
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -31,19 +36,27 @@ def test_create_custom_credential_type(run_module, admin_user, silence_deprecati
@pytest.mark.django_db
def test_changed_false_with_api_changes(run_module, admin_user):
result = run_module('tower_credential_type', dict(
name='foo',
kind='cloud',
inputs={"fields": [{"id": "env_value", "label": "foo", "default": "foo"}]},
injectors={'env': {'TEST_ENV_VAR': '{{ env_value }}'}},
), admin_user)
result = run_module(
'tower_credential_type',
dict(
name='foo',
kind='cloud',
inputs={"fields": [{"id": "env_value", "label": "foo", "default": "foo"}]},
injectors={'env': {'TEST_ENV_VAR': '{{ env_value }}'}},
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
result = run_module('tower_credential_type', dict(
name='foo',
inputs={"fields": [{"id": "env_value", "label": "foo", "default": "foo"}]},
injectors={'env': {'TEST_ENV_VAR': '{{ env_value }}'}},
), admin_user)
result = run_module(
'tower_credential_type',
dict(
name='foo',
inputs={"fields": [{"id": "env_value", "label": "foo", "default": "foo"}]},
injectors={'env': {'TEST_ENV_VAR': '{{ env_value }}'}},
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert not result.get('changed'), result

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -12,12 +13,7 @@ def test_create_group(run_module, admin_user):
inv = Inventory.objects.create(name='test-inv', organization=org)
variables = {"ansible_network_os": "iosxr"}
result = run_module('tower_group', dict(
name='Test Group',
inventory='test-inv',
variables=variables,
state='present'
), admin_user)
result = run_module('tower_group', dict(name='Test Group', inventory='test-inv', variables=variables, state='present'), admin_user)
assert result.get('changed'), result
group = Group.objects.get(name='Test Group')
@@ -42,13 +38,11 @@ def test_associate_hosts_and_children(run_module, admin_user, organization):
child = Group.objects.create(inventory=inv, name='child_group')
result = run_module('tower_group', dict(
name='Test Group',
inventory='test-inv',
hosts=[inv_hosts[1].name, inv_hosts[2].name],
children=[child.name],
state='present'
), admin_user)
result = run_module(
'tower_group',
dict(name='Test Group', inventory='test-inv', hosts=[inv_hosts[1].name, inv_hosts[2].name], children=[child.name], state='present'),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result['changed'] is True
@@ -62,13 +56,7 @@ def test_associate_on_create(run_module, admin_user, organization):
child = Group.objects.create(name='test-child', inventory=inv)
host = Host.objects.create(name='test-host', inventory=inv)
result = run_module('tower_group', dict(
name='Test Group',
inventory='test-inv',
hosts=[host.name],
groups=[child.name],
state='present'
), admin_user)
result = run_module('tower_group', dict(name='Test Group', inventory='test-inv', hosts=[host.name], groups=[child.name], state='present'), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result['changed'] is True
@@ -82,12 +70,7 @@ def test_children_alias_of_groups(run_module, admin_user, organization):
inv = Inventory.objects.create(name='test-inv', organization=organization)
group = Group.objects.create(name='Test Group', inventory=inv)
child = Group.objects.create(inventory=inv, name='child_group')
result = run_module('tower_group', dict(
name='Test Group',
inventory='test-inv',
groups=[child.name],
state='present'
), admin_user)
result = run_module('tower_group', dict(name='Test Group', inventory='test-inv', groups=[child.name], state='present'), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result['changed'] is True
@@ -104,11 +87,7 @@ def test_tower_group_idempotent(run_module, admin_user):
inventory=inv,
)
result = run_module('tower_group', dict(
name='Test Group',
inventory='test-inv',
state='present'
), admin_user)
result = run_module('tower_group', dict(name='Test Group', inventory='test-inv', state='present'), admin_user)
result.pop('invocation')
assert result == {

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -9,12 +10,9 @@ from awx.main.tests.functional.conftest import kube_credential, credentialtype_k
@pytest.mark.django_db
def test_instance_group_create(run_module, admin_user):
result = run_module('tower_instance_group', {
'name': 'foo-group',
'policy_instance_percentage': 34,
'policy_instance_minimum': 12,
'state': 'present'
}, admin_user)
result = run_module(
'tower_instance_group', {'name': 'foo-group', 'policy_instance_percentage': 34, 'policy_instance_minimum': 12, 'state': 'present'}, admin_user
)
assert not result.get('failed', False), result
assert result['changed']
@@ -26,11 +24,7 @@ def test_instance_group_create(run_module, admin_user):
new_instance = Instance.objects.create(hostname='foo.example.com')
# Set the new instance group only to the one instnace
result = run_module('tower_instance_group', {
'name': 'foo-group',
'instances': [new_instance.hostname],
'state': 'present'
}, admin_user)
result = run_module('tower_instance_group', {'name': 'foo-group', 'instances': [new_instance.hostname], 'state': 'present'}, admin_user)
assert not result.get('failed', False), result
assert result['changed']
@@ -47,25 +41,20 @@ def test_instance_group_create(run_module, admin_user):
def test_container_group_create(run_module, admin_user, kube_credential):
pod_spec = "{ 'Nothing': True }"
result = run_module('tower_instance_group', {
'name': 'foo-c-group',
'credential': kube_credential.id,
'is_container_group': True,
'state': 'present'
}, admin_user)
result = run_module(
'tower_instance_group', {'name': 'foo-c-group', 'credential': kube_credential.id, 'is_container_group': True, 'state': 'present'}, admin_user
)
assert not result.get('failed', False), result['msg']
assert result['changed']
ig = InstanceGroup.objects.get(name='foo-c-group')
assert ig.pod_spec_override == ''
result = run_module('tower_instance_group', {
'name': 'foo-c-group',
'credential': kube_credential.id,
'is_container_group': True,
'pod_spec_override': pod_spec,
'state': 'present'
}, admin_user)
result = run_module(
'tower_instance_group',
{'name': 'foo-c-group', 'credential': kube_credential.id, 'is_container_group': True, 'pod_spec_override': pod_spec, 'state': 'present'},
admin_user,
)
assert not result.get('failed', False), result['msg']
assert result['changed']

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -11,13 +12,17 @@ from awx.main.tests.functional.conftest import insights_credential, credentialty
def test_inventory_create(run_module, admin_user, organization, insights_credential):
# Create an insights credential
result = run_module('tower_inventory', {
'name': 'foo-inventory',
'organization': organization.name,
'variables': {'foo': 'bar', 'another-foo': {'barz': 'bar2'}},
'insights_credential': insights_credential.name,
'state': 'present'
}, admin_user)
result = run_module(
'tower_inventory',
{
'name': 'foo-inventory',
'organization': organization.name,
'variables': {'foo': 'bar', 'another-foo': {'barz': 'bar2'}},
'insights_credential': insights_credential.name,
'state': 'present',
},
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
inv = Inventory.objects.get(name='foo-inventory')
@@ -26,24 +31,18 @@ def test_inventory_create(run_module, admin_user, organization, insights_credent
result.pop('module_args', None)
result.pop('invocation', None)
assert result == {
"name": "foo-inventory",
"id": inv.id,
"changed": True
}
assert result == {"name": "foo-inventory", "id": inv.id, "changed": True}
assert inv.organization_id == organization.id
@pytest.mark.django_db
def test_invalid_smart_inventory_create(run_module, admin_user, organization):
result = run_module('tower_inventory', {
'name': 'foo-inventory',
'organization': organization.name,
'kind': 'smart',
'host_filter': 'ansible',
'state': 'present'
}, admin_user)
result = run_module(
'tower_inventory',
{'name': 'foo-inventory', 'organization': organization.name, 'kind': 'smart', 'host_filter': 'ansible', 'state': 'present'},
admin_user,
)
assert result.get('failed', False), result
assert 'Invalid query ansible' in result['msg']
@@ -51,13 +50,11 @@ def test_invalid_smart_inventory_create(run_module, admin_user, organization):
@pytest.mark.django_db
def test_valid_smart_inventory_create(run_module, admin_user, organization):
result = run_module('tower_inventory', {
'name': 'foo-inventory',
'organization': organization.name,
'kind': 'smart',
'host_filter': 'name=my_host',
'state': 'present'
}, admin_user)
result = run_module(
'tower_inventory',
{'name': 'foo-inventory', 'organization': organization.name, 'kind': 'smart', 'host_filter': 'name=my_host', 'state': 'present'},
admin_user,
)
assert not result.get('failed', False), result
inv = Inventory.objects.get(name='foo-inventory')

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -26,14 +27,11 @@ def project(base_inventory):
@pytest.mark.django_db
def test_inventory_source_create(run_module, admin_user, base_inventory, project):
source_path = '/var/lib/awx/example_source_path/'
result = run_module('tower_inventory_source', dict(
name='foo',
inventory=base_inventory.name,
state='present',
source='scm',
source_path=source_path,
source_project=project.name
), admin_user)
result = run_module(
'tower_inventory_source',
dict(name='foo', inventory=base_inventory.name, state='present', source='scm', source_path=source_path, source_project=project.name),
admin_user,
)
assert result.pop('changed', None), result
inv_src = InventorySource.objects.get(name='foo')
@@ -51,12 +49,7 @@ def test_create_inventory_source_implied_org(run_module, admin_user):
inv = Inventory.objects.create(name='test-inv', organization=org)
# Credential is not required for ec2 source, because of IAM roles
result = run_module('tower_inventory_source', dict(
name='Test Inventory Source',
inventory='test-inv',
source='ec2',
state='present'
), admin_user)
result = run_module('tower_inventory_source', dict(name='Test Inventory Source', inventory='test-inv', source='ec2', state='present'), admin_user)
assert result.pop('changed', None), result
inv_src = InventorySource.objects.get(name='Test Inventory Source')
@@ -78,13 +71,11 @@ def test_create_inventory_source_multiple_orgs(run_module, admin_user):
org2 = Organization.objects.create(name='test-org-number-two')
inv2 = Inventory.objects.create(name='test-inv', organization=org2)
result = run_module('tower_inventory_source', dict(
name='Test Inventory Source',
inventory=inv2.name,
organization='test-org-number-two',
source='ec2',
state='present'
), admin_user)
result = run_module(
'tower_inventory_source',
dict(name='Test Inventory Source', inventory=inv2.name, organization='test-org-number-two', source='ec2', state='present'),
admin_user,
)
assert result.pop('changed', None), result
inv_src = InventorySource.objects.get(name='Test Inventory Source')
@@ -99,24 +90,14 @@ def test_create_inventory_source_multiple_orgs(run_module, admin_user):
@pytest.mark.django_db
def test_falsy_value(run_module, admin_user, base_inventory):
result = run_module('tower_inventory_source', dict(
name='falsy-test',
inventory=base_inventory.name,
source='ec2',
update_on_launch=True
), admin_user)
result = run_module('tower_inventory_source', dict(name='falsy-test', inventory=base_inventory.name, source='ec2', update_on_launch=True), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', None), result
inv_src = InventorySource.objects.get(name='falsy-test')
assert inv_src.update_on_launch is True
result = run_module('tower_inventory_source', dict(
name='falsy-test',
inventory=base_inventory.name,
source='ec2',
update_on_launch=False
), admin_user)
result = run_module('tower_inventory_source', dict(name='falsy-test', inventory=base_inventory.name, source='ec2', update_on_launch=False), admin_user)
inv_src.refresh_from_db()
assert inv_src.update_on_launch is False
@@ -146,12 +127,7 @@ def test_falsy_value(run_module, admin_user, base_inventory):
@pytest.mark.django_db
def test_missing_required_credential(run_module, admin_user, base_inventory):
result = run_module('tower_inventory_source', dict(
name='Test Azure Source',
inventory=base_inventory.name,
source='azure_rm',
state='present'
), admin_user)
result = run_module('tower_inventory_source', dict(name='Test Azure Source', inventory=base_inventory.name, source='azure_rm', state='present'), admin_user)
assert result.pop('failed', None) is True, result
assert 'Credential is required for a cloud source' in result.get('msg', '')
@@ -159,13 +135,11 @@ def test_missing_required_credential(run_module, admin_user, base_inventory):
@pytest.mark.django_db
def test_source_project_not_for_cloud(run_module, admin_user, base_inventory, project):
result = run_module('tower_inventory_source', dict(
name='Test ec2 Inventory Source',
inventory=base_inventory.name,
source='ec2',
state='present',
source_project=project.name
), admin_user)
result = run_module(
'tower_inventory_source',
dict(name='Test ec2 Inventory Source', inventory=base_inventory.name, source='ec2', state='present', source_project=project.name),
admin_user,
)
assert result.pop('failed', None) is True, result
assert 'Cannot set source_project if not SCM type' in result.get('msg', '')
@@ -173,13 +147,11 @@ def test_source_project_not_for_cloud(run_module, admin_user, base_inventory, pr
@pytest.mark.django_db
def test_source_path_not_for_cloud(run_module, admin_user, base_inventory):
result = run_module('tower_inventory_source', dict(
name='Test ec2 Inventory Source',
inventory=base_inventory.name,
source='ec2',
state='present',
source_path='where/am/I'
), admin_user)
result = run_module(
'tower_inventory_source',
dict(name='Test ec2 Inventory Source', inventory=base_inventory.name, source='ec2', state='present', source_path='where/am/I'),
admin_user,
)
assert result.pop('failed', None) is True, result
assert 'Cannot set source_path if not SCM type' in result.get('msg', '')
@@ -187,13 +159,13 @@ def test_source_path_not_for_cloud(run_module, admin_user, base_inventory):
@pytest.mark.django_db
def test_scm_source_needs_project(run_module, admin_user, base_inventory):
result = run_module('tower_inventory_source', dict(
name='SCM inventory without project',
inventory=base_inventory.name,
state='present',
source='scm',
source_path='/var/lib/awx/example_source_path/'
), admin_user)
result = run_module(
'tower_inventory_source',
dict(
name='SCM inventory without project', inventory=base_inventory.name, state='present', source='scm', source_path='/var/lib/awx/example_source_path/'
),
admin_user,
)
assert result.pop('failed', None), result
assert 'Project required for scm type sources' in result.get('msg', '')

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -10,46 +11,25 @@ from awx.main.models import Job
@pytest.mark.django_db
def test_job_wait_successful(run_module, admin_user):
job = Job.objects.create(status='successful', started=now(), finished=now())
result = run_module('tower_job_wait', dict(
job_id=job.id
), admin_user)
result = run_module('tower_job_wait', dict(job_id=job.id), admin_user)
result.pop('invocation', None)
assert result.pop('finished', '')[:10] == str(job.finished)[:10]
assert result.pop('started', '')[:10] == str(job.started)[:10]
assert result == {
"status": "successful",
"changed": False,
"elapsed": str(job.elapsed),
"id": job.id
}
assert result == {"status": "successful", "changed": False, "elapsed": str(job.elapsed), "id": job.id}
@pytest.mark.django_db
def test_job_wait_failed(run_module, admin_user):
job = Job.objects.create(status='failed', started=now(), finished=now())
result = run_module('tower_job_wait', dict(
job_id=job.id
), admin_user)
result = run_module('tower_job_wait', dict(job_id=job.id), admin_user)
result.pop('invocation', None)
assert result.pop('finished', '')[:10] == str(job.finished)[:10]
assert result.pop('started', '')[:10] == str(job.started)[:10]
assert result == {
"status": "failed",
"failed": True,
"changed": False,
"elapsed": str(job.elapsed),
"id": job.id,
"msg": "Job with id 1 failed"
}
assert result == {"status": "failed", "failed": True, "changed": False, "elapsed": str(job.elapsed), "id": job.id, "msg": "Job with id 1 failed"}
@pytest.mark.django_db
def test_job_wait_not_found(run_module, admin_user):
result = run_module('tower_job_wait', dict(
job_id=42
), admin_user)
result = run_module('tower_job_wait', dict(job_id=42), admin_user)
result.pop('invocation', None)
assert result == {
"failed": True,
"msg": "Unable to wait on job 42; that ID does not exist in Tower."
}
assert result == {"failed": True, "msg": "Unable to wait on job 42; that ID does not exist in Tower."}

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -10,11 +11,13 @@ from awx.main.models import ActivityStream, JobTemplate, Job, NotificationTempla
def test_create_job_template(run_module, admin_user, project, inventory):
module_args = {
'name': 'foo', 'playbook': 'helloworld.yml',
'project': project.name, 'inventory': inventory.name,
'name': 'foo',
'playbook': 'helloworld.yml',
'project': project.name,
'inventory': inventory.name,
'extra_vars': {'foo': 'bar'},
'job_type': 'run',
'state': 'present'
'state': 'present',
}
result = run_module('tower_job_template', module_args, admin_user)
@@ -22,14 +25,7 @@ def test_create_job_template(run_module, admin_user, project, inventory):
jt = JobTemplate.objects.get(name='foo')
assert jt.extra_vars == '{"foo": "bar"}'
assert result == {
"name": "foo",
"id": jt.id,
"changed": True,
"invocation": {
"module_args": module_args
}
}
assert result == {"name": "foo", "id": jt.id, "changed": True, "invocation": {"module_args": module_args}}
assert jt.project_id == project.id
assert jt.inventory_id == inventory.id
@@ -39,8 +35,10 @@ def test_create_job_template(run_module, admin_user, project, inventory):
def test_resets_job_template_values(run_module, admin_user, project, inventory):
module_args = {
'name': 'foo', 'playbook': 'helloworld.yml',
'project': project.name, 'inventory': inventory.name,
'name': 'foo',
'playbook': 'helloworld.yml',
'project': project.name,
'inventory': inventory.name,
'extra_vars': {'foo': 'bar'},
'job_type': 'run',
'state': 'present',
@@ -59,8 +57,10 @@ def test_resets_job_template_values(run_module, admin_user, project, inventory):
assert jt.ask_limit_on_launch
module_args = {
'name': 'foo', 'playbook': 'helloworld.yml',
'project': project.name, 'inventory': inventory.name,
'name': 'foo',
'playbook': 'helloworld.yml',
'project': project.name,
'inventory': inventory.name,
'extra_vars': {'foo': 'bar'},
'job_type': 'run',
'state': 'present',
@@ -89,17 +89,18 @@ def test_job_launch_with_prompting(run_module, admin_user, project, organization
playbook='helloworld.yml',
ask_variables_on_launch=True,
ask_inventory_on_launch=True,
ask_credential_on_launch=True
ask_credential_on_launch=True,
)
result = run_module(
'tower_job_launch',
dict(
job_template='foo',
inventory=inventory.name,
credential=machine_credential.name,
extra_vars={"var1": "My First Variable", "var2": "My Second Variable", "var3": "My Third Variable"},
),
admin_user,
)
result = run_module('tower_job_launch', dict(
job_template='foo',
inventory=inventory.name,
credential=machine_credential.name,
extra_vars={"var1": "My First Variable",
"var2": "My Second Variable",
"var3": "My Third Variable"
}
), admin_user)
assert result.pop('changed', None), result
job = Job.objects.get(id=result['id'])
@@ -109,51 +110,44 @@ def test_job_launch_with_prompting(run_module, admin_user, project, organization
@pytest.mark.django_db
def test_job_template_with_new_credentials(
run_module, admin_user, project, inventory,
machine_credential, vault_credential):
result = run_module('tower_job_template', dict(
name='foo',
playbook='helloworld.yml',
project=project.name,
inventory=inventory.name,
credentials=[machine_credential.name, vault_credential.name]
), admin_user)
def test_job_template_with_new_credentials(run_module, admin_user, project, inventory, machine_credential, vault_credential):
result = run_module(
'tower_job_template',
dict(
name='foo', playbook='helloworld.yml', project=project.name, inventory=inventory.name, credentials=[machine_credential.name, vault_credential.name]
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', False), result
jt = JobTemplate.objects.get(pk=result['id'])
assert set([machine_credential.id, vault_credential.id]) == set([
cred.pk for cred in jt.credentials.all()])
assert set([machine_credential.id, vault_credential.id]) == set([cred.pk for cred in jt.credentials.all()])
prior_ct = ActivityStream.objects.count()
result = run_module('tower_job_template', dict(
name='foo',
playbook='helloworld.yml',
project=project.name,
inventory=inventory.name,
credentials=[machine_credential.name, vault_credential.name]
), admin_user)
result = run_module(
'tower_job_template',
dict(
name='foo', playbook='helloworld.yml', project=project.name, inventory=inventory.name, credentials=[machine_credential.name, vault_credential.name]
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert not result.get('changed', True), result
jt.refresh_from_db()
assert result['id'] == jt.id
assert set([machine_credential.id, vault_credential.id]) == set([
cred.pk for cred in jt.credentials.all()])
assert set([machine_credential.id, vault_credential.id]) == set([cred.pk for cred in jt.credentials.all()])
assert ActivityStream.objects.count() == prior_ct
@pytest.mark.django_db
def test_job_template_with_survey_spec(run_module, admin_user, project, inventory, survey_spec):
result = run_module('tower_job_template', dict(
name='foo',
playbook='helloworld.yml',
project=project.name,
inventory=inventory.name,
survey_spec=survey_spec,
survey_enabled=True
), admin_user)
result = run_module(
'tower_job_template',
dict(name='foo', playbook='helloworld.yml', project=project.name, inventory=inventory.name, survey_spec=survey_spec, survey_enabled=True),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', False), result
jt = JobTemplate.objects.get(pk=result['id'])
@@ -161,14 +155,11 @@ def test_job_template_with_survey_spec(run_module, admin_user, project, inventor
assert jt.survey_spec == survey_spec
prior_ct = ActivityStream.objects.count()
result = run_module('tower_job_template', dict(
name='foo',
playbook='helloworld.yml',
project=project.name,
inventory=inventory.name,
survey_spec=survey_spec,
survey_enabled=True
), admin_user)
result = run_module(
'tower_job_template',
dict(name='foo', playbook='helloworld.yml', project=project.name, inventory=inventory.name, survey_spec=survey_spec, survey_enabled=True),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert not result.get('changed', True), result
jt.refresh_from_db()
@@ -180,14 +171,11 @@ def test_job_template_with_survey_spec(run_module, admin_user, project, inventor
@pytest.mark.django_db
def test_job_template_with_wrong_survey_spec(run_module, admin_user, project, inventory, survey_spec):
result = run_module('tower_job_template', dict(
name='foo',
playbook='helloworld.yml',
project=project.name,
inventory=inventory.name,
survey_spec=survey_spec,
survey_enabled=True
), admin_user)
result = run_module(
'tower_job_template',
dict(name='foo', playbook='helloworld.yml', project=project.name, inventory=inventory.name, survey_spec=survey_spec, survey_enabled=True),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', False), result
jt = JobTemplate.objects.get(pk=result['id'])
@@ -198,14 +186,11 @@ def test_job_template_with_wrong_survey_spec(run_module, admin_user, project, in
del survey_spec['description']
result = run_module('tower_job_template', dict(
name='foo',
playbook='helloworld.yml',
project=project.name,
inventory=inventory.name,
survey_spec=survey_spec,
survey_enabled=True
), admin_user)
result = run_module(
'tower_job_template',
dict(name='foo', playbook='helloworld.yml', project=project.name, inventory=inventory.name, survey_spec=survey_spec, survey_enabled=True),
admin_user,
)
assert result.get('failed', True)
assert result.get('msg') == "Failed to update survey: Field 'description' is missing from survey spec."
@@ -213,35 +198,23 @@ def test_job_template_with_wrong_survey_spec(run_module, admin_user, project, in
@pytest.mark.django_db
def test_job_template_with_survey_encrypted_default(run_module, admin_user, project, inventory, silence_warning):
spec = {
"spec": [
{
"index": 0,
"question_name": "my question?",
"default": "very_secret_value",
"variable": "myvar",
"type": "password",
"required": False
}
],
"spec": [{"index": 0, "question_name": "my question?", "default": "very_secret_value", "variable": "myvar", "type": "password", "required": False}],
"description": "test",
"name": "test"
"name": "test",
}
for i in range(2):
result = run_module('tower_job_template', dict(
name='foo',
playbook='helloworld.yml',
project=project.name,
inventory=inventory.name,
survey_spec=spec,
survey_enabled=True
), admin_user)
result = run_module(
'tower_job_template',
dict(name='foo', playbook='helloworld.yml', project=project.name, inventory=inventory.name, survey_spec=spec, survey_enabled=True),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', False), result # not actually desired, but assert for sanity
silence_warning.assert_called_once_with(
"The field survey_spec of job_template {0} has encrypted data and "
"may inaccurately report task is changed.".format(result['id']))
"The field survey_spec of job_template {0} has encrypted data and " "may inaccurately report task is changed.".format(result['id'])
)
@pytest.mark.django_db
@@ -253,15 +226,9 @@ def test_associate_only_on_success(run_module, admin_user, organization, project
ask_inventory_on_launch=True,
)
create_kwargs = dict(
notification_configuration={
'url': 'http://www.example.com/hook',
'headers': {
'X-Custom-Header': 'value123'
},
'password': 'bar'
},
notification_configuration={'url': 'http://www.example.com/hook', 'headers': {'X-Custom-Header': 'value123'}, 'password': 'bar'},
notification_type='webhook',
organization=organization
organization=organization,
)
nt1 = NotificationTemplate.objects.create(name='nt1', **create_kwargs)
nt2 = NotificationTemplate.objects.create(name='nt2', **create_kwargs)
@@ -269,12 +236,9 @@ def test_associate_only_on_success(run_module, admin_user, organization, project
jt.notification_templates_error.add(nt1)
# test preservation of error NTs when success NTs are added
result = run_module('tower_job_template', dict(
name='foo',
playbook='helloworld.yml',
project=project.name,
notification_templates_success=['nt2']
), admin_user)
result = run_module(
'tower_job_template', dict(name='foo', playbook='helloworld.yml', project=project.name, notification_templates_success=['nt2']), admin_user
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', True), result
@@ -282,12 +246,7 @@ def test_associate_only_on_success(run_module, admin_user, organization, project
assert list(jt.notification_templates_error.values_list('id', flat=True)) == [nt1.id]
# test removal to empty list
result = run_module('tower_job_template', dict(
name='foo',
playbook='helloworld.yml',
project=project.name,
notification_templates_success=[]
), admin_user)
result = run_module('tower_job_template', dict(name='foo', playbook='helloworld.yml', project=project.name, notification_templates_success=[]), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', True), result

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -8,10 +9,7 @@ from awx.main.models import Label
@pytest.mark.django_db
def test_create_label(run_module, admin_user, organization):
result = run_module('tower_label', dict(
name='test-label',
organization=organization.name
), admin_user)
result = run_module('tower_label', dict(name='test-label', organization=organization.name), admin_user)
assert not result.get('failed'), result.get('msg', result)
assert result.get('changed', False)
@@ -20,10 +18,7 @@ def test_create_label(run_module, admin_user, organization):
@pytest.mark.django_db
def test_create_label_using_org_id(run_module, admin_user, organization):
result = run_module('tower_label', dict(
name='test-label',
organization=organization.id
), admin_user)
result = run_module('tower_label', dict(name='test-label', organization=organization.id), admin_user)
assert not result.get('failed'), result.get('msg', result)
assert result.get('changed', False)
@@ -34,11 +29,7 @@ def test_create_label_using_org_id(run_module, admin_user, organization):
def test_modify_label(run_module, admin_user, organization):
label = Label.objects.create(name='test-label', organization=organization)
result = run_module('tower_label', dict(
name='test-label',
new_name='renamed-label',
organization=organization.name
), admin_user)
result = run_module('tower_label', dict(name='test-label', new_name='renamed-label', organization=organization.name), admin_user)
assert not result.get('failed'), result.get('msg', result)
assert result.get('changed', False)

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import json
@@ -41,9 +42,7 @@ def test_version_warning(collection_import, silence_warning):
my_module._COLLECTION_TYPE = "not-junk"
my_module.collection_to_version['not-junk'] = 'not-junk'
my_module.get_endpoint('ping')
silence_warning.assert_called_once_with(
'You are running collection version 1.0.0 but connecting to tower version 1.2.3'
)
silence_warning.assert_called_once_with('You are running collection version 1.0.0 but connecting to tower version 1.2.3')
def test_type_warning(collection_import, silence_warning):
@@ -57,20 +56,13 @@ def test_type_warning(collection_import, silence_warning):
my_module._COLLECTION_TYPE = "junk"
my_module.collection_to_version['junk'] = 'junk'
my_module.get_endpoint('ping')
silence_warning.assert_called_once_with(
'You are using the junk version of this collection but connecting to not-junk'
)
silence_warning.assert_called_once_with('You are using the junk version of this collection but connecting to not-junk')
def test_duplicate_config(collection_import, silence_warning):
# imports done here because of PATH issues unique to this test suite
TowerAPIModule = collection_import('plugins.module_utils.tower_api').TowerAPIModule
data = {
'name': 'zigzoom',
'zig': 'zoom',
'tower_username': 'bob',
'tower_config_file': 'my_config'
}
data = {'name': 'zigzoom', 'zig': 'zoom', 'tower_username': 'bob', 'tower_config_file': 'my_config'}
with mock.patch.object(TowerAPIModule, 'load_config') as mock_load:
argument_spec = dict(
@@ -95,13 +87,11 @@ def test_no_templated_values(collection_import):
"""
TowerAPIModule = collection_import('plugins.module_utils.tower_api').TowerAPIModule
assert TowerAPIModule._COLLECTION_VERSION == "0.0.1-devel", (
'The collection version is templated when the collection is built '
'and the code should retain the placeholder of "0.0.1-devel".'
'The collection version is templated when the collection is built ' 'and the code should retain the placeholder of "0.0.1-devel".'
)
InventoryModule = collection_import('plugins.inventory.tower').InventoryModule
assert InventoryModule.NAME == 'awx.awx.tower', (
'The inventory plugin FQCN is templated when the collection is built '
'and the code should retain the default of awx.awx.'
'The inventory plugin FQCN is templated when the collection is built ' 'and the code should retain the default of awx.awx.'
)
@@ -115,15 +105,10 @@ def test_conflicting_name_and_id(run_module, admin_user):
org_by_id = Organization.objects.create(name='foo')
slug = str(org_by_id.id)
org_by_name = Organization.objects.create(name=slug)
result = run_module('tower_team', {
'name': 'foo_team', 'description': 'fooin around',
'organization': slug
}, admin_user)
result = run_module('tower_team', {'name': 'foo_team', 'description': 'fooin around', 'organization': slug}, admin_user)
assert not result.get('failed', False), result.get('msg', result)
team = Team.objects.filter(name='foo_team').first()
assert str(team.organization_id) == slug, (
'Lookup by id should be preferenced over name in cases of conflict.'
)
assert str(team.organization_id) == slug, 'Lookup by id should be preferenced over name in cases of conflict.'
assert team.organization.name == 'foo'
@@ -131,11 +116,21 @@ def test_multiple_lookup(run_module, admin_user):
org1 = Organization.objects.create(name='foo')
org2 = Organization.objects.create(name='bar')
inv = Inventory.objects.create(name='Foo Inv')
proj1 = Project.objects.create(name='foo', organization=org1, scm_type='git', scm_url="https://github.com/ansible/ansible-tower-samples",)
proj2 = Project.objects.create(name='foo', organization=org2, scm_type='git', scm_url="https://github.com/ansible/ansible-tower-samples",)
result = run_module('tower_job_template', {
'name': 'Demo Job Template', 'project': proj1.name, 'inventory': inv.id, 'playbook': 'hello_world.yml'
}, admin_user)
proj1 = Project.objects.create(
name='foo',
organization=org1,
scm_type='git',
scm_url="https://github.com/ansible/ansible-tower-samples",
)
proj2 = Project.objects.create(
name='foo',
organization=org2,
scm_type='git',
scm_url="https://github.com/ansible/ansible-tower-samples",
)
result = run_module(
'tower_job_template', {'name': 'Demo Job Template', 'project': proj1.name, 'inventory': inv.id, 'playbook': 'hello_world.yml'}, admin_user
)
assert result.get('failed', False)
assert 'projects' in result['msg']
assert 'foo' in result['msg']

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -7,19 +8,17 @@ from awx.main.models import NotificationTemplate, Job
def compare_with_encrypted(model_config, param_config):
'''Given a model_config from the database, assure that this is consistent
"""Given a model_config from the database, assure that this is consistent
with the config given in the notification_configuration parameter
this requires handling of password fields
'''
"""
for key, model_val in model_config.items():
param_val = param_config.get(key, 'missing')
if isinstance(model_val, str) and (model_val.startswith('$encrypted$') or param_val.startswith('$encrypted$')):
assert model_val.startswith('$encrypted$') # must be saved as encrypted
assert len(model_val) > len('$encrypted$')
else:
assert model_val == param_val, 'Config key {0} did not match, (model: {1}, input: {2})'.format(
key, model_val, param_val
)
assert model_val == param_val, 'Config key {0} did not match, (model: {1}, input: {2})'.format(key, model_val, param_val)
@pytest.mark.django_db
@@ -31,15 +30,20 @@ def test_create_modify_notification_template(run_module, admin_user, organizatio
'recipients': ['foo2@invalid.com'],
'host': 'smtp.example.com',
'port': 25,
'use_tls': False, 'use_ssl': False,
'timeout': 4
'use_tls': False,
'use_ssl': False,
'timeout': 4,
}
result = run_module('tower_notification_template', dict(
name='foo-notification-template',
organization=organization.name,
notification_type='email',
notification_configuration=nt_config,
), admin_user)
result = run_module(
'tower_notification_template',
dict(
name='foo-notification-template',
organization=organization.name,
notification_type='email',
notification_configuration=nt_config,
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.pop('changed', None), result
@@ -49,22 +53,30 @@ def test_create_modify_notification_template(run_module, admin_user, organizatio
# Test no-op, this is impossible if the notification_configuration is given
# because we cannot determine if password fields changed
result = run_module('tower_notification_template', dict(
name='foo-notification-template',
organization=organization.name,
notification_type='email',
), admin_user)
result = run_module(
'tower_notification_template',
dict(
name='foo-notification-template',
organization=organization.name,
notification_type='email',
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert not result.pop('changed', None), result
# Test a change in the configuration
nt_config['timeout'] = 12
result = run_module('tower_notification_template', dict(
name='foo-notification-template',
organization=organization.name,
notification_type='email',
notification_configuration=nt_config,
), admin_user)
result = run_module(
'tower_notification_template',
dict(
name='foo-notification-template',
organization=organization.name,
notification_type='email',
notification_configuration=nt_config,
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.pop('changed', None), result
@@ -74,39 +86,46 @@ def test_create_modify_notification_template(run_module, admin_user, organizatio
@pytest.mark.django_db
def test_invalid_notification_configuration(run_module, admin_user, organization):
result = run_module('tower_notification_template', dict(
name='foo-notification-template',
organization=organization.name,
notification_type='email',
notification_configuration={},
), admin_user)
result = run_module(
'tower_notification_template',
dict(
name='foo-notification-template',
organization=organization.name,
notification_type='email',
notification_configuration={},
),
admin_user,
)
assert result.get('failed', False), result.get('msg', result)
assert 'Missing required fields for Notification Configuration' in result['msg']
@pytest.mark.django_db
def test_deprecated_to_modern_no_op(run_module, admin_user, organization):
nt_config = {
'url': 'http://www.example.com/hook',
'headers': {
'X-Custom-Header': 'value123'
}
}
result = run_module('tower_notification_template', dict(
name='foo-notification-template',
organization=organization.name,
notification_type='webhook',
notification_configuration=nt_config,
), admin_user)
nt_config = {'url': 'http://www.example.com/hook', 'headers': {'X-Custom-Header': 'value123'}}
result = run_module(
'tower_notification_template',
dict(
name='foo-notification-template',
organization=organization.name,
notification_type='webhook',
notification_configuration=nt_config,
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.pop('changed', None), result
result = run_module('tower_notification_template', dict(
name='foo-notification-template',
organization=organization.name,
notification_type='webhook',
notification_configuration=nt_config,
), admin_user)
result = run_module(
'tower_notification_template',
dict(
name='foo-notification-template',
organization=organization.name,
notification_type='webhook',
notification_configuration=nt_config,
),
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert not result.pop('changed', None), result
@@ -119,21 +138,20 @@ def test_build_notification_message_undefined(run_module, admin_user, organizati
like "{{ job.created_by.first_name | default('unknown') }}"."""
job = Job.objects.create(name='foobar')
nt_config = {
'url': 'http://www.example.com/hook',
'headers': {
'X-Custom-Header': 'value123'
}
}
nt_config = {'url': 'http://www.example.com/hook', 'headers': {'X-Custom-Header': 'value123'}}
custom_start_template = {'body': '{"started_by": "{{ job.summary_fields.created_by.username | default(\'My Placeholder\') }}"}'}
messages = {'started': custom_start_template, 'success': None, 'error': None, 'workflow_approval': None}
result = run_module('tower_notification_template', dict(
name='foo-notification-template',
organization=organization.name,
notification_type='webhook',
notification_configuration=nt_config,
messages=messages,
), admin_user)
result = run_module(
'tower_notification_template',
dict(
name='foo-notification-template',
organization=organization.name,
notification_type='webhook',
notification_configuration=nt_config,
messages=messages,
),
admin_user,
)
nt = NotificationTemplate.objects.get(id=result['id'])
body = job.build_notification_message(nt, 'running')

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -26,13 +27,6 @@ def test_create_organization(run_module, admin_user):
assert result.get('changed'), result
org = Organization.objects.get(name='foo')
assert result == {
"name": "foo",
"changed": True,
"id": org.id,
"invocation": {
"module_args": module_args
}
}
assert result == {"name": "foo", "changed": True, "id": org.id, "invocation": {"module_args": module_args}}
assert org.description == 'barfoo'

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -8,17 +9,12 @@ from awx.main.models import Project
@pytest.mark.django_db
def test_create_project(run_module, admin_user, organization, silence_warning):
result = run_module('tower_project', dict(
name='foo',
organization=organization.name,
scm_type='git',
scm_url='https://foo.invalid',
wait=False,
scm_update_cache_timeout=5
), admin_user)
silence_warning.assert_called_once_with(
'scm_update_cache_timeout will be ignored since scm_update_on_launch '
'was not set to true')
result = run_module(
'tower_project',
dict(name='foo', organization=organization.name, scm_type='git', scm_url='https://foo.invalid', wait=False, scm_update_cache_timeout=5),
admin_user,
)
silence_warning.assert_called_once_with('scm_update_cache_timeout will be ignored since scm_update_on_launch ' 'was not set to true')
assert result.pop('changed', None), result
@@ -27,7 +23,4 @@ def test_create_project(run_module, admin_user, organization, silence_warning):
assert proj.organization == organization
result.pop('invocation')
assert result == {
'name': 'foo',
'id': proj.id
}
assert result == {'name': 'foo', 'id': proj.id}

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -13,12 +14,7 @@ def test_grant_organization_permission(run_module, admin_user, organization, sta
if state == 'absent':
organization.admin_role.members.add(rando)
result = run_module('tower_role', {
'user': rando.username,
'organization': organization.name,
'role': 'admin',
'state': state
}, admin_user)
result = run_module('tower_role', {'user': rando.username, 'organization': organization.name, 'role': 'admin', 'state': state}, admin_user)
assert not result.get('failed', False), result.get('msg', result)
if state == 'present':
@@ -35,12 +31,7 @@ def test_grant_workflow_permission(run_module, admin_user, organization, state):
if state == 'absent':
wfjt.execute_role.members.add(rando)
result = run_module('tower_role', {
'user': rando.username,
'workflow': wfjt.name,
'role': 'execute',
'state': state
}, admin_user)
result = run_module('tower_role', {'user': rando.username, 'workflow': wfjt.name, 'role': 'execute', 'state': state}, admin_user)
assert not result.get('failed', False), result.get('msg', result)
if state == 'present':
@@ -57,13 +48,11 @@ def test_grant_workflow_list_permission(run_module, admin_user, organization, st
if state == 'absent':
wfjt.execute_role.members.add(rando)
result = run_module('tower_role', {
'user': rando.username,
'lookup_organization': wfjt.organization.name,
'workflows': [wfjt.name],
'role': 'execute',
'state': state
}, admin_user)
result = run_module(
'tower_role',
{'user': rando.username, 'lookup_organization': wfjt.organization.name, 'workflows': [wfjt.name], 'role': 'execute', 'state': state},
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
if state == 'present':
@@ -80,12 +69,7 @@ def test_grant_workflow_approval_permission(run_module, admin_user, organization
if state == 'absent':
wfjt.execute_role.members.add(rando)
result = run_module('tower_role', {
'user': rando.username,
'workflow': wfjt.name,
'role': 'approval',
'state': state
}, admin_user)
result = run_module('tower_role', {'user': rando.username, 'workflow': wfjt.name, 'role': 'approval', 'state': state}, admin_user)
assert not result.get('failed', False), result.get('msg', result)
if state == 'present':
@@ -97,12 +81,7 @@ def test_grant_workflow_approval_permission(run_module, admin_user, organization
@pytest.mark.django_db
def test_invalid_role(run_module, admin_user, project):
rando = User.objects.create(username='rando')
result = run_module('tower_role', {
'user': rando.username,
'project': project.name,
'role': 'adhoc',
'state': 'present'
}, admin_user)
result = run_module('tower_role', {'user': rando.username, 'project': project.name, 'role': 'adhoc', 'state': 'present'}, admin_user)
assert result.get('failed', False)
msg = result.get('msg')
assert 'has no role adhoc_role' in msg

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -12,11 +13,7 @@ from awx.api.serializers import SchedulePreviewSerializer
@pytest.mark.django_db
def test_create_schedule(run_module, job_template, admin_user):
my_rrule = 'DTSTART;TZID=Zulu:20200416T034507 RRULE:FREQ=MONTHLY;INTERVAL=1'
result = run_module('tower_schedule', {
'name': 'foo_schedule',
'unified_job_template': job_template.name,
'rrule': my_rrule
}, admin_user)
result = run_module('tower_schedule', {'name': 'foo_schedule', 'unified_job_template': job_template.name, 'rrule': my_rrule}, admin_user)
assert not result.get('failed', False), result.get('msg', result)
schedule = Schedule.objects.filter(name='foo_schedule').first()
@@ -27,32 +24,49 @@ def test_create_schedule(run_module, job_template, admin_user):
assert schedule.rrule == my_rrule
@pytest.mark.parametrize("freq, kwargs, expect", [
# Test with a valid start date (no time) (also tests none frequency and count)
('none', {'start_date': '2020-04-16'}, 'DTSTART;TZID=America/New_York:20200416T000000 RRULE:FREQ=DAILY;COUNT=1;INTERVAL=1'),
# Test with a valid start date and time
('none', {'start_date': '2020-04-16 03:45:07'}, 'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=DAILY;COUNT=1;INTERVAL=1'),
# Test end_on as count (also integration test)
('minute', {'start_date': '2020-4-16 03:45:07', 'end_on': '2'}, 'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=MINUTELY;COUNT=2;INTERVAL=1'),
# Test end_on as date
('minute', {'start_date': '2020-4-16 03:45:07', 'end_on': '2020-4-17 03:45:07'},
'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=MINUTELY;UNTIL=20200417T034507;INTERVAL=1'),
# Test on_days as a single day
('week', {'start_date': '2020-4-16 03:45:07', 'on_days': 'saturday'},
'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=WEEKLY;BYDAY=SA;INTERVAL=1'),
# Test on_days as multiple days (with some whitespaces)
('week', {'start_date': '2020-4-16 03:45:07', 'on_days': 'saturday,monday , friday'},
'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=WEEKLY;BYDAY=MO,FR,SA;INTERVAL=1'),
# Test valid month_day_number
('month', {'start_date': '2020-4-16 03:45:07', 'month_day_number': '18'},
'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=MONTHLY;BYMONTHDAY=18;INTERVAL=1'),
# Test a valid on_the
('month', {'start_date': '2020-4-16 03:45:07', 'on_the': 'second sunday'},
'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=MONTHLY;BYSETPOS=2;BYDAY=SU;INTERVAL=1'),
# Test an valid timezone
('month', {'start_date': '2020-4-16 03:45:07', 'timezone': 'Zulu'},
'DTSTART;TZID=Zulu:20200416T034507 RRULE:FREQ=MONTHLY;INTERVAL=1'),
])
@pytest.mark.parametrize(
"freq, kwargs, expect",
[
# Test with a valid start date (no time) (also tests none frequency and count)
('none', {'start_date': '2020-04-16'}, 'DTSTART;TZID=America/New_York:20200416T000000 RRULE:FREQ=DAILY;COUNT=1;INTERVAL=1'),
# Test with a valid start date and time
('none', {'start_date': '2020-04-16 03:45:07'}, 'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=DAILY;COUNT=1;INTERVAL=1'),
# Test end_on as count (also integration test)
('minute', {'start_date': '2020-4-16 03:45:07', 'end_on': '2'}, 'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=MINUTELY;COUNT=2;INTERVAL=1'),
# Test end_on as date
(
'minute',
{'start_date': '2020-4-16 03:45:07', 'end_on': '2020-4-17 03:45:07'},
'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=MINUTELY;UNTIL=20200417T034507;INTERVAL=1',
),
# Test on_days as a single day
(
'week',
{'start_date': '2020-4-16 03:45:07', 'on_days': 'saturday'},
'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=WEEKLY;BYDAY=SA;INTERVAL=1',
),
# Test on_days as multiple days (with some whitespaces)
(
'week',
{'start_date': '2020-4-16 03:45:07', 'on_days': 'saturday,monday , friday'},
'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=WEEKLY;BYDAY=MO,FR,SA;INTERVAL=1',
),
# Test valid month_day_number
(
'month',
{'start_date': '2020-4-16 03:45:07', 'month_day_number': '18'},
'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=MONTHLY;BYMONTHDAY=18;INTERVAL=1',
),
# Test a valid on_the
(
'month',
{'start_date': '2020-4-16 03:45:07', 'on_the': 'second sunday'},
'DTSTART;TZID=America/New_York:20200416T034507 RRULE:FREQ=MONTHLY;BYSETPOS=2;BYDAY=SU;INTERVAL=1',
),
# Test an valid timezone
('month', {'start_date': '2020-4-16 03:45:07', 'timezone': 'Zulu'}, 'DTSTART;TZID=Zulu:20200416T034507 RRULE:FREQ=MONTHLY;INTERVAL=1'),
],
)
def test_rrule_lookup_plugin(collection_import, freq, kwargs, expect):
LookupModule = collection_import('plugins.lookup.tower_schedule_rrule').LookupModule
generated_rule = LookupModule.get_rrule(freq, kwargs)
@@ -75,31 +89,39 @@ def test_empty_schedule_rrule(collection_import, freq):
assert LookupModule.get_rrule(freq, {}).endswith(' RRULE:FREQ={0};INTERVAL=1'.format(pfreq))
@pytest.mark.parametrize("freq, kwargs, msg", [
# Test end_on as junk
('minute', {'start_date': '2020-4-16 03:45:07', 'end_on': 'junk'},
'Parameter end_on must either be an integer or in the format YYYY-MM-DD'),
# Test on_days as junk
('week', {'start_date': '2020-4-16 03:45:07', 'on_days': 'junk'},
'Parameter on_days must only contain values monday, tuesday, wednesday, thursday, friday, saturday, sunday'),
# Test combo of both month_day_number and on_the
('month', dict(start_date='2020-4-16 03:45:07', on_the='something', month_day_number='else'),
"Month based frequencies can have month_day_number or on_the but not both"),
# Test month_day_number as not an integer
('month', dict(start_date='2020-4-16 03:45:07', month_day_number='junk'), "month_day_number must be between 1 and 31"),
# Test month_day_number < 1
('month', dict(start_date='2020-4-16 03:45:07', month_day_number='0'), "month_day_number must be between 1 and 31"),
# Test month_day_number > 31
('month', dict(start_date='2020-4-16 03:45:07', month_day_number='32'), "month_day_number must be between 1 and 31"),
# Test on_the as junk
('month', dict(start_date='2020-4-16 03:45:07', on_the='junk'), "on_the parameter must be two words separated by a space"),
# Test on_the with invalid occurance
('month', dict(start_date='2020-4-16 03:45:07', on_the='junk wednesday'), "The first string of the on_the parameter is not valid"),
# Test on_the with invalid weekday
('month', dict(start_date='2020-4-16 03:45:07', on_the='second junk'), "Weekday portion of on_the parameter is not valid"),
# Test an invalid timezone
('month', dict(start_date='2020-4-16 03:45:07', timezone='junk'), 'Timezone parameter is not valid'),
])
@pytest.mark.parametrize(
"freq, kwargs, msg",
[
# Test end_on as junk
('minute', {'start_date': '2020-4-16 03:45:07', 'end_on': 'junk'}, 'Parameter end_on must either be an integer or in the format YYYY-MM-DD'),
# Test on_days as junk
(
'week',
{'start_date': '2020-4-16 03:45:07', 'on_days': 'junk'},
'Parameter on_days must only contain values monday, tuesday, wednesday, thursday, friday, saturday, sunday',
),
# Test combo of both month_day_number and on_the
(
'month',
dict(start_date='2020-4-16 03:45:07', on_the='something', month_day_number='else'),
"Month based frequencies can have month_day_number or on_the but not both",
),
# Test month_day_number as not an integer
('month', dict(start_date='2020-4-16 03:45:07', month_day_number='junk'), "month_day_number must be between 1 and 31"),
# Test month_day_number < 1
('month', dict(start_date='2020-4-16 03:45:07', month_day_number='0'), "month_day_number must be between 1 and 31"),
# Test month_day_number > 31
('month', dict(start_date='2020-4-16 03:45:07', month_day_number='32'), "month_day_number must be between 1 and 31"),
# Test on_the as junk
('month', dict(start_date='2020-4-16 03:45:07', on_the='junk'), "on_the parameter must be two words separated by a space"),
# Test on_the with invalid occurance
('month', dict(start_date='2020-4-16 03:45:07', on_the='junk wednesday'), "The first string of the on_the parameter is not valid"),
# Test on_the with invalid weekday
('month', dict(start_date='2020-4-16 03:45:07', on_the='second junk'), "Weekday portion of on_the parameter is not valid"),
# Test an invalid timezone
('month', dict(start_date='2020-4-16 03:45:07', timezone='junk'), 'Timezone parameter is not valid'),
],
)
def test_rrule_lookup_plugin_failure(collection_import, freq, kwargs, msg):
LookupModule = collection_import('plugins.lookup.tower_schedule_rrule').LookupModule
with pytest.raises(AnsibleError) as e:

View File

@@ -1,18 +1,11 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
import json
from awx.main.models import (
Organization,
Project,
Inventory,
Host,
CredentialType,
Credential,
JobTemplate
)
from awx.main.models import Organization, Project, Inventory, Host, CredentialType, Credential, JobTemplate
# warns based on password_management param, but not security issue
@@ -25,23 +18,14 @@ def test_receive_send_jt(run_module, admin_user, mocker, silence_deprecation):
scm_type='git',
scm_url='https://github.com/ansible/test-playbooks.git',
organization=org,
allow_override=True # so we do not require playbooks populated
allow_override=True, # so we do not require playbooks populated
)
inv = Inventory.objects.create(name='SRtest', organization=org)
Host.objects.create(name='SRtest', inventory=inv)
ct = CredentialType.defaults['ssh']()
ct.save()
cred = Credential.objects.create(
name='SRtest',
credential_type=ct,
organization=org
)
jt = JobTemplate.objects.create(
name='SRtest',
project=proj,
inventory=inv,
playbook='helloworld.yml'
)
cred = Credential.objects.create(name='SRtest', credential_type=ct, organization=org)
jt = JobTemplate.objects.create(name='SRtest', project=proj, inventory=inv, playbook='helloworld.yml')
jt.credentials.add(cred)
jt.admin_role.members.add(admin_user) # work around send/receive bug
@@ -51,10 +35,7 @@ def test_receive_send_jt(run_module, admin_user, mocker, silence_deprecation):
assert 'assets' in result, result
assets = result['assets']
assert not result.get('changed', True)
assert set(a['asset_type'] for a in assets) == set((
'organization', 'inventory', 'job_template', 'credential', 'project',
'user'
))
assert set(a['asset_type'] for a in assets) == set(('organization', 'inventory', 'job_template', 'credential', 'project', 'user'))
# delete everything
for obj in (jt, inv, proj, cred, org):

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -9,10 +10,7 @@ from awx.conf.models import Setting
@pytest.mark.django_db
def test_setting_flat_value(run_module, admin_user):
the_value = 'CN=service_account,OU=ServiceAccounts,DC=domain,DC=company,DC=org'
result = run_module('tower_settings', dict(
name='AUTH_LDAP_BIND_DN',
value=the_value
), admin_user)
result = run_module('tower_settings', dict(name='AUTH_LDAP_BIND_DN', value=the_value), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -21,15 +19,8 @@ def test_setting_flat_value(run_module, admin_user):
@pytest.mark.django_db
def test_setting_dict_value(run_module, admin_user):
the_value = {
'email': 'mail',
'first_name': 'givenName',
'last_name': 'surname'
}
result = run_module('tower_settings', dict(
name='AUTH_LDAP_USER_ATTR_MAP',
value=the_value
), admin_user)
the_value = {'email': 'mail', 'first_name': 'givenName', 'last_name': 'surname'}
result = run_module('tower_settings', dict(name='AUTH_LDAP_USER_ATTR_MAP', value=the_value), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -38,16 +29,8 @@ def test_setting_dict_value(run_module, admin_user):
@pytest.mark.django_db
def test_setting_nested_type(run_module, admin_user):
the_value = {
'email': 'mail',
'first_name': 'givenName',
'last_name': 'surname'
}
result = run_module('tower_settings', dict(
settings={
'AUTH_LDAP_USER_ATTR_MAP': the_value
}
), admin_user)
the_value = {'email': 'mail', 'first_name': 'givenName', 'last_name': 'surname'}
result = run_module('tower_settings', dict(settings={'AUTH_LDAP_USER_ATTR_MAP': the_value}), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -57,10 +40,7 @@ def test_setting_nested_type(run_module, admin_user):
@pytest.mark.django_db
def test_setting_bool_value(run_module, admin_user):
for the_value in (True, False):
result = run_module('tower_settings', dict(
name='ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC',
value=the_value
), admin_user)
result = run_module('tower_settings', dict(name='ACTIVITY_STREAM_ENABLED_FOR_INVENTORY_SYNC', value=the_value), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -10,12 +11,7 @@ from awx.main.models import Organization, Team
def test_create_team(run_module, admin_user):
org = Organization.objects.create(name='foo')
result = run_module('tower_team', {
'name': 'foo_team',
'description': 'fooin around',
'state': 'present',
'organization': 'foo'
}, admin_user)
result = run_module('tower_team', {'name': 'foo_team', 'description': 'fooin around', 'state': 'present', 'organization': 'foo'}, admin_user)
team = Team.objects.filter(name='foo_team').first()
@@ -33,18 +29,10 @@ def test_create_team(run_module, admin_user):
@pytest.mark.django_db
def test_modify_team(run_module, admin_user):
org = Organization.objects.create(name='foo')
team = Team.objects.create(
name='foo_team',
organization=org,
description='flat foo'
)
team = Team.objects.create(name='foo_team', organization=org, description='flat foo')
assert team.description == 'flat foo'
result = run_module('tower_team', {
'name': 'foo_team',
'description': 'fooin around',
'organization': 'foo'
}, admin_user)
result = run_module('tower_team', {'name': 'foo_team', 'description': 'fooin around', 'organization': 'foo'}, admin_user)
team.refresh_from_db()
result.pop('invocation')
assert result == {
@@ -54,13 +42,6 @@ def test_modify_team(run_module, admin_user):
assert team.description == 'fooin around'
# 2nd modification, should cause no change
result = run_module('tower_team', {
'name': 'foo_team',
'description': 'fooin around',
'organization': 'foo'
}, admin_user)
result = run_module('tower_team', {'name': 'foo_team', 'description': 'fooin around', 'organization': 'foo'}, admin_user)
result.pop('invocation')
assert result == {
"id": team.id,
"changed": False
}
assert result == {"id": team.id, "changed": False}

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -19,10 +20,7 @@ def mock_auth_stuff():
@pytest.mark.django_db
def test_create_user(run_module, admin_user, mock_auth_stuff):
result = run_module('tower_user', dict(
username='Bob',
password='pass4word'
), admin_user)
result = run_module('tower_user', dict(username='Bob', password='pass4word'), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
@@ -33,27 +31,20 @@ def test_create_user(run_module, admin_user, mock_auth_stuff):
@pytest.mark.django_db
def test_password_no_op_warning(run_module, admin_user, mock_auth_stuff, silence_warning):
for i in range(2):
result = run_module('tower_user', dict(
username='Bob',
password='pass4word'
), admin_user)
result = run_module('tower_user', dict(username='Bob', password='pass4word'), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed') # not actually desired, but assert for sanity
silence_warning.assert_called_once_with(
"The field password of user {0} has encrypted data and "
"may inaccurately report task is changed.".format(result['id']))
"The field password of user {0} has encrypted data and " "may inaccurately report task is changed.".format(result['id'])
)
@pytest.mark.django_db
def test_update_password_on_create(run_module, admin_user, mock_auth_stuff):
for i in range(2):
result = run_module('tower_user', dict(
username='Bob',
password='pass4word',
update_secrets=False
), admin_user)
result = run_module('tower_user', dict(username='Bob', password='pass4word', update_secrets=False), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert not result.get('changed')
@@ -61,18 +52,11 @@ def test_update_password_on_create(run_module, admin_user, mock_auth_stuff):
@pytest.mark.django_db
def test_update_user(run_module, admin_user, mock_auth_stuff):
result = run_module('tower_user', dict(
username='Bob',
password='pass4word',
is_system_auditor=True
), admin_user)
result = run_module('tower_user', dict(username='Bob', password='pass4word', is_system_auditor=True), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed'), result
update_result = run_module('tower_user', dict(
username='Bob',
is_system_auditor=False
), admin_user)
update_result = run_module('tower_user', dict(username='Bob', is_system_auditor=False), admin_user)
assert update_result.get('changed')
user = User.objects.get(id=result['id'])

View File

@@ -1,4 +1,5 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -8,14 +9,18 @@ from awx.main.models import WorkflowJobTemplate, NotificationTemplate
@pytest.mark.django_db
def test_create_workflow_job_template(run_module, admin_user, organization, survey_spec):
result = run_module('tower_workflow_job_template', {
'name': 'foo-workflow',
'organization': organization.name,
'extra_vars': {'foo': 'bar', 'another-foo': {'barz': 'bar2'}},
'survey_spec': survey_spec,
'survey_enabled': True,
'state': 'present'
}, admin_user)
result = run_module(
'tower_workflow_job_template',
{
'name': 'foo-workflow',
'organization': organization.name,
'extra_vars': {'foo': 'bar', 'another-foo': {'barz': 'bar2'}},
'survey_spec': survey_spec,
'survey_enabled': True,
'state': 'present',
},
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
wfjt = WorkflowJobTemplate.objects.get(name='foo-workflow')
@@ -30,10 +35,7 @@ def test_create_workflow_job_template(run_module, admin_user, organization, surv
@pytest.mark.django_db
def test_create_modify_no_survey(run_module, admin_user, organization, survey_spec):
result = run_module('tower_workflow_job_template', {
'name': 'foo-workflow',
'organization': organization.name
}, admin_user)
result = run_module('tower_workflow_job_template', {'name': 'foo-workflow', 'organization': organization.name}, admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', False), result
@@ -43,25 +45,15 @@ def test_create_modify_no_survey(run_module, admin_user, organization, survey_sp
result.pop('invocation', None)
assert result == {"name": "foo-workflow", "id": wfjt.id, "changed": True}
result = run_module('tower_workflow_job_template', {
'name': 'foo-workflow',
'organization': organization.name
}, admin_user)
result = run_module('tower_workflow_job_template', {'name': 'foo-workflow', 'organization': organization.name}, admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert not result.get('changed', True), result
@pytest.mark.django_db
def test_survey_spec_only_changed(run_module, admin_user, organization, survey_spec):
wfjt = WorkflowJobTemplate.objects.create(
organization=organization, name='foo-workflow',
survey_enabled=True, survey_spec=survey_spec
)
result = run_module('tower_workflow_job_template', {
'name': 'foo-workflow',
'organization': organization.name,
'state': 'present'
}, admin_user)
wfjt = WorkflowJobTemplate.objects.create(organization=organization, name='foo-workflow', survey_enabled=True, survey_spec=survey_spec)
result = run_module('tower_workflow_job_template', {'name': 'foo-workflow', 'organization': organization.name, 'state': 'present'}, admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert not result.get('changed', True), result
wfjt.refresh_from_db()
@@ -69,12 +61,9 @@ def test_survey_spec_only_changed(run_module, admin_user, organization, survey_s
survey_spec['description'] = 'changed description'
result = run_module('tower_workflow_job_template', {
'name': 'foo-workflow',
'organization': organization.name,
'survey_spec': survey_spec,
'state': 'present'
}, admin_user)
result = run_module(
'tower_workflow_job_template', {'name': 'foo-workflow', 'organization': organization.name, 'survey_spec': survey_spec, 'state': 'present'}, admin_user
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', True), result
wfjt.refresh_from_db()
@@ -83,15 +72,8 @@ def test_survey_spec_only_changed(run_module, admin_user, organization, survey_s
@pytest.mark.django_db
def test_survey_spec_only_changed(run_module, admin_user, organization, survey_spec):
wfjt = WorkflowJobTemplate.objects.create(
organization=organization, name='foo-workflow',
survey_enabled=True, survey_spec=survey_spec
)
result = run_module('tower_workflow_job_template', {
'name': 'foo-workflow',
'organization': organization.name,
'state': 'present'
}, admin_user)
wfjt = WorkflowJobTemplate.objects.create(organization=organization, name='foo-workflow', survey_enabled=True, survey_spec=survey_spec)
result = run_module('tower_workflow_job_template', {'name': 'foo-workflow', 'organization': organization.name, 'state': 'present'}, admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert not result.get('changed', True), result
wfjt.refresh_from_db()
@@ -99,12 +81,9 @@ def test_survey_spec_only_changed(run_module, admin_user, organization, survey_s
del survey_spec['description']
result = run_module('tower_workflow_job_template', {
'name': 'foo-workflow',
'organization': organization.name,
'survey_spec': survey_spec,
'state': 'present'
}, admin_user)
result = run_module(
'tower_workflow_job_template', {'name': 'foo-workflow', 'organization': organization.name, 'survey_spec': survey_spec, 'state': 'present'}, admin_user
)
assert result.get('failed', True)
assert result.get('msg') == "Failed to update survey: Field 'description' is missing from survey spec."
@@ -112,19 +91,14 @@ def test_survey_spec_only_changed(run_module, admin_user, organization, survey_s
@pytest.mark.django_db
def test_associate_only_on_success(run_module, admin_user, organization, project):
wfjt = WorkflowJobTemplate.objects.create(
organization=organization, name='foo-workflow',
organization=organization,
name='foo-workflow',
# survey_enabled=True, survey_spec=survey_spec
)
create_kwargs = dict(
notification_configuration={
'url': 'http://www.example.com/hook',
'headers': {
'X-Custom-Header': 'value123'
},
'password': 'bar'
},
notification_configuration={'url': 'http://www.example.com/hook', 'headers': {'X-Custom-Header': 'value123'}, 'password': 'bar'},
notification_type='webhook',
organization=organization
organization=organization,
)
nt1 = NotificationTemplate.objects.create(name='nt1', **create_kwargs)
nt2 = NotificationTemplate.objects.create(name='nt2', **create_kwargs)
@@ -132,11 +106,9 @@ def test_associate_only_on_success(run_module, admin_user, organization, project
wfjt.notification_templates_error.add(nt1)
# test preservation of error NTs when success NTs are added
result = run_module('tower_workflow_job_template', {
'name': 'foo-workflow',
'organization': organization.name,
'notification_templates_success': ['nt2']
}, admin_user)
result = run_module(
'tower_workflow_job_template', {'name': 'foo-workflow', 'organization': organization.name, 'notification_templates_success': ['nt2']}, admin_user
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', True), result
@@ -144,11 +116,9 @@ def test_associate_only_on_success(run_module, admin_user, organization, project
assert list(wfjt.notification_templates_error.values_list('id', flat=True)) == [nt1.id]
# test removal to empty list
result = run_module('tower_workflow_job_template', {
'name': 'foo-workflow',
'organization': organization.name,
'notification_templates_success': []
}, admin_user)
result = run_module(
'tower_workflow_job_template', {'name': 'foo-workflow', 'organization': organization.name, 'notification_templates_success': []}, admin_user
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', True), result
@@ -158,17 +128,9 @@ def test_associate_only_on_success(run_module, admin_user, organization, project
@pytest.mark.django_db
def test_delete_with_spec(run_module, admin_user, organization, survey_spec):
WorkflowJobTemplate.objects.create(
organization=organization, name='foo-workflow',
survey_enabled=True, survey_spec=survey_spec
)
result = run_module('tower_workflow_job_template', {
'name': 'foo-workflow',
'organization': organization.name,
'state': 'absent'
}, admin_user)
WorkflowJobTemplate.objects.create(organization=organization, name='foo-workflow', survey_enabled=True, survey_spec=survey_spec)
result = run_module('tower_workflow_job_template', {'name': 'foo-workflow', 'organization': organization.name, 'state': 'absent'}, admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', True), result
assert WorkflowJobTemplate.objects.filter(
name='foo-workflow', organization=organization).count() == 0
assert WorkflowJobTemplate.objects.filter(name='foo-workflow', organization=organization).count() == 0

View File

@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
@@ -16,7 +17,7 @@ def job_template(project, inventory):
name='foo-jt',
ask_variables_on_launch=True,
ask_credential_on_launch=True,
ask_limit_on_launch=True
ask_limit_on_launch=True,
)
@@ -29,23 +30,23 @@ def wfjt(organization):
@pytest.mark.django_db
def test_create_workflow_job_template_node(run_module, admin_user, wfjt, job_template):
this_identifier = '42🐉'
result = run_module('tower_workflow_job_template_node', {
'identifier': this_identifier,
'workflow_job_template': 'foo-workflow',
'organization': wfjt.organization.name,
'unified_job_template': 'foo-jt',
'state': 'present'
}, admin_user)
result = run_module(
'tower_workflow_job_template_node',
{
'identifier': this_identifier,
'workflow_job_template': 'foo-workflow',
'organization': wfjt.organization.name,
'unified_job_template': 'foo-jt',
'state': 'present',
},
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
node = WorkflowJobTemplateNode.objects.get(identifier=this_identifier)
result.pop('invocation', None)
assert result == {
"name": this_identifier, # FIXME: should this be identifier instead
"id": node.id,
"changed": True
}
assert result == {"name": this_identifier, "id": node.id, "changed": True} # FIXME: should this be identifier instead
assert node.identifier == this_identifier
assert node.workflow_job_template_id == wfjt.id
@@ -56,12 +57,16 @@ def test_create_workflow_job_template_node(run_module, admin_user, wfjt, job_tem
def test_create_workflow_job_template_node_approval_node(run_module, admin_user, wfjt, job_template):
"""This is a part of the API contract for creating approval nodes"""
this_identifier = '42🐉'
result = run_module('tower_workflow_job_template_node', {
'identifier': this_identifier,
'workflow_job_template': wfjt.name,
'organization': wfjt.organization.name,
'approval_node': {'name': 'foo-jt-approval'}
}, admin_user)
result = run_module(
'tower_workflow_job_template_node',
{
'identifier': this_identifier,
'workflow_job_template': wfjt.name,
'organization': wfjt.organization.name,
'approval_node': {'name': 'foo-jt-approval'},
},
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', False), result
@@ -77,16 +82,20 @@ def test_create_workflow_job_template_node_approval_node(run_module, admin_user,
@pytest.mark.django_db
def test_make_use_of_prompts(run_module, admin_user, wfjt, job_template, machine_credential, vault_credential):
result = run_module('tower_workflow_job_template_node', {
'identifier': '42',
'workflow_job_template': 'foo-workflow',
'organization': wfjt.organization.name,
'unified_job_template': 'foo-jt',
'extra_data': {'foo': 'bar', 'another-foo': {'barz': 'bar2'}},
'limit': 'foo_hosts',
'credentials': [machine_credential.name, vault_credential.name],
'state': 'present'
}, admin_user)
result = run_module(
'tower_workflow_job_template_node',
{
'identifier': '42',
'workflow_job_template': 'foo-workflow',
'organization': wfjt.organization.name,
'unified_job_template': 'foo-jt',
'extra_data': {'foo': 'bar', 'another-foo': {'barz': 'bar2'}},
'limit': 'foo_hosts',
'credentials': [machine_credential.name, vault_credential.name],
'state': 'present',
},
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', False)
@@ -100,23 +109,23 @@ def test_make_use_of_prompts(run_module, admin_user, wfjt, job_template, machine
@pytest.mark.django_db
def test_create_with_edges(run_module, admin_user, wfjt, job_template):
next_nodes = [
WorkflowJobTemplateNode.objects.create(
identifier='foo{0}'.format(i),
workflow_job_template=wfjt,
unified_job_template=job_template
) for i in range(3)
WorkflowJobTemplateNode.objects.create(identifier='foo{0}'.format(i), workflow_job_template=wfjt, unified_job_template=job_template) for i in range(3)
]
result = run_module('tower_workflow_job_template_node', {
'identifier': '42',
'workflow_job_template': 'foo-workflow',
'organization': wfjt.organization.name,
'unified_job_template': 'foo-jt',
'success_nodes': ['foo0'],
'always_nodes': ['foo1'],
'failure_nodes': ['foo2'],
'state': 'present'
}, admin_user)
result = run_module(
'tower_workflow_job_template_node',
{
'identifier': '42',
'workflow_job_template': 'foo-workflow',
'organization': wfjt.organization.name,
'unified_job_template': 'foo-jt',
'success_nodes': ['foo0'],
'always_nodes': ['foo1'],
'failure_nodes': ['foo2'],
'state': 'present',
},
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
assert result.get('changed', False)

View File

@@ -1,35 +1,32 @@
from __future__ import (absolute_import, division, print_function)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
import pytest
from awx.main.models import (
WorkflowJobTemplate, JobTemplate, Project, InventorySource,
Inventory, WorkflowJobTemplateNode
)
from awx.main.models import WorkflowJobTemplate, JobTemplate, Project, InventorySource, Inventory, WorkflowJobTemplateNode
@pytest.mark.django_db
def test_create_workflow_job_template(run_module, admin_user, organization, survey_spec, silence_deprecation):
result = run_module('tower_workflow_template', {
'name': 'foo-workflow',
'organization': organization.name,
'extra_vars': {'foo': 'bar', 'another-foo': {'barz': 'bar2'}},
'survey': survey_spec,
'survey_enabled': True,
'state': 'present'
}, admin_user)
result = run_module(
'tower_workflow_template',
{
'name': 'foo-workflow',
'organization': organization.name,
'extra_vars': {'foo': 'bar', 'another-foo': {'barz': 'bar2'}},
'survey': survey_spec,
'survey_enabled': True,
'state': 'present',
},
admin_user,
)
wfjt = WorkflowJobTemplate.objects.get(name='foo-workflow')
assert wfjt.extra_vars == '{"foo": "bar", "another-foo": {"barz": "bar2"}}'
result.pop('invocation', None)
assert result == {
"workflow_template": "foo-workflow", # TODO: remove after refactor
"state": "present",
"id": wfjt.id,
"changed": True
}
assert result == {"workflow_template": "foo-workflow", "state": "present", "id": wfjt.id, "changed": True} # TODO: remove after refactor
assert wfjt.organization_id == organization.id
assert wfjt.survey_spec == survey_spec
@@ -39,14 +36,11 @@ def test_create_workflow_job_template(run_module, admin_user, organization, surv
def test_with_nested_workflow(run_module, admin_user, organization, silence_deprecation):
wfjt1 = WorkflowJobTemplate.objects.create(name='first', organization=organization)
result = run_module('tower_workflow_template', {
'name': 'foo-workflow',
'organization': organization.name,
'schema': [
{'workflow': wfjt1.name}
],
'state': 'present'
}, admin_user)
result = run_module(
'tower_workflow_template',
{'name': 'foo-workflow', 'organization': organization.name, 'schema': [{'workflow': wfjt1.name}], 'state': 'present'},
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
wfjt = WorkflowJobTemplate.objects.get(name='foo-workflow')
@@ -60,51 +54,34 @@ def test_schema_with_branches(run_module, admin_user, organization, silence_depr
proj = Project.objects.create(organization=organization, name='Ansible Examples')
inv = Inventory.objects.create(organization=organization, name='test-inv')
jt = JobTemplate.objects.create(
project=proj,
playbook='helloworld.yml',
inventory=inv,
name='Hello world'
)
inv_src = InventorySource.objects.create(
inventory=inv,
name='AWS servers',
source='ec2'
)
jt = JobTemplate.objects.create(project=proj, playbook='helloworld.yml', inventory=inv, name='Hello world')
inv_src = InventorySource.objects.create(inventory=inv, name='AWS servers', source='ec2')
result = run_module('tower_workflow_template', {
'name': 'foo-workflow',
'organization': organization.name,
'schema': [
{
'job_template': 'Hello world',
'failure': [
{
'inventory_source': 'AWS servers',
'success': [
{
'project': 'Ansible Examples',
'always': [
{
'job_template': "Hello world"
}
]
}
]
}
]
}
],
'state': 'present'
}, admin_user)
result = run_module(
'tower_workflow_template',
{
'name': 'foo-workflow',
'organization': organization.name,
'schema': [
{
'job_template': 'Hello world',
'failure': [{'inventory_source': 'AWS servers', 'success': [{'project': 'Ansible Examples', 'always': [{'job_template': "Hello world"}]}]}],
}
],
'state': 'present',
},
admin_user,
)
assert not result.get('failed', False), result.get('msg', result)
wfjt = WorkflowJobTemplate.objects.get(name='foo-workflow')
root_nodes = wfjt.workflow_nodes.filter(**{
'%ss_success__isnull' % WorkflowJobTemplateNode.__name__.lower(): True,
'%ss_failure__isnull' % WorkflowJobTemplateNode.__name__.lower(): True,
'%ss_always__isnull' % WorkflowJobTemplateNode.__name__.lower(): True,
})
root_nodes = wfjt.workflow_nodes.filter(
**{
'%ss_success__isnull' % WorkflowJobTemplateNode.__name__.lower(): True,
'%ss_failure__isnull' % WorkflowJobTemplateNode.__name__.lower(): True,
'%ss_always__isnull' % WorkflowJobTemplateNode.__name__.lower(): True,
}
)
assert len(root_nodes) == 1
node = root_nodes[0]
assert node.unified_job_template == jt
@@ -118,13 +95,8 @@ def test_schema_with_branches(run_module, admin_user, organization, silence_depr
@pytest.mark.django_db
def test_with_missing_ujt(run_module, admin_user, organization, silence_deprecation):
result = run_module('tower_workflow_template', {
'name': 'foo-workflow',
'organization': organization.name,
'schema': [
{'foo': 'bar'}
],
'state': 'present'
}, admin_user)
result = run_module(
'tower_workflow_template', {'name': 'foo-workflow', 'organization': organization.name, 'schema': [{'foo': 'bar'}], 'state': 'present'}, admin_user
)
assert result.get('failed', False), result
assert 'You should provide exactly one of the attributes job_template,' in result['msg']