Blame plugins/modules/ipavault.py

Packit Service 0f71a7
#!/usr/bin/python
Packit Service 0f71a7
# -*- coding: utf-8 -*-
Packit Service 0f71a7
Packit Service 0f71a7
# Authors:
Packit Service 0f71a7
#   Rafael Guterres Jeffman <rjeffman@redhat.com>
Packit Service 0f71a7
#
Packit Service 0f71a7
# Copyright (C) 2019 Red Hat
Packit Service 0f71a7
# see file 'COPYING' for use and warranty information
Packit Service 0f71a7
#
Packit Service 0f71a7
# This program is free software; you can redistribute it and/or modify
Packit Service 0f71a7
# it under the terms of the GNU General Public License as published by
Packit Service 0f71a7
# the Free Software Foundation, either version 3 of the License, or
Packit Service 0f71a7
# (at your option) any later version.
Packit Service 0f71a7
#
Packit Service 0f71a7
# This program is distributed in the hope that it will be useful,
Packit Service 0f71a7
# but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 0f71a7
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 0f71a7
# GNU General Public License for more details.
Packit Service 0f71a7
#
Packit Service 0f71a7
# You should have received a copy of the GNU General Public License
Packit Service 0f71a7
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit Service 0f71a7
Packit Service 0f71a7
ANSIBLE_METADATA = {
Packit Service 0f71a7
    "metadata_version": "1.0",
Packit Service 0f71a7
    "supported_by": "community",
Packit Service 0f71a7
    "status": ["preview"],
Packit Service 0f71a7
}
Packit Service 0f71a7
Packit Service 0f71a7
DOCUMENTATION = """
Packit Service 0f71a7
---
Packit Service 0f71a7
module: ipavault
Packit Service 0f71a7
short description: Manage vaults and secret vaults.
Packit Service 0f71a7
description: Manage vaults and secret vaults. KRA service must be enabled.
Packit Service 0f71a7
options:
Packit Service 0f71a7
  ipaadmin_principal:
Packit Service 0f71a7
    description: The admin principal
Packit Service 0f71a7
    default: admin
Packit Service 0f71a7
  ipaadmin_password:
Packit Service 0f71a7
    description: The admin password
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
  name:
Packit Service 0f71a7
    description: The vault name
Packit Service 0f71a7
    required: true
Packit Service 0f71a7
    aliases: ["cn"]
Packit Service 0f71a7
  description:
Packit Service 0f71a7
    description: The vault description
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
  public_key:
Packit Service 0f71a7
    description: Base64 encode public key.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: string
Packit Service 0f71a7
    aliases: ["ipavaultpublickey", "vault_public_key"]
Packit Service 0f71a7
  public_key_file:
Packit Service 0f71a7
    description: Path to file with public key.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: string
Packit Service 0f71a7
    aliases: ["vault_public_key_file"]
Packit Service 0f71a7
  private_key:
Packit Service 0f71a7
    description: Base64 encode private key.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: string
Packit Service 0f71a7
    aliases: ["ipavaultprivatekey", "vault_private_key"]
Packit Service 0f71a7
  private_key_file:
Packit Service 0f71a7
    description: Path to file with private key.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: string
Packit Service 0f71a7
    aliases: ["vault_private_key_file"]
Packit Service 0f71a7
  password:
Packit Service 0f71a7
    description: password to be used on symmetric vault.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: string
Packit Service 0f71a7
    aliases: ["ipavaultpassword", "vault_password"]
Packit Service 0f71a7
  password_file:
Packit Service 0f71a7
    description: file with password to be used on symmetric vault.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: string
Packit Service 0f71a7
    aliases: ["vault_password_file"]
Packit Service 0f71a7
  salt:
Packit Service 0f71a7
    description: Vault salt.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: list
Packit Service 0f71a7
    aliases: ["ipavaultsalt", "vault_salt"]
Packit Service 0f71a7
  vault_type:
Packit Service 0f71a7
    description: Vault types are based on security level.
Packit Service 0f71a7
    required: true
Packit Service 0f71a7
    default: symmetric
Packit Service 0f71a7
    choices: ["standard", "symmetric", "asymmetric"]
Packit Service 0f71a7
    aliases: ["ipavaulttype"]
Packit Service 0f71a7
  service:
Packit Service 0f71a7
    description: Any service can own one or more service vaults.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: list
Packit Service 0f71a7
  username:
Packit Service 0f71a7
    description: Any user can own one or more user vaults.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: string
Packit Service 0f71a7
    aliases: ["user"]
Packit Service 0f71a7
  shared:
Packit Service 0f71a7
    description: Vault is shared.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: boolean
Packit Service 0f71a7
  users:
Packit Service 0f71a7
    description: Users that are member of the vault.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: list
Packit Service 0f71a7
  groups:
Packit Service 0f71a7
    description: Groups that are member of the vault.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: list
Packit Service 0f71a7
  owners:
Packit Service 0f71a7
    description: Users that are owners of the vault.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: list
Packit Service 0f71a7
  ownergroups:
Packit Service 0f71a7
    description: Groups that are owners of the vault.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: list
Packit Service 0f71a7
  ownerservices:
Packit Service 0f71a7
    description: Services that are owners of the vault.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: list
Packit Service 0f71a7
  services:
Packit Service 0f71a7
    description: Services that are member of the container.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: list
Packit Service 0f71a7
  data:
Packit Service 0f71a7
    description: Data to be stored in the vault.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: string
Packit Service 0f71a7
    aliases: ["ipavaultdata", "vault_data"]
Packit Service 0f71a7
  in:
Packit Service 0f71a7
    description: Path to file with data to be stored in the vault.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: string
Packit Service 0f71a7
    aliases: ["datafile_in"]
Packit Service 0f71a7
  out:
Packit Service 0f71a7
    description: Path to file to store data retrieved from the vault.
Packit Service 0f71a7
    required: false
Packit Service 0f71a7
    type: string
Packit Service 0f71a7
    aliases: ["datafile_out"]
Packit Service 0f71a7
  action:
Packit Service 0f71a7
    description: Work on vault or member level.
Packit Service 0f71a7
    default: vault
Packit Service 0f71a7
    choices: ["vault", "member"]
Packit Service 0f71a7
  state:
Packit Service 0f71a7
    description: State to ensure
Packit Service 0f71a7
    default: present
Packit Service 0f71a7
    choices: ["present", "absent", "retrieved"]
Packit Service 0f71a7
author:
Packit Service 0f71a7
    - Rafael Jeffman
Packit Service 0f71a7
"""
Packit Service 0f71a7
Packit Service 0f71a7
EXAMPLES = """
Packit Service 0f71a7
# Ensure vault symvault is present
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: symvault
Packit Service 0f71a7
    username: admin
Packit Service 0f71a7
    vault_type: symmetric
Packit Service 0f71a7
    password: SomeVAULTpassword
Packit Service 0f71a7
    salt: MTIzNDU2Nzg5MAo=
Packit Service 0f71a7
Packit Service 0f71a7
# Ensure group ipausers is a vault member.
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: symvault
Packit Service 0f71a7
    username: admin
Packit Service 0f71a7
    groups: ipausers
Packit Service 0f71a7
    action: member
Packit Service 0f71a7
Packit Service 0f71a7
# Ensure group ipausers is not a vault member.
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: symvault
Packit Service 0f71a7
    username: admin
Packit Service 0f71a7
    groups: ipausers
Packit Service 0f71a7
    action: member
Packit Service 0f71a7
    state: absent
Packit Service 0f71a7
Packit Service 0f71a7
# Ensure vault users are present.
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: symvault
Packit Service 0f71a7
    username: admin
Packit Service 0f71a7
    users:
Packit Service 0f71a7
    - user01
Packit Service 0f71a7
    - user02
Packit Service 0f71a7
    action: member
Packit Service 0f71a7
Packit Service 0f71a7
# Ensure vault users are absent.
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: symvault
Packit Service 0f71a7
    username: admin
Packit Service 0f71a7
    users:
Packit Service 0f71a7
    - user01
Packit Service 0f71a7
    - user02
Packit Service 0f71a7
    action: member
Packit Service 0f71a7
    status: absent
Packit Service 0f71a7
Packit Service 0f71a7
# Ensure user owns vault.
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: symvault
Packit Service 0f71a7
    username: admin
Packit Service 0f71a7
    action: member
Packit Service 0f71a7
    owners: user01
Packit Service 0f71a7
Packit Service 0f71a7
# Ensure user does not own vault.
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: symvault
Packit Service 0f71a7
    username: admin
Packit Service 0f71a7
    owners: user01
Packit Service 0f71a7
    action: member
Packit Service 0f71a7
    status: absent
Packit Service 0f71a7
Packit Service 0f71a7
# Ensure data is archived to a symmetric vault
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: symvault
Packit Service 0f71a7
    username: admin
Packit Service 0f71a7
    password: SomeVAULTpassword
Packit Service 0f71a7
    data: >
Packit Service 0f71a7
      Data archived.
Packit Service 0f71a7
      More data archived.
Packit Service 0f71a7
    action: member
Packit Service 0f71a7
Packit Service 0f71a7
# Retrieve data archived from a symmetric vault
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: symvault
Packit Service 0f71a7
    username: admin
Packit Service 0f71a7
    password: SomeVAULTpassword
Packit Service 0f71a7
    state: retrieved
Packit Service 0f71a7
  register: result
Packit Service 0f71a7
- debug:
Packit Service 0f71a7
    msg: "{{ result.data | b64decode }}"
Packit Service 0f71a7
Packit Service 0f71a7
# Ensure vault symvault is absent
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: symvault
Packit Service 0f71a7
    user: admin
Packit Service 0f71a7
    state: absent
Packit Service 0f71a7
Packit Service 0f71a7
# Ensure asymmetric vault is present.
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: asymvault
Packit Service 0f71a7
    username: user01
Packit Service 0f71a7
    description: An asymmetric vault
Packit Service 0f71a7
    vault_type: asymmetric
Packit Service 0f71a7
    public_key:
Packit Service 0f71a7
      LS0tLS1CRUdJTiBQVUJMSUMgS0VZLS0tLS0KTUlHZk1BMEdDU3FHU0liM0RRRUJBUVVBQTR
Packit Service 0f71a7
      HTkFEQ0JpUUtCZ1FDdGFudjRkK3ptSTZ0T3ova1RXdGowY3AxRAowUENoYy8vR0pJMTUzTi
Packit Service 0f71a7
      9CN3UrN0h3SXlRVlZoNUlXZG1UcCtkWXYzd09yeVpPbzYvbHN5eFJaZ2pZRDRwQ3VGCjlxM
Packit Service 0f71a7
      295VTFEMnFOZERYeGtSaFFETXBiUEVSWWlHbE1jbzdhN0hIVDk1bGNQbmhObVFkb3VGdHlV
Packit Service 0f71a7
      bFBUVS96V1kKZldYWTBOeU1UbUtoeFRseUV3SURBUUFCCi0tLS0tRU5EIFBVQkxJQyBLRVk
Packit Service 0f71a7
      tLS0tLQo=
Packit Service 0f71a7
Packit Service 0f71a7
# Ensure data is archived in an asymmetric vault
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: asymvault
Packit Service 0f71a7
    username: admin
Packit Service 0f71a7
    data: >
Packit Service 0f71a7
      Data archived.
Packit Service 0f71a7
      More data archived.
Packit Service 0f71a7
    action: member
Packit Service 0f71a7
Packit Service 0f71a7
# Retrive data archived in an asymmetric vault, using a private key file.
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: asymvault
Packit Service 0f71a7
    username: admin
Packit Service 0f71a7
    private_key_file: private.pem
Packit Service 0f71a7
    state: retrieved
Packit Service 0f71a7
Packit Service 0f71a7
# Ensure asymmetric vault is absent.
Packit Service 0f71a7
- ipavault:
Packit Service 0f71a7
    ipaadmin_password: SomeADMINpassword
Packit Service 0f71a7
    name: asymvault
Packit Service 0f71a7
    username: user01
Packit Service 0f71a7
    vault_type: asymmetric
Packit Service 0f71a7
    state: absent
Packit Service 0f71a7
"""
Packit Service 0f71a7
Packit Service 0f71a7
RETURN = """
Packit Service 0f71a7
user:
Packit Service 0f71a7
  description: The vault data.
Packit Service 0f71a7
  returned: If state is retrieved.
Packit Service 0f71a7
  type: string
Packit Service 0f71a7
"""
Packit Service 0f71a7
Packit Service 0f71a7
import os
Packit Service 0f71a7
from base64 import b64decode
Packit Service 0f71a7
from ansible.module_utils.basic import AnsibleModule
Packit Service 0f71a7
from ansible.module_utils.ansible_freeipa_module import temp_kinit, \
Packit Service 0f71a7
    temp_kdestroy, valid_creds, api_connect, api_command, \
