Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[6.15.z] Add tests for ansible-tower/AAP integration with Satellite #16910

Open
wants to merge 1 commit into
base: 6.15.z
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions conf/ansible.yaml.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
AAP_INTEGRATION:
AAP_FQDN: env-aap-01.example.com
# USERNAME: Login for AAP
USERNAME:
# PASSWORD: Password for AAP
PASSWORD:
# Red Hat Satellite 6 type credentials for dynamic inventory testing
SATELLITE_CREDENTIALS:
# Satellite as a Dynamic Inventory in Ansible Tower
SATELLITE_INVENTORY:
# Job template and host_config_key for ansible-callback with Satellite testing
CALLBACK_JOB_TEMPLATE:
HOST_CONFIG_KEY:
2 changes: 1 addition & 1 deletion pytest_fixtures/component/provision_pxe.py
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ def pxe_loader(request):
'ipxe': {'vm_firmware': 'bios', 'pxe_loader': 'iPXE Embedded'},
'http_uefi': {'vm_firmware': 'uefi', 'pxe_loader': 'Grub2 UEFI HTTP'},
}
return Box(PXE_LOADER_MAP[getattr(request, 'param', 'bios')])
return Box(PXE_LOADER_MAP[getattr(request, 'param', 'uefi')])


@pytest.fixture
Expand Down
294 changes: 294 additions & 0 deletions tests/foreman/cli/test_ansible.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@

from time import sleep

import awxkit
from fauxfactory import gen_string
import pytest
from wait_for import wait_for
import yaml

from robottelo.config import (
Expand Down Expand Up @@ -732,3 +734,295 @@ def _finalize():
)
result = target_sat.cli.JobInvocation.info({'id': job_id})['success']
assert result == '1'


@pytest.mark.upgrade
class TestAnsibleAAPIntegration:
"""Test class for Satellite integration with Ansible Automation Controller

:CaseComponent: Ansible-ConfigurationManagement
"""

def update_sat_credentials_in_aap(
self,
aap_client,
sat,
username=settings.server.admin_username,
password=settings.server.admin_password,
creds_name=settings.AAP_INTEGRATION.satellite_credentials,
):
# Find the Satellite credentials in AAP and update it for target_sat.hostname and user credentials
creds_list = aap_client.get(
'/api/v2/credentials/', query_parameters=f'name={creds_name}'
).json()
new_creds = {
'inputs': {
'host': f'https://{sat.hostname}',
'username': username,
'password': password,
}
}
response = aap_client.patch(
f'/api/v2/credentials/{creds_list["results"][0]["id"]}/', json=new_creds
)
assert response.ok

@pytest.fixture(scope='class')
def aap_client(self):
client = awxkit.api.client.Connection(f'https://{settings.AAP_INTEGRATION.AAP_FQDN}/')
client.login(settings.AAP_INTEGRATION.USERNAME, settings.AAP_INTEGRATION.PASSWORD)
yield client
client.logout()

@pytest.mark.parametrize('auth_type', ['admin', 'non-admin'])
@pytest.mark.rhel_ver_list([settings.content_host.default_rhel_version])
def test_positive_ansible_dynamic_inventory(
self,
request,
target_sat,
module_org,
module_location,
module_ak_with_cv,
aap_client,
rhel_contenthost,
auth_type,
):
"""Verify AAP is able to pull a dynamic inventory of hosts from Satellite,
with admin and non-admin user.

:id: ad25aee5-4ea3-4743-a301-1c6271856g19

:steps:
1. Register content host to Satellite with admin and non-admin user
2. Update Satellite type credentials in AAP
3. Find Satellite inventory, inventory source and sync inventory source in AAP
4. Verify registered hosts are added to Satellite inventory

:expectedresults: All hosts managed by Satellite are added to Satellite inventory.
"""
inventory_name = settings.AAP_INTEGRATION.satellite_inventory

