def main():
    module = KatelloEntityAnsibleModule(
        argument_spec=dict(
            manifest_path=dict(type='path'),
            state=dict(default='present', choices=['absent', 'present', 'refreshed']),
            repository_url=dict(aliases=['redhat_repository_url']),
        ),
        foreman_spec=dict(
            organization=dict(type='entity', required=True, thin=False),
        ),
        required_if=[
            ['state', 'present', ['manifest_path']],
        ],
        supports_check_mode=False,
    )

    module.task_timeout = 5 * 60

    with module.api_connection():
        organization = module.lookup_entity('organization')
        scope = module.scope_for('organization')

        try:
            existing_manifest = organization['owner_details']['upstreamConsumer']
        except KeyError:
            existing_manifest = None

        if module.state == 'present':
            if 'repository_url' in module.foreman_params:
                payload = {'redhat_repository_url': module.foreman_params['repository_url']}
                org_spec = dict(id=dict(), redhat_repository_url=dict())
                organization = module.ensure_entity('organizations', payload, organization, state='present', foreman_spec=org_spec)

            try:
                with open(module.foreman_params['manifest_path'], 'rb') as manifest_file:
                    files = {'content': (module.foreman_params['manifest_path'], manifest_file, 'application/zip')}
                    params = {}
                    if 'repository_url' in module.foreman_params:
                        params['repository_url'] = module.foreman_params['repository_url']
                    params.update(scope)
                    result = module.resource_action('subscriptions', 'upload', params, files=files, record_change=False, ignore_task_errors=True)
                    for error in result['humanized']['errors']:
                        if "same as existing data" in error:
                            # Nothing changed, but everything ok
                            break
                        if "older than existing data" in error:
                            module.fail_json(msg="Manifest is older than existing data.")
                        else:
                            module.fail_json(msg="Upload of the manifest failed: %s" % error)
                    else:
                        module.set_changed()
            except IOError as e:
                module.fail_json(msg="Unable to read the manifest file: %s" % e)
        elif module.desired_absent and existing_manifest:
            module.resource_action('subscriptions', 'delete_manifest', scope)
        elif module.state == 'refreshed':
            if existing_manifest:
                module.resource_action('subscriptions', 'refresh_manifest', scope)
            else:
                module.fail_json(msg="No manifest found to refresh.")
def main():
    module = KatelloEntityAnsibleModule(
        entity_spec=dict(
            name=dict(required=True),
            description=dict(),
            interval=dict(choices=['hourly', 'daily', 'weekly', 'custom cron'], required=True),
            enabled=dict(type='bool', required=True),
            sync_date=dict(required=True),
            cron_expression=dict(),
            state=dict(default='present', choices=['present_with_defaults', 'present', 'absent']),
        ),
        argument_spec=dict(
            products=dict(type='list', elements='str'),
        ),
        required_if=[
            ['interval', 'custom cron', ['cron_expression']],
        ],
    )

    entity_dict = module.clean_params()

    if (entity_dict['interval'] != 'custom cron') and ('cron_expression' in entity_dict):
        module.fail_json(msg='"cron_expression" cannot be combined with "interval"!="custom cron".')

    with module.api_connection():
        entity_dict, scope = module.handle_organization_param(entity_dict)

        entity = module.find_resource_by_name('sync_plans', name=entity_dict['name'], params=scope, failsafe=True)

        products = entity_dict.pop('products', None)

        sync_plan = module.ensure_entity('sync_plans', entity_dict, entity, params=scope)

        if not (module.desired_absent or module.state == 'present_with_defaults') and products is not None:
            products = module.find_resources_by_name('products', products, params=scope, thin=True)
            desired_product_ids = set(product['id'] for product in products)
            current_product_ids = set(product['id'] for product in entity['products']) if entity else set()

            module.record_before('sync_plans/products', {'id': sync_plan['id'], 'product_ids': current_product_ids})
            module.record_after('sync_plans/products', {'id': sync_plan['id'], 'product_ids': desired_product_ids})
            module.record_after_full('sync_plans/products', {'id': sync_plan['id'], 'product_ids': desired_product_ids})

            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:
                        payload = {
                            'id': sync_plan['id'],
                            'product_ids': list(product_ids_to_add),
                        }
                        payload.update(scope)
                        module.resource_action('sync_plans', 'add_products', payload)
                    product_ids_to_remove = current_product_ids - desired_product_ids
                    if product_ids_to_remove:
                        payload = {
                            'id': sync_plan['id'],
                            'product_ids': list(product_ids_to_remove),
                        }
                        payload.update(scope)
                        module.resource_action('sync_plans', 'remove_products', payload)
                else:
                    module.set_changed()