def mk_inventory(name, organization=None, persisted=True): inv = Inventory(name=name) if organization is not None: inv.organization = organization if persisted: inv.save() return inv
def test_host_summary_generation_with_deleted_hosts(): hostnames = [f'Host {i}' for i in range(10)] inv = Inventory() inv.save() Host.objects.bulk_create([Host(created=now(), modified=now(), name=h, inventory_id=inv.id) for h in hostnames]) j = Job(inventory=inv) j.save() host_map = dict((host.name, host.id) for host in inv.hosts.all()) # delete half of the hosts during the playbook run for h in inv.hosts.all()[:5]: h.delete() JobEvent.create_from_data( job_id=j.pk, parent_uuid='abc123', event='playbook_on_stats', event_data={ 'ok': dict((hostname, len(hostname)) for hostname in hostnames), 'changed': {}, 'dark': {}, 'failures': {}, 'ignored': {}, 'processed': {}, 'rescued': {}, 'skipped': {}, }, host_map=host_map, ).save() ids = sorted([s.host_id or -1 for s in j.job_host_summaries.order_by('id').all()]) names = sorted([s.host_name for s in j.job_host_summaries.all()]) assert ids == [-1, -1, -1, -1, -1, 6, 7, 8, 9, 10] assert names == ['Host 0', 'Host 1', 'Host 2', 'Host 3', 'Host 4', 'Host 5', 'Host 6', 'Host 7', 'Host 8', 'Host 9']
def test_invalid_kind_clean_insights_credential(): cred_type = CredentialType.defaults['insights']() insights_cred = Credential(credential_type=cred_type) inv = Inventory(kind='smart', insights_credential=insights_cred) with pytest.raises(ValidationError) as e: inv.clean_insights_credential() assert json.dumps(str(e.value)) == json.dumps(str([u'Assignment not allowed for Smart Inventory']))
def test_invalid_clean_insights_credential(): cred_type = CredentialType.defaults['scm']() cred = Credential(credential_type=cred_type) inv = Inventory(insights_credential=cred) with pytest.raises(ValidationError) as e: inv.clean_insights_credential() assert json.dumps(str(e.value)) == json.dumps(str([u"Credential kind must be 'insights'."]))
def test_create_inventory_smart_inventory_sources(post, get, inventory, admin_user, organization): data = {'name': 'Inventory Source 1', 'description': 'Test Inventory Source'} smart_inventory = Inventory(name='smart', kind='smart', organization=organization, host_filter='inventory_sources__source=ec2') smart_inventory.save() post(reverse('api:inventory_inventory_sources_list', kwargs={'pk': smart_inventory.id}), data, admin_user) resp = get(reverse('api:inventory_inventory_sources_list', kwargs={'pk': smart_inventory.id}), admin_user) jdata = json.loads(resp.content) assert getattr(smart_inventory, 'kind') == 'smart' assert jdata['count'] == 0
def test_empty_inventory(post, get, admin_user, organization, group_factory): inventory = Inventory(name='basic_inventory', kind='', organization=organization) inventory.save() resp = get(reverse('api:inventory_script_view', kwargs={'version': 'v2', 'pk': inventory.pk}), admin_user) jdata = json.loads(resp.content) jdata.pop('all') assert inventory.hosts.count() == 0 assert jdata == {}
def test_host_summary_generation_with_limit(): # Make an inventory with 10 hosts, run a playbook with a --limit # pointed at *one* host, # Verify that *only* that host has an associated JobHostSummary and that # *only* that host has an updated value for .last_job. hostnames = [f'Host {i}' for i in range(10)] inv = Inventory() inv.save() Host.objects.bulk_create([ Host(created=now(), modified=now(), name=h, inventory_id=inv.id) for h in hostnames ]) j = Job(inventory=inv) j.save() # host map is a data structure that tracks a mapping of host name --> ID # for the inventory, _regardless_ of whether or not there's a limit # applied to the actual playbook run host_map = dict((host.name, host.id) for host in inv.hosts.all()) # by making the playbook_on_stats *only* include Host 1, we're emulating # the behavior of a `--limit=Host 1` matching_host = Host.objects.get(name='Host 1') JobEvent.create_from_data( job_id=j.pk, parent_uuid='abc123', event='playbook_on_stats', event_data={ 'ok': { matching_host.name: len(matching_host.name) }, # effectively, limit=Host 1 'changed': {}, 'dark': {}, 'failures': {}, 'ignored': {}, 'processed': {}, 'rescued': {}, 'skipped': {}, }, host_map=host_map).save() # since the playbook_on_stats only references one host, # there should *only* be on JobHostSummary record (and it should # be related to the appropriate Host) assert JobHostSummary.objects.count() == 1 for h in Host.objects.all(): if h.name == 'Host 1': assert h.last_job_id == j.id assert h.last_job_host_summary_id == JobHostSummary.objects.first( ).id else: # all other hosts in the inventory should remain untouched assert h.last_job_id is None assert h.last_job_host_summary_id is None
def test_ungrouped_hosts(post, get, admin_user, organization, group_factory): inventory = Inventory(name='basic_inventory', kind='', organization=organization) inventory.save() Host.objects.create(name='first_host', inventory=inventory) Host.objects.create(name='second_host', inventory=inventory) resp = get(reverse('api:inventory_script_view', kwargs={'version': 'v2', 'pk': inventory.pk}), admin_user) jdata = json.loads(resp.content) assert inventory.hosts.count() == 2 assert len(jdata['all']['hosts']) == 2
def job(container_group): return Job(pk=1, id=1, project=Project(), instance_group=container_group, inventory=Inventory(), job_template=JobTemplate(id=1, name='foo'))
def get_serializer_context(self, *args, **kwargs): full_context = super(OrganizationDetail, self).get_serializer_context(*args, **kwargs) if not hasattr(self, 'kwargs') or 'pk' not in self.kwargs: return full_context org_id = int(self.kwargs['pk']) org_counts = {} access_kwargs = { 'accessor': self.request.user, 'role_field': 'read_role' } direct_counts = Organization.objects.filter(id=org_id).annotate( users=Count('member_role__members', distinct=True), admins=Count('admin_role__members', distinct=True)).values('users', 'admins') if not direct_counts: return full_context org_counts = direct_counts[0] org_counts['inventories'] = Inventory.accessible_objects( **access_kwargs).filter(organization__id=org_id).count() org_counts['teams'] = Team.accessible_objects(**access_kwargs).filter( organization__id=org_id).count() org_counts['projects'] = Project.accessible_objects( **access_kwargs).filter(organization__id=org_id).count() org_counts['job_templates'] = JobTemplate.accessible_objects( **access_kwargs).filter(organization__id=org_id).count() full_context['related_field_counts'] = {} full_context['related_field_counts'][org_id] = org_counts return full_context
def test_job_metavars(self): maker = User(username='******', pk=47, id=47) inv = Inventory(name='example-inv', id=45) assert Job( name='fake-job', pk=42, id=42, launch_type='manual', created_by=maker, inventory=inv ).awx_meta_vars() == { 'tower_job_id': 42, 'awx_job_id': 42, 'tower_job_launch_type': 'manual', 'awx_job_launch_type': 'manual', 'awx_user_name': 'joe', 'tower_user_name': 'joe', 'awx_user_email': '', 'tower_user_email': '', 'awx_user_first_name': '', 'tower_user_first_name': '', 'awx_user_last_name': '', 'tower_user_last_name': '', 'awx_user_id': 47, 'tower_user_id': 47, 'tower_inventory_id': 45, 'awx_inventory_id': 45, 'tower_inventory_name': 'example-inv', 'awx_inventory_name': 'example-inv' }
def job_template_with_ids(job_template_factory): # Create non-persisted objects with IDs to send to job_template_factory ssh_type = CredentialType(kind='ssh') credential = Credential(id=1, pk=1, name='testcred', credential_type=ssh_type) net_type = CredentialType(kind='net') net_cred = Credential(id=2, pk=2, name='testnetcred', credential_type=net_type) cloud_type = CredentialType(kind='aws') cloud_cred = Credential(id=3, pk=3, name='testcloudcred', credential_type=cloud_type) inv = Inventory(id=11, pk=11, name='testinv') proj = Project(id=14, pk=14, name='testproj') jt_objects = job_template_factory('testJT', project=proj, inventory=inv, credential=credential, cloud_credential=cloud_cred, network_credential=net_cred, persisted=False) return jt_objects.job_template
def jt(self, survey_spec_factory): return JobTemplate( name='fake-jt', survey_enabled=True, survey_spec=survey_spec_factory(variables='var1', default_type='password'), project=Project('fake-proj'), project_id=42, inventory=Inventory('fake-inv'), inventory_id=42 )
def test_host_summary_generation(): hostnames = [f'Host {i}' for i in range(100)] inv = Inventory() inv.save() Host.objects.bulk_create([ Host(created=now(), modified=now(), name=h, inventory_id=inv.id) for h in hostnames ]) j = Job(inventory=inv) j.save() host_map = dict((host.name, host.id) for host in inv.hosts.all()) JobEvent.create_from_data(job_id=j.pk, parent_uuid='abc123', event='playbook_on_stats', event_data={ 'ok': dict((hostname, len(hostname)) for hostname in hostnames), 'changed': {}, 'dark': {}, 'failures': {}, 'ignored': {}, 'processed': {}, 'rescued': {}, 'skipped': {}, }, host_map=host_map).save() assert j.job_host_summaries.count() == len(hostnames) assert sorted([s.host_name for s in j.job_host_summaries.all()]) == sorted(hostnames) for s in j.job_host_summaries.all(): assert host_map[s.host_name] == s.host_id assert s.ok == len(s.host_name) assert s.changed == 0 assert s.dark == 0 assert s.failures == 0 assert s.ignored == 0 assert s.processed == 0 assert s.rescued == 0 assert s.skipped == 0 for host in Host.objects.all(): assert host.last_job_id == j.id assert host.last_job_host_summary.host == host
def test_jt_extra_vars_counting(self, provided_vars, valid): jt = JobTemplate(name='foo', extra_vars={'tmpl_var': 'bar'}, project=Project(), project_id=42, playbook='helloworld.yml', inventory=Inventory(), inventory_id=42) prompted_fields, ignored_fields, errors = jt._accept_or_ignore_job_kwargs( extra_vars=provided_vars) self.process_vars_and_assert(jt, provided_vars, valid)
def wfjt_node_with_prompts(wfjt_node_no_prompts): wfjt_node_no_prompts.char_prompts = example_prompts wfjt_node_no_prompts.inventory = Inventory(name='example-inv') ssh_type = CredentialType.defaults['ssh']() wfjt_node_no_prompts.credential = Credential(name='example-inv', credential_type=ssh_type, inputs={ 'username': '******', 'password': '******' }) return wfjt_node_no_prompts
def test_change_jt_sensitive_data(job_template_with_ids, mocker, user_unit): """Assure that can_add is called with all ForeignKeys.""" class RoleReturnsTrue(Role): class Meta: proxy = True def __contains__(self, accessor): return True job_template_with_ids.admin_role = RoleReturnsTrue() job_template_with_ids.organization.job_template_admin_role = RoleReturnsTrue( ) inv2 = Inventory() inv2.use_role = RoleReturnsTrue() data = {'inventory': inv2} access = JobTemplateAccess(user_unit) assert not access.changes_are_non_sensitive(job_template_with_ids, data) job_template_with_ids.inventory.use_role = RoleReturnsTrue() job_template_with_ids.project.use_role = RoleReturnsTrue() assert access.can_change(job_template_with_ids, data)
def test_job_metavars(self): maker = User(username='******', pk=47, id=47) inv = Inventory(name='example-inv', id=45) result_hash = {} for name in JOB_VARIABLE_PREFIXES: result_hash['{}_job_id'.format(name)] = 42 result_hash['{}_job_launch_type'.format(name)] = 'manual' result_hash['{}_user_name'.format(name)] = 'joe' result_hash['{}_user_email'.format(name)] = '' result_hash['{}_user_first_name'.format(name)] = '' result_hash['{}_user_last_name'.format(name)] = '' result_hash['{}_user_id'.format(name)] = 47 result_hash['{}_inventory_id'.format(name)] = 45 result_hash['{}_inventory_name'.format(name)] = 'example-inv' assert Job(name='fake-job', pk=42, id=42, launch_type='manual', created_by=maker, inventory=inv).awx_meta_vars() == result_hash
def test_host_filter_not_smart(self, setup_ec2_gce, organization): smart_inventory = Inventory( name='smart', organization=organization, host_filter='inventory_sources__source=ec2') assert len(smart_inventory.hosts.all()) == 0
def inventory(): return Inventory(id=5)
response = put( reverse('api:credential_detail', kwargs={'pk': cred.pk}), params, admin ) assert response.status_code == 200 cred = Credential.objects.all()[:1].get() assert cred.inputs['username'] == 'joe' assert 'password' not in cred.inputs @pytest.mark.django_db @pytest.mark.parametrize('relation, related_obj', [ ['ad_hoc_commands', AdHocCommand()], ['insights_inventories', Inventory()], ['unifiedjobs', Job()], ['unifiedjobtemplates', JobTemplate()], ['unifiedjobtemplates', InventorySource()], ['projects', Project()], ['workflowjobnodes', WorkflowJobNode()], ]) def test_credential_type_mutability(patch, organization, admin, credentialtype_ssh, credentialtype_aws, relation, related_obj): cred = Credential( credential_type=credentialtype_ssh, name='Best credential ever', organization=organization, inputs={ 'username': u'jim', 'password': u'pass'
def test_valid_kind_clean_insights_credential(): inv = Inventory(kind='smart') inv.clean_insights_credential()
def test_valid_clean_insights_credential(): cred_type = CredentialType.defaults['insights']() insights_cred = Credential(credential_type=cred_type) inv = Inventory(insights_credential=insights_cred) inv.clean_insights_credential()
def wfjt_node_with_prompts(wfjt_node_no_prompts, mocker): wfjt_node_no_prompts.char_prompts = example_prompts wfjt_node_no_prompts.inventory = Inventory(name='example-inv') return wfjt_node_no_prompts
def job_node_with_prompts(job_node_no_prompts, mocker): job_node_no_prompts.char_prompts = example_prompts job_node_no_prompts.inventory = Inventory(name='example-inv', id=45) job_node_no_prompts.inventory_id = 45 return job_node_no_prompts
def get_queryset(self): qs = Inventory.accessible_objects(self.request.user, 'read_role') qs = qs.select_related('admin_role', 'read_role', 'update_role', 'use_role', 'adhoc_role') qs = qs.prefetch_related('created_by', 'modified_by', 'organization') return qs