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

Enabling Robottelo for IPv6 Testing #14160

Merged
merged 7 commits into from
Jun 13, 2024
Merged
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
1 change: 1 addition & 0 deletions conf/capsule.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ CAPSULE:
OS: deploy-rhel # workflow to deploy OS that is ready to run the product
# Dictionary of arguments which should be passed along to the deploy workflow
DEPLOY_ARGUMENTS:
# deploy_network_type: '@jinja {{"ipv6" if this.server.is_ipv6 else "ipv4"}}'
3 changes: 2 additions & 1 deletion conf/dynaconf_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from robottelo.logging import logger
from robottelo.utils.ohsnap import dogfood_repository
from robottelo.utils.url import is_url
from robottelo.utils.url import ipv6_hostname_translation, is_url


def post(settings):
Expand All @@ -26,6 +26,7 @@ def post(settings):
)
data = get_repos_config(settings)
write_cache(settings_cache_path, data)
ipv6_hostname_translation(settings, data)
config_migrations(settings, data)
data['dynaconf_merge'] = True
return data
Expand Down
5 changes: 5 additions & 0 deletions conf/server.yaml.template
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ SERVER:
SOURCE: "internal"
# The RHEL Base OS Version(x.y) where the Satellite is installed
RHEL_VERSION: '7'
# If the the satellite server is IPv6 server
IS_IPV6: False
# HTTP Proxy url for IPv6 satellite to connect for outer world access
HTTP_PROXY_IPv6_URL:
# run-on-one - All xdist runners default to the first satellite
# balance - xdist runners will be split between available satellites
# on-demand - any xdist runner without a satellite will have a new one provisioned.
Expand All @@ -32,6 +36,7 @@ SERVER:
OS: deploy-rhel # workflow to deploy OS that is ready to run the product
# Dictionary of arguments which should be passed along to the deploy workflow
# DEPLOY_ARGUMENTS:
# deploy_network_type: '@jinja {{"ipv6" if this.server.is_ipv6 else "ipv4"}}'
# HTTP scheme when building the server URL
# Suggested values for "scheme" are "http" and "https".
SCHEME: https
Expand Down
4 changes: 3 additions & 1 deletion pytest_fixtures/component/maintain.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ def module_stash(request):
@pytest.fixture(scope='module')
def sat_maintain(request, module_target_sat, module_capsule_configured):
if settings.remotedb.server:
yield Satellite(settings.remotedb.server)
sat = Satellite(settings.remotedb.server)
sat.enable_ipv6_http_proxy()
yield sat
else:
module_target_sat.register_to_cdn(pool_ids=settings.subscription.fm_rhn_poolid.split())
hosts = {'satellite': module_target_sat, 'capsule': module_capsule_configured}
Expand Down
3 changes: 3 additions & 0 deletions pytest_fixtures/core/broker.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def _target_sat_imp(request, _default_sat, satellite_factory):
"""This is the actual working part of the following target_sat fixtures"""
if request.node.get_closest_marker(name='destructive'):
new_sat = satellite_factory()
new_sat.enable_ipv6_http_proxy()
yield new_sat
new_sat.teardown()
Broker(hosts=[new_sat]).checkin()
Expand All @@ -32,6 +33,8 @@ def _target_sat_imp(request, _default_sat, satellite_factory):
settings.set('server.hostname', installer_sat.hostname)
yield installer_sat
else:
if _default_sat:
_default_sat.enable_ipv6_http_proxy()
yield _default_sat


Expand Down
18 changes: 13 additions & 5 deletions pytest_fixtures/core/sat_cap_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ def resolve_deploy_args(args_dict):
def _target_satellite_host(request, satellite_factory):
if 'sanity' not in request.config.option.markexpr:
new_sat = satellite_factory()
new_sat.enable_ipv6_http_proxy()
yield new_sat
new_sat.teardown()
Broker(hosts=[new_sat]).checkin()
Expand All @@ -48,6 +49,7 @@ def cached_capsule_cdn_register(hostname=None):
def _target_capsule_host(request, capsule_factory):
if 'sanity' not in request.config.option.markexpr and not request.config.option.n_minus:
new_cap = capsule_factory()
new_cap.enable_ipv6_http_proxy()
yield new_cap
new_cap.teardown()
Broker(hosts=[new_cap]).checkin()
Expand Down Expand Up @@ -94,6 +96,7 @@ def factory(retry_limit=3, delay=300, workflow=None, **broker_args):
def large_capsule_host(capsule_factory):
"""A fixture that provides a Capsule based on config settings"""
new_cap = capsule_factory(deploy_flavor=settings.flavors.custom_db)
new_cap.enable_ipv6_http_proxy()
yield new_cap
new_cap.teardown()
Broker(hosts=[new_cap]).checkin()
Expand Down Expand Up @@ -244,6 +247,7 @@ def module_lb_capsule(retry_limit=3, delay=300, **broker_args):
)
cap_hosts = wait_for(hosts.checkout, timeout=timeout, delay=delay)

