mirror of
https://github.com/ansible/awx.git
synced 2026-01-14 11:20:39 -03:30
fix tests for new inv plugin behavior
* Enforce plugin:
This commit is contained in:
parent
a8a47f314e
commit
34adbe6028
@ -7,6 +7,7 @@ import time
|
||||
import logging
|
||||
import re
|
||||
import copy
|
||||
import json
|
||||
import os.path
|
||||
from urllib.parse import urljoin
|
||||
import yaml
|
||||
@ -1157,6 +1158,20 @@ class InventorySource(UnifiedJobTemplate, InventorySourceOptions, CustomVirtualE
|
||||
raise ValidationError(_("Cannot set source_path if not SCM type."))
|
||||
return self.source_path
|
||||
|
||||
def clean_source_vars(self):
|
||||
injector = self.injectors.get(self.source)
|
||||
source_vars = dict(self.source_vars_dict) # make a copy
|
||||
if injector and self.source_vars_dict.get('plugin', '') != injector.get_proper_name():
|
||||
source_vars['plugin'] = injector.get_proper_name()
|
||||
elif not injector:
|
||||
source_vars = dict(self.source_vars_dict) # make a copy
|
||||
collection_pattern = re.compile("^(.+)\.(.+)\.(.+)$") # noqa
|
||||
if 'plugin' not in source_vars:
|
||||
raise ValidationError(_("plugin: must be present and of the form namespace.collection.inv_plugin"))
|
||||
elif not bool(collection_pattern.match(source_vars['plugin'])):
|
||||
raise ValidationError(_("plugin: must be of the form namespace.collection.inv_plugin"))
|
||||
return json.dumps(source_vars)
|
||||
|
||||
'''
|
||||
RelatedJobsMixin
|
||||
'''
|
||||
@ -1344,6 +1359,12 @@ class PluginFileInjector(object):
|
||||
# This is InventoryOptions instance, could be source or inventory update
|
||||
self.ansible_version = ansible_version
|
||||
|
||||
@classmethod
|
||||
def get_proper_name(cls):
|
||||
if cls.plugin_name is None:
|
||||
return None
|
||||
return f'{cls.namespace}.{cls.collection}.{cls.plugin_name}'
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
"""Inventory filename for using the inventory plugin
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
conditional_groups:
|
||||
azure: true
|
||||
default_host_filters: []
|
||||
exclude_host_filters:
|
||||
- resource_group not in ['foo_resources', 'bar_resources']
|
||||
- '"Creator" not in tags.keys()'
|
||||
- tags["Creator"] != "jmarshall"
|
||||
- '"peanutbutter" not in tags.keys()'
|
||||
- tags["peanutbutter"] != "jelly"
|
||||
- location not in ['southcentralus', 'westus']
|
||||
fail_on_template_errors: false
|
||||
hostvar_expressions:
|
||||
ansible_host: private_ipv4_addresses[0]
|
||||
computer_name: name
|
||||
private_ip: private_ipv4_addresses[0] if private_ipv4_addresses else None
|
||||
provisioning_state: provisioning_state | title
|
||||
public_ip: public_ipv4_addresses[0] if public_ipv4_addresses else None
|
||||
public_ip_id: public_ip_id if public_ip_id is defined else None
|
||||
public_ip_name: public_ip_name if public_ip_name is defined else None
|
||||
tags: tags if tags else None
|
||||
type: resource_type
|
||||
keyed_groups:
|
||||
- key: location
|
||||
prefix: ''
|
||||
separator: ''
|
||||
- key: tags.keys() | list if tags else []
|
||||
prefix: ''
|
||||
separator: ''
|
||||
- key: security_group
|
||||
prefix: ''
|
||||
separator: ''
|
||||
- key: resource_group
|
||||
prefix: ''
|
||||
separator: ''
|
||||
- key: os_disk.operating_system_type
|
||||
prefix: ''
|
||||
separator: ''
|
||||
- key: dict(tags.keys() | map("regex_replace", "^(.*)$", "\1_") | list | zip(tags.values() | list)) if tags else []
|
||||
prefix: ''
|
||||
separator: ''
|
||||
plain_host_names: true
|
||||
plugin: azure.azcollection.azure_rm
|
||||
use_contrib_script_compatible_sanitization: true
|
||||
@ -1,81 +0,0 @@
|
||||
boto_profile: /tmp/my_boto_stuff
|
||||
compose:
|
||||
ansible_host: public_dns_name
|
||||
ec2_account_id: owner_id
|
||||
ec2_ami_launch_index: ami_launch_index | string
|
||||
ec2_architecture: architecture
|
||||
ec2_block_devices: dict(block_device_mappings | map(attribute='device_name') | list | zip(block_device_mappings | map(attribute='ebs.volume_id') | list))
|
||||
ec2_client_token: client_token
|
||||
ec2_dns_name: public_dns_name
|
||||
ec2_ebs_optimized: ebs_optimized
|
||||
ec2_eventsSet: events | default("")
|
||||
ec2_group_name: placement.group_name
|
||||
ec2_hypervisor: hypervisor
|
||||
ec2_id: instance_id
|
||||
ec2_image_id: image_id
|
||||
ec2_instance_profile: iam_instance_profile | default("")
|
||||
ec2_instance_type: instance_type
|
||||
ec2_ip_address: public_ip_address
|
||||
ec2_kernel: kernel_id | default("")
|
||||
ec2_key_name: key_name
|
||||
ec2_launch_time: launch_time | regex_replace(" ", "T") | regex_replace("(\+)(\d\d):(\d)(\d)$", ".\g<2>\g<3>Z")
|
||||
ec2_monitored: monitoring.state in ['enabled', 'pending']
|
||||
ec2_monitoring_state: monitoring.state
|
||||
ec2_persistent: persistent | default(false)
|
||||
ec2_placement: placement.availability_zone
|
||||
ec2_platform: platform | default("")
|
||||
ec2_private_dns_name: private_dns_name
|
||||
ec2_private_ip_address: private_ip_address
|
||||
ec2_public_dns_name: public_dns_name
|
||||
ec2_ramdisk: ramdisk_id | default("")
|
||||
ec2_reason: state_transition_reason
|
||||
ec2_region: placement.region
|
||||
ec2_requester_id: requester_id | default("")
|
||||
ec2_root_device_name: root_device_name
|
||||
ec2_root_device_type: root_device_type
|
||||
ec2_security_group_ids: security_groups | map(attribute='group_id') | list | join(',')
|
||||
ec2_security_group_names: security_groups | map(attribute='group_name') | list | join(',')
|
||||
ec2_sourceDestCheck: source_dest_check | default(false) | lower | string
|
||||
ec2_spot_instance_request_id: spot_instance_request_id | default("")
|
||||
ec2_state: state.name
|
||||
ec2_state_code: state.code
|
||||
ec2_state_reason: state_reason.message if state_reason is defined else ""
|
||||
ec2_subnet_id: subnet_id | default("")
|
||||
ec2_tag_Name: tags.Name
|
||||
ec2_virtualization_type: virtualization_type
|
||||
ec2_vpc_id: vpc_id | default("")
|
||||
filters:
|
||||
instance-state-name:
|
||||
- running
|
||||
groups:
|
||||
ec2: true
|
||||
hostnames:
|
||||
- dns-name
|
||||
iam_role_arn: arn:aws:iam::123456789012:role/test-role
|
||||
keyed_groups:
|
||||
- key: placement.availability_zone
|
||||
parent_group: zones
|
||||
prefix: ''
|
||||
separator: ''
|
||||
- key: instance_type | regex_replace("[^A-Za-z0-9\_]", "_")
|
||||
parent_group: types
|
||||
prefix: type
|
||||
- key: placement.region
|
||||
parent_group: regions
|
||||
prefix: ''
|
||||
separator: ''
|
||||
- key: dict(tags.keys() | map("regex_replace", "[^A-Za-z0-9\_]", "_") | list | zip(tags.values() | map("regex_replace", "[^A-Za-z0-9\_]", "_") | list))
|
||||
parent_group: tags
|
||||
prefix: tag
|
||||
- key: tags.keys() | map("regex_replace", "[^A-Za-z0-9\_]", "_") | list
|
||||
parent_group: tags
|
||||
prefix: tag
|
||||
- key: placement.availability_zone
|
||||
parent_group: '{{ placement.region }}'
|
||||
prefix: ''
|
||||
separator: ''
|
||||
plugin: amazon.aws.aws_ec2
|
||||
regions:
|
||||
- us-east-2
|
||||
- ap-south-1
|
||||
use_contrib_script_compatible_sanitization: true
|
||||
@ -1,50 +0,0 @@
|
||||
auth_kind: serviceaccount
|
||||
compose:
|
||||
ansible_ssh_host: networkInterfaces[0].accessConfigs[0].natIP | default(networkInterfaces[0].networkIP)
|
||||
gce_description: description if description else None
|
||||
gce_id: id
|
||||
gce_image: image
|
||||
gce_machine_type: machineType
|
||||
gce_metadata: metadata.get("items", []) | items2dict(key_name="key", value_name="value")
|
||||
gce_name: name
|
||||
gce_network: networkInterfaces[0].network.name
|
||||
gce_private_ip: networkInterfaces[0].networkIP
|
||||
gce_public_ip: networkInterfaces[0].accessConfigs[0].natIP | default(None)
|
||||
gce_status: status
|
||||
gce_subnetwork: networkInterfaces[0].subnetwork.name
|
||||
gce_tags: tags.get("items", [])
|
||||
gce_zone: zone
|
||||
hostnames:
|
||||
- name
|
||||
- public_ip
|
||||
- private_ip
|
||||
keyed_groups:
|
||||
- key: gce_subnetwork
|
||||
prefix: network
|
||||
- key: gce_private_ip
|
||||
prefix: ''
|
||||
separator: ''
|
||||
- key: gce_public_ip
|
||||
prefix: ''
|
||||
separator: ''
|
||||
- key: machineType
|
||||
prefix: ''
|
||||
separator: ''
|
||||
- key: zone
|
||||
prefix: ''
|
||||
separator: ''
|
||||
- key: gce_tags
|
||||
prefix: tag
|
||||
- key: status | lower
|
||||
prefix: status
|
||||
- key: image
|
||||
prefix: ''
|
||||
separator: ''
|
||||
plugin: google.cloud.gcp_compute
|
||||
projects:
|
||||
- fooo
|
||||
retrieve_image_info: true
|
||||
use_contrib_script_compatible_sanitization: true
|
||||
zones:
|
||||
- us-east4-a
|
||||
- us-west1-b
|
||||
@ -1,7 +1,3 @@
|
||||
ansible:
|
||||
expand_hostvars: true
|
||||
fail_on_errors: true
|
||||
use_hostnames: false
|
||||
clouds:
|
||||
devstack:
|
||||
auth:
|
||||
@ -11,5 +7,5 @@ clouds:
|
||||
project_domain_name: fooo
|
||||
project_name: fooo
|
||||
username: fooo
|
||||
private: false
|
||||
private: true
|
||||
verify: false
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
expand_hostvars: true
|
||||
fail_on_errors: true
|
||||
inventory_hostname: uuid
|
||||
plugin: openstack.cloud.openstack
|
||||
@ -1,20 +0,0 @@
|
||||
base_source_var: value_of_var
|
||||
compose:
|
||||
ansible_host: (devices.values() | list)[0][0] if devices else None
|
||||
groups:
|
||||
dev: '"dev" in tags'
|
||||
keyed_groups:
|
||||
- key: cluster
|
||||
prefix: cluster
|
||||
separator: _
|
||||
- key: status
|
||||
prefix: status
|
||||
separator: _
|
||||
- key: tags
|
||||
prefix: tag
|
||||
separator: _
|
||||
ovirt_hostname_preference:
|
||||
- name
|
||||
- fqdn
|
||||
ovirt_insecure: false
|
||||
plugin: ovirt.ovirt.ovirt
|
||||
@ -1,30 +0,0 @@
|
||||
base_source_var: value_of_var
|
||||
compose:
|
||||
ansible_ssh_host: foreman['ip6'] | default(foreman['ip'], true)
|
||||
group_prefix: foo_group_prefix
|
||||
keyed_groups:
|
||||
- key: foreman['environment_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_') | regex_replace('none', '')
|
||||
prefix: foo_group_prefixenvironment_
|
||||
separator: ''
|
||||
- key: foreman['location_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')
|
||||
prefix: foo_group_prefixlocation_
|
||||
separator: ''
|
||||
- key: foreman['organization_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')
|
||||
prefix: foo_group_prefixorganization_
|
||||
separator: ''
|
||||
- key: foreman['content_facet_attributes']['lifecycle_environment_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')
|
||||
prefix: foo_group_prefixlifecycle_environment_
|
||||
separator: ''
|
||||
- key: foreman['content_facet_attributes']['content_view_name'] | lower | regex_replace(' ', '') | regex_replace('[^A-Za-z0-9_]', '_')
|
||||
prefix: foo_group_prefixcontent_view_
|
||||
separator: ''
|
||||
- key: '"%s-%s-%s" | format(app, tier, color)'
|
||||
separator: ''
|
||||
- key: '"%s-%s" | format(app, color)'
|
||||
separator: ''
|
||||
legacy_hostvars: true
|
||||
plugin: theforeman.foreman.foreman
|
||||
validate_certs: false
|
||||
want_facts: true
|
||||
want_hostcollections: true
|
||||
want_params: true
|
||||
@ -1,3 +0,0 @@
|
||||
include_metadata: true
|
||||
inventory_id: 42
|
||||
plugin: awx.awx.tower
|
||||
@ -1,55 +0,0 @@
|
||||
compose:
|
||||
ansible_host: guest.ipAddress
|
||||
ansible_ssh_host: guest.ipAddress
|
||||
ansible_uuid: 99999999 | random | to_uuid
|
||||
availablefield: availableField
|
||||
configissue: configIssue
|
||||
configstatus: configStatus
|
||||
customvalue: customValue
|
||||
effectiverole: effectiveRole
|
||||
guestheartbeatstatus: guestHeartbeatStatus
|
||||
layoutex: layoutEx
|
||||
overallstatus: overallStatus
|
||||
parentvapp: parentVApp
|
||||
recenttask: recentTask
|
||||
resourcepool: resourcePool
|
||||
rootsnapshot: rootSnapshot
|
||||
triggeredalarmstate: triggeredAlarmState
|
||||
filters:
|
||||
- config.zoo == "DC0_H0_VM0"
|
||||
hostnames:
|
||||
- config.foo
|
||||
keyed_groups:
|
||||
- key: config.asdf
|
||||
prefix: ''
|
||||
separator: ''
|
||||
plugin: community.vmware.vmware_vm_inventory
|
||||
properties:
|
||||
- availableField
|
||||
- configIssue
|
||||
- configStatus
|
||||
- customValue
|
||||
- datastore
|
||||
- effectiveRole
|
||||
- guestHeartbeatStatus
|
||||
- layout
|
||||
- layoutEx
|
||||
- name
|
||||
- network
|
||||
- overallStatus
|
||||
- parentVApp
|
||||
- permission
|
||||
- recentTask
|
||||
- resourcePool
|
||||
- rootSnapshot
|
||||
- snapshot
|
||||
- triggeredAlarmState
|
||||
- value
|
||||
- capability
|
||||
- config
|
||||
- guest
|
||||
- runtime
|
||||
- storage
|
||||
- summary
|
||||
strict: false
|
||||
with_nested_properties: true
|
||||
@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import pytest
|
||||
import json
|
||||
from unittest import mock
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
@ -8,8 +9,6 @@ from awx.api.versioning import reverse
|
||||
|
||||
from awx.main.models import InventorySource, Inventory, ActivityStream
|
||||
|
||||
import json
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def scm_inventory(inventory, project):
|
||||
@ -457,6 +456,56 @@ def test_inventory_source_vars_prohibition(post, inventory, admin_user):
|
||||
assert 'FOOBAR' in r.data['source_vars'][0]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('source,source_var_actual,source_var_expected,description', [
|
||||
('ec2', {'plugin': 'blah'}, {'plugin': 'amazon.aws.aws_ec2'}, 'source plugin mismatch'),
|
||||
('ec2', {'plugin': 'amazon.aws.aws_ec2'}, {'plugin': 'amazon.aws.aws_ec2'}, 'valid plugin'),
|
||||
])
|
||||
def test_inventory_source_vars_source_plugin_ok(post, inventory, admin_user, source, source_var_actual, source_var_expected, description):
|
||||
r = post(reverse('api:inventory_source_list'),
|
||||
{'name': 'new inv src', 'source_vars': json.dumps(source_var_actual), 'inventory': inventory.pk, 'source': source},
|
||||
admin_user, expect=201)
|
||||
|
||||
assert r.data['source_vars'] == json.dumps(source_var_expected)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('source_var_actual,description', [
|
||||
({'plugin': 'namespace.collection.script'}, 'valid scm user plugin'),
|
||||
])
|
||||
def test_inventory_source_vars_source_plugin_scm_ok(post, inventory, admin_user, project, source_var_actual, description):
|
||||
r = post(reverse('api:inventory_source_list'),
|
||||
{'name': 'new inv src',
|
||||
'source_vars': json.dumps(source_var_actual),
|
||||
'inventory': inventory.pk,
|
||||
'source': 'scm',
|
||||
'source_project': project.id,},
|
||||
admin_user, expect=201)
|
||||
|
||||
assert r.data['source_vars'] == json.dumps(source_var_actual)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('source_var_actual,err_msg,description', [
|
||||
({'foo': 'bar'}, 'plugin: must be present and of the form namespace.collection.inv_plugin', 'no plugin line'),
|
||||
({'plugin': ''}, 'plugin: must be of the form namespace.collection.inv_plugin', 'blank plugin line'),
|
||||
({'plugin': '.'}, 'plugin: must be of the form namespace.collection.inv_plugin', 'missing namespace, collection name, and inventory plugin'),
|
||||
({'plugin': 'a.'}, 'plugin: must be of the form namespace.collection.inv_plugin', 'missing collection name and inventory plugin'),
|
||||
({'plugin': 'a.b'}, 'plugin: must be of the form namespace.collection.inv_plugin', 'missing inventory plugin'),
|
||||
({'plugin': 'a.b.'}, 'plugin: must be of the form namespace.collection.inv_plugin', 'missing inventory plugin'),
|
||||
])
|
||||
def test_inventory_source_vars_source_plugin_scm_invalid(post, inventory, admin_user, project, source_var_actual, err_msg, description):
|
||||
r = post(reverse('api:inventory_source_list'),
|
||||
{'name': 'new inv src',
|
||||
'source_vars': json.dumps(source_var_actual),
|
||||
'inventory': inventory.pk,
|
||||
'source': 'scm',
|
||||
'source_project': project.id,},
|
||||
admin_user, expect=400)
|
||||
|
||||
assert err_msg in r.data['source_vars'][0]
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('role,expect', [
|
||||
('admin_role', 200),
|
||||
@ -522,7 +571,8 @@ class TestInventorySourceCredential:
|
||||
data={
|
||||
'inventory': inventory.pk, 'name': 'fobar', 'source': 'scm',
|
||||
'source_project': project.pk, 'source_path': '',
|
||||
'credential': vault_credential.pk
|
||||
'credential': vault_credential.pk,
|
||||
'source_vars': 'plugin: a.b.c',
|
||||
},
|
||||
expect=400,
|
||||
user=admin_user
|
||||
@ -561,7 +611,7 @@ class TestInventorySourceCredential:
|
||||
data={
|
||||
'inventory': inventory.pk, 'name': 'fobar', 'source': 'scm',
|
||||
'source_project': project.pk, 'source_path': '',
|
||||
'credential': os_cred.pk
|
||||
'credential': os_cred.pk, 'source_vars': 'plugin: a.b.c',
|
||||
},
|
||||
expect=201,
|
||||
user=admin_user
|
||||
@ -636,8 +686,14 @@ class TestControlledBySCM:
|
||||
assert scm_inventory.inventory_sources.count() == 0
|
||||
|
||||
def test_adding_inv_src_ok(self, post, scm_inventory, project, admin_user):
|
||||
post(reverse('api:inventory_inventory_sources_list', kwargs={'pk': scm_inventory.id}),
|
||||
{'name': 'new inv src', 'source_project': project.pk, 'update_on_project_update': False, 'source': 'scm', 'overwrite_vars': True},
|
||||
post(reverse('api:inventory_inventory_sources_list',
|
||||
kwargs={'pk': scm_inventory.id}),
|
||||
{'name': 'new inv src',
|
||||
'source_project': project.pk,
|
||||
'update_on_project_update': False,
|
||||
'source': 'scm',
|
||||
'overwrite_vars': True,
|
||||
'source_vars': 'plugin: a.b.c'},
|
||||
admin_user, expect=201)
|
||||
|
||||
def test_adding_inv_src_prohibited(self, post, scm_inventory, project, admin_user):
|
||||
@ -657,7 +713,7 @@ class TestControlledBySCM:
|
||||
def test_adding_inv_src_without_proj_access_prohibited(self, post, project, inventory, rando):
|
||||
inventory.admin_role.members.add(rando)
|
||||
post(reverse('api:inventory_inventory_sources_list', kwargs={'pk': inventory.id}),
|
||||
{'name': 'new inv src', 'source_project': project.pk, 'source': 'scm', 'overwrite_vars': True},
|
||||
{'name': 'new inv src', 'source_project': project.pk, 'source': 'scm', 'overwrite_vars': True, 'source_vars': 'plugin: a.b.c'},
|
||||
rando, expect=403)
|
||||
|
||||
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
import pytest
|
||||
from unittest import mock
|
||||
import json
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
@ -259,30 +258,19 @@ class TestInventorySourceInjectors:
|
||||
injector = InventorySource.injectors[source]('2.7.7')
|
||||
assert injector.filename == filename
|
||||
|
||||
def test_group_by_azure(self):
|
||||
injector = InventorySource.injectors['azure_rm']('2.9')
|
||||
inv_src = InventorySource(
|
||||
name='azure source', source='azure_rm',
|
||||
source_vars={'group_by_os_family': True}
|
||||
)
|
||||
group_by_on = injector.inventory_as_dict(inv_src, '/tmp/foo')
|
||||
# suspicious, yes, that is just what the script did
|
||||
expected_groups = 6
|
||||
assert len(group_by_on['keyed_groups']) == expected_groups
|
||||
inv_src.source_vars = json.dumps({'group_by_os_family': False})
|
||||
group_by_off = injector.inventory_as_dict(inv_src, '/tmp/foo')
|
||||
# much better, everyone should turn off the flag and live in the future
|
||||
assert len(group_by_off['keyed_groups']) == expected_groups - 1
|
||||
|
||||
def test_tower_plugin_named_url(self):
|
||||
injector = InventorySource.injectors['tower']('2.9')
|
||||
inv_src = InventorySource(
|
||||
name='my tower source', source='tower',
|
||||
# named URL pattern "inventory++organization"
|
||||
instance_filters='Designer hair 읰++Cosmetic_products䵆'
|
||||
)
|
||||
result = injector.inventory_as_dict(inv_src, '/tmp/foo')
|
||||
assert result['inventory_id'] == 'Designer%20hair%20%EC%9D%B0++Cosmetic_products%E4%B5%86'
|
||||
@pytest.mark.parametrize('source,proper_name', [
|
||||
('ec2', 'amazon.aws.aws_ec2'),
|
||||
('openstack', 'openstack.cloud.openstack'),
|
||||
('gce', 'google.cloud.gcp_compute'),
|
||||
('azure_rm', 'azure.azcollection.azure_rm'),
|
||||
('vmware', 'community.vmware.vmware_vm_inventory'),
|
||||
('rhv', 'ovirt.ovirt.ovirt'),
|
||||
('satellite6', 'theforeman.foreman.foreman'),
|
||||
('tower', 'awx.awx.tower'),
|
||||
])
|
||||
def test_plugin_proper_names(self, source, proper_name):
|
||||
injector = InventorySource.injectors[source]('2.9')
|
||||
assert injector.get_proper_name() == proper_name
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
||||
@ -14,69 +14,6 @@ from django.conf import settings
|
||||
|
||||
DATA = os.path.join(os.path.dirname(data.__file__), 'inventory')
|
||||
|
||||
TEST_SOURCE_FIELDS = {
|
||||
'vmware': {
|
||||
'instance_filters': '{{ config.name == "only_my_server" }},{{ somevar == "bar"}}',
|
||||
'group_by': 'fouo'
|
||||
},
|
||||
'ec2': {
|
||||
'instance_filters': 'foobaa',
|
||||
# group_by selected to capture some non-trivial cross-interactions
|
||||
'group_by': 'availability_zone,instance_type,tag_keys,region',
|
||||
'source_regions': 'us-east-2,ap-south-1'
|
||||
},
|
||||
'gce': {
|
||||
'source_regions': 'us-east4-a,us-west1-b' # surfaced as env var
|
||||
},
|
||||
'azure_rm': {
|
||||
'source_regions': 'southcentralus,westus'
|
||||
},
|
||||
'tower': {
|
||||
'instance_filters': '42'
|
||||
}
|
||||
}
|
||||
|
||||
INI_TEST_VARS = {
|
||||
'ec2': {
|
||||
'boto_profile': '/tmp/my_boto_stuff',
|
||||
'iam_role_arn': 'arn:aws:iam::123456789012:role/test-role',
|
||||
'hostname_variable': 'public_dns_name',
|
||||
'destination_variable': 'public_dns_name'
|
||||
},
|
||||
'gce': {},
|
||||
'openstack': {
|
||||
'private': False,
|
||||
'use_hostnames': False,
|
||||
'expand_hostvars': True,
|
||||
'fail_on_errors': True
|
||||
},
|
||||
'tower': {}, # there are none
|
||||
'vmware': {
|
||||
'alias_pattern': "{{ config.foo }}",
|
||||
'host_filters': '{{ config.zoo == "DC0_H0_VM0" }}',
|
||||
'groupby_patterns': "{{ config.asdf }}",
|
||||
# setting VMWARE_VALIDATE_CERTS is duplicated with env var
|
||||
},
|
||||
'azure_rm': {
|
||||
'use_private_ip': True,
|
||||
'resource_groups': 'foo_resources,bar_resources',
|
||||
'tags': 'Creator:jmarshall, peanutbutter:jelly'
|
||||
},
|
||||
'satellite6': {
|
||||
'satellite6_group_patterns': '["{app}-{tier}-{color}", "{app}-{color}"]',
|
||||
'satellite6_group_prefix': 'foo_group_prefix',
|
||||
'satellite6_want_hostcollections': True,
|
||||
'satellite6_want_ansible_ssh_host': True,
|
||||
'satellite6_want_facts': True
|
||||
},
|
||||
'rhv': { # options specific to the plugin
|
||||
'ovirt_insecure': False,
|
||||
'groups': {
|
||||
'dev': '"dev" in tags'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def generate_fake_var(element):
|
||||
"""Given a credential type field element, makes up something acceptable.
|
||||
@ -245,25 +182,21 @@ def create_reference_data(source_dir, env, content):
|
||||
@pytest.mark.django_db
|
||||
@pytest.mark.parametrize('this_kind', CLOUD_PROVIDERS)
|
||||
def test_inventory_update_injected_content(this_kind, inventory, fake_credential_factory):
|
||||
injector = InventorySource.injectors[this_kind]
|
||||
if injector.plugin_name is None:
|
||||
pytest.skip('Use of inventory plugin is not enabled for this source')
|
||||
|
||||
src_vars = dict(base_source_var='value_of_var')
|
||||
if this_kind in INI_TEST_VARS:
|
||||
src_vars.update(INI_TEST_VARS[this_kind])
|
||||
extra_kwargs = {}
|
||||
if this_kind in TEST_SOURCE_FIELDS:
|
||||
extra_kwargs.update(TEST_SOURCE_FIELDS[this_kind])
|
||||
src_vars['plugin'] = injector.get_proper_name()
|
||||
inventory_source = InventorySource.objects.create(
|
||||
inventory=inventory,
|
||||
source=this_kind,
|
||||
source_vars=src_vars,
|
||||
**extra_kwargs
|
||||
)
|
||||
inventory_source.credentials.add(fake_credential_factory(this_kind))
|
||||
inventory_update = inventory_source.create_unified_job()
|
||||
task = RunInventoryUpdate()
|
||||
|
||||
if InventorySource.injectors[this_kind].plugin_name is None:
|
||||
pytest.skip('Use of inventory plugin is not enabled for this source')
|
||||
|
||||
def substitute_run(envvars=None, **_kw):
|
||||
"""This method will replace run_pexpect
|
||||
instead of running, it will read the private data directory contents
|
||||
@ -274,6 +207,12 @@ def test_inventory_update_injected_content(this_kind, inventory, fake_credential
|
||||
assert envvars.pop('ANSIBLE_INVENTORY_ENABLED') == 'auto'
|
||||
set_files = bool(os.getenv("MAKE_INVENTORY_REFERENCE_FILES", 'false').lower()[0] not in ['f', '0'])
|
||||
env, content = read_content(private_data_dir, envvars, inventory_update)
|
||||
|
||||
# Assert inventory plugin inventory file is in private_data_dir
|
||||
inventory_filename = InventorySource.injectors[inventory_update.source]('2.9').filename
|
||||
assert len([True for k in content.keys() if k.endswith(inventory_filename)]) > 0, \
|
||||
f"'{inventory_filename}' file not found in inventory update runtime files {content.keys()}"
|
||||
|
||||
env.pop('ANSIBLE_COLLECTIONS_PATHS', None) # collection paths not relevant to this test
|
||||
base_dir = os.path.join(DATA, 'plugins')
|
||||
if not os.path.exists(base_dir):
|
||||
@ -283,6 +222,8 @@ def test_inventory_update_injected_content(this_kind, inventory, fake_credential
|
||||
create_reference_data(source_dir, env, content)
|
||||
pytest.skip('You set MAKE_INVENTORY_REFERENCE_FILES, so this created files, unset to run actual test.')
|
||||
else:
|
||||
source_dir = os.path.join(base_dir, this_kind) # this_kind is a global
|
||||
|
||||
if not os.path.exists(source_dir):
|
||||
raise FileNotFoundError(
|
||||
'Maybe you never made reference files? '
|
||||
@ -292,9 +233,6 @@ def test_inventory_update_injected_content(this_kind, inventory, fake_credential
|
||||
expected_file_list = os.listdir(files_dir)
|
||||
except FileNotFoundError:
|
||||
expected_file_list = []
|
||||
assert set(expected_file_list) == set(content.keys()), (
|
||||
'Inventory update runtime environment does not have expected files'
|
||||
)
|
||||
for f_name in expected_file_list:
|
||||
with open(os.path.join(files_dir, f_name), 'r') as f:
|
||||
ref_content = f.read()
|
||||
|
||||
@ -72,23 +72,6 @@ def test_invalid_kind_clean_insights_credential():
|
||||
assert json.dumps(str(e.value)) == json.dumps(str([u'Assignment not allowed for Smart Inventory']))
|
||||
|
||||
|
||||
@pytest.mark.parametrize('source_vars,validate_certs', [
|
||||
({'ssl_verify': True}, True),
|
||||
({'ssl_verify': False}, False),
|
||||
({'validate_certs': True}, True),
|
||||
({'validate_certs': False}, False)])
|
||||
def test_satellite_plugin_backwards_support_for_ssl_verify(source_vars, validate_certs):
|
||||
injector = InventorySource.injectors['satellite6']('2.9')
|
||||
inv_src = InventorySource(
|
||||
name='satellite source', source='satellite6',
|
||||
source_vars=source_vars
|
||||
)
|
||||
|
||||
ret = injector.inventory_as_dict(inv_src, '/tmp/foo')
|
||||
assert 'validate_certs' in ret
|
||||
assert ret['validate_certs'] in (validate_certs, str(validate_certs))
|
||||
|
||||
|
||||
class TestControlledBySCM():
|
||||
def test_clean_source_path_valid(self):
|
||||
inv_src = InventorySource(source_path='/not_real/',
|
||||
|
||||
@ -8,8 +8,6 @@ from datetime import timedelta
|
||||
|
||||
# global settings
|
||||
from django.conf import global_settings
|
||||
# ugettext lazy
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
# Update this module's local settings from the global settings module.
|
||||
this_module = sys.modules[__name__]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user