password = settings.server.admin_password
if auth_type == 'admin':
login = gen_string('alpha')
user = target_sat.api.User(
admin=True,
login=login,
password=password,
organization=[module_org],
location=[module_location],
).create()
else:
login = gen_string('alpha')
role = target_sat.api.Role(
name=gen_string('alpha'), location=[module_location], organization=[module_org]
).create()
for perm in ['view_hosts', 'view_hostgroups', 'view_facts']:
permission = target_sat.api.Permission().search(query={'search': f'name={perm}'})
target_sat.api.Filter(permission=permission, role=role).create()
user = target_sat.api.User(
role=[role],
admin=False,
login=login,
password=password,
organization=[module_org],
location=[module_location],
).create()
target_sat.cli.User.add_role(
{'login': user.login, 'role': 'Ansible Tower Inventory Reader'}
)
result = rhel_contenthost.register(
module_org,
module_location,
module_ak_with_cv.name,
target_sat,
auth_username=user.login,
auth_password=password,
force=True,
)
assert result.status == 0, f'Failed to register host: {result.stderr}'

if is_open('SAT-28613') and auth_type == 'non-admin':
host = rhel_contenthost.nailgun_host
host.location = module_location
host.update(['location'])

# Find the Satellite credentials in AAP and update it for target_sat.hostname and user credentials
self.update_sat_credentials_in_aap(aap_client, target_sat, username=login)

# Find the Satellite inventory in AAP and update it for target_sat and user credentials
inv_list = aap_client.get(
'/api/v2/inventories/', query_parameters=f'name={inventory_name}'
).json()
inv_source_list = aap_client.get(
f'/api/v2/inventories/{inv_list["results"][0]["id"]}/inventory_sources/'
).json()
sync_response = aap_client.post(
f'/api/v2/inventory_sources/{inv_source_list["results"][0]["id"]}/update/'
)
assert sync_response.ok
wait_for(
lambda: rhel_contenthost.hostname
in [
host['name']
for host in aap_client.get(
f'/api/v2/inventories/{inv_list["results"][0]["id"]}/hosts/'
).json()['results']
],
timeout=180,
delay=30,
)
# Find the hosts in Satellite inventory in AAP and verify if target_sat is listed in inventory
hosts_list = aap_client.get(
f'/api/v2/inventories/{inv_list["results"][0]["id"]}/hosts/'
).json()
assert rhel_contenthost.hostname in [host['name'] for host in hosts_list['results']]

@pytest.mark.on_premises_provisioning
@pytest.mark.rhel_ver_list([settings.content_host.default_rhel_version])
def test_positive_ansible_provisioning_callback(
self,
request,
aap_client,
module_provisioning_sat,
module_sca_manifest_org,
module_location,
provisioning_host,
pxe_loader,
module_provisioning_rhel_content,
provisioning_hostgroup,
module_lce_library,
module_default_org_view,
):
"""Verify provisioning callback functionality which allows to run an Ansible playbook
on the new RHEL provisioned host.

:id: a272a594-f758-40ef-95ec-813245e44b66

:steps:
1. Configure Satellite for provisioning
2. Update Satellite type credentials in AAP
3. Create or update a hostgroup to add hostgroup parameters for provisioning callback
4. Provision a RHEL hosts which must be added to Satellite inventory
5. Find Satellite inventory, inventory source and sync inventory source in AAP
6. Start ansible-callback systemd service, and Verify that job_template execution has begun in AAP

:expectedresults:
1. All hosts managed by Satellite are added to Satellite inventory.
2. Starting ansible-callback systemd service, starts a job_template execution in AAP
"""
host_mac_addr = provisioning_host._broker_args['provisioning_nic_mac_addr']
sat = module_provisioning_sat.sat
aap_fqdn = settings.AAP_INTEGRATION.AAP_FQDN
job_template = settings.AAP_INTEGRATION.callback_job_template
config_key = settings.AAP_INTEGRATION.host_config_key
inventory_name = settings.AAP_INTEGRATION.satellite_inventory
extra_vars_dict = '{"package_install": "tmux"}'

# Find the Satellite credentials in AAP and update it for sat.hostname and user credentials
self.update_sat_credentials_in_aap(aap_client, sat)

