Skip to content

Commit

Permalink
API-factory setup registered host method
Browse files Browse the repository at this point in the history
  • Loading branch information
damoore044 committed May 13, 2024
1 parent 9fb55a2 commit fd1bdc6
Show file tree
Hide file tree
Showing 2 changed files with 344 additions and 48 deletions.
245 changes: 245 additions & 0 deletions robottelo/host_helpers/api_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,251 @@ 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,
unregister=False,
rex_key=False,
force=False,
):
"""
* 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.
param satellite: sat instance where needed entities exist.
param client: instance of a rhel contenthost to register.
param unregister (bool): unregister the host at the start, in case it is already registered
default: False, a reused fixture contenthost may fail if registered prior,
unregister before calling, or ensure it is a new host.
param enable_repos (bool): enable all available repos on the client, after registration?
default: False, be sure to enable any repo(s) for client, after calling this method.
param rex_key (bool): add a Remote Execution Key to client for satellite?
default: False
param force (bool): force registration of the client to bypass?
default: False, a reused fixture contenthost will fail if registered prior.
type: Below arguments can be any of the following:
* (int): pass id of entity to be read
* (str): pass name of entity to be searched
* (entity): pass an entity instance
param organization: pass an Organization instance, name, or id to use.
param activation_key: pass an Activation-Key instance, name, or id.
param environment: pass a Lifecycle-Environment instance, name, or id.
for example: can pass string name 'Library'.
param content_view: pass a Content-View instance, name, or id.
for example: can pass string name 'Default Organization View'.
Notes:
1. Will fail if passed entities do not exist in the same organization and satellite.
2. Use param `enable_repos`, to try enabling any repositories on client,
that were added to content-view prior. But if there are no
repositories added/made available, this will fail.
3. The Default Organization View cannot be published, promoted, edited, or deleted.
but you can register the client to it.
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 environment already. Skip for 'Library'.
4. assign environment and content-view to the activation-key, if not associated.
5. Register the host, using the activation-key associated with content.
6. Add a rex_key to the client if desired, enable all available repositories if desired.
return: if Succeeded: dict containing the updated entities:
{
'result', 'client', 'organization', 'activation_key',
'environment', 'content_view',
}
return: if Failed: dict containing the result and reason
{
'result': 'error'
'client': None, unless registration was successful
'message': Details of 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
if not force and client.subscribed:
if unregister:
client.unregister()
else:
method_error['message'] = (
'Passed client is already registered.'
' Unregister the host prior to calling this method.'
' Or, pass unregister=True, to unregister within this method first,'
' Or, pass force=True, to bypass during registration.'
)
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 for org name itself, will be just scoped to satellite
if entity == 'Organization':
search_query = f'name="{value}"'
# equivalent: _satellite_.api.{KEY}().search(...name={VALUE})
result = getattr(self._satellite.api, entity)().search(
query={'search': search_query}
)
# search of non-org entity by name, will be scoped to organization
else:
search_query = (
f"name='{value}' and organization_id={entities['Organization'].id}"
)
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'])

# register with now setup entities, using ak
entities = {k: v.read() for k, v in entities.items()}
result = client.register(
activation_keys=entities['ActivationKey'].name,
target=self._satellite,
org=entities['Organization'],
loc=None,
force=force,
)
if result.status != 0:
method_error['message'] = (
f'Failed to register the host: {client.hostname}.\n{result.stderr}'
)
return method_error
if not client.subscribed:
method_error['client'] = client
method_error['message'] = (
f'Failed to subscribe the host: {client.hostname},'
f' to content-view: {entities["ContentView"].name}'
)
return method_error
if rex_key:
client.add_rex_key(self._satellite)

# enable all repositories available to client, using subscription manager,
# ie: any repos added to content-view prior to calling this method.
# note: this will fail if no repos are available to client from CV/AK
if enable_repos:
output = client.execute(r'subscription-manager repos --enable \*')
if output.status != 0:
method_error['client'] = client
method_error['message'] = (
'Failed to enable all available repositories using subscription-manager.'
f' For client: {client.hostname}.\n{output.stdout}'
)
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

0 comments on commit fd1bdc6

Please sign in to comment.