Beispiel #1
0
def get_aws_region(module, boto3=False):
    region = module.params.get('region')

    if region:
        return region

    if 'AWS_REGION' in os.environ:
        return os.environ['AWS_REGION']
    if 'AWS_DEFAULT_REGION' in os.environ:
        return os.environ['AWS_DEFAULT_REGION']
    if 'EC2_REGION' in os.environ:
        return os.environ['EC2_REGION']

    if not boto3:
        if not HAS_BOTO:
            module.fail_json(msg=missing_required_lib('boto'), exception=BOTO_IMP_ERR)
        # boto.config.get returns None if config not found
        region = boto.config.get('Boto', 'aws_region')
        if region:
            return region
        return boto.config.get('Boto', 'ec2_region')

    if not HAS_BOTO3:
        module.fail_json(msg=missing_required_lib('boto3'), exception=BOTO3_IMP_ERR)

    # here we don't need to make an additional call, will default to 'us-east-1' if the below evaluates to None.
    try:
        profile_name = module.params.get('profile')
        return botocore.session.Session(profile=profile_name).get_config_variable('region')
    except botocore.exceptions.ProfileNotFound as e:
        return None
Beispiel #2
0
    def __init__(self, *args, **kwargs):

        kwargs['argument_spec'] = self.argspec
        AssibleModule.__init__(self, *args, **kwargs)

        if not HAS_K8S_MODULE_HELPER:
            self.fail_json(msg=missing_required_lib('openshift'), exception=K8S_IMP_ERR,
                           error=to_native(k8s_import_exception))
        self.openshift_version = openshift.__version__

        if not HAS_YAML:
            self.fail_json(msg=missing_required_lib("PyYAML"), exception=YAML_IMP_ERR)
Beispiel #3
0
def main():
    module = AssibleModule(
        argument_spec=dict(
            ignore_selinux_state=dict(type='bool', default=False),
            login=dict(type='str', required=True),
            seuser=dict(type='str'),
            selevel=dict(type='str', aliases=['serange'], default='s0'),
            state=dict(type='str', default='present', choices=['absent', 'present']),
            reload=dict(type='bool', default=True),
        ),
        required_if=[
            ["state", "present", ["seuser"]]
        ],
        supports_check_mode=True
    )
    if not HAVE_SELINUX:
        module.fail_json(msg=missing_required_lib("libselinux"), exception=SELINUX_IMP_ERR)

    if not HAVE_SEOBJECT:
        module.fail_json(msg=missing_required_lib("seobject from policycoreutils"), exception=SEOBJECT_IMP_ERR)

    ignore_selinux_state = module.params['ignore_selinux_state']

    if not get_runtime_status(ignore_selinux_state):
        module.fail_json(msg="SELinux is disabled on this host.")

    login = module.params['login']
    seuser = module.params['seuser']
    serange = module.params['selevel']
    state = module.params['state']
    do_reload = module.params['reload']

    result = {
        'login': login,
        'seuser': seuser,
        'serange': serange,
        'state': state,
    }

    if state == 'present':
        result['changed'] = semanage_login_add(module, login, seuser, do_reload, serange)
    elif state == 'absent':
        result['changed'] = semanage_login_del(module, login, seuser, do_reload)
    else:
        module.fail_json(msg='Invalid value of argument "state": {0}'.format(state))

    module.exit_json(**result)
Beispiel #4
0
def ensure_required_libs(module):
    """Check required libraries."""
    if not HAS_PSYCOPG2:
        module.fail_json(msg=missing_required_lib('psycopg2'))

    if module.params.get('ca_cert') and LooseVersion(
            psycopg2.__version__) < LooseVersion('2.4.3'):
        module.fail_json(
            msg=
            'psycopg2 must be at least 2.4.3 in order to use the ca_cert parameter'
        )
Beispiel #5
0
def main():
    module = AssibleModule(
        argument_spec=dict(
            ignore_selinux_state=dict(type='bool', default=False),
            target=dict(type='str', required=True, aliases=['path']),
            ftype=dict(type='str', default='a', choices=option_to_file_type_str.keys()),
            setype=dict(type='str', required=True),
            seuser=dict(type='str'),
            selevel=dict(type='str', aliases=['serange']),
            state=dict(type='str', default='present', choices=['absent', 'present']),
            reload=dict(type='bool', default=True),
        ),
        supports_check_mode=True,
    )
    if not HAVE_SELINUX:
        module.fail_json(msg=missing_required_lib("libselinux-python"), exception=SELINUX_IMP_ERR)

    if not HAVE_SEOBJECT:
        module.fail_json(msg=missing_required_lib("policycoreutils-python"), exception=SEOBJECT_IMP_ERR)

    ignore_selinux_state = module.params['ignore_selinux_state']

    if not get_runtime_status(ignore_selinux_state):
        module.fail_json(msg="SELinux is disabled on this host.")

    target = module.params['target']
    ftype = module.params['ftype']
    setype = module.params['setype']
    seuser = module.params['seuser']
    serange = module.params['selevel']
    state = module.params['state']
    do_reload = module.params['reload']

    result = dict(target=target, ftype=ftype, setype=setype, state=state)

    if state == 'present':
        semanage_fcontext_modify(module, result, target, ftype, setype, do_reload, serange, seuser)
    elif state == 'absent':
        semanage_fcontext_delete(module, result, target, ftype, do_reload)
    else:
        module.fail_json(msg='Invalid value of argument "state": {0}'.format(state))
Beispiel #6
0
    def is_available(self):
        ''' we expect the python bindings installed, but this gives warning if they are missing and we have rpm cli'''
        we_have_lib = super(RPM, self).is_available()

        try:
            get_bin_path('rpm')
            if not we_have_lib:
                module.warn('Found "rpm" but %s' %
                            (missing_required_lib('rpm')))
        except ValueError:
            pass

        return we_have_lib
Beispiel #7
0
 def is_available(self):
     ''' we expect the python bindings installed, but if there is apt/apt-get give warning about missing bindings'''
     we_have_lib = super(APT, self).is_available()
     if not we_have_lib:
         for exe in ('apt', 'apt-get', 'aptitude'):
             try:
                 get_bin_path(exe)
             except ValueError:
                 continue
             else:
                 module.warn('Found "%s" but %s' %
                             (exe, missing_required_lib('apt')))
                 break
     return we_have_lib
