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

Errata WIP for remaining UI Failures #15085

Merged
merged 2 commits into from
Jun 21, 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
2 changes: 2 additions & 0 deletions robottelo/constants/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,8 @@
REAL_RHEL7_0_ERRATA_ID = 'RHBA-2020:3615' # for REAL_RHEL7_0_0_PACKAGE
REAL_RHEL7_1_ERRATA_ID = 'RHBA-2017:0395' # tcsh bug fix update
REAL_RHEL8_1_ERRATA_ID = 'RHSA-2022:4867' # for REAL_RHEL8_1_PACKAGE
REAL_RHEL8_ERRATA_CVES = ['CVE-2021-27023', 'CVE-2021-27025']
REAL_RHSCLIENT_ERRATA = 'RHSA-2023:5982' # for RH Satellite Client 8
FAKE_1_YUM_REPOS_COUNT = 32
FAKE_3_YUM_REPOS_COUNT = 78
FAKE_9_YUM_SECURITY_ERRATUM = [
Expand Down
252 changes: 252 additions & 0 deletions robottelo/host_helpers/api_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,258 @@ def wait_for_errata_applicability_task(
f'No task was found using query " {search_query} " for host id: {host_id}'
)

def register_host_and_needed_setup(
self,
client,
organization,
activation_key,
environment,
content_view,
enable_repos=False,
rex_key=False,
force=False,
loc=None,
):
"""Helper will setup desired entities to host content. Then, register the
host client to the entities, using associated activation-key.

Attempt to make needed associations between detached entities.
Add desired repos to the content-view prior to calling this helper.

Or, add them to content-view after calling, then publish/promote.
The host will be registered to location: None (visible to all locations).

param client : instance, required
An instance of RHEL content host to register.
param enable_repos : bool, optional
Enable all available repos on the client after registration? Default is False.
Be sure to enable any repo(s) for the client after calling this method.
param rex_key : bool, optional
Add a Remote Execution Key to the client for satellite? Default is False.
param force : bool, optional
Force registration of the client to bypass? Default is False.
A reused fixture content host will fail if already registered.
param loc : instance, optional
Pass a location to limit host visibility. Default is None,
making the client available to all locations.

Required arguments below, can be any of the following type:
int: pass id of the entity to be read
str: pass name of the entity to be searched
entity: pass an entity instance

param organization : int, str, or entity
Pass an Organization instance, name, or id to use.
param activation_key : int, str, or entity
Pass an Activation-Key instance, name, or id.
param environment : int, str, or entity
Pass a Lifecycle-Environment instance, name, or id.
Example: can pass string name 'Library'.
param content_view : int, str, or entity
Pass a Content-View instance, name, or id.
Example: can pass string name 'Default Organization View'.

Note: The Default Organization View cannot be published, promoted, edited etc,
but you can register the client to it. Use the 'Library' environment.

Steps:
1. Get needed entities from arguments (id, name, or instance). Read all as instance.
2. Publish the content-view if no versions exist or needs_publish.
3. Promote the newest content-view-version if not in the environment already. Skip for 'Library'.
4. Assign environment and content-view to the activation-key if not associated.
5. If desired, enable all repositories from content-view for activation-key.
6. Register the host with options, using the activation-key associated with the content.
7. Check host was registered, identity matches passed entities.

Return: dictionary containing the following entries
if succeeded:
result: 'success'
client: registered host client
organization: entities['Organization']
activation_key: entities['ActivationKey']
environment: entities['LifecycleEnvironment']
content_view: entities['ContentView']

if failed:
result: 'error'
client: None, unless registration was successful
message: Details of the failure encountered
"""

method_error = {
'result': 'error',
'client': None,
'message': None,
}
entities = {
'Organization': organization,
'ActivationKey': activation_key,
'LifecycleEnvironment': environment,
'ContentView': content_view,
}
if not hasattr(client, 'hostname'):
method_error['message'] = (
'Argument "client" must be instance, with attribute "hostname".'
)
return method_error
# for entity arguments matched to above params:
# fetch entity instance on satellite,
# from given id or name, else read passed argument as an instance.
for entity, value in entities.items():
param = None
# passed int for entity, try to read by id
if isinstance(value, int):
# equivalent: _satellite_.api.{KEY}(id=VALUE).read()
param = getattr(self._satellite.api, entity)(id=value).read()
# passed str, search for entity by name
elif isinstance(value, str):
search_query = f'name="{value}"'
if entity == 'Organization':
# search for org name itself, will be just scoped to satellite
# equivalent: _satellite_.api.{KEY}().search(...name={VALUE})
result = getattr(self._satellite.api, entity)().search(
query={'search': search_query}
)
else:
# search of non-org entity by name, will be scoped to organization
result = getattr(self._satellite.api, entity)(
organization=entities['Organization']
).search(query={'search': search_query})
if not len(result) > 0:
method_error['message'] = (
f'Could not find {entity} name: {value}, by search query: "{search_query}"'
)
return method_error
param = result[0]
# did not pass int (id) or str (name), must be readable entity instance
else:
if not hasattr(value, 'id'):
method_error['message'] = (
f'Passed entity {entity}, has no attribute id:\n{value}'
)
return method_error
param = value
# updated param, should now be only an entity isntance
if not hasattr(param, 'id'):
method_error['message'] = (
f'Did not get readable instance from parameter on {self._satellite.hostname}:'
f' Param:{entity}:\n{value}'
)
return method_error
# entity found, read updated instance into dictionary
entities[entity] = param.read()

if ( # publish a content-view-version if none exist, or needs_publish is True
len(entities['ContentView'].version) == 0
or entities['ContentView'].needs_publish is True
):
entities['ContentView'].publish()
# read updated entitites after modifying CV
entities = {k: v.read() for k, v in entities.items()}

# promote to non-Library env if not already present:
# skip for 'Library' env selected or passed arg,
# any published version(s) will already be in Library.
if all(
[
environment != 'Library',
entities['LifecycleEnvironment'].name != 'Library',
entities['LifecycleEnvironment'] not in entities['ContentView'].environment,
]
):
# promote newest version by id
entities['ContentView'].version.sort(key=lambda version: version.id)
entities['ContentView'].version[-1].promote(
data={'environment_ids': entities['LifecycleEnvironment'].id}
)
# updated entities after promoting
entities = {k: v.read() for k, v in entities.items()}

if ( # assign env to ak if not present
entities['ActivationKey'].environment is None
or entities['ActivationKey'].environment.id != entities['LifecycleEnvironment'].id
):
entities['ActivationKey'].environment = entities['LifecycleEnvironment']
entities['ActivationKey'].update(['environment'])
entities = {k: v.read() for k, v in entities.items()}
if ( # assign cv to ak if not present
entities['ActivationKey'].content_view is None
or entities['ActivationKey'].content_view.id != entities['ContentView'].id
):
entities['ActivationKey'].content_view = entities['ContentView']
entities['ActivationKey'].update(['content_view'])

entities = {k: v.read() for k, v in entities.items()}
if enable_repos:
repositories = entities['ContentView'].repository
if len(repositories) < 1:
method_error['message'] = (
f' Cannot enable repositories for clients activation-key: {entities["ActivationKey"].name}'
f' There are no repositories added to the content-view: {entities["ContentView"].name}.'
)
return method_error
for repo in repositories:
# fetch content-label for any repo in cv
repo_content_label = self._satellite.cli.Repository.info(
{
'name': repo.read().name,
'organization-id': entities['Organization'].id,
'product': repo.read().product.read().name,
}
)['content-label']
# override the repository to enabled for ak
self._satellite.cli.ActivationKey.content_override(
{
'content-label': repo_content_label,
'id': entities['ActivationKey'].id,
'organization-id': entities['Organization'].id,
'value': int(True),
}
)

# register with now setup entities, using ak
result = client.register(
activation_keys=entities['ActivationKey'].name,
target=self._satellite,
org=entities['Organization'],
setup_remote_execution_pull=rex_key,
force=force,
loc=loc,
)
if result.status != 0:
method_error['message'] = (
f'Failed to register the host: {client.hostname}.\n{result.stderr}'
)
return method_error

# check identity of now registered client, matches expected entities
if not all(
[
client.subscribed,
client.identity['registered_to'] == self._satellite.hostname,
client.identity['org_name'] == entities['Organization'].name,
client.identity['environment_name']
== (f'{entities["LifecycleEnvironment"].name}/{entities["ContentView"].name}'),
]
):
method_error['client'] = client
method_error['message'] = (
f'Registered client identity field(s) do not match expected:\n{client.identity}'
)
return method_error

entities = {k: v.read() for k, v in entities.items()}
return ( # dict containing registered host client, and updated entities
{
'result': 'success',
'client': client,
'organization': entities['Organization'],
'activation_key': entities['ActivationKey'],
'environment': entities['LifecycleEnvironment'],
'content_view': entities['ContentView'],
}
)

def wait_for_syncplan_tasks(self, repo_backend_id=None, timeout=10, repo_name=None):
"""Search the pulp tasks and identify repositories sync tasks with
specified name or backend_identifier
Expand Down
Loading
Loading