Packit Service 0f71a7
    gen_add_del_lists, compare_args_ipa, module_params_get
Packit Service 0f71a7
from ipalib.errors import EmptyModlist
Packit Service 0f71a7
Packit Service 0f71a7
Packit Service 0f71a7
def find_vault(module, name, username, service, shared):
Packit Service 0f71a7
    _args = {
Packit Service 0f71a7
        "all": True,
Packit Service 0f71a7
        "cn": name,
Packit Service 0f71a7
    }
Packit Service 0f71a7
Packit Service 0f71a7
    if username is not None:
Packit Service 0f71a7
        _args['username'] = username
Packit Service 0f71a7
    elif service is not None:
Packit Service 0f71a7
        _args['service'] = service
Packit Service 0f71a7
    else:
Packit Service 0f71a7
        _args['shared'] = shared
Packit Service 0f71a7
Packit Service 0f71a7
    _result = api_command(module, "vault_find", name, _args)
Packit Service 0f71a7
Packit Service 0f71a7
    if len(_result["result"]) > 1:
Packit Service 0f71a7
        module.fail_json(
Packit Service 0f71a7
            msg="There is more than one vault '%s'" % (name))
Packit Service 0f71a7
    if len(_result["result"]) == 1:
Packit Service 0f71a7
        return _result["result"][0]