Beispiel #8
0
def main():
    module = AssibleModule(
        argument_spec=dict(
            path=dict(type='path'),
            content=dict(type='str'),
        ),
        required_one_of=(['path', 'content'], ),
        mutually_exclusive=(['path', 'content'], ),
        supports_check_mode=True,
    )

    if not CRYPTOGRAPHY_FOUND:
        module.fail_json(msg=missing_required_lib(
            'cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)),
                         exception=CRYPTOGRAPHY_IMP_ERR)

    try:
        crl = CRLInfo(module)
        result = crl.get_info()
        module.exit_json(**result)
    except crypto_utils.OpenSSLObjectError as e:
        module.fail_json(msg=to_native(e))
Beispiel #9
0
    def __init__(self, **kwargs):
        local_settings = {}
        for key in AssibleAWSModule.default_settings:
            try:
                local_settings[key] = kwargs.pop(key)
            except KeyError:
                local_settings[key] = AssibleAWSModule.default_settings[key]
        self.settings = local_settings

        if local_settings["default_args"]:
            # ec2_argument_spec contains the region so we use that; there's a patch coming which
            # will add it to aws_argument_spec so if that's accepted then later we should change
            # over
            argument_spec_full = ec2_argument_spec()
            try:
                argument_spec_full.update(kwargs["argument_spec"])
            except (TypeError, NameError):
                pass
            kwargs["argument_spec"] = argument_spec_full

        self._module = AssibleAWSModule.default_settings["module_class"](
            **kwargs)

        if local_settings["check_boto3"] and not HAS_BOTO3:
            self._module.fail_json(
                msg=missing_required_lib('botocore or boto3'))

        self.check_mode = self._module.check_mode
        self._diff = self._module._diff
        self._name = self._module._name

        self._botocore_endpoint_log_stream = StringIO()
        self.logger = None
        if self.params.get('debug_botocore_endpoint_logs'):
            self.logger = logging.getLogger('botocore.endpoint')
            self.logger.setLevel(logging.DEBUG)
            self.logger.addHandler(
                logging.StreamHandler(self._botocore_endpoint_log_stream))
Beispiel #10
0
    def __init__(self, argument_spec, **kwargs):
        args = dict(
            tower_host=dict(),
            tower_username=dict(),
            tower_password=dict(no_log=True),
            validate_certs=dict(type='bool', aliases=['tower_verify_ssl']),
            tower_config_file=dict(type='path'),
        )
        args.update(argument_spec)

        mutually_exclusive = kwargs.get('mutually_exclusive', [])
        kwargs['mutually_exclusive'] = mutually_exclusive.extend((
            ('tower_config_file', 'tower_host'),
            ('tower_config_file', 'tower_username'),
            ('tower_config_file', 'tower_password'),
            ('tower_config_file', 'validate_certs'),
        ))

        super(TowerModule, self).__init__(argument_spec=args, **kwargs)

        if not HAS_TOWER_CLI:
            self.fail_json(msg=missing_required_lib('assible-tower-cli'),
                           exception=TOWER_CLI_IMP_ERR)
Beispiel #11
0
def ECSClient(entrust_api_user=None, entrust_api_key=None, entrust_api_cert=None, entrust_api_cert_key=None, entrust_api_specification_path=None):
    """Create an ECS client"""

    if not YAML_FOUND:
        raise SessionConfigurationException(missing_required_lib("PyYAML"), exception=YAML_IMP_ERR)

    if entrust_api_specification_path is None:
        entrust_api_specification_path = "https://cloud.entrust.net/EntrustCloud/documentation/cms-api-2.1.0.yaml"

    # Not functionally necessary with current uses of this module_util, but better to be explicit for future use cases
    entrust_api_user = to_text(entrust_api_user)
    entrust_api_key = to_text(entrust_api_key)
    entrust_api_cert_key = to_text(entrust_api_cert_key)
    entrust_api_specification_path = to_text(entrust_api_specification_path)

    return ECSSession(
        "ecs",
        entrust_api_user=entrust_api_user,
        entrust_api_key=entrust_api_key,
        entrust_api_cert=entrust_api_cert,
        entrust_api_cert_key=entrust_api_cert_key,
        entrust_api_specification_path=entrust_api_specification_path,
    ).client()
def main():
    module = AssibleModule(
        argument_spec=dict(
            login_user=dict(default=None),
            login_password=dict(default=None, no_log=True),
            login_host=dict(default='localhost'),
            login_port=dict(default=27017, type='int'),
            login_database=dict(default=None),
            replica_set=dict(default=None),
            param=dict(required=True),
            value=dict(required=True),
            param_type=dict(default="str", choices=['str', 'int']),
            ssl=dict(default=False, type='bool'),
        )
    )

    if not pymongo_found:
        module.fail_json(msg=missing_required_lib('pymongo'))

    login_user = module.params['login_user']
    login_password = module.params['login_password']
    login_host = module.params['login_host']
    login_port = module.params['login_port']
    login_database = module.params['login_database']

    replica_set = module.params['replica_set']
    ssl = module.params['ssl']

    param = module.params['param']
    param_type = module.params['param_type']
    value = module.params['value']

    # Verify parameter is coherent with specified type
    try:
        if param_type == 'int':
            value = int(value)
    except ValueError:
        module.fail_json(msg="value '%s' is not %s" % (value, param_type))

    try:
        if replica_set:
            client = MongoClient(login_host, int(login_port), replicaset=replica_set, ssl=ssl)
        else:
            client = MongoClient(login_host, int(login_port), ssl=ssl)

        if login_user is None and login_password is None:
            mongocnf_creds = load_mongocnf()
            if mongocnf_creds is not False:
                login_user = mongocnf_creds['user']
                login_password = mongocnf_creds['password']
        elif login_password is None or login_user is None:
            module.fail_json(msg='when supplying login arguments, both login_user and login_password must be provided')

        if login_user is not None and login_password is not None:
            client.admin.authenticate(login_user, login_password, source=login_database)

    except ConnectionFailure as e:
        module.fail_json(msg='unable to connect to database: %s' % to_native(e), exception=traceback.format_exc())

    db = client.admin

    try:
        after_value = db.command("setParameter", **{param: value})
    except OperationFailure as e:
        module.fail_json(msg="unable to change parameter: %s" % to_native(e), exception=traceback.format_exc())

    if "was" not in after_value:
        module.exit_json(changed=True, msg="Unable to determine old value, assume it changed.")
    else:
        module.exit_json(changed=(value != after_value["was"]), before=after_value["was"],
                         after=value)
Beispiel #13
0
def main():
    argument_spec = postgres_common_argument_spec()
    argument_spec.update(
        database=dict(required=True, aliases=['db', 'login_db']),
        state=dict(default='present', choices=['present', 'absent']),
        privs=dict(required=False, aliases=['priv']),
        type=dict(default='table',
                  choices=[
                      'table',
                      'sequence',
                      'function',
                      'database',
                      'schema',
                      'language',
                      'tablespace',
                      'group',
                      'default_privs',
                      'foreign_data_wrapper',
                      'foreign_server',
                      'type',
                  ]),
        objs=dict(required=False, aliases=['obj']),
        schema=dict(required=False),
        roles=dict(required=True, aliases=['role']),
        session_role=dict(required=False),
        target_roles=dict(required=False),
        grant_option=dict(required=False,
                          type='bool',
                          aliases=['admin_option']),
        host=dict(default='', aliases=['login_host']),
        unix_socket=dict(default='', aliases=['login_unix_socket']),
        login=dict(default='postgres', aliases=['login_user']),
        password=dict(default='', aliases=['login_password'], no_log=True),
        fail_on_role=dict(type='bool', default=True),
    )

    module = AssibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
    )

    fail_on_role = module.params['fail_on_role']

    # Create type object as namespace for module params
    p = type('Params', (), module.params)
    # param "schema": default, allowed depends on param "type"
    if p.type in ['table', 'sequence', 'function', 'type', 'default_privs']:
        p.schema = p.schema or 'public'
    elif p.schema:
        module.fail_json(msg='Argument "schema" is not allowed '
                         'for type "%s".' % p.type)

    # param "objs": default, required depends on param "type"
    if p.type == 'database':
        p.objs = p.objs or p.database
    elif not p.objs:
        module.fail_json(msg='Argument "objs" is required '
                         'for type "%s".' % p.type)

    # param "privs": allowed, required depends on param "type"
    if p.type == 'group':
        if p.privs:
            module.fail_json(msg='Argument "privs" is not allowed '
                             'for type "group".')
    elif not p.privs:
        module.fail_json(msg='Argument "privs" is required '
                         'for type "%s".' % p.type)

    # Connect to Database
    if not psycopg2:
        module.fail_json(msg=missing_required_lib('psycopg2'),
                         exception=PSYCOPG2_IMP_ERR)
    try:
        conn = Connection(p, module)
    except psycopg2.Error as e:
        module.fail_json(msg='Could not connect to database: %s' %
                         to_native(e),
                         exception=traceback.format_exc())
    except TypeError as e:
        if 'sslrootcert' in e.args[0]:
            module.fail_json(
                msg=
                'Postgresql server must be at least version 8.4 to support sslrootcert'
            )
        module.fail_json(msg="unable to connect to database: %s" %
                         to_native(e),
                         exception=traceback.format_exc())
    except ValueError as e:
        # We raise this when the psycopg library is too old
        module.fail_json(msg=to_native(e))

    if p.session_role:
        try:
            conn.cursor.execute('SET ROLE "%s"' % p.session_role)
        except Exception as e:
            module.fail_json(msg="Could not switch to role %s: %s" %
                             (p.session_role, to_native(e)),
                             exception=traceback.format_exc())

    try:
        # privs
        if p.privs:
            privs = frozenset(pr.upper() for pr in p.privs.split(','))
            if not privs.issubset(VALID_PRIVS):
                module.fail_json(msg='Invalid privileges specified: %s' %
                                 privs.difference(VALID_PRIVS))
        else:
            privs = None
        # objs:
        if p.type == 'table' and p.objs == 'ALL_IN_SCHEMA':
            objs = conn.get_all_tables_in_schema(p.schema)
        elif p.type == 'sequence' and p.objs == 'ALL_IN_SCHEMA':
            objs = conn.get_all_sequences_in_schema(p.schema)
        elif p.type == 'function' and p.objs == 'ALL_IN_SCHEMA':
            objs = conn.get_all_functions_in_schema(p.schema)
        elif p.type == 'default_privs':
            if p.objs == 'ALL_DEFAULT':
                objs = frozenset(VALID_DEFAULT_OBJS.keys())
            else:
                objs = frozenset(obj.upper() for obj in p.objs.split(','))
                if not objs.issubset(VALID_DEFAULT_OBJS):
                    module.fail_json(
                        msg='Invalid Object set specified: %s' %
                        objs.difference(VALID_DEFAULT_OBJS.keys()))
            # Again, do we have valid privs specified for object type:
            valid_objects_for_priv = frozenset(
                obj for obj in objs if privs.issubset(VALID_DEFAULT_OBJS[obj]))
            if not valid_objects_for_priv == objs:
                module.fail_json(
                    msg=
                    'Invalid priv specified. Valid object for priv: {0}. Objects: {1}'
                    .format(valid_objects_for_priv, objs))
        else:
            objs = p.objs.split(',')

            # function signatures are encoded using ':' to separate args
            if p.type == 'function':
                objs = [obj.replace(':', ',') for obj in objs]

        # roles
        if p.roles == 'PUBLIC':
            roles = 'PUBLIC'
        else:
            roles = p.roles.split(',')

            if len(roles) == 1 and not role_exists(module, conn.cursor,
                                                   roles[0]):
                module.exit_json(changed=False)

                if fail_on_role:
                    module.fail_json(msg="Role '%s' does not exist" %
                                     roles[0].strip())

                else:
                    module.warn("Role '%s' does not exist, nothing to do" %
                                roles[0].strip())

        # check if target_roles is set with type: default_privs
        if p.target_roles and not p.type == 'default_privs':
            module.warn(
                '"target_roles" will be ignored '
                'Argument "type: default_privs" is required for usage of "target_roles".'
            )

        # target roles
        if p.target_roles:
            target_roles = p.target_roles.split(',')
        else:
            target_roles = None

        changed = conn.manipulate_privs(
            obj_type=p.type,
            privs=privs,
            objs=objs,
            roles=roles,
            target_roles=target_roles,
            state=p.state,
            grant_option=p.grant_option,
            schema_qualifier=p.schema,
            fail_on_role=fail_on_role,
        )

    except Error as e:
        conn.rollback()
        module.fail_json(msg=e.message, exception=traceback.format_exc())

    except psycopg2.Error as e:
        conn.rollback()
        module.fail_json(msg=to_native(e.message))

    if module.check_mode:
        conn.rollback()
    else:
        conn.commit()
    module.exit_json(changed=changed, queries=executed_queries)
