Make state exists universal in collection (#13890)

Make state: exists available for all API modules

Make state:exists return the ID just like it would if it created the resource
This commit is contained in:
John Westcott IV
2023-05-10 08:05:29 -04:00
committed by GitHub
parent 53260213ba
commit 7f020052db
40 changed files with 918 additions and 135 deletions

View File

@@ -47,35 +47,14 @@ class ItemNotDefined(Exception):
class ControllerModule(AnsibleModule): class ControllerModule(AnsibleModule):
url = None url = None
AUTH_ARGSPEC = dict( AUTH_ARGSPEC = dict(
controller_host=dict( controller_host=dict(required=False, aliases=['tower_host'], fallback=(env_fallback, ['CONTROLLER_HOST', 'TOWER_HOST'])),
required=False, controller_username=dict(required=False, aliases=['tower_username'], fallback=(env_fallback, ['CONTROLLER_USERNAME', 'TOWER_USERNAME'])),
aliases=['tower_host'], controller_password=dict(no_log=True, aliases=['tower_password'], required=False, fallback=(env_fallback, ['CONTROLLER_PASSWORD', 'TOWER_PASSWORD'])),
fallback=(env_fallback, ['CONTROLLER_HOST', 'TOWER_HOST'])), validate_certs=dict(type='bool', aliases=['tower_verify_ssl'], required=False, fallback=(env_fallback, ['CONTROLLER_VERIFY_SSL', 'TOWER_VERIFY_SSL'])),
controller_username=dict(
required=False,
aliases=['tower_username'],
fallback=(env_fallback, ['CONTROLLER_USERNAME', 'TOWER_USERNAME'])),
controller_password=dict(
no_log=True,
aliases=['tower_password'],
required=False,
fallback=(env_fallback, ['CONTROLLER_PASSWORD', 'TOWER_PASSWORD'])),
validate_certs=dict(
type='bool',
aliases=['tower_verify_ssl'],
required=False,
fallback=(env_fallback, ['CONTROLLER_VERIFY_SSL', 'TOWER_VERIFY_SSL'])),
controller_oauthtoken=dict( controller_oauthtoken=dict(
type='raw', type='raw', no_log=True, aliases=['tower_oauthtoken'], required=False, fallback=(env_fallback, ['CONTROLLER_OAUTH_TOKEN', 'TOWER_OAUTH_TOKEN'])
no_log=True, ),
aliases=['tower_oauthtoken'], controller_config_file=dict(type='path', aliases=['tower_config_file'], required=False, default=None),
required=False,
fallback=(env_fallback, ['CONTROLLER_OAUTH_TOKEN', 'TOWER_OAUTH_TOKEN'])),
controller_config_file=dict(
type='path',
aliases=['tower_config_file'],
required=False,
default=None),
) )
short_params = { short_params = {
'host': 'controller_host', 'host': 'controller_host',
@@ -320,9 +299,7 @@ class ControllerAPIModule(ControllerModule):
def __init__(self, argument_spec, direct_params=None, error_callback=None, warn_callback=None, **kwargs): def __init__(self, argument_spec, direct_params=None, error_callback=None, warn_callback=None, **kwargs):
kwargs['supports_check_mode'] = True kwargs['supports_check_mode'] = True
super().__init__( super().__init__(argument_spec=argument_spec, direct_params=direct_params, error_callback=error_callback, warn_callback=warn_callback, **kwargs)
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) self.session = Request(cookies=CookieJar(), validate_certs=self.verify_ssl)
if 'update_secrets' in self.params: if 'update_secrets' in self.params:
@@ -400,7 +377,7 @@ class ControllerAPIModule(ControllerModule):
response['json']['next'] = next_page response['json']['next'] = next_page
return response return response
def get_one(self, endpoint, name_or_id=None, allow_none=True, **kwargs): def get_one(self, endpoint, name_or_id=None, allow_none=True, check_exists=False, **kwargs):
new_kwargs = kwargs.copy() new_kwargs = kwargs.copy()
if name_or_id: if name_or_id:
name_field = self.get_name_field_from_endpoint(endpoint) name_field = self.get_name_field_from_endpoint(endpoint)
@@ -441,6 +418,11 @@ class ControllerAPIModule(ControllerModule):
# Or we weren't running with a or search and just got back too many to begin with. # Or we weren't running with a or search and just got back too many to begin with.
self.fail_wanted_one(response, endpoint, new_kwargs.get('data')) self.fail_wanted_one(response, endpoint, new_kwargs.get('data'))
if check_exists:
name_field = self.get_name_field_from_endpoint(endpoint)
self.json_output['id'] = response['json']['results'][0]['id']
self.exit_json(**self.json_output)
return response['json']['results'][0] return response['json']['results'][0]
def fail_wanted_one(self, response, endpoint, query_params): def fail_wanted_one(self, response, endpoint, query_params):
@@ -448,7 +430,8 @@ class ControllerAPIModule(ControllerModule):
if len(sample['json']['results']) > 1: if len(sample['json']['results']) > 1:
sample['json']['results'] = sample['json']['results'][:2] + ['...more results snipped...'] sample['json']['results'] = sample['json']['results'][:2] + ['...more results snipped...']
url = self.build_url(endpoint, query_params) url = self.build_url(endpoint, query_params)
display_endpoint = url.geturl()[len(self.host):] # truncate to not include the base URL host_length = len(self.host)
display_endpoint = url.geturl()[host_length:] # truncate to not include the base URL
self.fail_json( 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, query=query_params,
@@ -970,11 +953,7 @@ class ControllerAPIModule(ControllerModule):
# Attempt to delete our current token from /api/v2/tokens/ # Attempt to delete our current token from /api/v2/tokens/
# Post to the tokens endpoint with baisc auth to try and get a token # Post to the tokens endpoint with baisc auth to try and get a token
endpoint = self.url_prefix.rstrip('/') + '/api/v2/tokens/{0}/'.format(self.oauth_token_id) endpoint = self.url_prefix.rstrip('/') + '/api/v2/tokens/{0}/'.format(self.oauth_token_id)
api_token_url = ( api_token_url = (self.url._replace(path=endpoint, query=None)).geturl() # in error cases, fail_json exists before exception handling
self.url._replace(
path=endpoint, query=None # in error cases, fail_json exists before exception handling
)
).geturl()
try: try:
self.session.open( self.session.open(

View File

@@ -60,7 +60,7 @@ options:
description: description:
- Desired state of the resource. - Desired state of the resource.
default: "present" default: "present"
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
type: str type: str
skip_authorization: skip_authorization:
description: description:
@@ -106,7 +106,7 @@ def main():
client_type=dict(choices=['public', 'confidential']), client_type=dict(choices=['public', 'confidential']),
organization=dict(required=True), organization=dict(required=True),
redirect_uris=dict(type="list", elements='str'), redirect_uris=dict(type="list", elements='str'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
skip_authorization=dict(type='bool'), skip_authorization=dict(type='bool'),
) )
@@ -127,7 +127,7 @@ def main():
org_id = module.resolve_name_to_id('organizations', organization) org_id = module.resolve_name_to_id('organizations', organization)
# Attempt to look up application based on the provided name and org ID # 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, check_exists=(state == 'exists'), **{'data': {'organization': org_id}})
if state == 'absent': if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this # If the state was absent we can let the module delete it if needed, the module will handle exiting from this

View File

@@ -247,7 +247,7 @@ def main():
if organization: if organization:
lookup_data['organization'] = org_id lookup_data['organization'] = org_id
credential = module.get_one('credentials', name_or_id=name, **{'data': lookup_data}) credential = module.get_one('credentials', name_or_id=name, check_exists=(state == 'exists'), **{'data': lookup_data})
# Attempt to look up credential to copy based on the provided name # Attempt to look up credential to copy based on the provided name
if copy_from: if copy_from:
@@ -265,10 +265,6 @@ def main():
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this # 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(credential) module.delete_if_needed(credential)
if state == 'exists' and credential is not None:
# If credential exists and state is exists, we're done here.
module.exit_json(**module.json_output)
# Attempt to look up the related items the user specified (these will fail the module if not found) # Attempt to look up the related items the user specified (these will fail the module if not found)
if user: if user:
user_id = module.resolve_name_to_id('users', user) user_id = module.resolve_name_to_id('users', user)

View File

@@ -48,7 +48,7 @@ options:
state: state:
description: description:
- Desired state of the resource. - Desired state of the resource.
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
default: "present" default: "present"
type: str type: str
@@ -80,7 +80,7 @@ def main():
target_credential=dict(required=True), target_credential=dict(required=True),
source_credential=dict(), source_credential=dict(),
metadata=dict(type="dict"), metadata=dict(type="dict"),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -101,7 +101,7 @@ def main():
'target_credential': target_credential_id, 'target_credential': target_credential_id,
'input_field_name': input_field_name, 'input_field_name': input_field_name,
} }
credential_input_source = module.get_one('credential_input_sources', **{'data': lookup_data}) credential_input_source = module.get_one('credential_input_sources', check_exists=(state == 'exists'), **{'data': lookup_data})
if state == 'absent': if state == 'absent':
module.delete_if_needed(credential_input_source) module.delete_if_needed(credential_input_source)

View File

@@ -59,7 +59,7 @@ options:
description: description:
- Desired state of the resource. - Desired state of the resource.
default: "present" default: "present"
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
type: str type: str
extends_documentation_fragment: awx.awx.auth extends_documentation_fragment: awx.awx.auth
''' '''
@@ -98,7 +98,7 @@ def main():
kind=dict(choices=list(KIND_CHOICES.keys())), kind=dict(choices=list(KIND_CHOICES.keys())),
inputs=dict(type='dict'), inputs=dict(type='dict'),
injectors=dict(type='dict'), injectors=dict(type='dict'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -124,7 +124,7 @@ def main():
credential_type_params['injectors'] = module.params.get('injectors') credential_type_params['injectors'] = module.params.get('injectors')
# Attempt to look up credential_type based on the provided name # Attempt to look up credential_type based on the provided name
credential_type = module.get_one('credential_types', name_or_id=name) credential_type = module.get_one('credential_types', name_or_id=name, check_exists=(state == 'exists'))
if state == 'absent': if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this # If the state was absent we can let the module delete it if needed, the module will handle exiting from this

View File

@@ -50,7 +50,7 @@ options:
state: state:
description: description:
- Desired state of the resource. - Desired state of the resource.
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
default: "present" default: "present"
type: str type: str
pull: pull:
@@ -83,7 +83,7 @@ def main():
description=dict(), description=dict(),
organization=dict(), organization=dict(),
credential=dict(), credential=dict(),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
# NOTE: Default for pull differs from API (which is blank by default) # NOTE: Default for pull differs from API (which is blank by default)
pull=dict(choices=['always', 'missing', 'never'], default='missing'), pull=dict(choices=['always', 'missing', 'never'], default='missing'),
) )
@@ -99,7 +99,7 @@ def main():
state = module.params.get('state') state = module.params.get('state')
pull = module.params.get('pull') pull = module.params.get('pull')
existing_item = module.get_one('execution_environments', name_or_id=name) existing_item = module.get_one('execution_environments', name_or_id=name, check_exists=(state == 'exists'))
if state == 'absent': if state == 'absent':
module.delete_if_needed(existing_item) module.delete_if_needed(existing_item)

View File

@@ -67,7 +67,7 @@ options:
description: description:
- Desired state of the resource. - Desired state of the resource.
default: "present" default: "present"
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
type: str type: str
new_name: new_name:
description: description:
@@ -115,7 +115,7 @@ def main():
children=dict(type='list', elements='str', aliases=['groups']), children=dict(type='list', elements='str', aliases=['groups']),
preserve_existing_hosts=dict(type='bool', default=False), preserve_existing_hosts=dict(type='bool', default=False),
preserve_existing_children=dict(type='bool', default=False, aliases=['preserve_existing_groups']), preserve_existing_children=dict(type='bool', default=False, aliases=['preserve_existing_groups']),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -135,7 +135,7 @@ def main():
inventory_id = module.resolve_name_to_id('inventories', inventory) inventory_id = module.resolve_name_to_id('inventories', inventory)
# Attempt to look up the object based on the provided name and inventory ID # 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, check_exists=(state == 'exists'), **{'data': {'inventory': inventory_id}})
if state == 'absent': if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this # If the state was absent we can let the module delete it if needed, the module will handle exiting from this

View File

@@ -50,7 +50,7 @@ options:
state: state:
description: description:
- Desired state of the resource. - Desired state of the resource.
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
default: "present" default: "present"
type: str type: str
extends_documentation_fragment: awx.awx.auth extends_documentation_fragment: awx.awx.auth
@@ -83,7 +83,7 @@ def main():
inventory=dict(required=True), inventory=dict(required=True),
enabled=dict(type='bool'), enabled=dict(type='bool'),
variables=dict(type='dict'), variables=dict(type='dict'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -102,7 +102,7 @@ def main():
inventory_id = module.resolve_name_to_id('inventories', inventory) inventory_id = module.resolve_name_to_id('inventories', inventory)
# Attempt to look up host based on the provided name and inventory ID # 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, check_exists=(state == 'exists'), **{'data': {'inventory': inventory_id}})
if state == 'absent': if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this # If the state was absent we can let the module delete it if needed, the module will handle exiting from this

View File

@@ -81,7 +81,7 @@ options:
state: state:
description: description:
- Desired state of the resource. - Desired state of the resource.
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
default: "present" default: "present"
type: str type: str
extends_documentation_fragment: awx.awx.auth extends_documentation_fragment: awx.awx.auth
@@ -107,7 +107,7 @@ def main():
policy_instance_list=dict(type='list', elements='str'), policy_instance_list=dict(type='list', elements='str'),
pod_spec_override=dict(), pod_spec_override=dict(),
instances=dict(required=False, type="list", elements='str'), instances=dict(required=False, type="list", elements='str'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -128,7 +128,7 @@ def main():
state = module.params.get('state') state = module.params.get('state')
# Attempt to look up an existing item based on the provided data # Attempt to look up an existing item based on the provided data
existing_item = module.get_one('instance_groups', name_or_id=name) existing_item = module.get_one('instance_groups', name_or_id=name, check_exists=(state == 'exists'))
if state == 'absent': if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this # If the state was absent we can let the module delete it if needed, the module will handle exiting from this

View File

@@ -78,7 +78,7 @@ options:
description: description:
- Desired state of the resource. - Desired state of the resource.
default: "present" default: "present"
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
type: str type: str
extends_documentation_fragment: awx.awx.auth extends_documentation_fragment: awx.awx.auth
''' '''
@@ -149,7 +149,7 @@ def main():
host_filter=dict(), host_filter=dict(),
instance_groups=dict(type="list", elements='str'), instance_groups=dict(type="list", elements='str'),
prevent_instance_group_fallback=dict(type='bool'), prevent_instance_group_fallback=dict(type='bool'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
input_inventories=dict(type='list', elements='str'), input_inventories=dict(type='list', elements='str'),
) )
@@ -172,7 +172,7 @@ def main():
org_id = module.resolve_name_to_id('organizations', organization) org_id = module.resolve_name_to_id('organizations', organization)
# Attempt to look up inventory based on the provided name and org ID # 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, check_exists=(state == 'exists'), **{'data': {'organization': org_id}})
# Attempt to look up credential to copy based on the provided name # Attempt to look up credential to copy based on the provided name
if copy_from: if copy_from:

View File

@@ -118,7 +118,7 @@ options:
description: description:
- Desired state of the resource. - Desired state of the resource.
default: "present" default: "present"
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
type: str type: str
notification_templates_started: notification_templates_started:
description: description:
@@ -192,7 +192,7 @@ def main():
notification_templates_started=dict(type="list", elements='str'), notification_templates_started=dict(type="list", elements='str'),
notification_templates_success=dict(type="list", elements='str'), notification_templates_success=dict(type="list", elements='str'),
notification_templates_error=dict(type="list", elements='str'), notification_templates_error=dict(type="list", elements='str'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -219,6 +219,7 @@ def main():
inventory_source_object = module.get_one( inventory_source_object = module.get_one(
'inventory_sources', 'inventory_sources',
name_or_id=name, name_or_id=name,
check_exists=(state == 'exists'),
**{ **{
'data': { 'data': {
'inventory': inventory_object['id'], 'inventory': inventory_object['id'],

View File

@@ -295,7 +295,7 @@ options:
description: description:
- Desired state of the resource. - Desired state of the resource.
default: "present" default: "present"
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
type: str type: str
notification_templates_started: notification_templates_started:
description: description:
@@ -444,7 +444,7 @@ def main():
notification_templates_success=dict(type="list", elements='str'), notification_templates_success=dict(type="list", elements='str'),
notification_templates_error=dict(type="list", elements='str'), notification_templates_error=dict(type="list", elements='str'),
prevent_instance_group_fallback=dict(type="bool"), prevent_instance_group_fallback=dict(type="bool"),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -484,7 +484,7 @@ def main():
new_fields['execution_environment'] = module.resolve_name_to_id('execution_environments', ee) new_fields['execution_environment'] = module.resolve_name_to_id('execution_environments', ee)
# Attempt to look up an existing item based on the provided data # Attempt to look up an existing item based on the provided data
existing_item = module.get_one('job_templates', name_or_id=name, **{'data': search_fields}) existing_item = module.get_one('job_templates', name_or_id=name, check_exists=(state == 'exists'), **{'data': search_fields})
# Attempt to look up credential to copy based on the provided name # Attempt to look up credential to copy based on the provided name
if copy_from: if copy_from:

View File

@@ -41,7 +41,7 @@ options:
description: description:
- Desired state of the resource. - Desired state of the resource.
default: "present" default: "present"
choices: ["present"] choices: ["present", "exists"]
type: str type: str
extends_documentation_fragment: awx.awx.auth extends_documentation_fragment: awx.awx.auth
''' '''
@@ -62,7 +62,7 @@ def main():
name=dict(required=True), name=dict(required=True),
new_name=dict(), new_name=dict(),
organization=dict(required=True), organization=dict(required=True),
state=dict(choices=['present'], default='present'), state=dict(choices=['present', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -72,6 +72,7 @@ def main():
name = module.params.get('name') name = module.params.get('name')
new_name = module.params.get("new_name") new_name = module.params.get("new_name")
organization = module.params.get('organization') organization = module.params.get('organization')
state = module.params.get("state")
# Attempt to look up the related items the user specified (these will fail the module if not found) # Attempt to look up the related items the user specified (these will fail the module if not found)
organization_id = None organization_id = None
@@ -82,6 +83,7 @@ def main():
existing_item = module.get_one( existing_item = module.get_one(
'labels', 'labels',
name_or_id=name, name_or_id=name,
check_exists=(state == 'exists'),
**{ **{
'data': { 'data': {
'organization': organization_id, 'organization': organization_id,

View File

@@ -97,7 +97,7 @@ options:
description: description:
- Desired state of the resource. - Desired state of the resource.
default: "present" default: "present"
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
type: str type: str
extends_documentation_fragment: awx.awx.auth extends_documentation_fragment: awx.awx.auth
''' '''
@@ -222,7 +222,7 @@ def main():
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'), notification_configuration=dict(type='dict'),
messages=dict(type='dict'), messages=dict(type='dict'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -248,6 +248,7 @@ def main():
existing_item = module.get_one( existing_item = module.get_one(
'notification_templates', 'notification_templates',
name_or_id=name, name_or_id=name,
check_exists=(state == 'exists'),
**{ **{
'data': { 'data': {
'organization': organization_id, 'organization': organization_id,

View File

@@ -52,7 +52,7 @@ options:
description: description:
- Desired state of the resource. - Desired state of the resource.
default: "present" default: "present"
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
type: str type: str
instance_groups: instance_groups:
description: description:
@@ -130,7 +130,7 @@ def main():
notification_templates_error=dict(type="list", elements='str'), notification_templates_error=dict(type="list", elements='str'),
notification_templates_approvals=dict(type="list", elements='str'), notification_templates_approvals=dict(type="list", elements='str'),
galaxy_credentials=dict(type="list", elements='str'), galaxy_credentials=dict(type="list", elements='str'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -146,7 +146,7 @@ def main():
state = module.params.get('state') state = module.params.get('state')
# Attempt to look up organization based on the provided name # Attempt to look up organization based on the provided name
organization = module.get_one('organizations', name_or_id=name) organization = module.get_one('organizations', name_or_id=name, check_exists=(state == 'exists'))
if state == 'absent': if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this # If the state was absent we can let the module delete it if needed, the module will handle exiting from this

View File

@@ -122,7 +122,7 @@ options:
description: description:
- Desired state of the resource. - Desired state of the resource.
default: "present" default: "present"
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
type: str type: str
wait: wait:
description: description:
@@ -272,7 +272,7 @@ def main():
notification_templates_started=dict(type="list", elements='str'), notification_templates_started=dict(type="list", elements='str'),
notification_templates_success=dict(type="list", elements='str'), notification_templates_success=dict(type="list", elements='str'),
notification_templates_error=dict(type="list", elements='str'), notification_templates_error=dict(type="list", elements='str'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
wait=dict(type='bool', default=True), wait=dict(type='bool', default=True),
update_project=dict(default=False, type='bool'), update_project=dict(default=False, type='bool'),
interval=dict(default=2.0, type='float'), interval=dict(default=2.0, type='float'),
@@ -313,7 +313,7 @@ def main():
lookup_data['organization'] = org_id lookup_data['organization'] = org_id
# Attempt to look up project based on the provided name and org ID # Attempt to look up project based on the provided name and org ID
project = module.get_one('projects', name_or_id=name, data=lookup_data) project = module.get_one('projects', name_or_id=name, check_exists=(state == 'exists'), data=lookup_data)
# Attempt to look up credential to copy based on the provided name # Attempt to look up credential to copy based on the provided name
if copy_from: if copy_from:

View File

@@ -146,7 +146,7 @@ options:
state: state:
description: description:
- Desired state of the resource. - Desired state of the resource.
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
default: "present" default: "present"
type: str type: str
extends_documentation_fragment: awx.awx.auth extends_documentation_fragment: awx.awx.auth
@@ -220,7 +220,7 @@ def main():
unified_job_template=dict(), unified_job_template=dict(),
organization=dict(), organization=dict(),
enabled=dict(type='bool'), enabled=dict(type='bool'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -265,8 +265,13 @@ def main():
search_fields['name'] = unified_job_template search_fields['name'] = unified_job_template
unified_job_template_id = module.get_one('unified_job_templates', **{'data': search_fields})['id'] unified_job_template_id = module.get_one('unified_job_templates', **{'data': search_fields})['id']
sched_search_fields['unified_job_template'] = unified_job_template_id sched_search_fields['unified_job_template'] = unified_job_template_id
# Attempt to look up an existing item based on the provided data # Attempt to look up an existing item based on the provided data
existing_item = module.get_one('schedules', name_or_id=name, **{'data': sched_search_fields}) existing_item = module.get_one('schedules', name_or_id=name, check_exists=(state == 'exists'), **{'data': sched_search_fields})
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(existing_item)
association_fields = {} association_fields = {}
@@ -343,18 +348,14 @@ def main():
else: else:
new_fields['execution_environment'] = ee['id'] new_fields['execution_environment'] = ee['id']
if state == 'absent': # If the state was present and we can let the module build or update the existing item, this will return on its own
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this module.create_or_update_if_needed(
module.delete_if_needed(existing_item) existing_item,
elif state == 'present': new_fields,
# If the state was present and we can let the module build or update the existing item, this will return on its own endpoint='schedules',
module.create_or_update_if_needed( item_type='schedule',
existing_item, associations=association_fields,
new_fields, )
endpoint='schedules',
item_type='schedule',
associations=association_fields,
)
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -42,7 +42,7 @@ options:
state: state:
description: description:
- Desired state of the resource. - Desired state of the resource.
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
default: "present" default: "present"
type: str type: str
extends_documentation_fragment: awx.awx.auth extends_documentation_fragment: awx.awx.auth
@@ -69,7 +69,7 @@ def main():
new_name=dict(), new_name=dict(),
description=dict(), description=dict(),
organization=dict(required=True), organization=dict(required=True),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -86,7 +86,7 @@ def main():
org_id = module.resolve_name_to_id('organizations', organization) org_id = module.resolve_name_to_id('organizations', organization)
# Attempt to look up team based on the provided name and org ID # 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, check_exists=(state == 'exists'), **{'data': {'organization': org_id}})
if state == 'absent': if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this # If the state was absent we can let the module delete it if needed, the module will handle exiting from this

View File

@@ -69,7 +69,7 @@ options:
state: state:
description: description:
- Desired state of the resource. - Desired state of the resource.
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
default: "present" default: "present"
type: str type: str
extends_documentation_fragment: awx.awx.auth extends_documentation_fragment: awx.awx.auth
@@ -137,7 +137,7 @@ def main():
password=dict(no_log=True), password=dict(no_log=True),
update_secrets=dict(type='bool', default=True, no_log=False), update_secrets=dict(type='bool', default=True, no_log=False),
organization=dict(), organization=dict(),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -158,7 +158,7 @@ def main():
# Attempt to look up the related items the user specified (these will fail the module if not found) # Attempt to look up the related items the user specified (these will fail the module if not found)
# Attempt to look up an existing item based on the provided data # Attempt to look up an existing item based on the provided data
existing_item = module.get_one('users', name_or_id=username) existing_item = module.get_one('users', name_or_id=username, check_exists=(state == 'exists'))
if state == 'absent': if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this # If the state was absent we can let the module delete it if needed, the module will handle exiting from this

View File

@@ -144,6 +144,7 @@ options:
choices: choices:
- present - present
- absent - absent
- exists
default: "present" default: "present"
type: str type: str
notification_templates_started: notification_templates_started:
@@ -667,8 +668,7 @@ def create_workflow_nodes(module, response, workflow_nodes, workflow_id):
inv_lookup_data = {} inv_lookup_data = {}
if 'organization' in workflow_node['inventory']: if 'organization' in workflow_node['inventory']:
inv_lookup_data['organization'] = module.resolve_name_to_id('organizations', workflow_node['inventory']['organization']['name']) inv_lookup_data['organization'] = module.resolve_name_to_id('organizations', workflow_node['inventory']['organization']['name'])
workflow_node_fields['inventory'] = module.get_one( workflow_node_fields['inventory'] = module.get_one('inventories', name_or_id=workflow_node['inventory']['name'], data=inv_lookup_data)['id']
'inventories', name_or_id=workflow_node['inventory']['name'], data=inv_lookup_data)['id']
else: else:
workflow_node_fields['inventory'] = module.get_one('inventories', name_or_id=workflow_node['inventory'])['id'] workflow_node_fields['inventory'] = module.get_one('inventories', name_or_id=workflow_node['inventory'])['id']
@@ -843,7 +843,7 @@ def main():
notification_templates_approvals=dict(type="list", elements='str'), notification_templates_approvals=dict(type="list", elements='str'),
workflow_nodes=dict(type='list', elements='dict', aliases=['schema']), workflow_nodes=dict(type='list', elements='dict', aliases=['schema']),
destroy_current_nodes=dict(type='bool', default=False, aliases=['destroy_current_schema']), destroy_current_nodes=dict(type='bool', default=False, aliases=['destroy_current_schema']),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
# Create a module for ourselves # Create a module for ourselves
@@ -871,7 +871,7 @@ def main():
search_fields['organization'] = new_fields['organization'] = organization_id search_fields['organization'] = new_fields['organization'] = organization_id
# Attempt to look up an existing item based on the provided data # Attempt to look up an existing item based on the provided data
existing_item = module.get_one('workflow_job_templates', name_or_id=name, **{'data': search_fields}) existing_item = module.get_one('workflow_job_templates', name_or_id=name, check_exists=(state == 'exists'), **{'data': search_fields})
# Attempt to look up credential to copy based on the provided name # Attempt to look up credential to copy based on the provided name
if copy_from: if copy_from:

View File

@@ -179,7 +179,7 @@ options:
state: state:
description: description:
- Desired state of the resource. - Desired state of the resource.
choices: ["present", "absent"] choices: ["present", "absent", "exists"]
default: "present" default: "present"
type: str type: str
extends_documentation_fragment: awx.awx.auth extends_documentation_fragment: awx.awx.auth
@@ -285,7 +285,7 @@ def main():
job_slice_count=dict(type='int'), job_slice_count=dict(type='int'),
labels=dict(type='list', elements='str'), labels=dict(type='list', elements='str'),
timeout=dict(type='int'), timeout=dict(type='int'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent', 'exists'], default='present'),
) )
mutually_exclusive = [("unified_job_template", "approval_node")] mutually_exclusive = [("unified_job_template", "approval_node")]
required_if = [ required_if = [
@@ -327,7 +327,7 @@ def main():
search_fields['workflow_job_template'] = new_fields['workflow_job_template'] = workflow_job_template_id search_fields['workflow_job_template'] = new_fields['workflow_job_template'] = workflow_job_template_id
# Attempt to look up an existing item based on the provided data # Attempt to look up an existing item based on the provided data
existing_item = module.get_one('workflow_job_template_nodes', **{'data': search_fields}) existing_item = module.get_one('workflow_job_template_nodes', check_exists=(state == 'exists'), **{'data': search_fields})
if state == 'absent': if state == 'absent':
# If the state was absent we can let the module delete it if needed, the module will handle exiting from this # If the state was absent we can let the module delete it if needed, the module will handle exiting from this

View File

@@ -24,6 +24,43 @@
that: that:
- "result is changed" - "result is changed"
- name: Run an application with exists
application:
name: "{{ app1_name }}"
authorization_grant_type: "password"
client_type: "public"
organization: "Default"
state: exists
register: result
- assert:
that:
- "result is not changed"
- name: Delete our application
application:
name: "{{ app1_name }}"
organization: "Default"
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Run an application with exists
application:
name: "{{ app1_name }}"
authorization_grant_type: "password"
client_type: "public"
organization: "Default"
state: exists
register: result
- assert:
that:
- "result is changed"
- name: Delete our application - name: Delete our application
application: application:
name: "{{ app1_name }}" name: "{{ app1_name }}"

View File

@@ -47,6 +47,42 @@
that: that:
- "result is changed" - "result is changed"
- name: Create an Org-specific credential with an ID with exists
credential:
name: "{{ ssh_cred_name1 }}"
organization: Default
credential_type: Machine
state: exists
register: result
- assert:
that:
- "result is not changed"
- name: Delete an Org-specific credential with an ID
credential:
name: "{{ ssh_cred_name1 }}"
organization: Default
credential_type: Machine
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Create an Org-specific credential with an ID with exists
credential:
name: "{{ ssh_cred_name1 }}"
organization: Default
credential_type: Machine
state: exists
register: result
- assert:
that:
- "result is changed"
- name: Delete a Org-specific credential - name: Delete a Org-specific credential
credential: credential:
name: "{{ ssh_cred_name1 }}" name: "{{ ssh_cred_name1 }}"

View File

@@ -54,6 +54,51 @@
that: that:
- "result is changed" - "result is changed"
- name: Add credential Input Source with exists
credential_input_source:
input_field_name: password
target_credential: "{{ target_cred_result.id }}"
source_credential: "{{ src_cred_result.id }}"
metadata:
object_query: "Safe=MY_SAFE;Object=AWX-user"
object_query_format: "Exact"
state: exists
register: result
- assert:
that:
- "result is not changed"
- name: Delete credential Input Source
credential_input_source:
input_field_name: password
target_credential: "{{ target_cred_result.id }}"
source_credential: "{{ src_cred_result.id }}"
metadata:
object_query: "Safe=MY_SAFE;Object=AWX-user"
object_query_format: "Exact"
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Add credential Input Source with exists
credential_input_source:
input_field_name: password
target_credential: "{{ target_cred_result.id }}"
source_credential: "{{ src_cred_result.id }}"
metadata:
object_query: "Safe=MY_SAFE;Object=AWX-user"
object_query_format: "Exact"
state: exists
register: result
- assert:
that:
- "result is changed"
- name: Add Second credential Lookup - name: Add Second credential Lookup
credential: credential:
description: Credential for Testing Source Change description: Credential for Testing Source Change

View File

@@ -22,6 +22,48 @@
that: that:
- "result is changed" - "result is changed"
- name: Add Tower credential type with exists
credential_type:
description: Credential type for Test
name: "{{ cred_type_name }}"
kind: cloud
inputs: {"fields": [{"type": "string", "id": "username", "label": "Username"}, {"secret": true, "type": "string", "id": "password", "label": "Password"}], "required": ["username", "password"]}
injectors: {"extra_vars": {"test": "foo"}}
state: exists
register: result
- assert:
that:
- "result is not changed"
- name: Delete the credential type
credential_type:
description: Credential type for Test
name: "{{ cred_type_name }}"
kind: cloud
inputs: {"fields": [{"type": "string", "id": "username", "label": "Username"}, {"secret": true, "type": "string", "id": "password", "label": "Password"}], "required": ["username", "password"]}
injectors: {"extra_vars": {"test": "foo"}}
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Add Tower credential type with exists
credential_type:
description: Credential type for Test
name: "{{ cred_type_name }}"
kind: cloud
inputs: {"fields": [{"type": "string", "id": "username", "label": "Username"}, {"secret": true, "type": "string", "id": "password", "label": "Password"}], "required": ["username", "password"]}
injectors: {"extra_vars": {"test": "foo"}}
state: exists
register: result
- assert:
that:
- "result is changed"
- name: Rename Tower credential type - name: Rename Tower credential type
credential_type: credential_type:
name: "{{ cred_type_name }}" name: "{{ cred_type_name }}"

View File

@@ -22,6 +22,48 @@
that: that:
- "result is changed" - "result is changed"
- name: Add an EE with exists
execution_environment:
name: "{{ ee_name }}"
description: "EE for Testing"
image: quay.io/ansible/awx-ee
pull: always
organization: Default
state: exists
register: result
- assert:
that:
- "result is not changed"
- name: Delete an EE
execution_environment:
name: "{{ ee_name }}"
description: "EE for Testing"
image: quay.io/ansible/awx-ee
pull: always
organization: Default
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Add an EE with exists
execution_environment:
name: "{{ ee_name }}"
description: "EE for Testing"
image: quay.io/ansible/awx-ee
pull: always
organization: Default
state: exists
register: result
- assert:
that:
- "result is changed"
- name: Associate the Test EE with Default Org (this should fail) - name: Associate the Test EE with Default Org (this should fail)
execution_environment: execution_environment:
name: "{{ ee_name }}" name: "{{ ee_name }}"

View File

@@ -19,9 +19,9 @@
name: "{{ inv_name }}" name: "{{ inv_name }}"
organization: Default organization: Default
state: present state: present
register: result registuer: result
- name: Create a Group - name: Create Group 1
group: group:
name: "{{ group_name1 }}" name: "{{ group_name1 }}"
inventory: "{{ result.id }}" inventory: "{{ result.id }}"
@@ -34,7 +34,46 @@
that: that:
- "result is changed" - "result is changed"
- name: Create a Group - name: Create Group 1 with exists
group:
name: "{{ group_name1 }}"
inventory: "{{ inv_name }}"
state: exists
variables:
foo: bar
register: result
- assert:
that:
- "result is not changed"
- name: Delete Group 1
group:
name: "{{ group_name1 }}"
inventory: "{{ inv_name }}"
state: absent
variables:
foo: bar
register: result
- assert:
that:
- "result is changed"
- name: Create Group 1 with exists
group:
name: "{{ group_name1 }}"
inventory: "{{ inv_name }}"
state: exists
variables:
foo: bar
register: result
- assert:
that:
- "result is changed"
- name: Create Group 2
group: group:
name: "{{ group_name2 }}" name: "{{ group_name2 }}"
inventory: "{{ inv_name }}" inventory: "{{ inv_name }}"
@@ -47,7 +86,7 @@
that: that:
- "result is changed" - "result is changed"
- name: Create a Group - name: Create Group 3
group: group:
name: "{{ group_name3 }}" name: "{{ group_name3 }}"
inventory: "{{ inv_name }}" inventory: "{{ inv_name }}"
@@ -69,7 +108,7 @@
- "{{ host_name2 }}" - "{{ host_name2 }}"
- "{{ host_name3 }}" - "{{ host_name3 }}"
- name: Create a Group with hosts and sub group - name: Create Group 1 with hosts and sub group of Group 2
group: group:
name: "{{ group_name1 }}" name: "{{ group_name1 }}"
inventory: "{{ inv_name }}" inventory: "{{ inv_name }}"
@@ -83,7 +122,7 @@
foo: bar foo: bar
register: result register: result
- name: Create a Group with hosts and sub group - name: Create Group 1 with hosts and sub group
group: group:
name: "{{ group_name1 }}" name: "{{ group_name1 }}"
inventory: "{{ inv_name }}" inventory: "{{ inv_name }}"
@@ -104,18 +143,7 @@
that: that:
- group1_host_count == "3" - group1_host_count == "3"
- name: Delete a Group - name: Delete Group 2
group:
name: "{{ group_name1 }}"
inventory: "{{ inv_name }}"
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Delete a Group
group: group:
name: "{{ group_name2 }}" name: "{{ group_name2 }}"
inventory: "{{ inv_name }}" inventory: "{{ inv_name }}"
@@ -127,7 +155,7 @@
that: that:
- "result is not changed" - "result is not changed"
- name: Delete a Group - name: Delete Group 3
group: group:
name: "{{ group_name3 }}" name: "{{ group_name3 }}"
inventory: "{{ inv_name }}" inventory: "{{ inv_name }}"
@@ -136,7 +164,19 @@
- assert: - assert:
that: that:
- "result is not changed" - "result is changed"
# If we delete group 1 first it will delete group 2 and 3
- name: Delete Group 1
group:
name: "{{ group_name1 }}"
inventory: "{{ inv_name }}"
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Check module fails with correct msg - name: Check module fails with correct msg
group: group:

View File

@@ -29,6 +29,45 @@
that: that:
- "result is changed" - "result is changed"
- name: Create a Host with exists
host:
name: "{{ host_name }}"
inventory: "{{ inv_name }}"
state: exists
variables:
foo: bar
register: result
- assert:
that:
- "result is not changed"
- name: Delete a Host
host:
name: "{{ host_name }}"
inventory: "{{ inv_name }}"
state: absent
variables:
foo: bar
register: result
- assert:
that:
- "result is changed"
- name: Create a Host with exists
host:
name: "{{ host_name }}"
inventory: "{{ inv_name }}"
state: exists
variables:
foo: bar
register: result
- assert:
that:
- "result is changed"
- name: Delete a Host - name: Delete a Host
host: host:
name: "{{ result.id }}" name: "{{ result.id }}"

View File

@@ -38,6 +38,42 @@
that: that:
- "result is changed" - "result is changed"
- name: Create an Instance Group with exists
instance_group:
name: "{{ group_name1 }}"
policy_instance_percentage: 34
policy_instance_minimum: 12
state: exists
register: result
- assert:
that:
- "result is not changed"
- name: Delete an Instance Group
instance_group:
name: "{{ group_name1 }}"
policy_instance_percentage: 34
policy_instance_minimum: 12
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Create an Instance Group with exists
instance_group:
name: "{{ group_name1 }}"
policy_instance_percentage: 34
policy_instance_minimum: 12
state: exists
register: result
- assert:
that:
- "result is changed"
- name: Update an Instance Group - name: Update an Instance Group
instance_group: instance_group:
name: "{{ result.id }}" name: "{{ result.id }}"

View File

@@ -51,6 +51,45 @@
that: that:
- "result is changed" - "result is changed"
- name: Create an Inventory with exists
inventory:
name: "{{ inv_name1 }}"
organization: Default
instance_groups:
- "{{ group_name1 }}"
state: exists
register: result
- assert:
that:
- "result is not changed"
- name: Delete an Inventory
inventory:
name: "{{ inv_name1 }}"
organization: Default
instance_groups:
- "{{ group_name1 }}"
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Create an Inventory with exists
inventory:
name: "{{ inv_name1 }}"
organization: Default
instance_groups:
- "{{ group_name1 }}"
state: exists
register: result
- assert:
that:
- "result is changed"
- name: Test Inventory module idempotency - name: Test Inventory module idempotency
inventory: inventory:
name: "{{ result.id }}" name: "{{ result.id }}"

View File

@@ -30,7 +30,7 @@
organization: Default organization: Default
name: "{{ openstack_inv }}" name: "{{ openstack_inv }}"
- name: Create a source inventory - name: Create an source inventory
inventory_source: inventory_source:
name: "{{ openstack_inv_source }}" name: "{{ openstack_inv_source }}"
description: Source for Test inventory description: Source for Test inventory
@@ -47,6 +47,60 @@
that: that:
- "result is changed" - "result is changed"
- name: Create an source inventory with exists
inventory_source:
name: "{{ openstack_inv_source }}"
description: Source for Test inventory
inventory: "{{ openstack_inv }}"
credential: "{{ credential_result.id }}"
overwrite: true
update_on_launch: true
source_vars:
private: false
source: openstack
state: exists
register: result
- assert:
that:
- "result is not changed"
- name: Delete an source inventory
inventory_source:
name: "{{ openstack_inv_source }}"
description: Source for Test inventory
inventory: "{{ openstack_inv }}"
credential: "{{ credential_result.id }}"
overwrite: true
update_on_launch: true
source_vars:
private: false
source: openstack
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Create an source inventory with exists
inventory_source:
name: "{{ openstack_inv_source }}"
description: Source for Test inventory
inventory: "{{ openstack_inv }}"
credential: "{{ credential_result.id }}"
overwrite: true
update_on_launch: true
source_vars:
private: false
source: openstack
state: exists
register: result
- assert:
that:
- "result is changed"
- name: Delete the inventory source with an invalid cred and source_project specified - name: Delete the inventory source with an invalid cred and source_project specified
inventory_source: inventory_source:
name: "{{ result.id }}" name: "{{ result.id }}"

View File

@@ -10,6 +10,7 @@
cred1: "AWX-Collection-tests-job_template-cred1-{{ test_id }}" cred1: "AWX-Collection-tests-job_template-cred1-{{ test_id }}"
cred2: "AWX-Collection-tests-job_template-cred2-{{ test_id }}" cred2: "AWX-Collection-tests-job_template-cred2-{{ test_id }}"
cred3: "AWX-Collection-tests-job_template-cred3-{{ test_id }}" cred3: "AWX-Collection-tests-job_template-cred3-{{ test_id }}"
inv1: "AWX-Collection-tests-job_template-inv-{{ test_id }}"
proj1: "AWX-Collection-tests-job_template-proj-{{ test_id }}" proj1: "AWX-Collection-tests-job_template-proj-{{ test_id }}"
jt1: "AWX-Collection-tests-job_template-jt1-{{ test_id }}" jt1: "AWX-Collection-tests-job_template-jt1-{{ test_id }}"
jt2: "AWX-Collection-tests-job_template-jt2-{{ test_id }}" jt2: "AWX-Collection-tests-job_template-jt2-{{ test_id }}"
@@ -25,6 +26,11 @@
- Ansible Galaxy - Ansible Galaxy
register: result register: result
- name: Create an inventory
inventory:
name: "{{ inv1 }}"
organization: "{{ org_name }}"
- name: Create a Demo Project - name: Create a Demo Project
project: project:
name: "{{ proj1 }}" name: "{{ proj1 }}"
@@ -104,7 +110,7 @@
job_template: job_template:
name: "{{ jt1 }}" name: "{{ jt1 }}"
project: "{{ proj1 }}" project: "{{ proj1 }}"
inventory: Demo Inventory inventory: "{{ inv1 }}"
playbook: hello_world.yml playbook: hello_world.yml
credentials: credentials:
- "{{ cred1 }}" - "{{ cred1 }}"
@@ -119,6 +125,63 @@
that: that:
- "jt1_result is changed" - "jt1_result is changed"
- name: Create Job Template 1 with exists
job_template:
name: "{{ jt1 }}"
project: "{{ proj1 }}"
inventory: "{{ inv1 }}"
playbook: hello_world.yml
credentials:
- "{{ cred1 }}"
- "{{ cred2 }}"
instance_groups:
- "{{ group_name1 }}"
job_type: run
state: exists
register: jt1_result
- assert:
that:
- "jt1_result is not changed"
- name: Delete Job Template 1
job_template:
name: "{{ jt1 }}"
project: "{{ proj1 }}"
inventory: "{{ inv1 }}"
playbook: hello_world.yml
credentials:
- "{{ cred1 }}"
- "{{ cred2 }}"
instance_groups:
- "{{ group_name1 }}"
job_type: run
state: absent
register: jt1_result
- assert:
that:
- "jt1_result is changed"
- name: Create Job Template 1 with exists
job_template:
name: "{{ jt1 }}"
project: "{{ proj1 }}"
inventory: "{{ inv1 }}"
playbook: hello_world.yml
credentials:
- "{{ cred1 }}"
- "{{ cred2 }}"
instance_groups:
- "{{ group_name1 }}"
job_type: run
state: exists
register: jt1_result
- assert:
that:
- "jt1_result is changed"
- name: Add a credential to this JT - name: Add a credential to this JT
job_template: job_template:
name: "{{ jt1 }}" name: "{{ jt1 }}"
@@ -218,7 +281,7 @@
name: "{{ jt2 }}" name: "{{ jt2 }}"
organization: Default organization: Default
project: "{{ proj1 }}" project: "{{ proj1 }}"
inventory: Demo Inventory inventory: "{{ inv1 }}"
playbook: hello_world.yml playbook: hello_world.yml
credential: "{{ cred3 }}" credential: "{{ cred3 }}"
job_type: run job_type: run
@@ -236,7 +299,7 @@
name: "{{ jt2 }}" name: "{{ jt2 }}"
organization: Default organization: Default
project: "{{ proj1 }}" project: "{{ proj1 }}"
inventory: Demo Inventory inventory: "{{ inv1 }}"
playbook: hello_world.yml playbook: hello_world.yml
credential: "{{ cred3 }}" credential: "{{ cred3 }}"
job_type: run job_type: run
@@ -384,7 +447,7 @@
job_template: job_template:
name: "{{ jt2 }}" name: "{{ jt2 }}"
project: "{{ proj1 }}" project: "{{ proj1 }}"
inventory: Demo Inventory inventory: "{{ inv1 }}"
playbook: hello_world.yml playbook: hello_world.yml
credential: "{{ cred3 }}" credential: "{{ cred3 }}"
job_type: run job_type: run
@@ -444,6 +507,12 @@
organization: Default organization: Default
state: absent state: absent
- name: Delete an inventory
inventory:
name: "{{ inv1 }}"
organization: "{{ org_name }}"
state: absent
- name: "Remove the organization" - name: "Remove the organization"
organization: organization:
name: "{{ org_name }}" name: "{{ org_name }}"

View File

@@ -13,6 +13,22 @@
name: "{{ label_name }}" name: "{{ label_name }}"
organization: Default organization: Default
state: present state: present
register: results
- assert:
that:
- "results is changed"
- name: Create a Label with exists
label:
name: "{{ label_name }}"
organization: Default
state: exists
register: results
- assert:
that:
- "results is not changed"
- name: Check module fails with correct msg - name: Check module fails with correct msg
label: label:

View File

@@ -36,6 +36,75 @@
that: that:
- result is changed - result is changed
- name: Create Slack notification with custom messages with exists
notification_template:
name: "{{ slack_not }}"
organization: Default
notification_type: slack
notification_configuration:
token: a_token
channels:
- general
messages:
started:
message: "{{ '{{' }} job_friendly_name {{' }}' }} {{ '{{' }} job.id {{' }}' }} started"
success:
message: "{{ '{{' }} job_friendly_name {{ '}}' }} completed in {{ '{{' }} job.elapsed {{ '}}' }} seconds"
error:
message: "{{ '{{' }} job_friendly_name {{ '}}' }} FAILED! Please look at {{ '{{' }} job.url {{ '}}' }}"
state: exists
register: result
- assert:
that:
- result is not changed
- name: Delete Slack notification with custom messages
notification_template:
name: "{{ slack_not }}"
organization: Default
notification_type: slack
notification_configuration:
token: a_token
channels:
- general
messages:
started:
message: "{{ '{{' }} job_friendly_name {{' }}' }} {{ '{{' }} job.id {{' }}' }} started"
success:
message: "{{ '{{' }} job_friendly_name {{ '}}' }} completed in {{ '{{' }} job.elapsed {{ '}}' }} seconds"
error:
message: "{{ '{{' }} job_friendly_name {{ '}}' }} FAILED! Please look at {{ '{{' }} job.url {{ '}}' }}"
state: absent
register: result
- assert:
that:
- result is changed
- name: Create Slack notification with custom messages with exists
notification_template:
name: "{{ slack_not }}"
organization: Default
notification_type: slack
notification_configuration:
token: a_token
channels:
- general
messages:
started:
message: "{{ '{{' }} job_friendly_name {{' }}' }} {{ '{{' }} job.id {{' }}' }} started"
success:
message: "{{ '{{' }} job_friendly_name {{ '}}' }} completed in {{ '{{' }} job.elapsed {{ '}}' }} seconds"
error:
message: "{{ '{{' }} job_friendly_name {{ '}}' }} FAILED! Please look at {{ '{{' }} job.url {{ '}}' }}"
state: exists
register: result
- assert:
that:
- result is changed
- name: Delete Slack notification - name: Delete Slack notification
notification_template: notification_template:
name: "{{ slack_not }}" name: "{{ slack_not }}"

View File

@@ -25,6 +25,39 @@
- assert: - assert:
that: "result is changed" that: "result is changed"
- name: "Create a new organization with exists"
organization:
name: "{{ org_name }}"
galaxy_credentials:
- Ansible Galaxy
state: exists
register: result
- assert:
that: "result is not changed"
- name: "Delete a new organization"
organization:
name: "{{ org_name }}"
galaxy_credentials:
- Ansible Galaxy
state: absent
register: result
- assert:
that: "result is changed"
- name: "Create a new organization with exists"
organization:
name: "{{ org_name }}"
galaxy_credentials:
- Ansible Galaxy
state: exists
register: result
- assert:
that: "result is changed"
- name: "Make sure making the same org is not a change" - name: "Make sure making the same org is not a change"
organization: organization:
name: "{{ org_name }}" name: "{{ org_name }}"

View File

@@ -39,6 +39,48 @@
that: that:
- result is changed - result is changed
- name: Create a git project without credentials and wait with exists
project:
name: "{{ project_name1 }}"
organization: Default
scm_type: git
scm_url: https://github.com/ansible/test-playbooks
wait: true
state: exists
register: result
- assert:
that:
- result is not changed
- name: Delete a git project without credentials and wait
project:
name: "{{ project_name1 }}"
organization: Default
scm_type: git
scm_url: https://github.com/ansible/test-playbooks
wait: true
state: absent
register: result
- assert:
that:
- result is changed
- name: Create a git project without credentials and wait with exists
project:
name: "{{ project_name1 }}"
organization: Default
scm_type: git
scm_url: https://github.com/ansible/test-playbooks
wait: true
state: exists
register: result
- assert:
that:
- result is changed
- name: Recreate the project to validate not changed - name: Recreate the project to validate not changed
project: project:
name: "{{ project_name1 }}" name: "{{ project_name1 }}"

View File

@@ -76,6 +76,42 @@
that: that:
- result is changed - result is changed
- name: Build a real schedule with exists
schedule:
name: "{{ sched1 }}"
state: exists
unified_job_template: "Demo Job Template"
rrule: "DTSTART:20191219T130551Z RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=1"
register: result
- assert:
that:
- result is not changed
- name: Delete a real schedule
schedule:
name: "{{ sched1 }}"
state: absent
unified_job_template: "Demo Job Template"
rrule: "DTSTART:20191219T130551Z RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=1"
register: result
- assert:
that:
- result is changed
- name: Build a real schedule with exists
schedule:
name: "{{ sched1 }}"
state: exists
unified_job_template: "Demo Job Template"
rrule: "DTSTART:20191219T130551Z RRULE:FREQ=WEEKLY;INTERVAL=1;COUNT=1"
register: result
- assert:
that:
- result is changed
- name: Rebuild the same schedule - name: Rebuild the same schedule
schedule: schedule:
name: "{{ sched1 }}" name: "{{ sched1 }}"

View File

@@ -34,6 +34,39 @@
that: that:
- "result is changed" - "result is changed"
- name: Create a team with exists
team:
name: "{{ team_name }}"
organization: Default
state: exists
register: result
- assert:
that:
- "result is not changed"
- name: Delete a team
team:
name: "{{ team_name }}"
organization: Default
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Create a team with exists
team:
name: "{{ team_name }}"
organization: Default
state: exists
register: result
- assert:
that:
- "result is changed"
- name: Delete a team - name: Delete a team
team: team:
name: "{{ team_name }}" name: "{{ team_name }}"

View File

@@ -20,6 +20,42 @@
that: that:
- "result is changed" - "result is changed"
- name: Create a User with exists
user:
username: "{{ username }}"
first_name: Joe
password: "{{ 65535 | random | to_uuid }}"
state: exists
register: result
- assert:
that:
- "result is not changed"
- name: Delete a User
user:
username: "{{ username }}"
first_name: Joe
password: "{{ 65535 | random | to_uuid }}"
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Create a User with exists
user:
username: "{{ username }}"
first_name: Joe
password: "{{ 65535 | random | to_uuid }}"
state: exists
register: result
- assert:
that:
- "result is changed"
- name: Change a User by ID - name: Change a User by ID
user: user:
username: "{{ result.id }}" username: "{{ result.id }}"

View File

@@ -254,6 +254,65 @@
that: that:
- "result is changed" - "result is changed"
- name: Create a workflow job template with exists
workflow_job_template:
name: "{{ wfjt_name }}"
organization: Default
inventory: Demo Inventory
extra_vars: {'foo': 'bar', 'another-foo': {'barz': 'bar2'}}
labels:
- "{{ lab1 }}"
ask_inventory_on_launch: true
ask_scm_branch_on_launch: true
ask_limit_on_launch: true
ask_tags_on_launch: true
ask_variables_on_launch: true
state: exists
register: result
- assert:
that:
- "result is not changed"
- name: Delete a workflow job template
workflow_job_template:
name: "{{ wfjt_name }}"
organization: Default
inventory: Demo Inventory
extra_vars: {'foo': 'bar', 'another-foo': {'barz': 'bar2'}}
labels:
- "{{ lab1 }}"
ask_inventory_on_launch: true
ask_scm_branch_on_launch: true
ask_limit_on_launch: true
ask_tags_on_launch: true
ask_variables_on_launch: true
state: absent
register: result
- assert:
that:
- "result is changed"
- name: Create a workflow job template with exists
workflow_job_template:
name: "{{ wfjt_name }}"
organization: Default
inventory: Demo Inventory
extra_vars: {'foo': 'bar', 'another-foo': {'barz': 'bar2'}}
# We don't try with the label here because after we delete the first WFJT the label is delete with it because it has no references
ask_inventory_on_launch: true
ask_scm_branch_on_launch: true
ask_limit_on_launch: true
ask_tags_on_launch: true
ask_variables_on_launch: true
state: exists
register: result
- assert:
that:
- "result is changed"
- name: Create a workflow job template with bad label - name: Create a workflow job template with bad label
workflow_job_template: workflow_job_template:
name: "{{ wfjt_name }}" name: "{{ wfjt_name }}"