[cap.enable_ipv6_http_proxy() for cap in cap_hosts.out]
yield cap_hosts.out

[cap.teardown() for cap in cap_hosts.out]
Expand Down Expand Up @@ -278,6 +282,7 @@ def parametrized_enrolled_sat(
):
"""Yields a Satellite enrolled into [IDM, AD] as parameter."""
new_sat = satellite_factory()
new_sat.enable_ipv6_http_proxy()
ipa_host = IPAHost(new_sat)
new_sat.register_to_cdn()
if 'IDM' in request.param:
Expand All @@ -297,6 +302,7 @@ def get_deploy_args(request):
rhel_version = get_sat_rhel_version()
deploy_args = {
'deploy_rhel_version': rhel_version.base_version,
'deploy_network_type': 'ipv6' if settings.server.is_ipv6 else 'ipv4',
'deploy_flavor': settings.flavors.default,
'promtail_config_template_file': 'config_sat.j2',
'workflow': settings.server.deploy_workflows.os,
Expand Down Expand Up @@ -328,11 +334,13 @@ def cap_ready_rhel():
rhel_version = Version(settings.capsule.version.rhel_version)
deploy_args = {
'deploy_rhel_version': rhel_version.base_version,
'deploy_network_type': 'ipv6' if settings.server.is_ipv6 else 'ipv4',
'deploy_flavor': settings.flavors.default,
'promtail_config_template_file': 'config_sat.j2',
'workflow': settings.capsule.deploy_workflows.os,
}
with Broker(**deploy_args, host_class=Capsule) as host:
host.enable_ipv6_http_proxy()
yield host


Expand All @@ -352,7 +360,7 @@ def installer_satellite(request):
sat = lru_sat_ready_rhel(getattr(request, 'param', None))
sat.setup_firewall()
# # Register for RHEL8 repos, get Ohsnap repofile, and enable and download satellite
sat.register_to_cdn()
sat.register_to_cdn(enable_proxy=True)
sat.download_repofile(
product='satellite',
release=settings.server.version.release,
Expand All @@ -371,12 +379,12 @@ def installer_satellite(request):
).get_command(),
timeout='30m',
)
sat.enable_ipv6_http_proxy()
if 'sanity' in request.config.option.markexpr:
configure_nailgun()
configure_airgun()
yield sat
if 'sanity' not in request.config.option.markexpr:
sanity_sat = Satellite(sat.hostname)
sanity_sat.unregister()
broker_sat = Satellite.get_host_by_hostname(sanity_sat.hostname)
Broker(hosts=[broker_sat]).checkin()
sat = Satellite.get_host_by_hostname(sat.hostname)
sat.unregister()
Broker(hosts=[sat]).checkin()
5 changes: 3 additions & 2 deletions pytest_fixtures/core/xdist.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ def align_to_satellite(request, worker_id, satellite_factory):
if settings.server.hostname:
sanity_sat = Satellite(settings.server.hostname)
sanity_sat.unregister()
broker_sat = Satellite.get_host_by_hostname(sanity_sat.hostname)
Broker(hosts=[broker_sat]).checkin()
if settings.server.auto_checkin:
broker_sat = Satellite.get_host_by_hostname(sanity_sat.hostname)
Broker(hosts=[broker_sat]).checkin()
else:
# clear any hostname that may have been previously set
settings.set("server.hostname", None)
Expand Down
2 changes: 2 additions & 0 deletions robottelo/config/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
Validator('server.ssh_username', default='root'),
Validator('server.ssh_password', default=None),
Validator('server.verify_ca', default=False),
Validator('server.is_ipv6', is_type_of=bool, default=False),
Validator('server.http_proxy_ipv6_url', is_type_of=str, default=None),
],
content_host=[
Validator('content_host.default_rhel_version', must_exist=True),
Expand Down
11 changes: 8 additions & 3 deletions robottelo/host_helpers/contenthost_mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,16 @@ def _dogfood_helper(self, product, release, repo=None):
)
return product, release, v_major, repo

