示例#1
0
def main():
    module = ForemanTaxonomicEntityAnsibleModule(
        entity_spec=dict(
            name=dict(required=True),
            host=dict(required=True),
            port=dict(type='int', default=389),
            account=dict(),
            account_password=dict(no_log=True),
            base_dn=dict(),
            attr_login=dict(),
            attr_firstname=dict(),
            attr_lastname=dict(),
            attr_mail=dict(),
            attr_photo=dict(),
            onthefly_register=dict(type='bool'),
            usergroup_sync=dict(type='bool'),
            tls=dict(type='bool'),
            groups_base=dict(),
            server_type=dict(
                choices=["free_ipa", "active_directory", "posix"]),
            ldap_filter=dict(),
            use_netgroups=dict(type='bool'),
        ),
        required_if=[[
            'onthefly_register', True,
            ['attr_login', 'attr_firstname', 'attr_lastname', 'attr_mail']
        ]],
    )

    entity_dict = module.clean_params()

    # additional parameter checks
    if 'use_netgroups' in entity_dict and entity_dict[
            'server_type'] == 'active_directory':
        module.fail_json(
            msg='use_netgroups cannot be used when server_type=active_directory'
        )

    module.connect()

    entity = module.find_resource_by_name('auth_source_ldaps',
                                          name=entity_dict['name'],
                                          failsafe=True)

    entity_dict = module.handle_taxonomy_params(entity_dict)

    module.ensure_entity('auth_source_ldaps', entity_dict, entity)

    module.exit_json()
def main():
    module = ForemanTaxonomicEntityAnsibleModule(entity_spec=dict(
        login=dict(required=True, aliases=['name']),
        firstname=dict(required=False),
        lastname=dict(required=False),
        mail=dict(required=False),
        description=dict(required=False),
        admin=dict(required=False, type='bool', default=False),
        user_password=dict(required=False, no_log=True, flat_name='password'),
        default_location=dict(required=False,
                              type='entity',
                              flat_name='default_location_id'),
        default_organization=dict(required=False,
                                  type='entity',
                                  flat_name='default_organization_id'),
        auth_source=dict(required=False,
                         type='entity',
                         flat_name='auth_source_id'),
        timezone=dict(required=False, choices=timezone_list),
        locale=dict(required=False, choices=locale_list),
        roles=dict(required=False, type='entity_list', flat_name='role_ids'),
    ), )

    entity_dict = module.clean_params()

    module.connect()

    search = 'login="******"'.format(entity_dict['login'])
    entity = module.find_resource('users', search, failsafe=True)

    entity_dict = module.handle_taxonomy_params(entity_dict)

    if not module.desired_absent:
        if 'mail' not in entity_dict:
            if not entity:
                module.fail_json(
                    msg=
                    "The 'mail' parameter is required when creating a new user."
                )
            else:
                entity_dict['mail'] = entity['mail']

        if 'default_location' in entity_dict:
            entity_dict['default_location'] = module.find_resource_by_title(
                'locations', entity_dict['default_location'], thin=True)

        if 'default_organization' in entity_dict:
            entity_dict['default_organization'] = module.find_resource_by_name(
                'organizations',
                entity_dict['default_organization'],
                thin=True)

        if 'auth_source' in entity_dict:
            entity_dict['auth_source'] = module.find_resource_by_name(
                'auth_sources', entity_dict['auth_source'], thin=True)

        if 'roles' in entity_dict:
            entity_dict['roles'] = module.find_resources_by_name(
                'roles', entity_dict['roles'], thin=True)

    module.ensure_entity('users', entity_dict, entity)

    module.exit_json(entity_dict=entity_dict)