Beispiel #14
0
def main():
    module = AssibleModule(argument_spec=dict(
        login_user=dict(default=None),
        login_password=dict(default=None, no_log=True),
        login_host=dict(default='localhost'),
        login_port=dict(default='27017'),
        login_database=dict(default=None),
        replica_set=dict(default=None),
        database=dict(required=True, aliases=['db']),
        name=dict(required=True, aliases=['user']),
        password=dict(aliases=['pass'], no_log=True),
        ssl=dict(default=False, type='bool'),
        roles=dict(default=None, type='list', elements='raw'),
        state=dict(default='present', choices=['absent', 'present']),
        update_password=dict(default="always", choices=["always",
                                                        "on_create"]),
        ssl_cert_reqs=dict(
            default='CERT_REQUIRED',
            choices=['CERT_NONE', 'CERT_OPTIONAL', 'CERT_REQUIRED']),
    ),
                           supports_check_mode=True)

    if not pymongo_found:
        module.fail_json(msg=missing_required_lib('pymongo'))

    login_user = module.params['login_user']
    login_password = module.params['login_password']
    login_host = module.params['login_host']
    login_port = module.params['login_port']
    login_database = module.params['login_database']

    replica_set = module.params['replica_set']
    db_name = module.params['database']
    user = module.params['name']
    password = module.params['password']
    ssl = module.params['ssl']
    roles = module.params['roles'] or []
    state = module.params['state']
    update_password = module.params['update_password']

    try:
        connection_params = {
            "host": login_host,
            "port": int(login_port),
        }

        if replica_set:
            connection_params["replicaset"] = replica_set

        if ssl:
            connection_params["ssl"] = ssl
            connection_params["ssl_cert_reqs"] = getattr(
                ssl_lib, module.params['ssl_cert_reqs'])

        client = MongoClient(**connection_params)

        # NOTE: this check must be done ASAP.
        # We doesn't need to be authenticated (this ability has lost in PyMongo 3.6)
        if LooseVersion(PyMongoVersion) <= LooseVersion('3.5'):
            check_compatibility(module, client)

        if login_user is None and login_password is None:
            mongocnf_creds = load_mongocnf()
            if mongocnf_creds is not False:
                login_user = mongocnf_creds['user']
                login_password = mongocnf_creds['password']
        elif login_password is None or login_user is None:
            module.fail_json(
                msg=
                'when supplying login arguments, both login_user and login_password must be provided'
            )

        if login_user is not None and login_password is not None:
            client.admin.authenticate(login_user,
                                      login_password,
                                      source=login_database)
        elif LooseVersion(PyMongoVersion) >= LooseVersion('3.0'):
            if db_name != "admin":
                module.fail_json(
                    msg=
                    'The localhost login exception only allows the first admin account to be created'
                )
            # else: this has to be the first admin user added

    except Exception as e:
        module.fail_json(msg='unable to connect to database: %s' %
                         to_native(e),
                         exception=traceback.format_exc())

    if state == 'present':
        if password is None and update_password == 'always':
            module.fail_json(
                msg=
                'password parameter required when adding a user unless update_password is set to on_create'
            )

        try:
            if update_password != 'always':
                uinfo = user_find(client, user, db_name)
                if uinfo:
                    password = None
                    if not check_if_roles_changed(uinfo, roles, db_name):
                        module.exit_json(changed=False, user=user)

            if module.check_mode:
                module.exit_json(changed=True, user=user)

            user_add(module, client, db_name, user, password, roles)
        except Exception as e:
            module.fail_json(msg='Unable to add or update user: %s' %
                             to_native(e),
                             exception=traceback.format_exc())
        finally:
            try:
                client.close()
            except Exception:
                pass
            # Here we can  check password change if mongo provide a query for that : https://jira.mongodb.org/browse/SERVER-22848
            # newuinfo = user_find(client, user, db_name)
            # if uinfo['role'] == newuinfo['role'] and CheckPasswordHere:
            #    module.exit_json(changed=False, user=user)

    elif state == 'absent':
        try:
            user_remove(module, client, db_name, user)
        except Exception as e:
            module.fail_json(msg='Unable to remove user: %s' % to_native(e),
                             exception=traceback.format_exc())
        finally:
            try:
                client.close()
            except Exception:
                pass
    module.exit_json(changed=True, user=user)
