tower_group relationships

rollback some module_utils changes
add runtime error for 404 type things
This commit is contained in:
AlanCoding
2020-03-16 22:48:04 -04:00
committed by beeankha
parent ace5a0a2b3
commit 558814ef3b
3 changed files with 99 additions and 37 deletions

View File

@@ -222,6 +222,8 @@ class TowerModule(AnsibleModule):
def get_all_endpoint(self, endpoint, *args, **kwargs): def get_all_endpoint(self, endpoint, *args, **kwargs):
response = self.get_endpoint(endpoint, *args, **kwargs) response = self.get_endpoint(endpoint, *args, **kwargs)
if 'next' not in response['json']:
raise RuntimeError('Expected list from API at {0}, got: {1}'.format(endpoint, response))
next_page = response['json']['next'] next_page = response['json']['next']
if response['json']['count'] > 10000: if response['json']['count'] > 10000:
@@ -545,8 +547,7 @@ class TowerModule(AnsibleModule):
# 2. The response from Tower from patching to the endpoint. It's up to you to process the response and exit from the module. # 2. The response from Tower from patching to the endpoint. It's up to you to process the response and exit from the module.
# 3. An ItemNotDefined exception, if the existing_item does not exist # 3. An ItemNotDefined exception, if the existing_item does not exist
# Note: common error codes from the Tower API can cause the module to fail # Note: common error codes from the Tower API can cause the module to fail
if not existing_item: if existing_item:
self.fail_json(msg="The exstiing item is not defined and thus cannot be updated")
# If we have an item, we can see if it needs an update # If we have an item, we can see if it needs an update
try: try:
@@ -582,10 +583,14 @@ class TowerModule(AnsibleModule):
else: else:
self.fail_json(**{'msg': "Unable to update {0} {1}, see response".format(item_type, item_name), 'response': response}) self.fail_json(**{'msg': "Unable to update {0} {1}, see response".format(item_type, item_name), 'response': response})
else:
raise RuntimeError('update_if_needed called incorrectly without existing_item')
# Process any associations with this item # Process any associations with this item
if associations is not None: if associations is not None:
for association_type in associations: for association_type, id_list in associations.items():
self.modify_associations(response['json']['related'][association_type], associations[association_type]) endpoint = '{0}{1}/'.format(item_url, association_type)
self.modify_associations(endpoint, id_list)
# If we change something and have an on_change call it # If we change something and have an on_change call it
if on_update is not None and self.json_output['changed']: if on_update is not None and self.json_output['changed']:

View File

@@ -41,6 +41,18 @@ options:
description: description:
- Variables to use for the group. - Variables to use for the group.
type: dict type: dict
hosts:
description:
- List of hosts that should be put in this group.
required: False
type: list
elements: str
groups:
description:
- List of groups that should be nested inside in this group.
required: False
type: list
elements: str
state: state:
description: description:
- Desired state of the resource. - Desired state of the resource.
@@ -85,6 +97,8 @@ def main():
description=dict(required=False), description=dict(required=False),
inventory=dict(required=True), inventory=dict(required=True),
variables=dict(type='dict', required=False), variables=dict(type='dict', required=False),
hosts=dict(type='list', elements='str'),
groups=dict(type='list', elements='str'),
state=dict(choices=['present', 'absent'], default='present'), state=dict(choices=['present', 'absent'], default='present'),
) )
@@ -120,12 +134,31 @@ def main():
if variables is not None: if variables is not None:
group_fields['variables'] = json.dumps(variables) group_fields['variables'] = json.dumps(variables)
association_fields = {}
for resource, relationship in (('hosts', 'hosts'), ('groups', 'children')):
name_list = module.params.get(resource)
if name_list is None:
continue
id_list = []
for sub_name in name_list:
sub_obj = module.get_one(resource, **{
'data': {'inventory': inventory_id, 'name': sub_name}
})
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'])
if id_list:
association_fields[relationship] = id_list
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
module.delete_if_needed(group) module.delete_if_needed(group)
elif state == 'present': elif state == 'present':
# If the state was present we can let the module build or update the existing group, this will return on its own # 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') module.create_or_update_if_needed(
group, group_fields, endpoint='groups', item_type='group',
associations=association_fields
)
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -3,7 +3,7 @@ __metaclass__ = type
import pytest import pytest
from awx.main.models import Organization, Inventory, Group from awx.main.models import Organization, Inventory, Group, Host
@pytest.mark.django_db @pytest.mark.django_db
@@ -32,6 +32,30 @@ def test_create_group(run_module, admin_user):
} }
@pytest.mark.django_db
def test_associate_hosts_and_groups(run_module, admin_user, organization):
inv = Inventory.objects.create(name='test-inv', organization=organization)
group = Group.objects.create(name='Test Group', inventory=inv)
inv_hosts = [Host.objects.create(inventory=inv, name='foo{0}'.format(i)) for i in range(3)]
group.hosts.add(inv_hosts[0], inv_hosts[1])
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],
groups=[child.name],
state='present'
), admin_user)
assert not result.get('failed', False), result.get('msg', result)
assert result['changed'] is True
assert set(group.hosts.all()) == set([inv_hosts[1], inv_hosts[2]])
assert set(group.children.all()) == set([child])
@pytest.mark.django_db @pytest.mark.django_db
def test_tower_group_idempotent(run_module, admin_user): def test_tower_group_idempotent(run_module, admin_user):
# https://github.com/ansible/ansible/issues/46803 # https://github.com/ansible/ansible/issues/46803