def main():
    module = ForemanTaxonomicEntityAnsibleModule(
        entity_spec=dict(
            description_format=dict(),
            job_category=dict(),
            locked=dict(type='bool', default=False),
            name=dict(),
            provider_type=dict(),
            snippet=dict(type='bool'),
            template=dict(),
            template_inputs=dict(type='nested_list',
                                 entity_spec=template_input_entity_spec),
        ),
        argument_spec=dict(
            audit_comment=dict(),
            file_name=dict(type='path'),
            state=dict(default='present',
                       choices=['absent', 'present_with_defaults', 'present']),
        ),
        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: *'!")

    entity_dict = module.clean_params()
    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)
        # make sure certain values are set
        entity_dict = template_defaults.copy()
        entity_dict.update(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 module.state == 'present_with_defaults':
            module.fail_json(
                msg=
                "'state: present_with_defaults' and 'name: *' cannot be used together"
            )
        if module.desired_absent:
            if len(entity_dict.keys()) != 1:
                module.fail_json(
                    msg=
                    "When deleting all job templates, there is no need to specify further parameters."
                )

    with module.api_connection():
        if affects_multiple:
            entities = module.list_resource('job_templates')
            if not entities:
                # Nothing to do; shortcut to exit
                module.exit_json()
            if not module.desired_absent:  # not 'thin'
                entities = [
                    module.show_resource('job_templates', entity['id'])
                    for entity in entities
                ]
        else:
            entity = module.find_resource_by_name('job_templates',
                                                  name=entity_dict['name'],
                                                  failsafe=True)

        entity_dict = module.handle_taxonomy_params(entity_dict)

        # TemplateInputs need to be added as separate entities later
        template_inputs = entity_dict.get('template_inputs')

        if 'audit_comment' in entity_dict:
            extra_params = {'audit_comment': entity_dict['audit_comment']}
        else:
            extra_params = {}

        if not affects_multiple:
            job_template = module.ensure_entity('job_templates',
                                                entity_dict,
                                                entity,
                                                params=extra_params)

            update_dependent_entities = (
                module.state == 'present' or
                (module.state == 'present_with_defaults' and module.changed))
            if update_dependent_entities and template_inputs is not None:
                scope = {'template_id': job_template['id']}

                # Manage TemplateInputs here
                current_template_input_list = module.list_resource(
                    'template_inputs', params=scope) if entity else []
                current_template_inputs = {
                    item['name']: item
                    for item in current_template_input_list
                }
                for template_input_dict in template_inputs:
                    template_input_dict = {
                        key: value
                        for key, value in template_input_dict.items()
                        if value is not None
                    }

                    template_input_entity = current_template_inputs.pop(
                        template_input_dict['name'], None)

                    module.ensure_entity(
                        'template_inputs',
                        template_input_dict,
                        template_input_entity,
                        params=scope,
                        entity_spec=template_input_entity_spec,
                    )

                # At this point, desired template inputs have been removed from the dict.
                for template_input_entity in current_template_inputs.values():
                    module.ensure_entity(
                        'template_inputs',
                        None,
                        template_input_entity,
                        state="absent",
                        params=scope,
                        entity_spec=template_input_entity_spec,
                    )

        else:
            entity_dict.pop('name')
            for entity in entities:
                module.ensure_entity('job_templates',
                                     entity_dict,
                                     entity,
                                     params=extra_params)
def main():
    module = ForemanTaxonomicEntityAnsibleModule(
        argument_spec=dict(updated_name=dict(), ),
        entity_spec=dict(
            name=dict(required=True),
            description=dict(),
            network_type=dict(choices=['IPv4', 'IPv6'], default='IPv4'),
            dns_primary=dict(),
            dns_secondary=dict(),
            domains=dict(type='entity_list', flat_name='domain_ids'),
            gateway=dict(),
            network=dict(required=True),
            cidr=dict(type='int'),
            mask=dict(),
            from_ip=dict(flat_name='from'),
            to_ip=dict(flat_name='to'),
            boot_mode=dict(choices=['DHCP', 'Static'], default='DHCP'),
            ipam=dict(
                choices=['DHCP', 'Internal DB', 'Random DB', 'EUI-64', 'None'],
                default='DHCP'),
            dhcp_proxy=dict(type='entity', flat_name='dhcp_id'),
            httpboot_proxy=dict(type='entity', flat_name='httpboot_id'),
            tftp_proxy=dict(type='entity', flat_name='tftp_id'),
            discovery_proxy=dict(type='entity', flat_name='discovery_id'),
            dns_proxy=dict(type='entity', flat_name='dns_id'),
            template_proxy=dict(type='entity', flat_name='template_id'),
            remote_execution_proxies=dict(
                type='entity_list', flat_name='remote_execution_proxy_ids'),
            vlanid=dict(type='int'),
            mtu=dict(type='int'),
            parameters=dict(type='nested_list',
                            entity_spec=parameter_entity_spec),
        ),
        required_one_of=[['cidr', 'mask']],
    )

    if not HAS_IPADDRESS:
        module.fail_json(msg='The ipaddress Python module is required',
                         exception=IPADDRESS_IMP_ERR)

    entity_dict = module.clean_params()

    module.connect()

    entity = module.find_resource_by_name('subnets',
                                          entity_dict['name'],
                                          failsafe=True)

    entity_dict = module.handle_taxonomy_params(entity_dict)

    if not module.desired_absent:
        if entity and 'updated_name' in entity_dict:
            entity_dict['name'] = entity_dict.pop('updated_name')
        if entity_dict['network_type'] == 'IPv4':
            IPNetwork = ipaddress.IPv4Network
        else:
            IPNetwork = ipaddress.IPv6Network
        if 'mask' in entity_dict and 'cidr' not in entity_dict:
            entity_dict['cidr'] = IPNetwork(
                u'%s/%s' %
                (entity_dict['network'], entity_dict['mask'])).prefixlen
        elif 'mask' not in entity_dict and 'cidr' in entity_dict:
            entity_dict['mask'] = str(
                IPNetwork(
                    u'%s/%s' %
                    (entity_dict['network'], entity_dict['cidr'])).netmask)

        if 'domains' in entity_dict:
            entity_dict['domains'] = module.find_resources(
                'domains', entity_dict['domains'], thin=True)

        for feature in ('dhcp_proxy', 'httpboot_proxy', 'tftp_proxy',
                        'discovery_proxy', 'dns_proxy', 'template_proxy'):
            if feature in entity_dict:
                entity_dict[feature] = module.find_resource_by_name(
                    'smart_proxies', entity_dict[feature], thin=True)

        if 'remote_execution_proxies' in entity_dict:
            entity_dict[
                'remote_execution_proxies'] = module.find_resources_by_name(
                    'smart_proxies',
                    entity_dict['remote_execution_proxies'],
                    thin=True)

    parameters = entity_dict.get('parameters')

    subnet = module.ensure_entity('subnets', entity_dict, entity)

    if subnet:
        scope = {'subnet_id': subnet['id']}
        module.ensure_scoped_parameters(scope, entity, parameters)

    module.exit_json()
def main():
    module = ForemanTaxonomicEntityAnsibleModule(
        entity_spec=dict(
            name=dict(required=True),
            updated_name=dict(),
            description=dict(),
            provider=dict(choices=['vmware', 'libvirt', 'ovirt']),
            display_type=dict(type='invisible'),
            datacenter=dict(type='invisible'),
            url=dict(type='invisible'),
            user=dict(type='invisible'),
            password=dict(type='invisible'),
            use_v4=dict(type='invisible'),
            ovirt_quota=dict(type='invisible'),
        ),
        argument_spec=dict(
            provider_params=dict(type='dict',
                                 options=dict(
                                     url=dict(),
                                     display_type=dict(),
                                     user=dict(),
                                     password=dict(no_log=True),
                                     datacenter=dict(),
                                     use_v4=dict(type='bool'),
                                     ovirt_quota=dict(),
                                 )),
            state=dict(type='str',
                       default='present',
                       choices=['present', 'absent', 'present_with_defaults']),
        ),
        required_if=([
            'state', 'present_with_defaults', ['provider', 'provider_params']
        ], ),
    )

    entity_dict = module.clean_params()

    module.connect()

    entity = module.find_resource_by_name('compute_resources',
                                          name=entity_dict['name'],
                                          failsafe=True)

    entity_dict = module.handle_taxonomy_params(entity_dict)

    if not module.desired_absent:
        if 'updated_name' in entity_dict:
            entity_dict['name'] = entity_dict['updated_name']

        if 'provider' in entity_dict:
            entity_dict['provider'], provider_param_keys = get_provider_info(
                provider=entity_dict['provider'])
            provider_params = {
                k: v
                for k, v in entity_dict.pop('provider_params', dict()).items()
                if v is not None
            }

            for key in provider_param_keys:
                if key in provider_params:
                    entity_dict[key] = provider_params.pop(key)
            if provider_params:
                module.fail_json(
                    msg=
                    "Provider {0} does not support the following given parameters: {1}"
                    .format(entity_dict['provider'],
                            list(provider_params.keys())))

        # Add provider specific params
        elif entity is None:
            module.fail_json(
                msg=
                'To create a compute resource a valid provider must be supplied'
            )

    module.ensure_entity('compute_resources', entity_dict, entity)

    module.exit_json()
def main():
    module = ForemanTaxonomicEntityAnsibleModule(
        argument_spec=dict(
            audit_comment=dict(),
            file_name=dict(type='path'),
            state=dict(default='present',
                       choices=['absent', 'present_with_defaults', 'present']),
            updated_name=dict(),
        ),
        entity_spec=dict(
            kind=dict(choices=[
                'finish',
                'iPXE',
                'job_template',
                'POAP',
                'provision',
                'ptable',
                'PXELinux',
                'PXEGrub',
                'PXEGrub2',
                'script',
                'snippet',
                'user_data',
                'ZTP',
            ],
                      type='entity',
                      flat_name='template_kind_id'),
            template=dict(),
            locked=dict(type='bool'),
            name=dict(),
            operatingsystems=dict(type='entity_list',
                                  flat_name='operatingsystem_ids'),
            snippet=dict(type='invisible'),
        ),
        mutually_exclusive=[
            ['file_name', 'template'],
        ],
        required_one_of=[
            ['name', 'file_name', 'template'],
        ],
    )

    # We do not want a template text for bulk operations
    if module.params['name'] == '*':
        if module.params['file_name'] or module.params[
                'template'] or module.params['updated_name']:
            module.fail_json(
                msg=
                "Neither file_name nor template nor updated_name allowed if 'name: *'!"
            )

    entity_dict = module.clean_params()
    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 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.')

    affects_multiple = entity_dict['name'] == '*'
    # sanitize user input, filter unuseful configuration combinations with 'name: *'
    if affects_multiple:
        if module.state == 'present_with_defaults':
            module.fail_json(
                msg=
                "'state: present_with_defaults' and 'name: *' cannot be used together"
            )
        if module.desired_absent:
            if len(entity_dict.keys()) != 1:
                module.fail_json(
                    msg=
                    "When deleting all templates, there is no need to specify further parameters."
                )

    module.connect()

    if affects_multiple:
        entities = module.list_resource('provisioning_templates')
        if not entities:
            # Nothing to do; shortcut to exit
            module.exit_json()
        if not module.desired_absent:  # not 'thin'
            entities = [
                module.show_resource('provisioning_templates', entity['id'])
                for entity in entities
            ]
    else:
        entity = module.find_resource_by_name('provisioning_templates',
                                              name=entity_dict['name'],
                                              failsafe=True)

    entity_dict = module.handle_taxonomy_params(entity_dict)

    if not module.desired_absent:
        if not affects_multiple and entity and 'updated_name' in entity_dict:
            entity_dict['name'] = entity_dict.pop('updated_name')

        if 'operatingsystems' in entity_dict:
            entity_dict['operatingsystems'] = module.find_operatingsystems(
                entity_dict['operatingsystems'], thin=True)

    if not affects_multiple:
        entity_dict = find_template_kind(module, entity_dict)

    if 'audit_comment' in entity_dict:
        extra_params = {'audit_comment': entity_dict['audit_comment']}
    else:
        extra_params = {}

    if not affects_multiple:
        module.ensure_entity('provisioning_templates',
                             entity_dict,
                             entity,
                             params=extra_params)
    else:
        entity_dict.pop('name')
        for entity in entities:
            module.ensure_entity('provisioning_templates',
                                 entity_dict,
                                 entity,
                                 params=extra_params)

    module.exit_json()
示例#7
0
def main():
    module = ForemanTaxonomicEntityAnsibleModule(entity_spec=dict(
        name=dict(required=True), ), )

    entity_dict = module.clean_params()

    module.connect()

    entity = module.find_resource_by_name('environments',
                                          name=entity_dict['name'],
                                          failsafe=True)

    entity_dict = module.handle_taxonomy_params(entity_dict)

    module.ensure_entity('environments', entity_dict, entity)

    module.exit_json()
示例#8
0
def main():
    module = ForemanTaxonomicEntityAnsibleModule(
        argument_spec=dict(
            updated_name=dict(),
            state=dict(default='present',
                       choices=['present', 'present_with_defaults', 'absent']),
        ),
        entity_spec=dict(
            name=dict(required=True),
            operatingsystems=dict(type='entity_list',
                                  flat_name='operatingsystem_ids'),
            os_family=dict(choices=OS_LIST),
            path=dict(),
        ),
    )

    entity_dict = module.clean_params()

    module.connect()
    name = entity_dict['name']

    affects_multiple = name == '*'
    # sanitize user input, filter unuseful configuration combinations with 'name: *'
    if affects_multiple:
        if module.state == 'present_with_defaults':
            module.fail_json(
                msg=
                "'state: present_with_defaults' and 'name: *' cannot be used together"
            )
        if module.params['updated_name']:
            module.fail_json(msg="updated_name not allowed if 'name: *'!")
        if module.desired_absent:
            if list(entity_dict.keys()) != ['name']:
                entity_dict.pop('name', None)
                module.fail_json(
                    msg=
                    'When deleting all installation media, there is no need to specify further parameters: %s '
                    % entity_dict.keys())

    if affects_multiple:
        entities = module.list_resource('media')
        if not module.desired_absent:  # not 'thin'
            entities = [
                module.show_resource('media', entity['id'])
                for entity in entities
            ]
        if not entities:
            # Nothing to do shortcut to exit
            module.exit_json()
    else:
        entity = module.find_resource_by_name('media',
                                              name=entity_dict['name'],
                                              failsafe=True)

    entity_dict = module.handle_taxonomy_params(entity_dict)

    if not module.desired_absent:
        if not affects_multiple and entity and 'updated_name' in entity_dict:
            entity_dict['name'] = entity_dict.pop('updated_name')
        if 'operatingsystems' in entity_dict:
            entity_dict['operatingsystems'] = module.find_operatingsystems(
                entity_dict['operatingsystems'], thin=True)
            if not affects_multiple and len(
                    entity_dict['operatingsystems']
            ) == 1 and 'os_family' not in entity_dict and entity is None:
                entity_dict['os_family'] = module.show_resource(
                    'operatingsystems',
                    entity_dict['operatingsystems'][0]['id'])['family']

    if not affects_multiple:
        module.ensure_entity('media', entity_dict, entity)
    else:
        entity_dict.pop('name')
        for entity in entities:
            module.ensure_entity('media', entity_dict, entity)

    module.exit_json()
def main():
    module = ForemanTaxonomicEntityAnsibleModule(
        argument_spec=dict(updated_name=dict(), ),
        entity_spec=dict(
            name=dict(required=True),
            description=dict(aliases=['fullname'], flat_name='fullname'),
            dns_proxy=dict(type='entity', flat_name='dns_id', aliases=['dns']),
            parameters=dict(type='nested_list',
                            entity_spec=parameter_entity_spec),
        ),
    )

    entity_dict = module.clean_params()

    module.connect()

    # Try to find the Domain to work on
    entity = module.find_resource_by_name('domains',
                                          name=entity_dict['name'],
                                          failsafe=True)

    entity_dict = module.handle_taxonomy_params(entity_dict)

    if not module.desired_absent:
        if entity and 'updated_name' in entity_dict:
            entity_dict['name'] = entity_dict.pop('updated_name')
        if 'dns_proxy' in entity_dict:
            entity_dict['dns_proxy'] = module.find_resource_by_name(
                'smart_proxies', entity_dict['dns_proxy'], thin=True)

    parameters = entity_dict.get('parameters')

    domain = module.ensure_entity('domains', entity_dict, entity)

    if domain:
        scope = {'domain_id': domain['id']}
        module.ensure_scoped_parameters(scope, entity, parameters)

    module.exit_json()
示例#10
0
def main():
    module = ForemanTaxonomicEntityAnsibleModule(entity_spec=dict(
        name=dict(required=True),
        description=dict(),
        filters=dict(type='nested_list', entity_spec=filter_entity_spec),
    ), )

    entity_dict = module.clean_params()

    module.connect()

    entity = module.find_resource_by_name('roles',
                                          name=entity_dict['name'],
                                          failsafe=True)

    entity_dict = module.handle_taxonomy_params(entity_dict)

    filters = entity_dict.pop("filters", None)

    new_entity = module.ensure_entity('roles', entity_dict, entity)

    if not module.desired_absent and filters is not None:
        scope = {'role_id': new_entity['id']}

        if entity:
            current_filters = [
                module.show_resource('filters', filter['id'])
                for filter in entity['filters']
            ]
        else:
            current_filters = []
        desired_filters = copy.deepcopy(filters)

        for desired_filter in desired_filters:
            # search for an existing filter
            for current_filter in current_filters:
                if desired_filter['search'] == current_filter['search']:
                    if set(desired_filter['permissions']) == set(
                            perm['name']
                            for perm in current_filter['permissions']):
                        current_filters.remove(current_filter)
                        break
            else:
                desired_filter['permissions'] = module.find_resources_by_name(
                    'permissions', desired_filter['permissions'], thin=True)
                module.ensure_entity('filters',
                                     desired_filter,
                                     None,
                                     params=scope,
                                     state='present',
                                     entity_spec=filter_entity_spec)
        for current_filter in current_filters:
            module.ensure_entity('filters',
                                 None, {'id': current_filter['id']},
                                 params=scope,
                                 state='absent',
                                 entity_spec=filter_entity_spec)

    module.exit_json()
def main():
    module = ForemanTaxonomicEntityAnsibleModule(entity_spec=dict(
        name=dict(required=True),
        realm_proxy=dict(type='entity',
                         flat_name='realm_proxy_id',
                         required=True),
        realm_type=dict(required=True,
                        choices=[
                            'Red Hat Identity Management', 'FreeIPA',
                            'Active Directory'
                        ]),
    ), )

    entity_dict = module.clean_params()

    module.connect()

    entity = module.find_resource_by_name('realms',
                                          name=entity_dict['name'],
                                          failsafe=True)

    if not module.desired_absent:
        entity_dict['realm_proxy'] = module.find_resource_by_name(
            'smart_proxies', entity_dict['realm_proxy'], thin=True)

    module.ensure_entity('realms', entity_dict, entity)

    module.exit_json()
def main():
    module = ForemanTaxonomicEntityAnsibleModule(
        argument_spec=dict(
            file_name=dict(type='path'),
            state=dict(default='present',
                       choices=['absent', 'present_with_defaults', 'present']),
            updated_name=dict(),
        ),
        entity_spec=dict(
            layout=dict(),
            locked=dict(type='bool'),
            name=dict(),
            os_family=dict(choices=OS_LIST),
        ),
        mutually_exclusive=[
            ['file_name', 'layout'],
        ],
        required_one_of=[
            ['name', 'file_name', 'layout'],
        ],
    )

    # We do not want a layout text for bulk operations
    if module.params['name'] == '*':
        if module.params['file_name'] or module.params[
                'layout'] or module.params['updated_name']:
            module.fail_json(
                msg=
                "Neither file_name nor layout nor updated_name allowed if 'name: *'!"
            )

    entity_dict = module.clean_params()
    file_name = entity_dict.pop('file_name', None)

    if file_name or 'layout' in entity_dict:
        if file_name:
            parsed_dict = parse_template_from_file(file_name, module)
        else:
            parsed_dict = parse_template(entity_dict['layout'], module)
        parsed_dict['layout'] = parsed_dict.pop('template')
        if 'oses' in parsed_dict:
            parsed_dict['os_family'] = parsed_dict.pop('oses')
        # 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 partition table 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.')

    affects_multiple = entity_dict['name'] == '*'
    # sanitize user input, filter unuseful configuration combinations with 'name: *'
    if affects_multiple:
        if module.state == 'present_with_defaults':
            module.fail_json(
                msg=
                "'state: present_with_defaults' and 'name: *' cannot be used together"
            )
        if module.desired_absent:
            if len(entity_dict.keys()) != 1:
                module.fail_json(
                    msg=
                    'When deleting all partition tables, there is no need to specify further parameters.'
                )

    module.connect()

    if affects_multiple:
        entities = module.list_resource('ptables')
        if not entities:
            # Nothing to do; shortcut to exit
            module.exit_json()
        if not module.desired_absent:  # not 'thin'
            entities = [
                module.show_resource('ptables', entity['id'])
                for entity in entities
            ]
    else:
        entity = module.find_resource_by_name('ptables',
                                              name=entity_dict['name'],
                                              failsafe=True)

    entity_dict = module.handle_taxonomy_params(entity_dict)

    if not module.desired_absent:
        if not affects_multiple and entity and 'updated_name' in entity_dict:
            entity_dict['name'] = entity_dict.pop('updated_name')

    if not affects_multiple:
        module.ensure_entity('ptables', entity_dict, entity)
    else:
        entity_dict.pop('name')
        for entity in entities:
            module.ensure_entity('ptables', entity_dict, entity)

    module.exit_json()