Beispiel #15
0
def main():
    module = AssibleModule(argument_spec=dict(
        command=dict(required=True),
        chdir=dict(type='path'),
        creates=dict(type='path'),
        removes=dict(type='path'),
        responses=dict(type='dict', required=True),
        timeout=dict(type='int', default=30),
        echo=dict(type='bool', default=False),
    ))

    if not HAS_PEXPECT:
        module.fail_json(msg=missing_required_lib("pexpect"),
                         exception=PEXPECT_IMP_ERR)

    chdir = module.params['chdir']
    args = module.params['command']
    creates = module.params['creates']
    removes = module.params['removes']
    responses = module.params['responses']
    timeout = module.params['timeout']
    echo = module.params['echo']

    events = dict()
    for key, value in responses.items():
        if isinstance(value, list):
            response = response_closure(module, key, value)
        else:
            response = u'%s\n' % to_text(value).rstrip(u'\n')

        events[to_text(key)] = response

    if args.strip() == '':
        module.fail_json(rc=256, msg="no command given")

    if chdir:
        chdir = os.path.abspath(chdir)
        os.chdir(chdir)

    if creates:
        # do not run the command if the line contains creates=filename
        # and the filename already exists.  This allows idempotence
        # of command executions.
        if os.path.exists(creates):
            module.exit_json(cmd=args,
                             stdout="skipped, since %s exists" % creates,
                             changed=False,
                             rc=0)

    if removes:
        # do not run the command if the line contains removes=filename
        # and the filename does not exist.  This allows idempotence
        # of command executions.
        if not os.path.exists(removes):
            module.exit_json(cmd=args,
                             stdout="skipped, since %s does not exist" %
                             removes,
                             changed=False,
                             rc=0)

    startd = datetime.datetime.now()

    try:
        try:
            # Prefer pexpect.run from pexpect>=4
            out, rc = pexpect.run(args,
                                  timeout=timeout,
                                  withexitstatus=True,
                                  events=events,
                                  cwd=chdir,
                                  echo=echo,
                                  encoding='utf-8')
        except TypeError:
            # Use pexpect.runu in pexpect>=3.3,<4
            out, rc = pexpect.runu(args,
                                   timeout=timeout,
                                   withexitstatus=True,
                                   events=events,
                                   cwd=chdir,
                                   echo=echo)
    except (TypeError, AttributeError) as e:
        # This should catch all insufficient versions of pexpect
        # We deem them insufficient for their lack of ability to specify
        # to not echo responses via the run/runu functions, which would
        # potentially leak sensitive information
        module.fail_json(msg='Insufficient version of pexpect installed '
                         '(%s), this module requires pexpect>=3.3. '
                         'Error was %s' % (pexpect.__version__, to_native(e)))
    except pexpect.ExceptionPexpect as e:
        module.fail_json(msg='%s' % to_native(e),
                         exception=traceback.format_exc())

    endd = datetime.datetime.now()
    delta = endd - startd

    if out is None:
        out = ''

    result = dict(
        cmd=args,
        stdout=out.rstrip('\r\n'),
        rc=rc,
        start=str(startd),
        end=str(endd),
        delta=str(delta),
        changed=True,
    )

    if rc is None:
        module.fail_json(msg='command exceeded timeout', **result)
    elif rc != 0:
        module.fail_json(msg='non-zero return code', **result)

    module.exit_json(**result)
Beispiel #16
0
    def __init__(self, module):
        if not HAS_LIB_CS:
            module.fail_json(msg=missing_required_lib('cs'),
                             exception=CS_IMP_ERR)

        self.result = {
            'changed': False,
            'diff': {
                'before': dict(),
                'after': dict()
            }
        }

        # Common returns, will be merged with self.returns
        # search_for_key: replace_with_key
        self.common_returns = {
            'id': 'id',
            'name': 'name',
            'created': 'created',
            'zonename': 'zone',
            'state': 'state',
            'project': 'project',
            'account': 'account',
            'domain': 'domain',
            'displaytext': 'display_text',
            'displayname': 'display_name',
            'description': 'description',
        }

        # Init returns dict for use in subclasses
        self.returns = {}
        # these values will be casted to int
        self.returns_to_int = {}
        # these keys will be compared case sensitive in self.has_changed()
        self.case_sensitive_keys = [
            'id',
            'displaytext',
            'displayname',
            'description',
        ]

        self.module = module
        self._cs = None

        # Helper for VPCs
        self._vpc_networks_ids = None

        self.domain = None
        self.account = None
        self.project = None
        self.ip_address = None
        self.network = None
        self.physical_network = None
        self.vpc = None
        self.zone = None
        self.vm = None
        self.vm_default_nic = None
        self.os_type = None
        self.hypervisor = None
        self.capabilities = None
        self.network_acl = None