def download_repofile(self, product=None, release=None, snap=''):
def download_repofile(self, product=None, release=None, snap='', proxy=None):
"""Downloads the tools/client, capsule, or satellite repos on the machine"""
product, release, v_major, _ = self._dogfood_helper(product, release)
url = dogfood_repofile_url(settings.ohsnap, product, release, v_major, snap)
self.execute(f'curl -o /etc/yum.repos.d/dogfood.repo -L {url}')
if not proxy and settings.server.is_ipv6:
proxy = settings.server.http_proxy_ipv6_url
url = dogfood_repofile_url(settings.ohsnap, product, release, v_major, snap, proxy=proxy)
command = f'curl -o /etc/yum.repos.d/dogfood.repo -L {url}'
if settings.server.is_ipv6:
command += f' -x {settings.server.http_proxy_ipv6_url}'
self.execute(command)
Comment on lines +96 to +102
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seeing settings.server section being referenced in ContentHostMixins does not seem right. Can you please use different settings than the server ones?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its already there used in _dogfood_helper function to not surprise :)

The only way we have is to override the function in Satellite class, because though its defined in ContentHost class its used for Satellite in this case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also there are many places in Host classes which are not adhering to the class in which context they are. The best way to clean is to override the method in child class and call super method.

For this PR I don't want to sign up for that work, we could see it as a separate effort.


def dogfood_repository(self, repo=None, product=None, release=None, snap=''):
"""Returns a repository definition based on the arguments provided"""
Expand Down
94 changes: 93 additions & 1 deletion robottelo/hosts.py
jyejare marked this conversation as resolved.
Show resolved Hide resolved
jyejare marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def lru_sat_ready_rhel(rhel_ver):
rhel_version = rhel_ver or settings.server.version.rhel_version
deploy_args = {
'deploy_rhel_version': rhel_version,
'deploy_network_type': 'ipv6' if settings.server.is_ipv6 else 'ipv4',
'deploy_flavor': settings.flavors.default,
'promtail_config_template_file': 'config_sat.j2',
'workflow': settings.server.deploy_workflows.os,
Expand Down Expand Up @@ -823,6 +824,7 @@ def register_contenthost(
auto_attach=False,
serverurl=None,
baseurl=None,
enable_proxy=False,
):
"""Registers content host on foreman server either by specifying
organization name and activation key name or by specifying organization
Expand Down Expand Up @@ -879,6 +881,7 @@ def register_contenthost(
cmd += f' --serverurl {serverurl}'
if baseurl:
cmd += f' --baseurl {baseurl}'

return self.execute(cmd)

def unregister(self):
Expand Down Expand Up @@ -925,6 +928,13 @@ def put_ssh_key(self, source_key_path, destination_key_name):
if result.status != 0:
raise CLIFactoryError(f'Failed to chmod ssh key file:\n{result.stderr}')

def enable_rhsm_proxy(self, hostname, port=None):
"""Configures proxy for subscription manager"""
cmd = f"subscription-manager config --server.proxy_hostname={hostname}"
if port:
cmd += f' --server.proxy_port={port}'
self.execute(cmd)

def add_authorized_key(self, pub_key):
"""Inject a public key into the authorized keys file

Expand Down Expand Up @@ -1469,7 +1479,7 @@ def install_tracer(self):
raise ContentHostError('There was an error installing katello-host-tools-tracer')
self.execute('katello-tracer-upload')

def register_to_cdn(self, pool_ids=None):
def register_to_cdn(self, pool_ids=None, enable_proxy=False):
"""Subscribe satellite to CDN"""
if pool_ids is None:
pool_ids = [settings.subscription.rhn_poolid]
Expand All @@ -1479,6 +1489,7 @@ def register_to_cdn(self, pool_ids=None):
lce=None,
username=settings.subscription.rhn_username,
password=settings.subscription.rhn_password,
enable_proxy=enable_proxy,
)
if cmd_result.status != 0:
raise ContentHostError(
Expand Down Expand Up @@ -1633,6 +1644,17 @@ def enable_capsule_downstream_repos(self):
snap=settings.capsule.version.snap,
)