Packit Service 0f71a7
Packit Service 0f71a7
    return None
Packit Service 0f71a7
Packit Service 0f71a7
Packit Service 0f71a7
def gen_args(description, username, service, shared, vault_type, salt,
Packit Service 0f71a7
             password, password_file, public_key, public_key_file, vault_data,
Packit Service 0f71a7
             datafile_in, datafile_out):
Packit Service 0f71a7
    _args = {}
Packit Service 0f71a7
Packit Service 0f71a7
    if description is not None:
Packit Service 0f71a7
        _args['description'] = description
Packit Service 0f71a7
    if username is not None:
Packit Service 0f71a7
        _args['username'] = username
Packit Service 0f71a7
    if service is not None:
Packit Service 0f71a7
        _args['service'] = service
Packit Service 0f71a7
    if shared is not None:
Packit Service 0f71a7
        _args['shared'] = shared
Packit Service 0f71a7
    if vault_type is not None:
Packit Service 0f71a7
        _args['ipavaulttype'] = vault_type
Packit Service 0f71a7
    if salt is not None:
Packit Service 0f71a7
        _args['ipavaultsalt'] = salt
Packit Service 0f71a7
    if public_key is not None:
Packit Service 0f71a7
        _args['ipavaultpublickey'] = b64decode(public_key.encode('utf-8'))
Packit Service 0f71a7
    if public_key_file is not None:
Packit Service 0f71a7
        with open(public_key_file, 'r') as keyfile:
Packit Service 0f71a7
            keydata = keyfile.read()
Packit Service 0f71a7
            _args['ipavaultpublickey'] = keydata.strip().encode('utf-8')
Packit Service 0f71a7
Packit Service 0f71a7
    return _args
Packit Service 0f71a7
Packit Service 0f71a7
Packit Service 0f71a7
def gen_member_args(args, users, groups, services):
Packit Service 0f71a7
    _args = args.copy()
Packit Service 0f71a7
Packit Service 0f71a7
    for arg in ['ipavaulttype', 'description', 'ipavaultpublickey',
Packit Service 0f71a7
                'ipavaultsalt']:
Packit Service 0f71a7
        if arg in _args:
Packit Service 0f71a7
            del _args[arg]
Packit Service 0f71a7
Packit Service 0f71a7
    if any([users, groups, services]):
Packit Service 0f71a7
        if users is not None:
Packit Service 0f71a7
            _args['user'] = users
Packit Service 0f71a7
        if groups is not None:
Packit Service 0f71a7
            _args['group'] = groups
Packit Service 0f71a7
        if services is not None:
Packit Service 0f71a7
            _args['services'] = services
Packit Service 0f71a7
Packit Service 0f71a7
        return _args
Packit Service 0f71a7
Packit Service 0f71a7
    return None
Packit Service 0f71a7
Packit Service 0f71a7
Packit Service 0f71a7
def data_storage_args(args, data, password, password_file, private_key,
Packit Service 0f71a7
                      private_key_file, datafile_in, datafile_out):
Packit Service 0f71a7
    _args = {}
Packit Service 0f71a7
Packit Service 0f71a7
    if 'username' in args:
Packit Service 0f71a7
        _args['username'] = args['username']
Packit Service 0f71a7
    if 'service' in args:
Packit Service 0f71a7
        _args['service'] = args['service']
Packit Service 0f71a7
    if 'shared' in args:
Packit Service 0f71a7
        _args['shared'] = args['shared']
Packit Service 0f71a7
Packit Service 0f71a7
    if password is not None:
Packit Service 0f71a7
        _args['password'] = password
Packit Service 0f71a7
    if password_file is not None:
Packit Service 0f71a7
        _args['password_file'] = password_file
Packit Service 0f71a7
Packit Service 0f71a7
    if private_key is not None:
Packit Service 0f71a7
        _args['private_key'] = private_key
Packit Service 0f71a7
    if private_key_file is not None:
Packit Service 0f71a7
        _args['private_key_file'] = private_key_file
Packit Service 0f71a7
Packit Service 0f71a7
    if datafile_in is not None:
Packit Service 0f71a7
        _args['in'] = datafile_in
Packit Service 0f71a7
    else:
Packit Service 0f71a7
        if data is None:
Packit Service 0f71a7
            _args['data'] = b''
Packit Service 0f71a7
        else:
Packit Service 0f71a7
            _args['data'] = data.encode('utf-8')
Packit Service 0f71a7
Packit Service 0f71a7
    if datafile_out is not None:
Packit Service 0f71a7
        _args['out'] = datafile_out
Packit Service 0f71a7
Packit Service 0f71a7
    if private_key_file is not None:
Packit Service 0f71a7
        _args['private_key_file'] = private_key_file
Packit Service 0f71a7
Packit Service 0f71a7
    return _args
Packit Service 0f71a7
Packit Service 0f71a7
Packit Service 0f71a7
def check_parameters(module, state, action, description, username, service,
Packit Service 0f71a7
                     shared, users, groups, services, owners, ownergroups,
Packit Service 0f71a7
                     ownerservices, vault_type, salt, password, password_file,
Packit Service 0f71a7
                     public_key, public_key_file, private_key,
Packit Service 0f71a7
                     private_key_file, vault_data, datafile_in, datafile_out):
Packit Service 0f71a7
    invalid = []
Packit Service 0f71a7
    if state == "present":
Packit Service 0f71a7
        invalid = ['private_key', 'private_key_file', 'datafile_out']
Packit Service 0f71a7
Packit Service 0f71a7
        if action == "member":
Packit Service 0f71a7
            invalid.extend(['description'])
Packit Service 0f71a7
Packit Service 0f71a7
    elif state == "absent":
Packit Service 0f71a7
        invalid = ['description', 'salt', 'vault_type', 'private_key',
Packit Service 0f71a7
                   'private_key_file', 'datafile_in', 'datafile_out',
Packit Service 0f71a7
                   'vault_data']
Packit Service 0f71a7
Packit Service 0f71a7
        if action == "vault":
Packit Service 0f71a7
            invalid.extend(['users', 'groups', 'services', 'owners',
Packit Service 0f71a7
                            'ownergroups', 'ownerservices', 'password',
Packit Service 0f71a7
                            'password_file', 'public_key', 'public_key_file'])
Packit Service 0f71a7
Packit Service 0f71a7
    elif state == "retrieved":
Packit Service 0f71a7
        invalid = ['description', 'salt', 'datafile_in', 'users', 'groups',
Packit Service 0f71a7
                   'owners', 'ownergroups', 'public_key', 'public_key_file',
Packit Service 0f71a7
                   'vault_data']
Packit Service 0f71a7
        if action == 'member':
Packit Service 0f71a7
            module.fail_json(
Packit Service 0f71a7
                msg="State `retrieved` do not support action `member`.")
Packit Service 0f71a7
Packit Service 0f71a7
    for arg in invalid:
Packit Service 0f71a7
        if vars()[arg] is not None:
Packit Service 0f71a7
            module.fail_json(
Packit Service 0f71a7
                msg="Argument '%s' can not be used with state '%s', "
Packit Service 0f71a7
                    "action '%s'" % (arg, state, action))
Packit Service 0f71a7
Packit Service 0f71a7
    for arg in invalid:
Packit Service 0f71a7
        if vars()[arg] is not None:
Packit Service 0f71a7
            module.fail_json(
Packit Service 0f71a7
                msg="Argument '%s' can not be used with state '%s', "
Packit Service 0f71a7
                    "action '%s'" % (arg, state, action))
Packit Service 0f71a7
Packit Service 0f71a7
Packit Service 0f71a7
def check_encryption_params(module, state, action, vault_type, salt,
Packit Service 0f71a7
                            password, password_file, public_key,
Packit Service 0f71a7
                            public_key_file, private_key, private_key_file,
Packit Service 0f71a7
                            vault_data, datafile_in, datafile_out, res_find):
Packit Service 0f71a7
    vault_type_invalid = []
Packit Service 0f71a7
    if vault_type == "standard":
Packit Service 0f71a7
        vault_type_invalid = ['public_key', 'public_key_file', 'password',
Packit Service 0f71a7
                              'password_file', 'salt']
Packit Service 0f71a7
Packit Service 0f71a7
    if vault_type is None or vault_type == "symmetric":
Packit Service 0f71a7
        vault_type_invalid = ['public_key', 'public_key_file',
Packit Service 0f71a7
                              'private_key', 'private_key_file']
Packit Service 0f71a7
Packit Service 0f71a7
        if password is None and password_file is None and action != 'member':
Packit Service 0f71a7
            module.fail_json(
Packit Service 0f71a7
                msg="Symmetric vault requires password or password_file "
Packit Service 0f71a7
                    "to store data or change `salt`.")
Packit Service 0f71a7
Packit Service 0f71a7
    if vault_type == "asymmetric":
Packit Service 0f71a7
        vault_type_invalid = ['password', 'password_file']
Packit Service 0f71a7
        if not any([public_key, public_key_file]) and res_find is None:
Packit Service 0f71a7
            module.fail_json(
Packit Service 0f71a7
                msg="Assymmetric vault requires public_key "
Packit Service 0f71a7
                    "or public_key_file to store data.")
Packit Service 0f71a7
Packit Service 0f71a7
    for param in vault_type_invalid:
Packit Service 0f71a7
        if vars()[param] is not None:
Packit Service 0f71a7
            module.fail_json(
Packit Service 0f71a7
                msg="Argument '%s' cannot be used with vault type '%s'" %
Packit Service 0f71a7
                (param, vault_type or 'symmetric'))