Beispiel #17
0
    def __init__(self,
                 argument_spec=None,
                 supports_check_mode=False,
                 mutually_exclusive=None,
                 required_together=None,
                 required_if=None,
                 min_docker_version=MIN_DOCKER_VERSION,
                 min_docker_api_version=None,
                 option_minimal_versions=None,
                 option_minimal_versions_ignore_params=None,
                 fail_results=None):

        # Modules can put information in here which will always be returned
        # in case client.fail() is called.
        self.fail_results = fail_results or {}

        merged_arg_spec = dict()
        merged_arg_spec.update(DOCKER_COMMON_ARGS)
        if argument_spec:
            merged_arg_spec.update(argument_spec)
            self.arg_spec = merged_arg_spec

        mutually_exclusive_params = []
        mutually_exclusive_params += DOCKER_MUTUALLY_EXCLUSIVE
        if mutually_exclusive:
            mutually_exclusive_params += mutually_exclusive

        required_together_params = []
        required_together_params += DOCKER_REQUIRED_TOGETHER
        if required_together:
            required_together_params += required_together

        self.module = AssibleModule(
            argument_spec=merged_arg_spec,
            supports_check_mode=supports_check_mode,
            mutually_exclusive=mutually_exclusive_params,
            required_together=required_together_params,
            required_if=required_if)

        NEEDS_DOCKER_PY2 = (LooseVersion(min_docker_version) >=
                            LooseVersion('2.0.0'))

        self.docker_py_version = LooseVersion(docker_version)

        if HAS_DOCKER_MODELS and HAS_DOCKER_SSLADAPTER:
            self.fail(
                "Cannot have both the docker-py and docker python modules (old and new version of Docker "
                "SDK for Python) installed together as they use the same namespace and cause a corrupt "
                "installation. Please uninstall both packages, and re-install only the docker-py or docker "
                "python module (for %s's Python %s). It is recommended to install the docker module if no "
                "support for Python 2.6 is required. Please note that simply uninstalling one of the modules "
                "can leave the other module in a broken state." %
                (platform.node(), sys.executable))

        if not HAS_DOCKER_PY:
            if NEEDS_DOCKER_PY2:
                msg = missing_required_lib("Docker SDK for Python: docker")
                msg = msg + ", for example via `pip install docker`. The error was: %s"
            else:
                msg = missing_required_lib(
                    "Docker SDK for Python: docker (Python >= 2.7) or docker-py (Python 2.6)"
                )
                msg = msg + ", for example via `pip install docker` or `pip install docker-py` (Python 2.6). The error was: %s"
            self.fail(msg % HAS_DOCKER_ERROR)

        if self.docker_py_version < LooseVersion(min_docker_version):
            msg = "Error: Docker SDK for Python version is %s (%s's Python %s). Minimum version required is %s."
            if not NEEDS_DOCKER_PY2:
                # The minimal required version is < 2.0 (and the current version as well).
                # Advertise docker (instead of docker-py) for non-Python-2.6 users.
                msg += DOCKERPYUPGRADE_RECOMMEND_DOCKER
            elif docker_version < LooseVersion('2.0'):
                msg += DOCKERPYUPGRADE_SWITCH_TO_DOCKER
            else:
                msg += DOCKERPYUPGRADE_UPGRADE_DOCKER
            self.fail(msg % (docker_version, platform.node(), sys.executable,
                             min_docker_version))

        self.debug = self.module.params.get('debug')
        self.check_mode = self.module.check_mode
        self._connect_params = get_connect_params(self.auth_params,
                                                  fail_function=self.fail)

        try:
            super(AssibleDockerClient, self).__init__(**self._connect_params)
            self.docker_api_version_str = self.version()['ApiVersion']
        except APIError as exc:
            self.fail("Docker API error: %s" % exc)
        except Exception as exc:
            self.fail("Error connecting: %s" % exc)

        self.docker_api_version = LooseVersion(self.docker_api_version_str)
        if min_docker_api_version is not None:
            if self.docker_api_version < LooseVersion(min_docker_api_version):
                self.fail(
                    'Docker API version is %s. Minimum version required is %s.'
                    % (self.docker_api_version_str, min_docker_api_version))

        if option_minimal_versions is not None:
            self._get_minimal_versions(option_minimal_versions,
                                       option_minimal_versions_ignore_params)
Beispiel #18
0
 def wrapped(self, *args, **kwargs):
     if not HAS_NCCLIENT:
         raise AssibleError("%s: %s" % (missing_required_lib('ncclient'),
                                        to_native(NCCLIENT_IMP_ERR)))
     return func(self, *args, **kwargs)
Beispiel #19
0
def main():
    module = AssibleModule(
        argument_spec=dict(
            state=dict(type='str',
                       default='present',
                       choices=['present', 'absent']),
            mode=dict(type='str',
                      default='generate',
                      choices=['generate', 'update']),
            force=dict(type='bool', default=False),
            backup=dict(type='bool', default=False),
            path=dict(type='path', required=True),
            privatekey_path=dict(type='path'),
            privatekey_content=dict(type='str'),
            privatekey_passphrase=dict(type='str', no_log=True),
            issuer=dict(type='dict'),
            last_update=dict(type='str', default='+0s'),
            next_update=dict(type='str'),
            digest=dict(type='str', default='sha256'),
            ignore_timestamps=dict(type='bool', default=False),
            return_content=dict(type='bool', default=False),
            revoked_certificates=dict(
                type='list',
                elements='dict',
                options=dict(
                    path=dict(type='path'),
                    content=dict(type='str'),
                    serial_number=dict(type='int'),
                    revocation_date=dict(type='str', default='+0s'),
                    issuer=dict(type='list', elements='str'),
                    issuer_critical=dict(type='bool', default=False),
                    reason=dict(type='str',
                                choices=[
                                    'unspecified', 'key_compromise',
                                    'ca_compromise', 'affiliation_changed',
                                    'superseded', 'cessation_of_operation',
                                    'certificate_hold', 'privilege_withdrawn',
                                    'aa_compromise', 'remove_from_crl'
                                ]),
                    reason_critical=dict(type='bool', default=False),
                    invalidity_date=dict(type='str'),
                    invalidity_date_critical=dict(type='bool', default=False),
                ),
                required_one_of=[['path', 'content', 'serial_number']],
                mutually_exclusive=[['path', 'content', 'serial_number']],
            ),
        ),
        required_if=[
            ('state', 'present', ['privatekey_path',
                                  'privatekey_content'], True),
            ('state', 'present',
             ['issuer', 'next_update', 'revoked_certificates'], False),
        ],
        mutually_exclusive=(['privatekey_path', 'privatekey_content'], ),
        supports_check_mode=True,
        add_file_common_args=True,
    )

    if not CRYPTOGRAPHY_FOUND:
        module.fail_json(msg=missing_required_lib(
            'cryptography >= {0}'.format(MINIMAL_CRYPTOGRAPHY_VERSION)),
                         exception=CRYPTOGRAPHY_IMP_ERR)

    try:
        crl = CRL(module)

        if module.params['state'] == 'present':
            if module.check_mode:
                result = crl.dump(check_mode=True)
                result['changed'] = module.params['force'] or not crl.check()
                module.exit_json(**result)

            crl.generate()
        else:
            if module.check_mode:
                result = crl.dump(check_mode=True)
                result['changed'] = os.path.exists(module.params['path'])
                module.exit_json(**result)

            crl.remove()

        result = crl.dump()
        module.exit_json(**result)
    except crypto_utils.OpenSSLObjectError as exc:
        module.fail_json(msg=to_native(exc))