def enable_ipv6_http_proxy(self):
"""Execute procedures for enabling IPv6 HTTP Proxy on Capsule using SM"""
if all([settings.server.is_ipv6, settings.server.http_proxy_ipv6_url]):
url = urlparse(settings.server.http_proxy_ipv6_url)
self.enable_rhsm_proxy(url.hostname, url.port)

def disable_ipv6_http_proxy(self):
"""Executes procedures for disabling IPv6 HTTP Proxy on Capsule"""
if settings.server.is_ipv6:
self.execute('subscription-manager remove server.proxy_hostname server.proxy_port')

def capsule_setup(self, sat_host=None, capsule_cert_opts=None, **installer_kwargs):
"""Prepare the host and run the capsule installer"""
self._satellite = sat_host or Satellite()
Expand Down Expand Up @@ -1756,6 +1778,10 @@ def enable_satellite_or_capsule_module_for_rhel8(self):
Note: Make sure required repos are enabled before using this.
"""
if self.os_version.major == 8:
if settings.server.is_ipv6:
self.execute(
f"echo -e 'proxy={settings.server.http_proxy_ipv6_url}' >> /etc/dnf/dnf.conf"
)
Comment on lines +1781 to +1784
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why only for RHEL 8? 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The question is out of scope of this PR. But I think it is because the modularity started in RHEL8 but the condition could be changed to self.os_version.major == 8, I shall leave it to teams to fix.

assert (
self.execute(
f'dnf -y module enable {self.product_rpm_name}:el{self.os_version.major}'
Expand Down Expand Up @@ -1798,6 +1824,55 @@ def _swap_nailgun(self, new_version):
to_clear = [k for k in sys.modules if 'nailgun' in k]
[sys.modules.pop(k) for k in to_clear]

def enable_ipv6_http_proxy(self):
"""Execute procedures for enabling IPv6 HTTP Proxy"""
if not all([settings.server.is_ipv6, settings.server.http_proxy_ipv6_url]):
logger.warning(
'The IPv6 HTTP Proxy setting is not enabled. Skipping the IPv6 HTTP Proxy setup.'
)
return None
proxy_name = 'Robottelo IPv6 Automation Proxy'
if not self.cli.HttpProxy.exists(search=('name', proxy_name)):
http_proxy = self.api.HTTPProxy(
name=proxy_name, url=settings.server.http_proxy_ipv6_url
).create()
else:
logger.info(
'The IPv6 HTTP Proxy is already enabled. Skipping the IPv6 HTTP Proxy setup.'
)
http_proxy = self.api.HTTPProxy().search(query={'search': f'name={proxy_name}'})[0]
# Setting HTTP Proxy as default in the settings
self.cli.Settings.set(
{
'name': 'content_default_http_proxy',
'value': proxy_name,
}
)
self.cli.Settings.set(
{
'name': 'http_proxy',
'value': settings.server.http_proxy_ipv6_url,
}
)
return http_proxy

def disable_ipv6_http_proxy(self, http_proxy):
jyejare marked this conversation as resolved.
Show resolved Hide resolved
"""Execute procedures for disabling IPv6 HTTP Proxy"""
if http_proxy:
http_proxy.delete()
self.cli.Settings.set(
{
'name': 'content_default_http_proxy',
'value': '',
}
)
self.cli.Settings.set(
{
'name': 'http_proxy',
'value': '',
}
)

@property
def api(self):
"""Import all nailgun entities and wrap them under self.api"""
Expand Down Expand Up @@ -2326,6 +2401,23 @@ def sync_inventory_status(self, org):
)
return inventory_sync

def register_contenthost(
self,
org='Default_Organization',
lce='Library',
username=settings.server.admin_username,
password=settings.server.admin_password,
enable_proxy=False,
):
"""Satellite Registration to CDN"""
# Enabling proxy for IPv6
if enable_proxy and all([settings.server.is_ipv6, settings.server.http_proxy_ipv6_url]):
url = urlparse(settings.server.http_proxy_ipv6_url)
self.enable_rhsm_proxy(url.hostname, url.port)
return super().register_contenthost(
org=org, lce=lce, username=username, password=password, enable_proxy=enable_proxy
)


class SSOHost(Host):
"""Class for RHSSO functions and setup"""
Expand Down
Loading
Loading