def main(): module = ForemanAnsibleModule( argument_spec=dict( name=dict(required=True), value=dict(), ), supports_check_mode=True, ) (server_params, entity_dict) = module.parse_params() try: (server_url, username, password, verify_ssl) = server_params create_server(server_url, (username, password), verify_ssl) except Exception as e: module.fail_json(msg="Failed to connect to Foreman server: %s " % e) ping_server(module) entity = find_setting( module, name=entity_dict['name'], failsafe=False, ) if 'value' not in entity_dict: entity_dict['value'] = entity.default or "" entity_dict = sanitize_entity_dict(entity_dict, name_map) changed, entity = naildown_entity(Setting, entity_dict, entity, 'present', module, check_type=True) module.exit_json(changed=changed, foreman_setting=entity.to_json_dict())
def main(): module = ForemanAnsibleModule( argument_spec=dict( name=dict(required=True), value=dict(), ), supports_check_mode=True, ) entity_dict = module.parse_params() module.connect() entity = find_setting( module, name=entity_dict['name'], failsafe=False, ) if 'value' not in entity_dict: entity_dict['value'] = entity.default or "" entity_dict = sanitize_entity_dict(entity_dict, name_map) changed, entity = naildown_entity(Setting, entity_dict, entity, 'present', module, check_type=True) module.exit_json(changed=changed, foreman_setting=entity.to_json_dict())
def main(): module = AnsibleModule( argument_spec=dict( server_url=dict(required=True), username=dict(required=True), password=dict(required=True, no_log=True), verify_ssl=dict(type='bool', default=True), name=dict(required=True), value=dict(), ), supports_check_mode=True, ) if has_import_error: module.fail_json(msg=import_error_msg) entity_dict = dict([(k, v) for (k, v) in module.params.items() if v is not None]) server_url = entity_dict.pop('server_url') username = entity_dict.pop('username') password = entity_dict.pop('password') verify_ssl = entity_dict.pop('verify_ssl') try: create_server(server_url, (username, password), verify_ssl) except Exception as e: module.fail_json(msg="Failed to connect to Foreman server: %s " % e) ping_server(module) entity = find_setting( module, name=entity_dict['name'], failsafe=False, ) if 'value' not in entity_dict: entity_dict['value'] = entity.default or "" entity_dict = sanitize_entity_dict(entity_dict, name_map) changed, entity = naildown_entity(Setting, entity_dict, entity, 'present', module) module.exit_json(changed=changed, foreman_setting=entity.to_json_dict())
def main(): module = ForemanEntityAnsibleModule( argument_spec=dict( name=dict(required=True), updated_name=dict(), compute_attributes=dict(type='list'), ), supports_check_mode=True, ) (compute_profile_dict, state) = module.parse_params() name = compute_profile_dict.get('name') updated_name = compute_profile_dict.get('updated_name') compute_attributes = compute_profile_dict.pop('compute_attributes', list()) if len(compute_attributes) > 0 and state == 'absent': module.fail_json( msg='compute_attributes not allowed when state=absent') module.connect() try: # Try to find the compute_profile to work on compute_profile = find_compute_profile( module, name=compute_profile_dict['name'], failsafe=True) except Exception as e: module.fail_json(msg='Failed to find entity: %s ' % e) if state == 'present' and updated_name: compute_profile_dict['name'] = updated_name compute_profile_dict = sanitize_entity_dict(compute_profile_dict, name_map) (changed, compute_profile) = naildown_entity(ComputeProfile, compute_profile_dict, compute_profile, state, module) # Apply changes on underlying compute attributes only when present if state == 'present': # Update or create compute attributes for compute_attribute_dict in compute_attributes: changed |= compute_attribute(module, compute_profile, compute_attribute_dict) module.exit_json(changed=changed)
def main(): module = AnsibleModule( argument_spec=dict( # Foreman credentials server_url=dict(required=True), username=dict(required=True, no_log=True), password=dict(required=True, no_log=True), verify_ssl=dict(type='bool', default=True), # Entity parameter audit_comment=dict(), description_format=dict(), # effectice_user=dict(type='dict'), file_name=dict(type='path'), job_category=dict(), locations=dict(type='list'), locked=dict(type='bool', default=False), name=dict(), organizations=dict(type='list'), provider_type=dict(default='SSH'), snippet=dict(type='bool'), template=dict(), template_inputs=dict(type='list'), # Control parameter state=dict(default='present', choices=['absent', 'present_with_defaults', 'present']), ), supports_check_mode=True, mutually_exclusive=[ ['file_name', 'template'], ], required_one_of=[ ['name', 'file_name', 'template'], ], ) # We do not want a layout text for bulk operations if module.params['name'] == '*': if module.params['file_name'] or module.params['template']: module.fail_json( msg="Neither file_name nor template allowed if 'name: *'!") if HAS_IMPORT_ERROR: module.fail_json(msg=IMPORT_ERROR) entity_dict = dict([(k, v) for (k, v) in module.params.items() if v is not None]) server_url = entity_dict.pop('server_url') username = entity_dict.pop('username') password = entity_dict.pop('password') verify_ssl = entity_dict.pop('verify_ssl') state = entity_dict.pop('state') file_name = entity_dict.pop('file_name', None) if file_name or 'template' in entity_dict: if file_name: parsed_dict = parse_template_from_file(file_name, module) else: parsed_dict = parse_template(entity_dict['template'], module) # sanitize name from template data # The following condition can actually be hit, when someone is trying to import a # template with the name set to '*'. # Besides not being sensible, this would go horribly wrong in this module. if 'name' in parsed_dict and parsed_dict['name'] == '*': module.fail_json(msg="Cannot use '*' as a job template name!") # module params are priorized parsed_dict.update(entity_dict) entity_dict = parsed_dict # make sure, we have a name if 'name' not in entity_dict: if file_name: entity_dict['name'] = os.path.splitext( os.path.basename(file_name))[0] else: module.fail_json( msg='No name specified and no filename to infer it.') name = entity_dict['name'] affects_multiple = name == '*' # sanitize user input, filter unuseful configuration combinations with 'name: *' if affects_multiple: if state == 'present_with_defaults': module.fail_json( msg= "'state: present_with_defaults' and 'name: *' cannot be used together" ) if state == 'absent': if list(entity_dict.keys()) != ['name']: module.fail_json( msg= "When deleting all job templates, there is no need to specify further parameters." ) try: create_server(server_url, (username, password), verify_ssl) except Exception as e: module.fail_json(msg='Failed to connect to Foreman server: %s ' % e) ping_server(module) try: if affects_multiple: entities = find_entities(JobTemplate) else: entities = find_entities(JobTemplate, name=entity_dict['name']) except Exception as e: module.fail_json(msg='Failed to find entity: %s ' % e) # Set Locations of job template if 'locations' in entity_dict: entity_dict['locations'] = find_entities_by_name( Location, entity_dict['locations'], module) # Set Organizations of job template if 'organizations' in entity_dict: entity_dict['organizations'] = find_entities_by_name( Organization, entity_dict['organizations'], module) # TemplateInputs need to be added as separate entities later template_input_list = entity_dict.get('template_inputs', []) entity_dict = sanitize_entity_dict(entity_dict, name_map) changed = False if not affects_multiple: if entities: entity = entities[0] else: entity = None changed, result = naildown_entity(JobTemplate, entity_dict, entity, state, module) if state in ("present", "present_with_defaults"): # Manage TemplateInputs here for template_input_dict in template_input_list: template_input_dict = template_input_dict.copy() # assign template_input to a template template_input_dict['template'] = result ti_entity = find_template_input( module, str(template_input_dict['name']), result) changed |= naildown_entity_state(TemplateInput, template_input_dict, ti_entity, state, module) # remove template inputs if they aren't present in template_input_list found_tis = find_entities( entity_class=lambda: TemplateInput(template=result)) template_input_names = set(ti['name'] for ti in template_input_list) for ti in found_tis: if ti.name not in template_input_names: changed |= naildown_entity_state(TemplateInput, None, ti, "absent", module) else: entity_dict.pop('name') for entity in entities: changed |= naildown_entity_state(JobTemplate, entity_dict, entity, state, module) module.exit_json(changed=changed)
def main(): module = KatelloEntityAnsibleModule( argument_spec=dict( name=dict(required=True), new_name=dict(), lifecycle_environment=dict(), content_view=dict(), subscriptions=dict(type='list'), host_collections=dict(type='list'), content_overrides=dict(type='list'), auto_attach=dict(type='bool', default=True), state=dict(default='present', choices=[ 'present', 'present_with_defaults', 'absent', 'copied' ]), ), supports_check_mode=True, required_if=[ ['state', 'copied', ['new_name']], ], ) (entity_dict, state) = module.parse_params() module.connect() entity_dict['organization'] = find_organization( module, name=entity_dict['organization']) if 'lifecycle_environment' in entity_dict: entity_dict['lifecycle_environment'] = find_lifecycle_environment( module, entity_dict['lifecycle_environment'], entity_dict['organization']) if 'content_view' in entity_dict: entity_dict['content_view'] = find_content_view( module, entity_dict['content_view'], entity_dict['organization']) if 'host_collections' in entity_dict: entity_dict['host_collections'] = find_host_collections( module, entity_dict['host_collections'], entity_dict['organization']) activation_key_entity = find_activation_key( module, name=entity_dict['name'], organization=entity_dict['organization'], failsafe=True) activation_key_dict = sanitize_entity_dict(entity_dict, name_map) try: changed, activation_key_entity = naildown_entity( ActivationKey, activation_key_dict, activation_key_entity, state, module) # 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 state == 'present' or (state == 'present_with_defaults' and changed): if 'subscriptions' in entity_dict: subscriptions = entity_dict['subscriptions'] desired_subscription_ids = set( s.id for s in find_subscriptions( module, subscriptions, entity_dict['organization'])) current_subscriptions = [ Subscription(**result) for result in Subscription().search_normalize( activation_key_entity.subscriptions()['results']) ] current_subscription_ids = set(s.id for s in current_subscriptions) if desired_subscription_ids != current_subscription_ids: if not module.check_mode: for subscription_id in (desired_subscription_ids - current_subscription_ids): activation_key_entity.add_subscriptions( data={ 'quantity': 1, 'subscription_id': subscription_id }) for subscription_id in (current_subscription_ids - desired_subscription_ids): activation_key_entity.remove_subscriptions( data={'subscription_id': subscription_id}) changed = True if 'content_overrides' in entity_dict: content_overrides = entity_dict['content_overrides'] product_content = activation_key_entity.product_content() current_content_overrides = set( (product['content']['label'], product['enabled_content_override']) for product in product_content['results'] if product['enabled_content_override'] is not None) desired_content_overrides = set( (product['label'], override_to_boolnone(product['override'])) for product in content_overrides) if desired_content_overrides != current_content_overrides: if not module.check_mode: for ( label, override ) in current_content_overrides - desired_content_overrides: activation_key_entity.content_override( data={ 'content_override': { 'content_label': label, 'value': 'default' } }) for ( label, override ) in desired_content_overrides - current_content_overrides: activation_key_entity.content_override( data={ 'content_override': { 'content_label': label, 'value': str(override).lower() } }) changed = True module.exit_json(changed=changed) except Exception as e: module.fail_json(msg=e)
def main(): module = KatelloEntityAnsibleModule( argument_spec=dict( name=dict(required=True), composite=dict(type='bool', default=False), auto_publish=dict(type='bool', default=False), components=dict(type='list'), repositories=dict(type='list'), state=dict(default='present', choices=['present_with_defaults', 'present', 'absent']), ), mutually_exclusive=[['repositories', 'components']], ) (entity_dict, state) = module.parse_params() module.connect() entity_dict['organization'] = find_organization( module, name=entity_dict['organization']) if 'repositories' in entity_dict and not entity_dict['composite']: entity_dict['repositories'] = find_repositories( module, entity_dict['repositories'], entity_dict['organization']) content_view_entity = find_content_view( module, name=entity_dict['name'], organization=entity_dict['organization'], failsafe=True) content_view_dict = sanitize_entity_dict(entity_dict, name_map) changed, content_view_entity = naildown_entity(ContentView, content_view_dict, content_view_entity, state, module) # only update CVC's of newly created or updated CCV's if state == 'present' or (state == 'present_with_defaults' and changed): current_cvcs = [] if hasattr(content_view_entity, 'content_view_component'): current_cvcs = [ cvc.read() for cvc in content_view_entity.content_view_component ] if 'components' in entity_dict and content_view_entity.composite: for component in entity_dict['components']: cvc = component.copy() cvc['content_view'] = find_content_view( module, name=component['content_view'], organization=entity_dict['organization']) cvc_matched = None for _cvc in current_cvcs: if _cvc.content_view.id == cvc['content_view'].id: cvc_matched = _cvc force_update = list() if 'version' in component: cvc['version'] = find_content_view_version( module, cvc['content_view'], version=component['version']) cvc['latest'] = False if cvc_matched and cvc_matched.latest: # When changing to latest=False & version is the latest we must send 'content_view_version' to the server force_update.append('content_view_version') if cvc_matched: cvc['composite_content_view'] = content_view_entity cvc_dict = sanitize_entity_dict(cvc, cvc_map) cvc_changed = naildown_entity_state( ContentViewComponent, cvc_dict, cvc_matched, 'present', module, force_update=force_update) current_cvcs.remove(cvc_matched) if cvc_changed: changed = cvc_changed else: for attr in ['latest', 'version']: if attr not in cvc: cvc[attr] = None ContentViewComponent( composite_content_view=content_view_entity, content_view=cvc['content_view'], latest=cvc['latest'], content_view_version=cvc['version']).add() changed = True for cvc in current_cvcs: # desired cvcs have already been updated and removed from `current_cvcs` cvc.remove() changed = True module.exit_json(changed=changed)
def main(): module = AnsibleModule( argument_spec=dict( server_url=dict(required=True), username=dict(required=True, no_log=True), password=dict(required=True, no_log=True), verify_ssl=dict(type='bool', default=True), name=dict(required=True), organization=dict(required=True), composite=dict(type='bool', default=False), auto_publish=dict(type='bool', default=False), components=dict(type='list'), repositories=dict(type='list'), state=dict(default='present', choices=['present_with_defaults', 'present', 'absent']), ), supports_check_mode=True, mutually_exclusive=[['repositories', 'components']], ) if has_import_error: module.fail_json(msg=import_error_msg) entity_dict = dict( [(k, v) for (k, v) in module.params.items() if v is not None]) server_url = entity_dict.pop('server_url') username = entity_dict.pop('username') password = entity_dict.pop('password') verify_ssl = entity_dict.pop('verify_ssl') state = entity_dict.pop('state') try: create_server(server_url, (username, password), verify_ssl) except Exception as e: module.fail_json(msg="Failed to connect to Foreman server: %s " % e) ping_server(module) entity_dict['organization'] = find_organization(module, name=entity_dict['organization']) if 'repositories' in entity_dict and not entity_dict['composite']: entity_dict['repositories'] = find_repositories(module, entity_dict['repositories'], entity_dict['organization']) content_view_entity = find_content_view(module, name=entity_dict['name'], organization=entity_dict['organization'], failsafe=True) content_view_dict = sanitize_entity_dict(entity_dict, name_map) changed, content_view_entity = naildown_entity(ContentView, content_view_dict, content_view_entity, state, module) # only update CVC's of newly created or updated CCV's if state == 'present' or (state == 'present_with_defaults' and changed): current_cvcs = [] if hasattr(content_view_entity, 'content_view_component'): current_cvcs = [cvc.read() for cvc in content_view_entity.content_view_component] if 'components' in entity_dict and content_view_entity.composite: for component in entity_dict['components']: cvc = component.copy() cvc['content_view'] = find_content_view(module, name=component['content_view'], organization=entity_dict['organization']) cvc_matched = None for _cvc in current_cvcs: if _cvc.content_view.id == cvc['content_view'].id: cvc_matched = _cvc force_update = list() if 'version' in component: cvc['version'] = find_content_view_version(module, cvc['content_view'], version=component['version']) cvc['latest'] = False if cvc_matched and cvc_matched.latest: # When changing to latest=False & version is the latest we must send 'content_view_version' to the server force_update.append('content_view_version') if cvc_matched: cvc['composite_content_view'] = content_view_entity cvc_dict = sanitize_entity_dict(cvc, cvc_map) cvc_changed = naildown_entity_state(ContentViewComponent, cvc_dict, cvc_matched, 'present', module, force_update=force_update) current_cvcs.remove(cvc_matched) if cvc_changed: changed = cvc_changed else: for attr in ['latest', 'version']: if attr not in cvc: cvc[attr] = None ContentViewComponent(composite_content_view=content_view_entity, content_view=cvc['content_view'], latest=cvc['latest'], content_view_version=cvc['version']).add() changed = True for cvc in current_cvcs: # desired cvcs have already been updated and removed from `current_cvcs` cvc.remove() changed = True module.exit_json(changed=changed)
def main(): module = ForemanEntityAnsibleModule( argument_spec=dict( name=dict(required=True), release_name=dict(), description=dict(), family=dict(required=True), major=dict(required=True), minor=dict(), architectures=dict(type='list'), media=dict(type='list'), ptables=dict(type='list'), provisioning_templates=dict(type='list'), password_hash=dict(choices=['MD5', 'SHA256', 'SHA512']), parameters=dict(type='dict'), state=dict(default='present', choices=['present', 'present_with_defaults', 'absent']), ), ) (operating_system_dict, state) = module.parse_params() module.connect() try: # Try to find the Operating System to work on # name is however not unique, but description is, as well as "<name> <major>[.<minor>]" entity = None # If we have a description, search for it if 'description' in operating_system_dict and operating_system_dict['description'] != '': entity = find_operating_system_by_title(module, title=operating_system_dict['description'], failsafe=True) # If we did not yet find a unique OS, search by name & version if entity is None: search_dict = {'name': operating_system_dict['name']} if 'major' in operating_system_dict: search_dict['major'] = operating_system_dict['major'] if 'minor' in operating_system_dict: search_dict['minor'] = operating_system_dict['minor'] entities = find_entities(OperatingSystem, **search_dict) if len(entities) == 1: entity = entities[0] except Exception as e: module.fail_json(msg='Failed to find entity: %s ' % e) if not entity and (state == 'present' or state == 'present_with_defaults'): # we actually attempt to create a new one... for param_name in ['major', 'family', 'password_hash']: if param_name not in operating_system_dict.keys(): module.fail_json(msg='{} is a required parameter to create a new operating system.'.format(param_name)) # Set Architectures of Operating System if 'architectures' in operating_system_dict: operating_system_dict['architectures'] = find_entities_by_name( Architecture, operating_system_dict['architectures'], module) # Set Installation Media of Operating System if 'media' in operating_system_dict: operating_system_dict['media'] = find_entities_by_name( Media, operating_system_dict['media'], module) # Set Partition Tables of Operating System if 'ptables' in operating_system_dict: operating_system_dict['ptables'] = find_entities_by_name( PartitionTable, operating_system_dict['ptables'], module) # Set Provisioning Templates of Operating System if 'provisioning_templates' in operating_system_dict: operating_system_dict['provisioning_templates'] = find_entities_by_name( ProvisioningTemplate, operating_system_dict['provisioning_templates'], module) desired_parameters = operating_system_dict.get('parameters') operating_system_dict = sanitize_entity_dict(operating_system_dict, name_map) changed, operating_system = naildown_entity(OperatingSystem, operating_system_dict, entity, state, module) if desired_parameters is not None: if state == "present" or (state == "present_with_defaults" and entity is None): if entity: current_parameters = OperatingSystemParameter(operatingsystem=operating_system).search() current_parameters = {p.name: p for p in current_parameters} else: current_parameters = {} desired_parameters = {name: {'name': name, 'value': value, 'operatingsystem': operating_system} for name, value in desired_parameters.items()} for name in desired_parameters: current_parameter = current_parameters.pop(name, None) changed |= naildown_entity_state(OperatingSystemParameter, desired_parameters[name], current_parameter, "present", module) for current_parameter in current_parameters.values(): changed |= naildown_entity_state(OperatingSystemParameter, {}, current_parameter, "absent", module) module.exit_json(changed=changed)
def main(): module = AnsibleModule( argument_spec=dict( server_url=dict(required=True), username=dict(required=True, no_log=True), password=dict(required=True, no_log=True), verify_ssl=dict(type='bool', default=True), name=dict(required=True), new_name=dict(), organization=dict(required=True), lifecycle_environment=dict(), content_view=dict(), subscriptions=dict(type='list'), content_overrides=dict(type='list'), auto_attach=dict(type='bool', default=True), state=dict(default='present', choices=[ 'present', 'present_with_defaults', 'absent', 'copied' ]), ), supports_check_mode=True, required_if=[ ['state', 'copied', ['new_name']], ], ) if has_import_error: module.fail_json(msg=import_error_msg) entity_dict = dict([(k, v) for (k, v) in module.params.items() if v is not None]) server_url = entity_dict.pop('server_url') username = entity_dict.pop('username') password = entity_dict.pop('password') verify_ssl = entity_dict.pop('verify_ssl') state = entity_dict.pop('state') try: create_server(server_url, (username, password), verify_ssl) except Exception as e: module.fail_json(msg="Failed to connect to Foreman server: %s " % e) ping_server(module) entity_dict['organization'] = find_organization( module, name=entity_dict['organization']) if 'lifecycle_environment' in entity_dict: entity_dict['lifecycle_environment'] = find_lifecycle_environment( module, entity_dict['lifecycle_environment'], entity_dict['organization']) if 'content_view' in entity_dict: entity_dict['content_view'] = find_content_view( module, entity_dict['content_view'], entity_dict['organization']) activation_key_dict = sanitize_entity_dict(entity_dict, name_map) activation_key_entity = find_activation_key( module, name=entity_dict['name'], organization=entity_dict['organization'], failsafe=True) try: changed, activation_key_entity = naildown_entity( ActivationKey, activation_key_dict, activation_key_entity, state, module) # 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 state == 'present' or (state == 'present_with_defaults' and changed): if 'subscriptions' in entity_dict: subscriptions = entity_dict['subscriptions'] desired_subscription_ids = map( lambda s: s.id, find_subscriptions(module, subscriptions, entity_dict['organization'])) current_subscriptions = [ Subscription(**result) for result in Subscription().search_normalize( activation_key_entity.subscriptions()['results']) ] current_subscription_ids = map(lambda s: s.id, current_subscriptions) if set(desired_subscription_ids) != set( current_subscription_ids): if not module.check_mode: for subscription_id in set( desired_subscription_ids) - set( current_subscription_ids): activation_key_entity.add_subscriptions( data={ 'quantity': 1, 'subscription_id': subscription_id }) for subscription_id in set( current_subscription_ids) - set( desired_subscription_ids): activation_key_entity.remove_subscriptions( data={'subscription_id': subscription_id}) changed = True if 'content_overrides' in entity_dict: content_overrides = entity_dict['content_overrides'] product_content = activation_key_entity.product_content() current_content_overrides = set() for product in product_content['results']: if product['enabled_content_override'] is not None: current_content_overrides.add( (product['content']['label'], product['enabled_content_override'])) desired_content_overrides = set() for product in content_overrides: desired_content_overrides.add( (product['label'], override_to_boolnone(product['override']))) if desired_content_overrides != current_content_overrides: if not module.check_mode: for ( label, override ) in current_content_overrides - desired_content_overrides: activation_key_entity.content_override( data={ 'content_override': { 'content_label': label, 'value': 'default' } }) for ( label, override ) in desired_content_overrides - current_content_overrides: activation_key_entity.content_override( data={ 'content_override': { 'content_label': label, 'value': str(override_to_boolnone( override)).lower() } }) changed = True module.exit_json(changed=changed) except Exception as e: module.fail_json(msg=e)
def main(): module = ForemanEntityAnsibleModule( argument_spec=dict( name=dict(required=True), description=dict(), organization=dict(required=True), interval=dict(choices=['hourly', 'daily', 'weekly', 'custom cron'], required=True), enabled=dict(type='bool', required=True), sync_date=dict(required=True), cron_expression=dict(), products=dict(type='list'), ), required_if=[ ['interval', 'custom cron', ['cron_expression']], ], ) (entity_dict, state) = module.parse_params() if entity_dict['interval'] != 'custom cron': if 'cron_expression' in entity_dict: module.fail_json( msg= '"cron_expression" cannot be combined with "interval"!="custom cron".' ) module.connect() entity_dict['organization'] = find_organization( module, entity_dict['organization']) products = entity_dict.pop('products', None) sync_plan = find_sync_plan(module, entity_dict['name'], entity_dict['organization'], failsafe=True) entity_dict = sanitize_entity_dict(entity_dict, name_map) changed, sync_plan = naildown_entity(SyncPlan, entity_dict, sync_plan, state, module) if products is not None: products = find_products(module, products, entity_dict['organization']) desired_product_ids = set(p.id for p in products) current_product_ids = set(p.id for p in sync_plan.product) if desired_product_ids != current_product_ids: if not module.check_mode: product_ids_to_add = desired_product_ids - current_product_ids if product_ids_to_add: sync_plan.add_products( data={'product_ids': list(product_ids_to_add)}) product_ids_to_remove = current_product_ids - desired_product_ids if product_ids_to_remove: sync_plan.remove_products( data={'product_ids': list(product_ids_to_remove)}) changed = True module.exit_json(changed=changed)