Beispiel #20
0
    def _connect(self):
        if not HAS_NCCLIENT:
            raise AssibleError("%s: %s" % (
                missing_required_lib("ncclient"),
                to_native(NCCLIENT_IMP_ERR),
            ))

        self.queue_message("log", "ssh connection done, starting ncclient")

        allow_agent = True
        if self._play_context.password is not None:
            allow_agent = False
        setattr(self._play_context, "allow_agent", allow_agent)

        self.key_filename = (self._play_context.private_key_file
                             or self.get_option("private_key_file"))
        if self.key_filename:
            self.key_filename = str(os.path.expanduser(self.key_filename))

        self._ssh_config = self.get_option("netconf_ssh_config")
        if self._ssh_config in BOOLEANS_TRUE:
            self._ssh_config = True
        elif self._ssh_config in BOOLEANS_FALSE:
            self._ssh_config = None

        # Try to guess the network_os if the network_os is set to auto
        if self._network_os == "auto":
            for cls in netconf_loader.all(class_only=True):
                network_os = cls.guess_network_os(self)
                if network_os:
                    self.queue_message("vvv",
                                       "discovered network_os %s" % network_os)
                    self._network_os = network_os

        # If we have tried to detect the network_os but were unable to i.e. network_os is still 'auto'
        # then use default as the network_os

        if self._network_os == "auto":
            # Network os not discovered. Set it to default
            self.queue_message(
                "vvv",
                "Unable to discover network_os. Falling back to default.",
            )
            self._network_os = "default"
        try:
            ncclient_device_handler = self.netconf.get_option(
                "ncclient_device_handler")
        except KeyError:
            ncclient_device_handler = "default"
        self.queue_message(
            "vvv",
            "identified ncclient device handler: %s." %
            ncclient_device_handler,
        )
        device_params = {"name": ncclient_device_handler}

        try:
            port = self._play_context.port or 830
            self.queue_message(
                "vvv",
                "ESTABLISH NETCONF SSH CONNECTION FOR USER: %s on PORT %s TO %s WITH SSH_CONFIG = %s"
                % (
                    self._play_context.remote_user,
                    port,
                    self._play_context.remote_addr,
                    self._ssh_config,
                ),
            )
            self._manager = manager.connect(
                host=self._play_context.remote_addr,
                port=port,
                username=self._play_context.remote_user,
                password=self._play_context.password,
                key_filename=self.key_filename,
                hostkey_verify=self.get_option("host_key_checking"),
                look_for_keys=self.get_option("look_for_keys"),
                device_params=device_params,
                allow_agent=self._play_context.allow_agent,
                timeout=self.get_option("persistent_connect_timeout"),
                ssh_config=self._ssh_config,
            )

            self._manager._timeout = self.get_option(
                "persistent_command_timeout")
        except SSHUnknownHostError as exc:
            raise AssibleConnectionFailure(to_native(exc))
        except ImportError:
            raise AssibleError(
                "connection=netconf is not supported on {0}".format(
                    self._network_os))

        if not self._manager.connected:
            return 1, b"", b"not connected"

        self.queue_message("log",
                           "ncclient manager object created successfully")

        self._connected = True

        super(Connection, self)._connect()

        return (
            0,
            to_bytes(self._manager.session_id, errors="surrogate_or_strict"),
            b"",
        )
Beispiel #21
0
 def check_required_library(self):
     if not HAS_PIKA:
         self.module.fail_json(msg=missing_required_lib("pika"),
                               exception=PIKA_IMP_ERR)
Beispiel #22
0
    def __init__(self, k8s_kind=None, *args, **kwargs):
        self.client = None
        self.warnings = []

        mutually_exclusive = [
            ('resource_definition', 'src'),
            ('merge_type', 'apply'),
        ]

        KubernetesAssibleModule.__init__(self, *args,
                                         mutually_exclusive=mutually_exclusive,
                                         supports_check_mode=True,
                                         **kwargs)
        self.kind = k8s_kind or self.params.get('kind')
        self.api_version = self.params.get('api_version')
        self.name = self.params.get('name')
        self.namespace = self.params.get('namespace')
        resource_definition = self.params.get('resource_definition')
        validate = self.params.get('validate')
        if validate:
            if LooseVersion(self.openshift_version) < LooseVersion("0.8.0"):
                self.fail_json(msg="openshift >= 0.8.0 is required for validate")
        self.append_hash = self.params.get('append_hash')
        if self.append_hash:
            if not HAS_K8S_CONFIG_HASH:
                self.fail_json(msg=missing_required_lib("openshift >= 0.7.2", reason="for append_hash"),
                               exception=K8S_CONFIG_HASH_IMP_ERR)
        if self.params['merge_type']:
            if LooseVersion(self.openshift_version) < LooseVersion("0.6.2"):
                self.fail_json(msg=missing_required_lib("openshift >= 0.6.2", reason="for merge_type"))
        self.apply = self.params.get('apply', False)
        if self.apply:
            if not HAS_K8S_APPLY:
                self.fail_json(msg=missing_required_lib("openshift >= 0.9.2", reason="for apply"))

        if resource_definition:
            if isinstance(resource_definition, string_types):
                try:
                    self.resource_definitions = yaml.safe_load_all(resource_definition)
                except (IOError, yaml.YAMLError) as exc:
                    self.fail(msg="Error loading resource_definition: {0}".format(exc))
            elif isinstance(resource_definition, list):
                self.resource_definitions = resource_definition
            else:
                self.resource_definitions = [resource_definition]
        src = self.params.get('src')
        if src:
            self.resource_definitions = self.load_resource_definitions(src)
        try:
            self.resource_definitions = [item for item in self.resource_definitions if item]
        except AttributeError:
            pass

        if not resource_definition and not src:
            implicit_definition = dict(
                kind=self.kind,
                apiVersion=self.api_version,
                metadata=dict(name=self.name)
            )
            if self.namespace:
                implicit_definition['metadata']['namespace'] = self.namespace
            self.resource_definitions = [implicit_definition]
