Server IP : 85.214.239.14 / Your IP : 52.15.57.54 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /lib/python3/dist-packages/ansible_collections/theforeman/foreman/plugins/modules/ |
Upload File : |
#!/usr/bin/python # -*- coding: utf-8 -*- # (c) 2017, Andrew Kofink <ajkofink@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = ''' --- module: activation_key version_added: 1.0.0 short_description: Manage Activation Keys description: - Create and manage activation keys author: "Andrew Kofink (@akofink)" options: name: description: - Name of the activation key required: true type: str description: description: - Description of the activation key type: str lifecycle_environment: description: - Name of the lifecycle environment type: str content_view: description: - Name of the content view type: str subscriptions: description: - List of subscriptions that include either Name, Pool ID, or Upstream Pool ID. - Pool IDs are preferred since Names and Upstream Pool IDs are not guaranteed to be unique. The module will fail if it finds more than one match. type: list elements: dict suboptions: name: description: - Name of the Subscription to be added. - Mutually exclusive with I(pool_id) and I(upstream_pool_id). type: str required: false pool_id: description: - Pool ID of the Subscription to be added. - Mutually exclusive with I(name) and I(upstream_pool_id). - Also named C(Candlepin Id) in the CSV export of the subscriptions, - it is as well the C(UUID) as output by C(hammer subscription list). type: str required: false upstream_pool_id: description: - Upstream Pool ID of the Subscription to be added. - Mutually exclusive with I(name) and I(pool_id). - Also named C(Master Pools) in the Red Hat Portal. type: str required: false host_collections: description: - List of host collections to add to activation key type: list elements: str content_overrides: description: - List of content overrides that include label and override state - Label refers to repository C(content_label), e.g. rhel-7-server-rpms - Override state ('enabled', 'disabled', or 'default') sets initial state of repository for newly registered hosts type: list elements: dict suboptions: label: description: - Repository C(content_label) to override when registering hosts with the activation key type: str required: true override: description: - Override value to use for the repository when registering hosts with the activation key choices: - enabled - disabled - default type: str required: true auto_attach: description: - Set Auto-Attach on or off type: bool release_version: description: - Set the content release version type: str service_level: description: - Set the service level choices: - Self-Support - Standard - Premium type: str max_hosts: description: - Maximum number of registered content hosts. - Required if I(unlimited_hosts=false) type: int unlimited_hosts: description: - Can the activation key have unlimited hosts type: bool purpose_usage: description: - Sets the system purpose usage type: str purpose_role: description: - Sets the system purpose role type: str purpose_addons: description: - Sets the system purpose add-ons type: list elements: str state: description: - State of the Activation Key - If C(copied) the key will be copied to a new one with I(new_name) as the name and all other fields left untouched - C(present_with_defaults) will ensure the entity exists, but won't update existing ones default: present choices: - present - present_with_defaults - absent - copied type: str new_name: description: - Name of the new activation key when state == copied type: str extends_documentation_fragment: - theforeman.foreman.foreman - theforeman.foreman.foreman.organization ''' EXAMPLES = ''' - name: "Create client activation key" theforeman.foreman.activation_key: username: "admin" password: "changeme" server_url: "https://foreman.example.com" name: "Clients" organization: "Default Organization" lifecycle_environment: "Library" content_view: 'client content view' host_collections: - rhel7-servers - rhel7-production subscriptions: - pool_id: "8a88e9826db22df5016dd018abdd029b" - pool_id: "8a88e9826db22df5016dd01a23270344" - name: "Red Hat Enterprise Linux" content_overrides: - label: rhel-7-server-optional-rpms override: enabled auto_attach: false release_version: 7Server service_level: Standard ''' RETURN = ''' entity: description: Final state of the affected entities grouped by their type. returned: success type: dict contains: activation_keys: description: List of activation keys. type: list elements: dict ''' from ansible_collections.theforeman.foreman.plugins.module_utils.foreman_helper import KatelloEntityAnsibleModule, PER_PAGE def override_to_boolnone(override): value = None if isinstance(override, bool): value = override else: override = override.lower() if override == 'enabled': value = True elif override == 'disabled': value = False elif override == 'default': value = None return value class KatelloActivationKeyModule(KatelloEntityAnsibleModule): pass def main(): module = KatelloActivationKeyModule( foreman_spec=dict( name=dict(required=True), new_name=dict(), description=dict(), lifecycle_environment=dict(type='entity', flat_name='environment_id', scope=['organization']), content_view=dict(type='entity', scope=['organization']), host_collections=dict(type='entity_list', scope=['organization']), auto_attach=dict(type='bool'), release_version=dict(), service_level=dict(choices=['Self-Support', 'Standard', 'Premium']), max_hosts=dict(type='int'), unlimited_hosts=dict(type='bool'), purpose_usage=dict(), purpose_role=dict(), purpose_addons=dict(type='list', elements='str'), ), argument_spec=dict( subscriptions=dict(type='list', elements='dict', options=dict( name=dict(), pool_id=dict(), upstream_pool_id=dict(), ), required_one_of=[['name', 'pool_id', 'upstream_pool_id']], mutually_exclusive=[['name', 'pool_id', 'upstream_pool_id']], ), content_overrides=dict(type='list', elements='dict', options=dict( label=dict(required=True), override=dict(required=True, choices=['enabled', 'disabled', 'default']), )), state=dict(default='present', choices=['present', 'present_with_defaults', 'absent', 'copied']), ), required_if=[ ['state', 'copied', ['new_name']], ['unlimited_hosts', False, ['max_hosts']], ], ) with module.api_connection(): entity = module.lookup_entity('entity') scope = module.scope_for('organization') if module.state == 'copied': new_entity = module.find_resource_by_name('activation_keys', name=module.foreman_params['new_name'], params=scope, failsafe=True) if new_entity is not None: module.warn("Activation Key '{0}' already exists.".format(module.foreman_params['new_name'])) module.exit_json() subscriptions = module.foreman_params.pop('subscriptions', None) content_overrides = module.foreman_params.pop('content_overrides', None) if not module.desired_absent: module.lookup_entity('host_collections') host_collections = module.foreman_params.pop('host_collections', None) activation_key = module.run() # only update subscriptions of newly created or updated AKs # copied keys inherit the subscriptions of the origin, so one would not have to specify them again # deleted keys don't need subscriptions anymore either if module.state == 'present' or (module.state == 'present_with_defaults' and module.changed): # the auto_attach, release_version and service_level parameters can only be set on an existing AK with an update, # not during create, so let's force an update. see https://projects.theforeman.org/issues/27632 for details if any(key in module.foreman_params for key in ['auto_attach', 'release_version', 'service_level']) and module.changed: activation_key = module.ensure_entity('activation_keys', module.foreman_params, activation_key, params=scope) ak_scope = {'activation_key_id': activation_key['id']} ak_scope.update(scope) if subscriptions is not None: desired_subscriptions = [] for subscription in subscriptions: if subscription.get('name') is not None: desired_subscriptions.append(module.find_resource_by_name('subscriptions', subscription['name'], params=scope, thin=True)) if subscription.get('pool_id') is not None: desired_subscriptions.append(module.find_resource_by_id('subscriptions', subscription['pool_id'], params=scope, thin=True)) if subscription.get('upstream_pool_id') is not None: desired_subscriptions.append( module.find_resource_by('subscriptions', 'upstream_pool_id', subscription['upstream_pool_id'], params=scope, thin=True) ) desired_subscription_ids = set(item['id'] for item in desired_subscriptions) current_subscriptions = module.list_resource('subscriptions', params=ak_scope) if entity else [] current_subscription_ids = set(item['id'] for item in current_subscriptions) if desired_subscription_ids != current_subscription_ids: module.record_before('activation_keys/subscriptions', {'id': activation_key['id'], 'subscriptions': current_subscription_ids}) module.record_after('activation_keys/subscriptions', {'id': activation_key['id'], 'subscriptions': desired_subscription_ids}) module.record_after_full('activation_keys/subscriptions', {'id': activation_key['id'], 'subscriptions': desired_subscription_ids}) ids_to_remove = current_subscription_ids - desired_subscription_ids if ids_to_remove: payload = { 'id': activation_key['id'], 'subscriptions': [{'id': item} for item in ids_to_remove], } payload.update(scope) module.resource_action('activation_keys', 'remove_subscriptions', payload) ids_to_add = desired_subscription_ids - current_subscription_ids if ids_to_add: payload = { 'id': activation_key['id'], 'subscriptions': [{'id': item, 'quantity': 1} for item in ids_to_add], } payload.update(scope) module.resource_action('activation_keys', 'add_subscriptions', payload) if content_overrides is not None: if entity: product_content = module.resource_action( 'activation_keys', 'product_content', params={'id': activation_key['id'], 'content_access_mode_all': True, 'per_page': PER_PAGE}, ignore_check_mode=True, ) else: product_content = {'results': []} current_content_overrides = { product['content']['label']: product['enabled_content_override'] for product in product_content['results'] if product['enabled_content_override'] is not None } desired_content_overrides = { product['label']: override_to_boolnone(product['override']) for product in content_overrides } changed_content_overrides = [] module.record_before('activation_keys/content_overrides', {'id': activation_key['id'], 'content_overrides': current_content_overrides.copy()}) module.record_after('activation_keys/content_overrides', {'id': activation_key['id'], 'content_overrides': desired_content_overrides}) module.record_after_full('activation_keys/content_overrides', {'id': activation_key['id'], 'content_overrides': desired_content_overrides}) for label, override in desired_content_overrides.items(): if override is not None and override != current_content_overrides.pop(label, None): changed_content_overrides.append({'content_label': label, 'value': override}) for label in current_content_overrides.keys(): changed_content_overrides.append({'content_label': label, 'remove': True}) if changed_content_overrides: payload = { 'id': activation_key['id'], 'content_overrides': changed_content_overrides, } module.resource_action('activation_keys', 'content_override', payload) if host_collections is not None: if not entity: current_host_collection_ids = set() elif 'host_collection_ids' in activation_key: current_host_collection_ids = set(activation_key['host_collection_ids']) else: current_host_collection_ids = set(item['id'] for item in activation_key['host_collections']) desired_host_collections = host_collections desired_host_collection_ids = set(item['id'] for item in desired_host_collections) if desired_host_collection_ids != current_host_collection_ids: module.record_before('activation_keys/host_collections', {'id': activation_key['id'], 'host_collections': current_host_collection_ids}) module.record_after('activation_keys/host_collections', {'id': activation_key['id'], 'host_collections': desired_host_collection_ids}) module.record_after_full('activation_keys/host_collections', {'id': activation_key['id'], 'host_collections': desired_host_collection_ids}) ids_to_remove = current_host_collection_ids - desired_host_collection_ids if ids_to_remove: payload = { 'id': activation_key['id'], 'host_collection_ids': list(ids_to_remove), } module.resource_action('activation_keys', 'remove_host_collections', payload) ids_to_add = desired_host_collection_ids - current_host_collection_ids if ids_to_add: payload = { 'id': activation_key['id'], 'host_collection_ids': list(ids_to_add), } module.resource_action('activation_keys', 'add_host_collections', payload) if __name__ == '__main__': main()