Packit Service 0f71a7
Packit Service 0f71a7
Packit Service 0f71a7
def main():
Packit Service 0f71a7
    ansible_module = AnsibleModule(
Packit Service 0f71a7
        argument_spec=dict(
Packit Service 0f71a7
            # generalgroups
Packit Service 0f71a7
            ipaadmin_principal=dict(type="str", default="admin"),
Packit Service 0f71a7
            ipaadmin_password=dict(type="str", required=False, no_log=True),
Packit Service 0f71a7
Packit Service 0f71a7
            name=dict(type="list", aliases=["cn"], default=None,
Packit Service 0f71a7
                      required=True),
Packit Service 0f71a7
Packit Service 0f71a7
            description=dict(required=False, type="str", default=None),
Packit Service 0f71a7
            vault_type=dict(type="str", aliases=["ipavaulttype"],
Packit Service 0f71a7
                            default=None, required=False,
Packit Service 0f71a7
                            choices=["standard", "symmetric", "asymmetric"]),
Packit Service 0f71a7
            vault_public_key=dict(type="str", required=False, default=None,
Packit Service 0f71a7
                                  aliases=['ipavaultpublickey', 'public_key']),
Packit Service 0f71a7
            vault_public_key_file=dict(type="str", required=False,
Packit Service 0f71a7
                                       default=None,
Packit Service 0f71a7
                                       aliases=['public_key_file']),
Packit Service 0f71a7
            vault_private_key=dict(
Packit Service 0f71a7
                type="str", required=False, default=None, no_log=True,
Packit Service 0f71a7
                aliases=['ipavaultprivatekey', 'private_key']),
Packit Service 0f71a7
            vault_private_key_file=dict(type="str", required=False,
Packit Service 0f71a7
                                        default=None,
Packit Service 0f71a7
                                        aliases=['private_key_file']),
Packit Service 0f71a7
            vault_salt=dict(type="str", required=False, default=None,
Packit Service 0f71a7
                            aliases=['ipavaultsalt', 'salt']),
Packit Service 0f71a7
            username=dict(type="str", required=False, default=None,
Packit Service 0f71a7
                          aliases=['user']),
Packit Service 0f71a7
            service=dict(type="str", required=False, default=None),
Packit Service 0f71a7
            shared=dict(type="bool", required=False, default=None),
Packit Service 0f71a7
Packit Service 0f71a7
            users=dict(required=False, type='list', default=None),
Packit Service 0f71a7
            groups=dict(required=False, type='list', default=None),
Packit Service 0f71a7
            services=dict(required=False, type='list', default=None),
Packit Service 0f71a7
            owners=dict(required=False, type='list', default=None,
Packit Service 0f71a7
                        aliases=['ownerusers']),
Packit Service 0f71a7
            ownergroups=dict(required=False, type='list', default=None),
Packit Service 0f71a7
            ownerservices=dict(required=False, type='list', default=None),
Packit Service 0f71a7
            vault_data=dict(type="str", required=False, default=None,
Packit Service 0f71a7
                            no_log=True, aliases=['ipavaultdata', 'data']),
Packit Service 0f71a7
            datafile_in=dict(type="str", required=False, default=None,
Packit Service 0f71a7
                             aliases=['in']),
Packit Service 0f71a7
            datafile_out=dict(type="str", required=False, default=None,
Packit Service 0f71a7
                              aliases=['out']),
Packit Service 0f71a7
            vault_password=dict(type="str", required=False, default=None,
Packit Service 0f71a7
                                aliases=['ipavaultpassword', 'password'],
Packit Service 0f71a7
                                no_log=True),
Packit Service 0f71a7
            vault_password_file=dict(type="str", required=False, default=None,
Packit Service 0f71a7
                                     no_log=False, aliases=['password_file']),
Packit Service 0f71a7
            # state
Packit Service 0f71a7
            action=dict(type="str", default="vault",
Packit Service 0f71a7
                        choices=["vault", "data", "member"]),
Packit Service 0f71a7
            state=dict(type="str", default="present",
Packit Service 0f71a7
                       choices=["present", "absent", "retrieved"]),
Packit Service 0f71a7
        ),
Packit Service 0f71a7
        supports_check_mode=True,
Packit Service 0f71a7
        mutually_exclusive=[['username', 'service', 'shared'],
Packit Service 0f71a7
                            ['datafile_in', 'vault_data'],
Packit Service 0f71a7
                            ['vault_password', 'vault_password_file'],
Packit Service 0f71a7
                            ['vault_public_key', 'vault_public_key_file']],
Packit Service 0f71a7
    )
Packit Service 0f71a7
Packit Service 0f71a7
    ansible_module._ansible_debug = True
Packit Service 0f71a7
Packit Service 0f71a7
    # general
Packit Service 0f71a7
    ipaadmin_principal = module_params_get(ansible_module,
Packit Service 0f71a7
                                           "ipaadmin_principal")
Packit Service 0f71a7
    ipaadmin_password = module_params_get(ansible_module, "ipaadmin_password")
Packit Service 0f71a7
    names = module_params_get(ansible_module, "name")
Packit Service 0f71a7
Packit Service 0f71a7
    # present
Packit Service 0f71a7
    description = module_params_get(ansible_module, "description")
Packit Service 0f71a7
Packit Service 0f71a7
    username = module_params_get(ansible_module, "username")
Packit Service 0f71a7
    service = module_params_get(ansible_module, "service")
Packit Service 0f71a7
    shared = module_params_get(ansible_module, "shared")
Packit Service 0f71a7
Packit Service 0f71a7
    users = module_params_get(ansible_module, "users")
Packit Service 0f71a7
    groups = module_params_get(ansible_module, "groups")
Packit Service 0f71a7
    services = module_params_get(ansible_module, "services")
Packit Service 0f71a7
    owners = module_params_get(ansible_module, "owners")
Packit Service 0f71a7
    ownergroups = module_params_get(ansible_module, "ownergroups")
Packit Service 0f71a7
    ownerservices = module_params_get(ansible_module, "ownerservices")
Packit Service 0f71a7
Packit Service 0f71a7
    vault_type = module_params_get(ansible_module, "vault_type")
Packit Service 0f71a7
    salt = module_params_get(ansible_module, "vault_salt")
Packit Service 0f71a7
    password = module_params_get(ansible_module, "vault_password")
Packit Service 0f71a7
    password_file = module_params_get(ansible_module, "vault_password_file")