Beispiel #23
0
def main():

    argument_spec = rabbitmq_argument_spec()
    argument_spec.update(
        dict(state=dict(default='present',
                        choices=['present', 'absent'],
                        type='str'),
             name=dict(required=True, type='str'),
             durable=dict(default=True, type='bool'),
             auto_delete=dict(default=False, type='bool'),
             message_ttl=dict(default=None, type='int'),
             auto_expires=dict(default=None, type='int'),
             max_length=dict(default=None, type='int'),
             dead_letter_exchange=dict(default=None, type='str'),
             dead_letter_routing_key=dict(default=None, type='str'),
             arguments=dict(default=dict(), type='dict'),
             max_priority=dict(default=None, type='int')))
    module = AssibleModule(argument_spec=argument_spec,
                           supports_check_mode=True)

    url = "%s://%s:%s/api/queues/%s/%s" % (
        module.params['login_protocol'], module.params['login_host'],
        module.params['login_port'],
        urllib_parse.quote(module.params['vhost'], ''), module.params['name'])

    if not HAS_REQUESTS:
        module.fail_json(msg=missing_required_lib("requests"),
                         exception=REQUESTS_IMP_ERR)

    result = dict(changed=False, name=module.params['name'])

    # Check if queue already exists
    r = requests.get(url,
                     auth=(module.params['login_user'],
                           module.params['login_password']),
                     verify=module.params['ca_cert'],
                     cert=(module.params['client_cert'],
                           module.params['client_key']))

    if r.status_code == 200:
        queue_exists = True
        response = r.json()
    elif r.status_code == 404:
        queue_exists = False
        response = r.text
    else:
        module.fail_json(
            msg=
            "Invalid response from RESTAPI when trying to check if queue exists",
            details=r.text)

    if module.params['state'] == 'present':
        change_required = not queue_exists
    else:
        change_required = queue_exists

    # Check if attributes change on existing queue
    if not change_required and r.status_code == 200 and module.params[
            'state'] == 'present':
        if not (response['durable'] == module.params['durable']
                and response['auto_delete'] == module.params['auto_delete'] and
                (('x-message-ttl' in response['arguments']
                  and response['arguments']['x-message-ttl']
                  == module.params['message_ttl']) or
                 ('x-message-ttl' not in response['arguments']
                  and module.params['message_ttl'] is None)) and
                (('x-expires' in response['arguments']
                  and response['arguments']['x-expires']
                  == module.params['auto_expires']) or
                 ('x-expires' not in response['arguments']
                  and module.params['auto_expires'] is None)) and
                (('x-max-length' in response['arguments']
                  and response['arguments']['x-max-length']
                  == module.params['max_length']) or
                 ('x-max-length' not in response['arguments']
                  and module.params['max_length'] is None)) and
                (('x-dead-letter-exchange' in response['arguments']
                  and response['arguments']['x-dead-letter-exchange']
                  == module.params['dead_letter_exchange']) or
                 ('x-dead-letter-exchange' not in response['arguments']
                  and module.params['dead_letter_exchange'] is None)) and
                (('x-dead-letter-routing-key' in response['arguments']
                  and response['arguments']['x-dead-letter-routing-key']
                  == module.params['dead_letter_routing_key']) or
                 ('x-dead-letter-routing-key' not in response['arguments']
                  and module.params['dead_letter_routing_key'] is None)) and
                (('x-max-priority' in response['arguments']
                  and response['arguments']['x-max-priority']
                  == module.params['max_priority']) or
                 ('x-max-priority' not in response['arguments']
                  and module.params['max_priority'] is None))):
            module.fail_json(
                msg=
                "RabbitMQ RESTAPI doesn't support attribute changes for existing queues",
            )

    # Copy parameters to arguments as used by RabbitMQ
    for k, v in {
            'message_ttl': 'x-message-ttl',
            'auto_expires': 'x-expires',
            'max_length': 'x-max-length',
            'dead_letter_exchange': 'x-dead-letter-exchange',
            'dead_letter_routing_key': 'x-dead-letter-routing-key',
            'max_priority': 'x-max-priority'
    }.items():
        if module.params[k] is not None:
            module.params['arguments'][v] = module.params[k]

    # Exit if check_mode
    if module.check_mode:
        result['changed'] = change_required
        result['details'] = response
        result['arguments'] = module.params['arguments']
        module.exit_json(**result)

    # Do changes
    if change_required:
        if module.params['state'] == 'present':
            r = requests.put(url,
                             auth=(module.params['login_user'],
                                   module.params['login_password']),
                             headers={"content-type": "application/json"},
                             data=json.dumps({
                                 "durable":
                                 module.params['durable'],
                                 "auto_delete":
                                 module.params['auto_delete'],
                                 "arguments":
                                 module.params['arguments']
                             }),
                             verify=module.params['ca_cert'],
                             cert=(module.params['client_cert'],
                                   module.params['client_key']))
        elif module.params['state'] == 'absent':
            r = requests.delete(url,
                                auth=(module.params['login_user'],
                                      module.params['login_password']),
                                verify=module.params['ca_cert'],
                                cert=(module.params['client_cert'],
                                      module.params['client_key']))

        # RabbitMQ 3.6.7 changed this response code from 204 to 201
        if r.status_code == 204 or r.status_code == 201:
            result['changed'] = True
            module.exit_json(**result)
        else:
            module.fail_json(msg="Error creating queue",
                             status=r.status_code,
                             details=r.text)

    else:
        module.exit_json(changed=False, name=module.params['name'])
Beispiel #24
0
def main():
    arg_spec = dict(
        path=dict(required=True, aliases=["dest", "destfile"]),
        name=dict(required=True, aliases=["username"]),
        password=dict(required=False, default=None, no_log=True),
        crypt_scheme=dict(required=False, default="apr_md5_crypt"),
        state=dict(required=False, default="present"),
        create=dict(type='bool', default='yes'),
    )
    module = AssibleModule(argument_spec=arg_spec,
                           add_file_common_args=True,
                           supports_check_mode=True)

    path = module.params['path']
    username = module.params['name']
    password = module.params['password']
    crypt_scheme = module.params['crypt_scheme']
    state = module.params['state']
    create = module.params['create']
    check_mode = module.check_mode

    if not passlib_installed:
        module.fail_json(msg=missing_required_lib("passlib"),
                         exception=PASSLIB_IMP_ERR)

    # Check file for blank lines in effort to avoid "need more than 1 value to unpack" error.
    try:
        f = open(path, "r")
    except IOError:
        # No preexisting file to remove blank lines from
        f = None
    else:
        try:
            lines = f.readlines()
        finally:
            f.close()

        # If the file gets edited, it returns true, so only edit the file if it has blank lines
        strip = False
        for line in lines:
            if not line.strip():
                strip = True
                break

        if strip:
            # If check mode, create a temporary file
            if check_mode:
                temp = tempfile.NamedTemporaryFile()
                path = temp.name
            f = open(path, "w")
            try:
                [f.write(line) for line in lines if line.strip()]
            finally:
                f.close()

    try:
        if state == 'present':
            (msg, changed) = present(path, username, password, crypt_scheme,
                                     create, check_mode)
        elif state == 'absent':
            if not os.path.exists(path):
                module.exit_json(msg="%s not present" % username,
                                 warnings="%s does not exist" % path,
                                 changed=False)
            (msg, changed) = absent(path, username, check_mode)
        else:
            module.fail_json(msg="Invalid state: %s" % state)

        check_file_attrs(module, changed, msg)
        module.exit_json(msg=msg, changed=changed)
    except Exception as e:
        module.fail_json(msg=to_native(e))