# Find the Satellite inventory in AAP and update it for provisioning_sat and user credentials
inv_list = aap_client.get(
'/api/v2/inventories/', query_parameters=f'name={inventory_name}'
).json()
inv_source_list = aap_client.get(
f'/api/v2/inventories/{inv_list["results"][0]["id"]}/inventory_sources/'
).json()

# Find the provisioning callback job template id, which is required for provisioning
jt_list = aap_client.get(
'/api/v2/job_templates/', query_parameters=f"name={job_template}"
).json()
template_id = jt_list['results'][0]['id']

# Update the provisioning callback parameters in hostgroup
existing_params = provisioning_hostgroup.group_parameters_attributes
provisioning_hostgroup.group_parameters_attributes = [
{'name': 'ansible_tower_provisioning', 'value': 'true', 'parameter_type': 'boolean'},
{'name': 'ansible_tower_fqdn', 'value': aap_fqdn, 'parameter_type': 'string'},
{'name': 'ansible_host_config_key', 'value': config_key, 'parameter_type': 'string'},
{'name': 'ansible_job_template_id', 'value': template_id, 'parameter_type': 'integer'},
{'name': 'ansible_extra_vars', 'value': extra_vars_dict, 'parameter_type': 'string'},
] + existing_params
provisioning_hostgroup.update(['group_parameters_attributes'])

hostname = gen_string('alpha').lower()
host = sat.cli.Host.create(
{
'name': hostname,
'organization': module_sca_manifest_org.name,
'location': module_location.name,
'hostgroup': provisioning_hostgroup.name,
'mac': host_mac_addr,
'provision-method': 'build',
}
)
# teardown
request.addfinalizer(lambda: sat.provisioning_cleanup(host['name'], interface='CLI'))

hostname = f'{hostname}.{module_provisioning_sat.domain.name}'
assert hostname == host['name']

# Start the VM, do not ensure that we can connect to SSHD
provisioning_host.power_control(ensure=False)

# Host should do call back to the Satellite reporting
# the result of the installation. Wait until Satellite reports that the host is installed.
wait_for(
lambda: sat.cli.Host.info({'name': hostname})['status']['build-status']
!= 'Pending installation',
timeout=1800,
delay=30,
)
host_info = sat.cli.Host.info({'id': host['id']})
assert host_info['status']['build-status'] == 'Installed'
host_os = sat.api.OperatingSystem(
id=host_info['operating-system']['operating-system']['id']
).read()

# In the current infra environment we don't support, addressing hosts using FQDNs, falling back to IP.
# Change the hostname of the host as we know it already.
provisioning_host.hostname = host_info['network']['ipv4-address']
# Update host since it is not blank anymore
provisioning_host.blank = False

# Wait for the host to be rebooted and SSH daemon to be started.
provisioning_host.wait_for_connection()

if int(host_os.major) >= 9:
assert (
provisioning_host.execute(
'echo -e "\nPermitRootLogin yes" >> /etc/ssh/sshd_config; systemctl restart sshd'
).status
== 0
)

# Sync the AAP inventory to add a provisioning host
sync_response = aap_client.post(
f'/api/v2/inventory_sources/{inv_source_list["results"][0]["id"]}/update/'
)
assert sync_response.ok

wait_for(
lambda: hostname
in [
host['name']
for host in aap_client.get(
f'/api/v2/inventories/{inv_list["results"][0]["id"]}/hosts/'
).json()['results']
],
timeout=180,
delay=30,
)
# Find the hosts in AAP inventory and verify if provisioning host is listed in inventory
hosts_list = aap_client.get(
f'/api/v2/inventories/{inv_list["results"][0]["id"]}/hosts/'
).json()
assert hostname in [host['name'] for host in hosts_list['results']]

assert provisioning_host.execute('systemctl start ansible-callback').status == 0

# Verify user rocket and package tmux is installed via ansible-callback on provisioning host
assert provisioning_host.execute('cat /etc/passwd | grep rocket').status == 0
assert provisioning_host.execute('dnf list installed tmux').status == 0
Loading