Packit Service 0f71a7
    public_key = module_params_get(ansible_module, "vault_public_key")
Packit Service 0f71a7
    public_key_file = module_params_get(ansible_module,
Packit Service 0f71a7
                                        "vault_public_key_file")
Packit Service 0f71a7
    private_key = module_params_get(ansible_module, "vault_private_key")
Packit Service 0f71a7
    private_key_file = module_params_get(ansible_module,
Packit Service 0f71a7
                                         "vault_private_key_file")
Packit Service 0f71a7
Packit Service 0f71a7
    vault_data = module_params_get(ansible_module, "vault_data")
Packit Service 0f71a7
Packit Service 0f71a7
    datafile_in = module_params_get(ansible_module, "datafile_in")
Packit Service 0f71a7
    datafile_out = module_params_get(ansible_module, "datafile_out")
Packit Service 0f71a7
Packit Service 0f71a7
    action = module_params_get(ansible_module, "action")
Packit Service 0f71a7
    state = module_params_get(ansible_module, "state")
Packit Service 0f71a7
Packit Service 0f71a7
    # Check parameters
Packit Service 0f71a7
Packit Service 0f71a7
    if state == "present":
Packit Service 0f71a7
        if len(names) != 1:
Packit Service 0f71a7
            ansible_module.fail_json(
Packit Service 0f71a7
                msg="Only one vault can be added at a time.")
Packit Service 0f71a7
Packit Service 0f71a7
    elif state == "absent":
Packit Service 0f71a7
        if len(names) < 1:
Packit Service 0f71a7
            ansible_module.fail_json(msg="No name given.")
Packit Service 0f71a7
Packit Service 0f71a7
    elif state == "retrieved":
Packit Service 0f71a7
        if len(names) != 1:
Packit Service 0f71a7
            ansible_module.fail_json(
Packit Service 0f71a7
                msg="Only one vault can be retrieved at a time.")
Packit Service 0f71a7
Packit Service 0f71a7
    else:
Packit Service 0f71a7
        ansible_module.fail_json(msg="Invalid state '%s'" % state)
Packit Service 0f71a7
Packit Service 0f71a7
    check_parameters(ansible_module, state, action, description, username,
Packit Service 0f71a7
                     service, shared, users, groups, services, owners,
Packit Service 0f71a7
                     ownergroups, ownerservices, vault_type, salt, password,
Packit Service 0f71a7
                     password_file, public_key, public_key_file, private_key,
Packit Service 0f71a7
                     private_key_file, vault_data, datafile_in, datafile_out)
Packit Service 0f71a7
    # Init
Packit Service 0f71a7
Packit Service 0f71a7
    changed = False
Packit Service 0f71a7
    exit_args = {}
Packit Service 0f71a7
    ccache_dir = None
Packit Service 0f71a7
    ccache_name = None
Packit Service 0f71a7
    try:
Packit Service 0f71a7
        if not valid_creds(ansible_module, ipaadmin_principal):
Packit Service 0f71a7
            ccache_dir, ccache_name = temp_kinit(ipaadmin_principal,
Packit Service 0f71a7
                                                 ipaadmin_password)
Packit Service 0f71a7
            # Need to set krb5 ccache name, due to context='ansible-freeipa'
Packit Service 0f71a7
            if ccache_name is not None:
Packit Service 0f71a7
                os.environ["KRB5CCNAME"] = ccache_name
Packit Service 0f71a7
Packit Service 0f71a7
        api_connect(context='ansible-freeipa')
Packit Service 0f71a7
Packit Service 0f71a7
        commands = []
Packit Service 0f71a7
Packit Service 0f71a7
        for name in names:
Packit Service 0f71a7
            # Make sure vault exists
Packit Service 0f71a7
            res_find = find_vault(
Packit Service 0f71a7
                ansible_module, name, username, service, shared)
Packit Service 0f71a7
Packit Service 0f71a7
            # Generate args
Packit Service 0f71a7
            args = gen_args(description, username, service, shared, vault_type,
Packit Service 0f71a7
                            salt, password, password_file, public_key,
Packit Service 0f71a7
                            public_key_file, vault_data, datafile_in,
Packit Service 0f71a7
                            datafile_out)
Packit Service 0f71a7
            pwdargs = None
Packit Service 0f71a7
Packit Service 0f71a7
            # Set default vault_type if needed.
Packit Service 0f71a7
            if vault_type is None and vault_data is not None:
Packit Service 0f71a7
                if res_find is not None:
Packit Service 0f71a7
                    res_vault_type = res_find.get('ipavaulttype')[0]
Packit Service 0f71a7
                    args['ipavaulttype'] = vault_type = res_vault_type
Packit Service 0f71a7
                else:
Packit Service 0f71a7
                    args['ipavaulttype'] = vault_type = "symmetric"
Packit Service 0f71a7
Packit Service 0f71a7
            # Create command
Packit Service 0f71a7
            if state == "present":
Packit Service 0f71a7
                # verify data encription args
Packit Service 0f71a7
                check_encryption_params(
Packit Service 0f71a7
                    ansible_module, state, action, vault_type, salt, password,
Packit Service 0f71a7
                    password_file, public_key, public_key_file, private_key,
Packit Service 0f71a7
                    private_key_file, vault_data, datafile_in, datafile_out,
Packit Service 0f71a7
                    res_find)
Packit Service 0f71a7
Packit Service 0f71a7
                # Found the vault
Packit Service 0f71a7
                if action == "vault":
Packit Service 0f71a7
                    if res_find is not None:
Packit Service 0f71a7
                        # For all settings is args, check if there are
Packit Service 0f71a7
                        # different settings in the find result.
Packit Service 0f71a7
                        # If yes: modify
Packit Service 0f71a7
                        if not compare_args_ipa(ansible_module, args,
Packit Service 0f71a7
                                                res_find):
Packit Service 0f71a7
                            commands.append([name, "vault_mod_internal", args])
Packit Service 0f71a7
Packit Service 0f71a7
                    else:
Packit Service 0f71a7
                        commands.append([name, "vault_add_internal", args])