Beispiel #25
0
def main():
    state_map = dict(
        present=['install'],
        absent=['uninstall', '-y'],
        latest=['install', '-U'],
        forcereinstall=['install', '-U', '--force-reinstall'],
    )

    module = AssibleModule(
        argument_spec=dict(
            state=dict(type='str', default='present', choices=state_map.keys()),
            name=dict(type='list', elements='str'),
            version=dict(type='str'),
            requirements=dict(type='str'),
            virtualenv=dict(type='path'),
            virtualenv_site_packages=dict(type='bool', default=False),
            virtualenv_command=dict(type='path', default='virtualenv'),
            virtualenv_python=dict(type='str'),
            extra_args=dict(type='str'),
            editable=dict(type='bool', default=False),
            chdir=dict(type='path'),
            executable=dict(type='path'),
            umask=dict(type='str'),
        ),
        required_one_of=[['name', 'requirements']],
        mutually_exclusive=[['name', 'requirements'], ['executable', 'virtualenv']],
        supports_check_mode=True,
    )

    if not HAS_SETUPTOOLS:
        module.fail_json(msg=missing_required_lib("setuptools"),
                         exception=SETUPTOOLS_IMP_ERR)

    state = module.params['state']
    name = module.params['name']
    version = module.params['version']
    requirements = module.params['requirements']
    extra_args = module.params['extra_args']
    chdir = module.params['chdir']
    umask = module.params['umask']
    env = module.params['virtualenv']

    venv_created = False
    if env and chdir:
        env = os.path.join(chdir, env)

    if umask and not isinstance(umask, int):
        try:
            umask = int(umask, 8)
        except Exception:
            module.fail_json(msg="umask must be an octal integer",
                             details=to_native(sys.exc_info()[1]))

    old_umask = None
    if umask is not None:
        old_umask = os.umask(umask)
    try:
        if state == 'latest' and version is not None:
            module.fail_json(msg='version is incompatible with state=latest')

        if chdir is None:
            # this is done to avoid permissions issues with privilege escalation and virtualenvs
            chdir = tempfile.gettempdir()

        err = ''
        out = ''

        if env:
            if not os.path.exists(os.path.join(env, 'bin', 'activate')):
                venv_created = True
                out, err = setup_virtualenv(module, env, chdir, out, err)

        pip = _get_pip(module, env, module.params['executable'])

        cmd = [pip] + state_map[state]

        # If there's a virtualenv we want things we install to be able to use other
        # installations that exist as binaries within this virtualenv. Example: we
        # install cython and then gevent -- gevent needs to use the cython binary,
        # not just a python package that will be found by calling the right python.
        # So if there's a virtualenv, we add that bin/ to the beginning of the PATH
        # in run_command by setting path_prefix here.
        path_prefix = None
        if env:
            path_prefix = "/".join(pip.split('/')[:-1])

        # Automatically apply -e option to extra_args when source is a VCS url. VCS
        # includes those beginning with svn+, git+, hg+ or bzr+
        has_vcs = False
        if name:
            for pkg in name:
                if pkg and _is_vcs_url(pkg):
                    has_vcs = True
                    break

            # convert raw input package names to Package instances
            packages = [Package(pkg) for pkg in _recover_package_name(name)]
            # check invalid combination of arguments
            if version is not None:
                if len(packages) > 1:
                    module.fail_json(
                        msg="'version' argument is ambiguous when installing multiple package distributions. "
                            "Please specify version restrictions next to each package in 'name' argument."
                    )
                if packages[0].has_version_specifier:
                    module.fail_json(
                        msg="The 'version' argument conflicts with any version specifier provided along with a package name. "
                            "Please keep the version specifier, but remove the 'version' argument."
                    )
                # if the version specifier is provided by version, append that into the package
                packages[0] = Package(to_native(packages[0]), version)

        if module.params['editable']:
            args_list = []  # used if extra_args is not used at all
            if extra_args:
                args_list = extra_args.split(' ')
            if '-e' not in args_list:
                args_list.append('-e')
                # Ok, we will reconstruct the option string
                extra_args = ' '.join(args_list)

        if extra_args:
            cmd.extend(shlex.split(extra_args))

        if name:
            cmd.extend(to_native(p) for p in packages)
        elif requirements:
            cmd.extend(['-r', requirements])
        else:
            module.exit_json(
                changed=False,
                warnings=["No valid name or requirements file found."],
            )

        if module.check_mode:
            if extra_args or requirements or state == 'latest' or not name:
                module.exit_json(changed=True)

            pkg_cmd, out_pip, err_pip = _get_packages(module, pip, chdir)

            out += out_pip
            err += err_pip

            changed = False
            if name:
                pkg_list = [p for p in out.split('\n') if not p.startswith('You are using') and not p.startswith('You should consider') and p]

                if pkg_cmd.endswith(' freeze') and ('pip' in name or 'setuptools' in name):
                    # Older versions of pip (pre-1.3) do not have pip list.
                    # pip freeze does not list setuptools or pip in its output
                    # So we need to get those via a specialcase
                    for pkg in ('setuptools', 'pip'):
                        if pkg in name:
                            formatted_dep = _get_package_info(module, pkg, env)
                            if formatted_dep is not None:
                                pkg_list.append(formatted_dep)
                                out += '%s\n' % formatted_dep

                for package in packages:
                    is_present = _is_present(module, package, pkg_list, pkg_cmd)
                    if (state == 'present' and not is_present) or (state == 'absent' and is_present):
                        changed = True
                        break
            module.exit_json(changed=changed, cmd=pkg_cmd, stdout=out, stderr=err)

        out_freeze_before = None
        if requirements or has_vcs:
            _, out_freeze_before, _ = _get_packages(module, pip, chdir)

        rc, out_pip, err_pip = module.run_command(cmd, path_prefix=path_prefix, cwd=chdir)
        out += out_pip
        err += err_pip
        if rc == 1 and state == 'absent' and \
           ('not installed' in out_pip or 'not installed' in err_pip):
            pass  # rc is 1 when attempting to uninstall non-installed package
        elif rc != 0:
            _fail(module, cmd, out, err)

        if state == 'absent':
            changed = 'Successfully uninstalled' in out_pip
        else:
            if out_freeze_before is None:
                changed = 'Successfully installed' in out_pip
            else:
                _, out_freeze_after, _ = _get_packages(module, pip, chdir)
                changed = out_freeze_before != out_freeze_after

        changed = changed or venv_created

        module.exit_json(changed=changed, cmd=cmd, name=name, version=version,
                         state=state, requirements=requirements, virtualenv=env,
                         stdout=out, stderr=err)
    finally:
        if old_umask is not None:
            os.umask(old_umask)