def extract_inventory_relations(asset, relation_type): # Get the API options for the relation post_options = get_api_options(relation_type) # Get all of the hosts try: relations = tower_cli.get_resource(relation_type).list(all_pages=True, **{'inventory': asset['id']}) except TowerCLIError as e: raise TowerCLIError("Unable to get {} for {} : {}".format(relation_type, asset['id'], e)) return_relations = [] # If there are no results return an empty array if 'results' not in relations: return return_relations name_to_id_map = {} for relation in relations['results']: # if this relation is controlled by an inventory source we can skip it if 'has_inventory_sources' in relation and relation['has_inventory_sources']: continue name_to_id_map[relation['name']] = relation['id'] new_relation = {} map_node_to_post_options(post_options, relation, new_relation) if relation_type == 'inventory_source': # If this is an inventory source we also need to resolve the source_project if 'source_project' in relation and relation['source_project']: try: project = tower_cli.get_resource('project').get(relation['source_project']) except TowerCLIError as e: raise TowerCLIError("Unable to get project {} for {} : {}".format( relation['source_project'], relation_type, e )) new_relation['source_project'] = project['name'] if 'source_script' in relation and relation['source_script']: try: script = tower_cli.get_resource('inventory_script').get(relation['source_script']) except TowerCLIError as e: raise TowerCLIError("Unable to get inventory script {} for {} : {}".format( relation['source_script'], relation_type, e )) new_relation['source_script'] = script['name'] if 'credential' in relation and relation['credential']: try: credential = tower_cli.get_resource('credential').get(relation['credential']) except TowerCLIError as e: raise TowerCLIError("Unable to get inventory credential {} for {} : {}".format( relation['credential'], relation_type, e )) new_relation['credential'] = credential['name'] # Now get the schedules for this source if 'related' in relation and 'schedules' in relation['related']: schedule_data = extract_schedules(relation) new_relation['schedules'] = schedule_data['items'] del new_relation['inventory'] return_relations.append(new_relation) return {'items': return_relations, 'existing_name_to_id_map': name_to_id_map}
def main(): module = AnsibleModule( argument_spec=dict( name=dict(required=True), description=dict(), inventory=dict(required=True), enabled=dict(type='bool', default=True), variables=dict(), tower_host=dict(), tower_username=dict(), tower_password=dict(no_log=True), tower_verify_ssl=dict(type='bool', default=True), tower_config_file=dict(type='path'), state=dict(choices=['present', 'absent'], default='present'), ), supports_check_mode=True ) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') name = module.params.get('name') description = module.params.get('description') inventory = module.params.get('inventory') enabled = module.params.get('enabled') state = module.params.get('state') variables = module.params.get('variables') if variables: if variables.startswith('@'): filename = os.path.expanduser(variables[1:]) variables = module.contents_from_file(filename) json_output = {'host': name, 'state': state} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) host = tower_cli.get_resource('host') try: inv_res = tower_cli.get_resource('inventory') inv = inv_res.get(name=inventory) if state == 'present': result = host.modify(name=name, inventory=inv['id'], enabled=enabled, variables=variables, description=description, create_on_missing=True) json_output['id'] = result['id'] elif state == 'absent': result = host.delete(name=name, inventory=inv['id']) except (exc.NotFound) as excinfo: module.fail_json(msg='Failed to update host, inventory not found: {0}'.format(excinfo), changed=False) except (exc.ConnectionError, exc.BadRequest) as excinfo: module.fail_json(msg='Failed to update host: {0}'.format(excinfo), changed=False) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def main(): argument_spec = tower_argument_spec() argument_spec.update(dict( job_template=dict(required=True), job_type=dict(choices=['run', 'check', 'scan']), inventory=dict(), credential=dict(), limit=dict(), tags=dict(type='list'), extra_vars=dict(type='list'), )) module = AnsibleModule( argument_spec, supports_check_mode=True ) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') json_output = {} tags = module.params.get('tags') tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) try: params = module.params.copy() if isinstance(tags, list): params['tags'] = ','.join(tags) job = tower_cli.get_resource('job') lookup_fields = ('job_template', 'inventory', 'credential') for field in lookup_fields: try: name = params.pop(field) result = tower_cli.get_resource(field).get(name=name) params[field] = result['id'] except exc.NotFound as excinfo: module.fail_json(msg='Unable to launch job, {0}/{1} was not found: {2}'.format(field, name, excinfo), changed=False) result = job.launch(no_input=True, **params) json_output['id'] = result['id'] json_output['status'] = result['status'] except (exc.ConnectionError, exc.BadRequest) as excinfo: module.fail_json(msg='Unable to launch job: {0}'.format(excinfo), changed=False) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def main(): module = AnsibleModule( argument_spec=dict( name=dict(required=True), description=dict(), organization=dict(required=True), tower_host=dict(), tower_username=dict(), tower_password=dict(no_log=True), tower_verify_ssl=dict(type='bool', default=True), tower_config_file=dict(type='path'), state=dict(choices=['present', 'absent'], default='present'), ), supports_check_mode=True ) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') name = module.params.get('name') description = module.params.get('description') organization = module.params.get('organization') state = module.params.get('state') json_output = {'team': name, 'state': state} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) team = tower_cli.get_resource('team') try: org_res = tower_cli.get_resource('organization') org = org_res.get(name=organization) if state == 'present': result = team.modify(name=name, organization=org['id'], description=description, create_on_missing=True) json_output['id'] = result['id'] elif state == 'absent': result = team.delete(name=name, organization=org['id']) except (exc.NotFound) as excinfo: module.fail_json(msg='Failed to update team, organization not found: {0}'.format(excinfo), changed=False) except (exc.ConnectionError, exc.BadRequest, exc.NotFound) as excinfo: module.fail_json(msg='Failed to update team: {0}'.format(excinfo), changed=False) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def test_create_with_special_fields_new_functional(self): """Establish that the correct GET data is used with the new method for creating credentials.""" with client.test_mode as t: t.register_json('/credentials/', {'actions': {'POST': {'organization': 'information'}}}, method='OPTIONS') t.register_json('/credentials/', {'count': 0, 'results': [], 'next': None, 'previous': None}, method='GET') t.register_json('/credentials/', {'count': 0, 'results': [], 'next': None, 'previous': None}, method='GET') t.register_json('/credentials/', {'id': 42}, method='POST') cred_res = tower_cli.get_resource('credential') cred_res.create(name="foobar", user=1, credential_type=1) self.assertTrue(cred_res.fields[2].no_lookup) self.assertTrue(cred_res.fields[3].no_lookup) # Verify request data is correct self.assertEqual(len(t.requests), 2) self.assertEqual(t.requests[0].method, 'GET') self.assertEqual(t.requests[1].method, 'POST') self.assertIn('name=foobar', t.requests[0].url) # Make sure special fields not used for GET self.assertTrue('user' not in t.requests[0].url) # Make sure special files are used in actual POST self.assertIn('user', t.requests[1].body)
def create(self, credential=None, source=None, **kwargs): """Create a group and, if necessary, modify the inventory source within the group. """ # First, create the group. answer = super(Resource, self).create(**kwargs) # If the group already exists and we aren't supposed to make changes, # then we're done. if not kwargs.pop('force_on_exists', False) and not answer['changed']: return answer # Sanity check: A group was created, but do we need to do anything # with the inventory source at all? If no credential or source # was specified, then we'd just be updating the inventory source # with an effective no-op. if not credential and source in ('manual', None): return answer # Get the inventory source ID ("isid"). # Inventory sources are not created directly; rather, one was created # automatically when the group was created. isid = self._get_inventory_source_id(answer) # We now have our inventory source ID; modify it according to the # provided parameters. isrc = get_resource('inventory_source') return isrc.modify(isid, credential=credential, source=source, force_on_exists=True, **kwargs)
def modify(self, pk=None, credential=None, source=None, **kwargs): """Modify a group and, if necessary, the inventory source within the group. """ # First, modify the group. answer = super(Resource, self).modify(pk=pk, **kwargs) # If the group already exists and we aren't supposed to make changes, # then we're done. if not kwargs.pop('force_on_exists', True) and not answer['changed']: return answer # Get the inventory source ID ("isid"). # Inventory sources are not created directly; rather, one was created # automatically when the group was created. isid = self._get_inventory_source_id(answer) # We now have our inventory source ID; modify it according to the # provided parameters. # # Note: Any fields that were part of the group modification need # to be expunged from kwargs before making this call. isrc = get_resource('inventory_source') for field in self.fields: kwargs.pop(field.name, None) return isrc.modify(isid, credential=credential, source=source, force_on_exists=True, **kwargs)
def update_resources(module, p): '''update_resources attempts to fetch any of the resources given by name using their unique field (identity) ''' params = p.copy() for key in p: if key.startswith('tower_'): params.pop(key) params.pop('state', None) identity_map = { 'user': '******', 'team': 'name', 'target_team': 'name', 'inventory': 'name', 'job_template': 'name', 'credential': 'name', 'organization': 'name', 'project': 'name', } for k, v in identity_map.items(): try: if params[k]: key = 'team' if k == 'target_team' else k result = tower_cli.get_resource(key).get(**{v: params[k]}) params[k] = result['id'] except (exc.NotFound) as excinfo: module.fail_json(msg='Failed to update role, {0} not found: {1}'.format(k, excinfo), changed=False) return params
def create(self, organization=None, monitor=False, timeout=None, *args, **kwargs): """Create a new item of resource, with or w/o org. This would be a shared class with user, but it needs the ability to monitor if the flag is set. """ backup_endpoint = self.endpoint if organization: debug.log("using alternative endpoint specific to organization", header='details') # Get the organization from Tower, will lookup name if needed org_resource = get_resource('organization') org_data = org_resource.get(organization) org_pk = org_data['id'] self.endpoint = '/organizations/%s%s' % (org_pk, backup_endpoint) answer = super(Resource, self).create(*args, **kwargs) self.endpoint = backup_endpoint # if the monitor flag is set, wait for the SCM to update if monitor: project_id = answer['id'] return self.monitor(project_id, timeout=timeout) return answer
def test_create_without_special_fields(self): """Establish that a create without user, team, or credential works""" with mock.patch( 'tower_cli.models.base.Resource.create') as mock_create: cred_res = tower_cli.get_resource('credential') cred_res.create(name="foobar") mock_create.assert_called_once_with(name="foobar")
def convert(self, value, param, ctx): """Return the appropriate interger value. If a non-integer is provided, attempt a name-based lookup and return the primary key. """ resource = tower_cli.get_resource(self.resource_name) # Ensure that None is passed through without trying to # do anything. if value is None: return None # If we were already given an integer, do nothing. # This ensures that the convert method is idempotent. if isinstance(value, int): return value # Do we have a string that contains only digits? # If so, then convert it to an integer and return it. if re.match(r'^[\d]+$', value): return int(value) # Okay, we have a string. Try to do a name-based lookup on the # resource, and return back the ID that we get from that. # # This has the chance of erroring out, which is fine. try: debug.log('The %s field is given as a name; ' 'looking it up.' % param.name, header='details') rel = resource.get(**{resource.unique_criterion: value}) except exc.TowerCLIError as ex: raise exc.RelatedError('Could not get %s. %s' % (self.resource_name, str(ex))) # Done! Return the ID. return rel['id']
def main(): argument_spec = tower_argument_spec() argument_spec.update(dict( job_id=dict(type='int', required=True), fail_if_not_running=dict(type='bool', default=False), )) module = AnsibleModule( argument_spec=argument_spec, supports_check_mode=True, ) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') job_id = module.params.get('job_id') json_output = {} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) job = tower_cli.get_resource('job') params = module.params.copy() try: result = job.cancel(job_id, **params) json_output['id'] = job_id except (exc.ConnectionError, exc.BadRequest, exc.TowerCLIError) as excinfo: module.fail_json(msg='Unable to cancel job_id/{0}: {1}'.format(job_id, excinfo), changed=False) json_output['changed'] = result['changed'] json_output['status'] = result['status'] module.exit_json(**json_output)
def main(): argument_spec = tower_argument_spec() argument_spec.update(dict( name=dict(required=True), description=dict(), state=dict(choices=['present', 'absent'], default='present'), )) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') name = module.params.get('name') description = module.params.get('description') state = module.params.get('state') json_output = {'organization': name, 'state': state} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) organization = tower_cli.get_resource('organization') try: if state == 'present': result = organization.modify(name=name, description=description, create_on_missing=True) json_output['id'] = result['id'] elif state == 'absent': result = organization.delete(name=name) except (exc.ConnectionError, exc.BadRequest) as excinfo: module.fail_json(msg='Failed to update the organization: {0}'.format(excinfo), changed=False) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def __init__(self, data, wfjt, include_id=False): ujt_attrs = list(JOB_TYPES.values()) FK_FIELDS = ujt_attrs + ['inventory', 'credential'] node_attrs = {} attr_names = NODE_STANDARD_FIELDS + ujt_attrs if include_id: attr_names.append('id') for fd in attr_names: if fd not in data: continue if fd in FK_FIELDS and not isinstance(data[fd], int): # Node's template was given by name, do lookup ujt_res = get_resource(fd) ujt_data = ujt_res.get(name=data[fd]) node_attrs[fd] = ujt_data['id'] else: node_attrs[fd] = data[fd] node_attrs['workflow_job_template'] = wfjt for ujt_name in ujt_attrs: if ujt_name not in node_attrs: continue if 'unified_job_template' not in node_attrs: node_attrs['unified_job_template'] = node_attrs.pop(ujt_name) else: raise BadRequest( 'You should not provide more than one of the attributes' ' job_template, project and inventory_source.' ) self.unified_job_template = node_attrs.get('unified_job_template', None) self.node_attrs = node_attrs for rel in ['success_nodes', 'failure_nodes', 'always_nodes']: setattr( self, rel, [TreeNode(x, wfjt, include_id=include_id) for x in data.get(rel, data.get(rel[: -6], []))] )
def create(self, organization=None, monitor=False, timeout=None, fail_on_found=False, force_on_exists=False, **kwargs): """Create a new item of resource, with or w/o org. This would be a shared class with user, but it needs the ability to monitor if the flag is set. """ # First, run the create method, ignoring the organization given answer = super(Resource, self).write( create_on_missing=True, fail_on_found=fail_on_found, force_on_exists=force_on_exists, **kwargs ) project_id = answer['id'] # If an organization is given, associate it here if organization: # Get the organization from Tower, will lookup name if needed org_resource = get_resource('organization') org_data = org_resource.get(organization) org_pk = org_data['id'] debug.log("associating the project with its organization", header='details', nl=1) org_resource._assoc('projects', org_pk, project_id) # if the monitor flag is set, wait for the SCM to update if monitor: return self.monitor(project_id, timeout=timeout) return answer
def push_data(filename): with open(filename, 'r') as f: master_dict = yaml.load(f.read()) for res in res_list_reference: if res in master_dict: res_mod = tower_cli.get_resource(res) for entry in master_dict[res]: res_mod.create(**entry)
def main(): argument_spec = tower_argument_spec() argument_spec.update(dict( name=dict(required=True), description=dict(), job_type=dict(choices=['run', 'check', 'scan'], required=True), inventory=dict(), project=dict(required=True), playbook=dict(required=True), machine_credential=dict(), cloud_credential=dict(), network_credential=dict(), forks=dict(type='int'), limit=dict(), verbosity=dict(choices=['verbose', 'debug']), job_tags=dict(), skip_tags=dict(), host_config_key=dict(), extra_vars_path=dict(type='path', required=False), ask_extra_vars=dict(type='bool', default=False), ask_limit=dict(type='bool', default=False), ask_tags=dict(type='bool', default=False), ask_job_type=dict(type='bool', default=False), ask_inventory=dict(type='bool', default=False), ask_credential=dict(type='bool', default=False), become_enabled=dict(type='bool', default=False), state=dict(choices=['present', 'absent'], default='present'), )) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') name = module.params.get('name') state = module.params.get('state') json_output = {'job_template': name, 'state': state} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) jt = tower_cli.get_resource('job_template') params = update_resources(module, module.params) params = update_fields(params) params['create_on_missing'] = True try: if state == 'present': result = jt.modify(**params) json_output['id'] = result['id'] elif state == 'absent': result = jt.delete(**params) except (exc.ConnectionError, exc.BadRequest, exc.NotFound) as excinfo: module.fail_json(msg='Failed to update job template: {0}'.format(excinfo), changed=False) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def create(self, fail_on_found=False, force_on_exists=False, **kwargs): """Create a group and, if necessary, modify the inventory source within the group. """ group_fields = [f.name for f in self.fields] if kwargs.get('parent', None): parent_data = self.set_child_endpoint(parent=kwargs['parent'], inventory=kwargs.get( 'inventory', None)) kwargs['inventory'] = parent_data['inventory'] group_fields.append('group') elif 'inventory' not in kwargs: raise exc.UsageError('To create a group, you must provide a ' 'parent inventory or parent group.') # Break out the options for the group vs its inventory_source is_kwargs = {} for field in kwargs.copy(): if field not in group_fields: is_kwargs[field] = kwargs.pop(field) # Handle alias for "manual" source if is_kwargs.get('source', None) == 'manual': is_kwargs.pop('source') # First, create the group. answer = super(Resource, self).create(fail_on_found=fail_on_found, force_on_exists=force_on_exists, **kwargs) # If the group already exists and we aren't supposed to make changes, # then we're done. if not force_on_exists and not answer['changed']: return answer # Sanity check: A group was created, but do we need to do anything # with the inventory source at all? If no credential or source # was specified, then we'd just be updating the inventory source # with an effective no-op. if len(is_kwargs) == 0: return answer # Get the inventory source ID ("isid"). # Inventory sources are not created directly; rather, one was created # automatically when the group was created. isid = self._get_inventory_source_id(answer) # We now have our inventory source ID; modify it according to the # provided parameters. isrc = get_resource('inventory_source') is_answer = isrc.write(pk=isid, force_on_exists=True, **is_kwargs) # If either the inventory_source or the group objects were modified # then refelect this in the output to avoid confusing the user. if is_answer['changed']: answer['changed'] = True return answer
def main(): argument_spec = dict( name=dict(required=True), description=dict(required=False), kind=dict(required=False, choices=KIND_CHOICES.keys()), inputs=dict(type='dict', required=False), injectors=dict(type='dict', required=False), state=dict(choices=['present', 'absent'], default='present'), ) module = TowerModule( argument_spec=argument_spec, supports_check_mode=False ) name = module.params.get('name') kind = module.params.get('kind') state = module.params.get('state') json_output = {'credential_type': name, 'state': state} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) credential_type_res = tower_cli.get_resource('credential_type') params = {} params['name'] = name params['kind'] = kind params['managed_by_tower'] = False if module.params.get('description'): params['description'] = module.params.get('description') if module.params.get('inputs'): params['inputs'] = module.params.get('inputs') if module.params.get('injectors'): params['injectors'] = module.params.get('injectors') try: if state == 'present': params['create_on_missing'] = True result = credential_type_res.modify(**params) json_output['id'] = result['id'] elif state == 'absent': params['fail_on_missing'] = False result = credential_type_res.delete(**params) except (exc.ConnectionError, exc.BadRequest, exc.AuthError) as excinfo: module.fail_json( msg='Failed to update credential type: {0}'.format(excinfo), changed=False ) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def _get_schema(self, wfjt_id): """ Returns a dictionary that represents the node network of the workflow job template """ node_res = get_resource('node') node_results = node_res.list(workflow_job_template=wfjt_id, all_pages=True)['results'] return self._workflow_node_structure(node_results)
def test_create_with_special_fields_old(self): """Establish that creating with special fields passes through as-is if the API does not support this use mode.""" with client.test_mode as t: t.register_json('/credentials/', {'actions': {'POST': {}}}, method='OPTIONS') with mock.patch('tower_cli.models.base.Resource.create') as mock_create: cred_res = tower_cli.get_resource('credential') cred_res.create(name="foobar", organization="Foo Ops") mock_create.assert_called_once_with(name="foobar", organization="Foo Ops")
def create(self, fail_on_found=False, force_on_exists=False, **kwargs): """Create a group and, if necessary, modify the inventory source within the group. """ group_fields = [f.name for f in self.fields] if kwargs.get('parent', None): parent_data = self.set_child_endpoint( parent=kwargs['parent'], inventory=kwargs.get('inventory', None)) kwargs['inventory'] = parent_data['inventory'] group_fields.append('group') elif 'inventory' not in kwargs: raise exc.UsageError('To create a group, you must provide a ' 'parent inventory or parent group.') # Break out the options for the group vs its inventory_source is_kwargs = {} for field in kwargs.copy(): if field not in group_fields: is_kwargs[field] = kwargs.pop(field) # Handle alias for "manual" source if is_kwargs.get('source', None) == 'manual': is_kwargs.pop('source') # First, create the group. answer = super(Resource, self).create( fail_on_found=fail_on_found, force_on_exists=force_on_exists, **kwargs) # If the group already exists and we aren't supposed to make changes, # then we're done. if not force_on_exists and not answer['changed']: return answer # Sanity check: A group was created, but do we need to do anything # with the inventory source at all? If no credential or source # was specified, then we'd just be updating the inventory source # with an effective no-op. if len(is_kwargs) == 0: return answer # Get the inventory source ID ("isid"). # Inventory sources are not created directly; rather, one was created # automatically when the group was created. isid = self._get_inventory_source_id(answer) # We now have our inventory source ID; modify it according to the # provided parameters. isrc = get_resource('inventory_source') is_answer = isrc.write(pk=isid, force_on_exists=True, **is_kwargs) # If either the inventory_source or the group objects were modified # then refelect this in the output to avoid confusing the user. if is_answer['changed']: answer['changed'] = True return answer
def main(): argument_spec = tower_argument_spec() argument_spec.update(dict( name=dict(required=True), description=dict(), organization=dict(required=True), state=dict(choices=['present', 'absent'], default='present'), )) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') name = module.params.get('name') description = module.params.get('description') organization = module.params.get('organization') state = module.params.get('state') json_output = {'team': name, 'state': state} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) team = tower_cli.get_resource('team') try: org_res = tower_cli.get_resource('organization') org = org_res.get(name=organization) if state == 'present': result = team.modify(name=name, organization=org['id'], description=description, create_on_missing=True) json_output['id'] = result['id'] elif state == 'absent': result = team.delete(name=name, organization=org['id']) except (exc.NotFound) as excinfo: module.fail_json(msg='Failed to update team, organization not found: {0}'.format(excinfo), changed=False) except (exc.ConnectionError, exc.BadRequest, exc.NotFound) as excinfo: module.fail_json(msg='Failed to update team: {0}'.format(excinfo), changed=False) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def main(): module = AnsibleModule(argument_spec=dict( name=dict(required=True), description=dict(), job_type=dict(choices=['run', 'check', 'scan'], required=True), inventory=dict(), project=dict(required=True), playbook=dict(required=True), machine_credential=dict(), cloud_credential=dict(), network_credential=dict(), forks=dict(type='int'), limit=dict(), verbosity=dict(choices=['verbose', 'debug']), job_tags=dict(), skip_tags=dict(), extra_vars=dict(type='list', required=False), ask_extra_vars=dict(type='bool', default=False), ask_limit=dict(type='bool', default=False), ask_tags=dict(type='bool', default=False), ask_job_type=dict(type='bool', default=False), ask_inventory=dict(type='bool', default=False), ask_credential=dict(type='bool', default=False), become_enabled=dict(type='bool', default=False), config_file=dict(), state=dict(choices=['present', 'absent'], default='present'), ), supports_check_mode=False) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') name = module.params.get('name') state = module.params.get('state') json_output = {'job_template': name, 'state': state} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): jt = tower_cli.get_resource('job_template') params = update_fields(module.params) params = update_resources(module, params) params['create_on_missing'] = True try: if state == 'present': result = jt.modify(**params) json_output['id'] = result['id'] elif state == 'absent': result = jt.delete(**params) except (exc.ConnectionError, exc.BadRequest, exc.NotFound) as excinfo: module.fail_json(msg='{}'.format(excinfo), changed=False) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def main(): argument_spec = dict( job_id=dict(type='int', required=True), timeout=dict(type='int'), min_interval=dict(type='float', default=1), max_interval=dict(type='float', default=30), ) module = TowerModule(argument_spec, supports_check_mode=True) json_output = {} fail_json = None tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) job = tower_cli.get_resource('job') params = module.params.copy() # tower-cli gets very noisy when monitoring. # We pass in our our outfile to suppress the out during our monitor call. outfile = StringIO() params['outfile'] = outfile job_id = params.get('job_id') try: result = job.monitor(job_id, **params) except exc.Timeout: result = job.status(job_id) result['id'] = job_id json_output['msg'] = 'Timeout waiting for job to finish.' json_output['timeout'] = True except exc.NotFound as excinfo: fail_json = dict( msg='Unable to wait, no job_id {0} found: {1}'.format( job_id, excinfo), changed=False) except exc.JobFailure as excinfo: fail_json = dict( msg='Job with id={} failed, error: {}'.format(job_id, excinfo)) fail_json['success'] = False result = job.get(job_id) for k in ('id', 'status', 'elapsed', 'started', 'finished'): fail_json[k] = result.get(k) except (exc.ConnectionError, exc.BadRequest, exc.AuthError) as excinfo: fail_json = dict(msg='Unable to wait for job: {0}'.format(excinfo), changed=False) if fail_json is not None: module.fail_json(**fail_json) json_output['success'] = True for k in ('id', 'status', 'elapsed', 'started', 'finished'): json_output[k] = result.get(k) module.exit_json(**json_output)
def main(): module = AnsibleModule(argument_spec=dict( username=dict(required=True), first_name=dict(), last_name=dict(), password=dict(no_log=True), email=dict(required=True), superuser=dict(type='bool', default=False), auditor=dict(type='bool', default=False), tower_host=dict(), tower_username=dict(), tower_password=dict(no_log=True), tower_verify_ssl=dict(type='bool', default=True), tower_config_file=dict(type='path'), state=dict(choices=['present', 'absent'], default='present'), ), supports_check_mode=True) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') username = module.params.get('username') first_name = module.params.get('first_name') last_name = module.params.get('last_name') password = module.params.get('password') email = module.params.get('email') superuser = module.params.get('superuser') auditor = module.params.get('auditor') state = module.params.get('state') json_output = {'username': username, 'state': state} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) user = tower_cli.get_resource('user') try: if state == 'present': result = user.modify(username=username, first_name=first_name, last_name=last_name, email=email, password=password, is_superuser=superuser, is_auditor=auditor, create_on_missing=True) json_output['id'] = result['id'] elif state == 'absent': result = user.delete(username=username) except (exc.ConnectionError, exc.BadRequest) as excinfo: module.fail_json( msg='Failed to update the user: {0}'.format(excinfo), changed=False) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def main(): argument_spec = dict( name=dict(required=True), organization=dict(required=True), state=dict(choices=['present', 'absent'], default='present'), ) module = TowerModule(argument_spec=argument_spec, supports_check_mode=True) name = module.params.get('name') organization = module.params.get('organization') state = module.params.get('state') json_output = {'label': name, 'state': state} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) label = tower_cli.get_resource('label') try: org_res = tower_cli.get_resource('organization') org = org_res.get(name=organization) if state == 'present': result = label.modify(name=name, organization=org['id'], create_on_missing=True) json_output['id'] = result['id'] elif state == 'absent': result = label.delete(name=name, organization=org['id']) except (exc.NotFound) as excinfo: module.fail_json( msg='Failed to update label, organization not found: {0}'. format(excinfo), changed=False) except (exc.ConnectionError, exc.BadRequest, exc.NotFound, exc.AuthError) as excinfo: module.fail_json(msg='Failed to update label: {0}'.format(excinfo), changed=False) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def get_content(res_name): res = get_resource(res_name) content = OrderedDict() for field in res.fields: for attr in ATTR_TO_SHOW: content.setdefault(attr, []) attr_val = getattr(field, attr, 'N/A') attr_val = convert_to_str(field, attr, attr_val) content[attr].append(attr_val) return content
def sync(self, group, monitor=False, wait=False, timeout=None, **kwargs): """Update the given group's inventory source.""" isrc = get_resource('inventory_source') isid = self._get_inventory_source_id(group, kwargs) return isrc.update(isid, monitor=monitor, timeout=timeout, wait=wait, **kwargs)
def associate_host_to_group(name, groups, host, inv, json_output): group_obj = tower_cli.get_resource('group') host_res = host.get(inventory=inv['id'], name=name) for group in groups: group_res = group_obj.get(inventory=inv['id'], name=group.strip()) changed = host.associate(host=host_res['id'], group=group_res['id']) if changed['changed'] is True: json_output['group_added'] = group.strip() return True return False
def pull_data(): master_dict = {} for res in res_list_reference: res_mod = tower_cli.get_resource(res) res_response = res_mod.list(all_pages=True) standard_fields = res_fields[res] + res_extras[res].keys() master_dict[res] = [] for entry in res_response: item_dict = {} for field in standard_fields: if field in res_list_reference: target_mod = tower_cli.get_resource(field) target_entry = target_mod.get(int(entry[field])) item_dict[field] = target_entry['name'] elif entry[field] == '$encrypted$': pass else: item_dict[field] = entry[field] master_dict[res].append(item_dict) print yaml.dump(master_dict, default_flow_style=False)
def test_create_with_special_fields_new(self): """Establish that creating with special fields uses special no_lookup tool if given special fields and the API supports that use case.""" with client.test_mode as t: t.register_json('/credentials/', {'actions': {'POST': {'organization': 'information'}}}, method='OPTIONS') with mock.patch('tower_cli.models.base.Resource.create') as mock_create: cred_res = tower_cli.get_resource('credential') cred_res.create(name="foobar", organization="Foo Ops") mock_create.assert_called_once_with(name="foobar", organization="Foo Ops") self.assertTrue(cred_res.fields[2].no_lookup)
def list_resource_commands(self): """Returns a list of multi-commands for each resource type. """ resource_path = os.path.abspath( os.path.join(os.path.dirname(__file__), os.pardir, 'resources')) answer = set([]) for _, name, _ in pkgutil.iter_modules([resource_path]): res = tower_cli.get_resource(name) if not getattr(res, 'internal', False): answer.add(name) return sorted(answer)
def main(): module = AnsibleModule(argument_spec=dict( job_template=dict(required=True), job_type=dict(choices=['run', 'check', 'scan']), inventory=dict(), credential=dict(), limit=dict(), tags=dict(), extra_vars=dict(type='list', required=False), config_file=dict(), ), supports_check_mode=False) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') json_output = {} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): try: params = module.params.copy() job = tower_cli.get_resource('job') try: jt_name = params.pop('job_template') jt = tower_cli.get_resource('job_template').get(name=jt_name) except exc.NotFound as excinfo: module.fail_json(msg='{} job_template: {}'.format( excinfo, jt_name), changed=False) result = job.launch(jt['id'], no_input=True, **params) json_output['id'] = result['id'] json_output['status'] = result['status'] except (exc.ConnectionError, exc.BadRequest) as excinfo: module.fail_json(msg='{}'.format(excinfo), changed=False) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def create(self, organization=None, monitor=False, wait=False, timeout=None, fail_on_found=False, force_on_exists=False, **kwargs): """Create a new item of resource, with or w/o org. This would be a shared class with user, but it needs the ability to monitor if the flag is set. """ if 'job_timeout' in kwargs and 'timeout' not in kwargs: kwargs['timeout'] = kwargs.pop('job_timeout') post_associate = False if organization: # Processing the organization flag depends on version debug.log('Checking Organization Relationship.', header='details') r = client.options('/projects/') if 'organization' in r.json()['actions']['POST']: kwargs['organization'] = organization else: post_associate = True # First, run the create method, ignoring the organization given answer = super(Resource, self).write(create_on_missing=True, fail_on_found=fail_on_found, force_on_exists=force_on_exists, **kwargs) project_id = answer['id'] # If an organization is given, associate it here if post_associate: # Get the organization from Tower, will lookup name if needed org_resource = get_resource('organization') org_data = org_resource.get(organization) org_pk = org_data['id'] debug.log("associating the project with its organization", header='details', nl=1) org_resource._assoc('projects', org_pk, project_id) # if the monitor flag is set, wait for the SCM to update if monitor and answer.get('changed', False): return self.monitor(pk=None, parent_pk=project_id, timeout=timeout) elif wait and answer.get('changed', False): return self.wait(pk=None, parent_pk=project_id, timeout=timeout) return answer
def main(): argument_spec = tower_argument_spec() argument_spec.update(dict( job_id=dict(type='int', required=True), timeout=dict(type='int'), min_interval=dict(type='float', default=1), max_interval=dict(type='float', default=30), )) module = AnsibleModule( argument_spec, supports_check_mode=True ) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') json_output = {} fail_json = None tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) job = tower_cli.get_resource('job') params = module.params.copy() # tower-cli gets very noisy when monitoring. # We pass in our our outfile to suppress the out during our monitor call. outfile = StringIO() params['outfile'] = outfile job_id = params.get('job_id') try: result = job.monitor(job_id, **params) except exc.Timeout as excinfo: result = job.status(job_id) result['id'] = job_id json_output['msg'] = 'Timeout waiting for job to finish.' json_output['timeout'] = True except exc.NotFound as excinfo: fail_json = dict(msg='Unable to wait, no job_id {0} found: {1}'.format(job_id, excinfo), changed=False) except (exc.ConnectionError, exc.BadRequest) as excinfo: fail_json = dict(msg='Unable to wait for job: {0}'.format(excinfo), changed=False) if fail_json is not None: module.fail_json(**fail_json) json_output['success'] = True for k in ('id', 'status', 'elapsed', 'started', 'finished'): json_output[k] = result.get(k) module.exit_json(**json_output)
def get_resource_id(kind, name): """ Attempts to find a <kind> resource named <name> and return it's id. """ try: resource = tower_cli.get_resource(kind) item = resource.get(name=name) return item['id'] except (exc.NotFound) as excinfo: module.fail_json( msg="Could not update schedule, {0} not found: {1}".format( kind, name), changed=False)
def create(self, fail_on_found=False, force_on_exists=False, **kwargs): """Create a new label. There are two types of label creation: isolatedly creating a new label and creating a new label under a job template. Here the two types are discriminated by whether to provide --job-template option. Fields in the resource's `identity` tuple are used for a lookup; if a match is found, then no-op (unless `force_on_exists` is set) but do not fail (unless `fail_on_found` is set). =====API DOCS===== Create a label. :param job_template: Primary key or name of the job template for the created label to associate to. :type job_template: str :param fail_on_found: Flag that if set, the operation fails if an object matching the unique criteria already exists. :type fail_on_found: bool :param force_on_exists: Flag that if set, then if a match is found on unique fields, other fields will be updated to the provided values.; If unset, a match causes the request to be a no-op. :type force_on_exists: bool :param `**kwargs`: Keyword arguments which, all together, will be used as POST body to create the resource object. :returns: A dictionary combining the JSON output of the created resource, as well as two extra fields: "changed", a flag indicating if the resource is created successfully; "id", an integer which is the primary key of the created object. :rtype: dict :raises tower_cli.exceptions.TowerCLIError: When the label already exists and ``fail_on_found`` flag is on. =====API DOCS===== """ jt_id = kwargs.pop('job_template', None) old_endpoint = self.endpoint if jt_id is not None: jt = get_resource('job_template') jt.get(pk=jt_id) try: label_id = self.get(name=kwargs.get('name', None), organization=kwargs.get('organization', None))['id'] except exc.NotFound: pass else: if fail_on_found: raise exc.TowerCLIError('Label already exists and fail-on-found is switched on. Please use' ' "associate_label" method of job_template instead.') else: debug.log('Label already exists, associating with job template.', header='details') return jt.associate_label(job_template=jt_id, label=label_id) self.endpoint = '/job_templates/%d/labels/' % jt_id result = super(Resource, self).create(fail_on_found=fail_on_found, force_on_exists=force_on_exists, **kwargs) self.endpoint = old_endpoint return result
def main(): argument_spec = tower_argument_spec() argument_spec.update( dict( user=dict(), team=dict(), role=dict(choices=[ "admin", "read", "member", "execute", "adhoc", "update", "use", "auditor" ]), target_team=dict(), inventory=dict(), job_template=dict(), credential=dict(), organization=dict(), project=dict(), state=dict(choices=['present', 'absent'], default='present'), )) module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) if not HAS_TOWER_CLI: module.fail_json(msg='ansible-tower-cli required for this module') role_type = module.params.pop('role') state = module.params.get('state') json_output = {'role': role_type, 'state': state} tower_auth = tower_auth_config(module) with settings.runtime_values(**tower_auth): tower_check_mode(module) role = tower_cli.get_resource('role') params = update_resources(module, module.params) params['type'] = role_type try: if state == 'present': result = role.grant(**params) json_output['id'] = result['id'] elif state == 'absent': result = role.revoke(**params) except (exc.ConnectionError, exc.BadRequest, exc.NotFound) as excinfo: module.fail_json(msg='Failed to update role: {0}'.format(excinfo), changed=False) json_output['changed'] = result['changed'] module.exit_json(**json_output)
def get_job_template(template="Network-Validate-Traffic", host_name='127.0.0.1', user_name='admin', pass_word='admin'): with conf.settings.runtime_values(host=host_name, username=user_name, password=pass_word, verify_ssl=False): res = get_resource('job_template') result = res.list(all_pages=True) job_templates = result.get('results') for job_template in job_templates: if job_template.get('name').lower() == template.lower(): return job_template.get('url')
def test_sync(self): """Establish that the sync method correctly forwards to the inventory source method, after getting the inventory source ID. """ isrc = tower_cli.get_resource('inventory_source') with mock.patch.object(type(isrc), 'sync') as isrc_sync: with client.test_mode as t: t.register_json('/groups/1/', { 'id': 1, 'name': 'foo', 'inventory': 1, 'related': {'inventory_source': '/inventory_sources/42/'}, }, method='GET') self.gr.sync(1) isrc_sync.assert_called_once_with(42) self.assertEqual(len(t.requests), 1)
def test_create_with_special_fields_old(self): """Establish that creating with special fields passes through as-is if the API does not support this use mode.""" with client.test_mode as t: t.register_json('/credentials/', {'actions': { 'POST': {} }}, method='OPTIONS') with mock.patch( 'tower_cli.models.base.Resource.create') as mock_create: cred_res = tower_cli.get_resource('credential') cred_res.create(name="foobar", organization="Foo Ops") mock_create.assert_called_once_with(name="foobar", organization="Foo Ops")
def list_commands(self, ctx): """Return a list of commands present in the commands and resources folders, but not subcommands. """ answer = set() for filename in os.listdir('%s/%s/' % (tower_cli.whereami, 'resources')): if filename.endswith('.py') and not filename.startswith('_'): res = tower_cli.get_resource(filename[:-3]) if not getattr(res, 'internal', False): answer.add(filename[:-3]) for cmd_name in misc.__all__: answer.add(cmd_name) return sorted(answer)
def credential_type_for_v1_kind(params, module): credential_type_res = tower_cli.get_resource('credential_type') kind = params.pop('kind') arguments = {'managed_by_tower': True} if kind == 'ssh': if params.get('vault_password'): arguments['kind'] = 'vault' else: arguments['kind'] = 'ssh' elif kind in ('net', 'scm', 'insights', 'vault'): arguments['kind'] = kind elif kind in KIND_CHOICES: arguments.update(dict(kind='cloud', name=KIND_CHOICES[kind])) return credential_type_res.get(**arguments)
def list_resource_commands(self): """Returns a list of multi-commands for each resource type. """ resource_path = os.path.abspath(os.path.join( os.path.dirname(__file__), os.pardir, 'resources' )) answer = set([]) for _, name, _ in pkgutil.iter_modules([resource_path]): res = tower_cli.get_resource(name) if not getattr(res, 'internal', False): answer.add(name) return sorted(answer)
def test_type_name(self): """Establish that custom types are equipped with __name__ field and the upstream click.Choice's issue of having no __name__ field is properly dealt with. """ names = [ 'ad_hoc', 'credential', 'group', 'host', 'inventory', 'inventory_source', 'job', 'job_template', 'organization', 'project', 'team', 'user' ] for res_name in names: res = get_resource(res_name) self.assertEqual(type(res.fields), type([])) self.assertEqual(str(res.fields).startswith('[<Field:'), True)
def process(task_vars): with session(task_vars['tower_server'], task_vars['username'], task_vars['password']): job = get_resource('job') try: k_vars = {} if task_vars['inventory']: result = get_resource_id(get_resource('inventory'), task_vars['inventory']) print("* set inventory : {0}->{1}".format(task_vars['inventory'], result)) k_vars['inventory'] = result if task_vars['credential']: result = get_resource_id(get_resource('credential'), task_vars['credential']) print("* set credentials : {0}->{1}".format(task_vars['credential'], result)) k_vars['credential'] = result if task_vars['extraVars2']: vars_ = str(task_vars['extraVars2']) print("* set extra_vars : {0}".format(vars_)) # TODO: manage taskPasswordToken && taskPassword (turn hidden in waiting for...) k_vars['extra_vars'] = [vars_] print("\n") print("```") # started markdown code block res = job.launch(job_template=task_vars['jobTemplate'], monitor=task_vars['waitTillComplete'], **k_vars) finally: print("```") print("\n") # end markdown code block globals()['jobId'] = res['id'] globals()['jobStatus'] = res['status'] print("* [Job %s Link](%s/#/jobs/%s)" % (res['id'], task_vars['tower_server']['url'], res['id'])) if task_vars['stopOnFailure'] and not res['status'] == 'successful': raise Exception("Failed with status %s" % res['status'])
def convert(self, value, param, ctx): """Return the appropriate integer value. If a non-integer is provided, attempt a name-based lookup and return the primary key. """ resource = tower_cli.get_resource(self.resource_name) # Ensure that None is passed through without trying to # do anything. if value is None: return None # If we were already given an integer, do nothing. # This ensures that the convert method is idempotent. if isinstance(value, int): return value # Do we have a string that contains only digits? # If so, then convert it to an integer and return it. if re.match(r'^[\d]+$', value): return int(value) # Special case to allow disassociations if value == 'null': return value # Okay, we have a string. Try to do a name-based lookup on the # resource, and return back the ID that we get from that. # # This has the chance of erroring out, which is fine. try: debug.log('The %s field is given as a name; ' 'looking it up.' % param.name, header='details') lookup_data = {resource.identity[-1]: value} rel = resource.get(**lookup_data) except exc.MultipleResults: raise exc.MultipleRelatedError( 'Cannot look up {0} exclusively by name, because multiple {0} ' 'objects exist with that name.\n' 'Please send an ID. You can get the ID for the {0} you want ' 'with:\n' ' tower-cli {0} list --name "{1}"'.format(self.resource_name, value), ) except exc.TowerCLIError as ex: raise exc.RelatedError('Could not get %s. %s' % (self.resource_name, str(ex))) # Done! Return the ID. return rel['id']
def convert(self, value, param, ctx): """Return the appropriate integer value. If a non-integer is provided, attempt a name-based lookup and return the primary key. """ resource = tower_cli.get_resource(self.resource_name) # Ensure that None is passed through without trying to # do anything. if value is None: return None # If we were already given an integer, do nothing. # This ensures that the convert method is idempotent. if isinstance(value, int): return value # Do we have a string that contains only digits? # If so, then convert it to an integer and return it. if re.match(r'^[\d]+$', value): return int(value) # Special case to allow disassociations if value == 'null': return value # Okay, we have a string. Try to do a name-based lookup on the # resource, and return back the ID that we get from that. # # This has the chance of erroring out, which is fine. try: debug.log('The %s field is given as a name; ' 'looking it up.' % param.name, header='details') lookup_data = {resource.identity[-1]: value} rel = resource.get(**lookup_data) except exc.MultipleResults as ex: raise exc.MultipleRelatedError( 'Cannot look up {0} exclusively by name, because multiple {0} ' 'objects exist with that name.\n' 'Please send an ID. You can get the ID for the {0} you want ' 'with:\n' ' tower-cli {0} list --name "{1}"'.format( self.resource_name, value), ) except exc.TowerCLIError as ex: raise exc.RelatedError('Could not get %s. %s' % (self.resource_name, str(ex))) # Done! Return the ID. return rel['id']
def get_api_options(asset_type): if asset_type not in API_POST_OPTIONS: endpoint = tower_cli.get_resource(asset_type).endpoint response = client.options(endpoint) return_json = response.json() if "actions" not in return_json or "POST" not in return_json["actions"]: # Maybe we want to do a debug.log here debug.log("WARNING: Asset type {} has no API POST options no pre-checks can be performed".format( asset_type )) API_POST_OPTIONS[asset_type] = None else: API_POST_OPTIONS[asset_type] = return_json["actions"]["POST"] return API_POST_OPTIONS[asset_type]
def test_sync(self): """Establish that the sync method correctly forwards to the inventory source method, after getting the inventory source ID. """ isrc = tower_cli.get_resource("inventory_source") with mock.patch.object(type(isrc), "update") as isrc_sync: with client.test_mode as t: t.register_json( "/groups/1/", {"id": 1, "name": "foo", "inventory": 1, "related": {"inventory_source": "/inventory_sources/42/"}}, method="GET", ) self.gr.sync(1) isrc_sync.assert_called_once_with(42, monitor=False, timeout=None) self.assertEqual(len(t.requests), 1)
class TowerInventoryHost(TowerResource): res = tower_cli.get_resource('host') @classmethod def create(cls, **entries): """ Create inventory host """ return cls(**cls.res.create(**entries)) def add_to_group(self, group_id): """ Associate host to group """ self.res.associate(self.id, group_id)
def test_sync(self): """Establish that the sync method correctly forwards to the inventory source method, after getting the inventory source ID. """ isrc = tower_cli.get_resource('inventory_source') with mock.patch.object(type(isrc), 'update') as isrc_sync: with client.test_mode as t: t.register_json('/groups/1/', { 'id': 1, 'name': 'foo', 'inventory': 1, 'related': {'inventory_source': '/inventory_sources/42/'}, }, method='GET') self.gr.sync(1) isrc_sync.assert_called_once_with(42, monitor=False, timeout=None) self.assertEqual(len(t.requests), 1)
def get_api_options(asset_type): if asset_type not in API_POST_OPTIONS: endpoint = tower_cli.get_resource(asset_type).endpoint response = client.options(endpoint) return_json = response.json() if "actions" not in return_json or "POST" not in return_json["actions"]: # Maybe we want to do a debug.log here debug.log( "WARNING: Asset type {} has no API POST options no pre-checks can be performed" .format(asset_type)) API_POST_OPTIONS[asset_type] = None else: API_POST_OPTIONS[asset_type] = return_json["actions"]["POST"] return API_POST_OPTIONS[asset_type]
def create(self, fail_on_found=False, force_on_exists=False, **kwargs): """Create a notification template. All required configuration-related fields (required according to notification_type) must be provided. There are two types of notification template creation: isolatedly creating a new notification template and creating a new notification template under a job template. Here the two types are discriminated by whether to provide --job-template option. --status option controls more specific, job-run-status-related association. Fields in the resource's `identity` tuple are used for a lookup; if a match is found, then no-op (unless `force_on_exists` is set) but do not fail (unless `fail_on_found` is set). """ config_item = self._separate(kwargs) jt_id = kwargs.pop('job_template', None) status = kwargs.pop('status', 'any') old_endpoint = self.endpoint if jt_id is not None: jt = get_resource('job_template') jt.get(pk=jt_id) try: nt_id = self.get(**copy.deepcopy(kwargs))['id'] except exc.NotFound: pass else: if fail_on_found: raise exc.TowerCLIError('Notification template already ' 'exists and fail-on-found is ' 'switched on. Please use' ' "associate_notification" method' ' of job_template instead.') else: debug.log( 'Notification template already exists, ' 'associating with job template.', header='details') return jt.associate_notification(jt_id, nt_id, status=status) self.endpoint = '/job_templates/%d/notification_templates_%s/' %\ (jt_id, status) self._configuration(kwargs, config_item) result = super(Resource, self).create(**kwargs) self.endpoint = old_endpoint return result