Packit Service 0f71a7
                        if vault_type != 'standard' and vault_data is None:
Packit Service 0f71a7
                            vault_data = ''
Packit Service 0f71a7
Packit Service 0f71a7
                        # Set res_find to empty dict for next steps
Packit Service 0f71a7
                        res_find = {}
Packit Service 0f71a7
Packit Service 0f71a7
                    # Generate adittion and removal lists
Packit Service 0f71a7
                    user_add, user_del = \
Packit Service 0f71a7
                        gen_add_del_lists(users,
Packit Service 0f71a7
                                          res_find.get('member_user', []))
Packit Service 0f71a7
                    group_add, group_del = \
Packit Service 0f71a7
                        gen_add_del_lists(groups,
Packit Service 0f71a7
                                          res_find.get('member_group', []))
Packit Service 0f71a7
                    service_add, service_del = \
Packit Service 0f71a7
                        gen_add_del_lists(services,
Packit Service 0f71a7
                                          res_find.get('member_service', []))
Packit Service 0f71a7
Packit Service 0f71a7
                    owner_add, owner_del = \
Packit Service 0f71a7
                        gen_add_del_lists(owners,
Packit Service 0f71a7
                                          res_find.get('owner_user', []))
Packit Service 0f71a7
Packit Service 0f71a7
                    ownergroups_add, ownergroups_del = \
Packit Service 0f71a7
                        gen_add_del_lists(ownergroups,
Packit Service 0f71a7
                                          res_find.get('owner_group', []))
Packit Service 0f71a7
Packit Service 0f71a7
                    ownerservice_add, ownerservice_del = \
Packit Service 0f71a7
                        gen_add_del_lists(ownerservices,
Packit Service 0f71a7
                                          res_find.get('owner_service', []))
Packit Service 0f71a7
Packit Service 0f71a7
                    # Add users and groups
Packit Service 0f71a7
                    user_add_args = gen_member_args(args, user_add,
Packit Service 0f71a7
                                                    group_add, service_add)
Packit Service 0f71a7
                    if user_add_args is not None:
Packit Service 0f71a7
                        commands.append(
Packit Service 0f71a7
                            [name, 'vault_add_member', user_add_args])
Packit Service 0f71a7
Packit Service 0f71a7
                    # Remove users and groups
Packit Service 0f71a7
                    user_del_args = gen_member_args(args, user_del,
Packit Service 0f71a7
                                                    group_del, service_del)
Packit Service 0f71a7
                    if user_del_args is not None:
Packit Service 0f71a7
                        commands.append(
Packit Service 0f71a7
                            [name, 'vault_remove_member', user_del_args])
Packit Service 0f71a7
Packit Service 0f71a7
                    # Add owner users and groups
Packit Service 0f71a7
                    owner_add_args = gen_member_args(
Packit Service 0f71a7
                        args, owner_add, ownergroups_add, ownerservice_add)
Packit Service 0f71a7
                    if owner_add_args is not None:
Packit Service 0f71a7
                        # ansible_module.warn("OWNER ADD: %s" % owner_add_args)
Packit Service 0f71a7
                        commands.append(
Packit Service 0f71a7
                            [name, 'vault_add_owner', owner_add_args])
Packit Service 0f71a7
Packit Service 0f71a7
                    # Remove owner users and groups
Packit Service 0f71a7
                    owner_del_args = gen_member_args(
Packit Service 0f71a7
                        args, owner_del, ownergroups_del, ownerservice_del)
Packit Service 0f71a7
                    if owner_del_args is not None:
Packit Service 0f71a7
                        # ansible_module.warn("OWNER DEL: %s" % owner_del_args)
Packit Service 0f71a7
                        commands.append(
Packit Service 0f71a7
                            [name, 'vault_remove_owner', owner_del_args])
Packit Service 0f71a7
Packit Service 0f71a7
                    if vault_type == 'symmetric' \
Packit Service 0f71a7
                       and 'ipavaultsalt' not in args:
Packit Service 0f71a7
                        args['ipavaultsalt'] = os.urandom(32)
Packit Service 0f71a7
Packit Service 0f71a7
                    if vault_type == 'symmetric' \
Packit Service 0f71a7
                       and 'ipavaultsalt' not in args:
Packit Service 0f71a7
                        args['ipavaultsalt'] = os.urandom(32)
Packit Service 0f71a7
Packit Service 0f71a7
                elif action in "member":
Packit Service 0f71a7
                    # Add users and groups
Packit Service 0f71a7
                    if any([users, groups, services]):
Packit Service 0f71a7
                        user_args = gen_member_args(args, users, groups,
Packit Service 0f71a7
                                                    services)
Packit Service 0f71a7
                        commands.append([name, 'vault_add_member', user_args])
Packit Service 0f71a7
                    if any([owners, ownergroups, ownerservices]):
Packit Service 0f71a7
                        owner_args = gen_member_args(args, owners, ownergroups,
Packit Service 0f71a7
                                                     ownerservices)
Packit Service 0f71a7
                        commands.append([name, 'vault_add_owner', owner_args])
Packit Service 0f71a7
Packit Service 0f71a7
                pwdargs = data_storage_args(
Packit Service 0f71a7
                    args, vault_data, password, password_file, private_key,
Packit Service 0f71a7
                    private_key_file, datafile_in, datafile_out)
Packit Service 0f71a7
                if any([vault_data, datafile_in]):
Packit Service 0f71a7
                    commands.append([name, "vault_archive", pwdargs])
Packit Service 0f71a7
Packit Service 0f71a7
            elif state == "retrieved":
Packit Service 0f71a7
                if res_find is None:
Packit Service 0f71a7
                    ansible_module.fail_json(
Packit Service 0f71a7
                        msg="Vault `%s` not found to retrieve data." % name)
Packit Service 0f71a7
Packit Service 0f71a7
                vault_type = res_find['cn']
Packit Service 0f71a7
Packit Service 0f71a7
                # verify data encription args
Packit Service 0f71a7
                check_encryption_params(
Packit Service 0f71a7
                    ansible_module, state, action, vault_type, salt, password,
Packit Service 0f71a7
                    password_file, public_key, public_key_file, private_key,
Packit Service 0f71a7
                    private_key_file, vault_data, datafile_in, datafile_out,
Packit Service 0f71a7
                    res_find)
Packit Service 0f71a7
Packit Service 0f71a7
                pwdargs = data_storage_args(
Packit Service 0f71a7
                    args, vault_data, password, password_file, private_key,
Packit Service 0f71a7
                    private_key_file, datafile_in, datafile_out)
Packit Service 0f71a7
                if 'data' in pwdargs:
Packit Service 0f71a7
                    del pwdargs['data']
Packit Service 0f71a7
Packit Service 0f71a7
                commands.append([name, "vault_retrieve", pwdargs])
Packit Service 0f71a7
Packit Service 0f71a7
            elif state == "absent":
Packit Service 0f71a7
                if 'ipavaulttype' in args:
Packit Service 0f71a7
                    del args['ipavaulttype']
Packit Service 0f71a7
Packit Service 0f71a7
                if action == "vault":
Packit Service 0f71a7
                    if res_find is not None:
Packit Service 0f71a7
                        commands.append([name, "vault_del", args])
Packit Service 0f71a7
Packit Service 0f71a7
                elif action == "member":
Packit Service 0f71a7
                    # remove users and groups
Packit Service 0f71a7
                    if any([users, groups, services]):
Packit Service 0f71a7
                        user_args = gen_member_args(
Packit Service 0f71a7
                            args, users, groups, services)
Packit Service 0f71a7
                        commands.append(
Packit Service 0f71a7
                            [name, 'vault_remove_member', user_args])
Packit Service 0f71a7
Packit Service 0f71a7
                    if any([owners, ownergroups, ownerservices]):
Packit Service 0f71a7
                        owner_args = gen_member_args(
Packit Service 0f71a7
                            args, owners, ownergroups, ownerservices)
Packit Service 0f71a7
                        commands.append(
Packit Service 0f71a7
                            [name, 'vault_remove_owner', owner_args])
Packit Service 0f71a7
                else:
Packit Service 0f71a7
                    ansible_module.fail_json(
Packit Service 0f71a7
                        msg="Invalid action '%s' for state '%s'" %
Packit Service 0f71a7
                        (action, state))
Packit Service 0f71a7
            else:
Packit Service 0f71a7
                ansible_module.fail_json(msg="Unknown state '%s'" % state)
Packit Service 0f71a7
Packit Service 0f71a7
        # Execute commands
Packit Service 0f71a7
Packit Service 0f71a7
        errors = []
Packit Service 0f71a7
        for name, command, args in commands:
Packit Service 0f71a7
            try:
Packit Service 0f71a7
                # ansible_module.warn("RUN: %s %s %s" % (command, name, args))
Packit Service 0f71a7
                result = api_command(ansible_module, command, name, args)
Packit Service 0f71a7
Packit Service 0f71a7
                if command == 'vault_archive':
Packit Service 0f71a7
                    changed = 'Archived data into' in result['summary']
Packit Service 0f71a7
                elif command == 'vault_retrieve':
Packit Service 0f71a7
                    if 'result' not in result:
Packit Service 0f71a7
                        raise Exception("No result obtained.")
Packit Service 0f71a7
                    if 'data' in result['result']:
Packit Service 0f71a7
                        exit_args['data'] = result['result']['data']
Packit Service 0f71a7
                    elif 'vault_data' in result['result']:
Packit Service 0f71a7
                        exit_args['data'] = result['result']['vault_data']
Packit Service 0f71a7
                    else:
Packit Service 0f71a7
                        raise Exception("No data retrieved.")
Packit Service 0f71a7
                    changed = False
Packit Service 0f71a7
                else:
Packit Service 0f71a7
                    # ansible_module.warn("RESULT: %s" % (result))
Packit Service 0f71a7
                    if "completed" in result:
Packit Service 0f71a7
                        if result["completed"] > 0:
Packit Service 0f71a7
                            changed = True
Packit Service 0f71a7
                    else:
Packit Service 0f71a7
                        changed = True
Packit Service 0f71a7
            except EmptyModlist:
Packit Service 0f71a7
                result = {}
Packit Service 0f71a7
            except Exception as exception:
Packit Service 0f71a7
                ansible_module.fail_json(
Packit Service 0f71a7
                    msg="%s: %s: %s" % (command, name, str(exception)))
Packit Service 0f71a7
Packit Service 0f71a7
            # Get all errors
Packit Service 0f71a7
            # All "already a member" and "not a member" failures in the
Packit Service 0f71a7
            # result are ignored. All others are reported.
Packit Service 0f71a7
            if "failed" in result and len(result["failed"]) > 0:
Packit Service 0f71a7
                for item in result["failed"]:
Packit Service 0f71a7
                    failed_item = result["failed"][item]
Packit Service 0f71a7
                    for member_type in failed_item:
Packit Service 0f71a7
                        for member, failure in failed_item[member_type]:
Packit Service 0f71a7
                            if "already a member" in failure \
Packit Service 0f71a7
                               or "not a member" in failure:
Packit Service 0f71a7
                                continue
Packit Service 0f71a7
                            errors.append("%s: %s %s: %s" % (
Packit Service 0f71a7
                                command, member_type, member, failure))
Packit Service 0f71a7
        if len(errors) > 0:
Packit Service 0f71a7
            ansible_module.fail_json(msg=", ".join(errors))
Packit Service 0f71a7
Packit Service 0f71a7
    except Exception as exception:
Packit Service 0f71a7
        ansible_module.fail_json(msg=str(exception))
Packit Service 0f71a7
Packit Service 0f71a7
    finally:
Packit Service 0f71a7
        temp_kdestroy(ccache_dir, ccache_name)
Packit Service 0f71a7
Packit Service 0f71a7
    # Done
Packit Service 0f71a7
    ansible_module.exit_json(changed=changed, **exit_args)
Packit Service 0f71a7
Packit Service 0f71a7
Packit Service 0f71a7
if __name__ == "__main__":
Packit Service 0f71a7
    main()