def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(settings=dict(type="dict", required=False,
                                     default={}), )
    add_dss_connection_args(module_args)

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    args = MakeNamespace(module.params)

    result = dict(changed=False,
                  message="UNCHANGED",
                  previous_settings=None,
                  settings=None)

    client = None
    general_settings = None
    try:
        client = get_client_from_parsed_args(module)
        general_settings = client.get_general_settings()
        current_values = extract_keys(general_settings.settings, args.settings)

        # Prepare the result for dry-run mode
        result["previous_settings"] = current_values
        result["dss_general_settings"] = general_settings.settings
        result["changed"] = current_values != args.settings
        if result["changed"]:
            result["message"] = "MODIFIED"

        if module.check_mode:
            module.exit_json(**result)

        # Apply the changes
        update(general_settings.settings, args.settings)
        general_settings.save()
        module.exit_json(**result)
    except Exception as e:
        module.fail_json(msg="{}\n\n{}\n\n{}".format(
            str(e), traceback.format_exc(), "".join(traceback.format_stack())))
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        name=dict(type="str", required=True),
        state=dict(type="str", required=False, default="present"),
        postgresql_host=dict(type="str", default=None, required=False),
        postgresql_port=dict(type="str", default=None, required=False),
        user=dict(type="str", default=None, required=False),
        password=dict(type="str", required=False, no_log=True),
        database=dict(type="str", default=None, required=False),
        additional_args=dict(type="dict", default={}, required=False),
    )
    add_dss_connection_args(module_args)

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    args = MakeNamespace(module.params)
    if args.state not in ["present", "absent"]:
        module.fail_json(
            msg=
            "Invalid value '{}' for argument state : must be either 'present' or 'absent'"
            .format(args.source_type))

    result = dict(
        changed=False,
        message="UNCHANGED",
    )

    try:
        client = get_client_from_parsed_args(module)
        exists = True
        create = False
        connection = client.get_connection(args.name)
        current_def = None
        try:
            current_def = connection.get_definition()
        except DataikuException as e:
            # if e.message.startswith("com.dataiku.dip.server.controllers.NotFoundException"):
            if str(
                    e
            ) == "java.lang.IllegalArgumentException: Connection '{}' does not exist".format(
                    args.name):
                exists = False
                if args.state == "present":
                    create = True
            else:
                raise
        except Exception as e:
            raise

        current_def = None
        encrypted_password_before_change = None
        if exists:
            result[
                "previous_group_def"] = current_def = connection.get_definition(
                )
            # Check this is the same type
            if current_def["type"] != connection_template["type"]:
                module.fail_json(
                    msg="Connection '{}' already exists but is of type '{}'".
                    format(args.name, current_def["type"]))
                return
            # Remove some values from the current def
            encrypted_password_before_change = current_def["params"].get(
                "password", None)
            if encrypted_password_before_change is not None:
                del current_def["params"]["password"]
        else:
            if args.state == "present":
                for mandatory_create_param in [
                        "user", "password", "database", "postgresql_host"
                ]:
                    if module.params[mandatory_create_param] is None:
                        module.fail_json(
                            msg=
                            "Connection '{}' does not exist and cannot be created without the '{}' parameter"
                            .format(args.name, mandatory_create_param))

        # Build the new definition
        new_def = copy.deepcopy(
            current_def
        ) if exists else connection_template  # Used for modification

        # Apply every attribute except the password for now
        new_def["name"] = args.name
        if args.database is not None:
            new_def["params"]["db"] = args.database
        if args.user is not None:
            new_def["params"]["user"] = args.user
        if args.postgresql_host is not None:
            new_def["params"]["host"] = args.postgresql_host
        if args.postgresql_port is not None:
            new_def["params"]["port"] = args.postgresql_port

        # Bonus args
        update(new_def, args.additional_args)

        # Prepare the result for dry-run mode
        result["changed"] = create or (exists and args.state == "absent") or (
            exists and current_def != new_def)
        if result["changed"]:
            if create:
                result["message"] = "CREATED"
            elif exists:
                if args.state == "absent":
                    result["message"] = "DELETED"
                elif current_def != new_def:
                    result["message"] = "MODIFIED"

        if args.state == "present":
            result["connection_def"] = new_def

        if module.check_mode:
            module.exit_json(**result)

        ## Apply the changes
        if result["changed"] or (args.password is not None and exists):
            if create:
                new_def["params"]["password"] = args.password
                params = {
                    "db": args.database,
                    "user": args.user,
                    "password": args.password,
                    "host": args.postgresql_host,
                }
                if args.postgresql_port is not None:
                    params["port"] = args.postgresql_port
                connection = client.create_connection(
                    args.name, connection_template["type"], params)
                connection.set_definition(
                    new_def)  # 2nd call to apply additional parameters
            elif exists:
                if args.state == "absent":
                    connection.delete()
                elif current_def != new_def or args.password is not None:
                    if args.password is not None:
                        new_def["params"]["password"] = args.password
                    else:
                        new_def["params"][
                            "password"] = encrypted_password_before_change
                    result["message"] = str(connection.set_definition(new_def))
                    if args.password is not None:
                        # Get again the definition to test again the encrypted pass
                        new_def_after_submit = connection.get_definition()
                        if encrypted_password_before_change != new_def_after_submit[
                                "params"]["password"]:
                            result["changed"] = True
                            result["message"] = "MODIFIED"

        module.exit_json(**result)
    except Exception as e:
        module.fail_json(msg="{}\n\n{}\n\n{}".format(
            str(e), traceback.format_exc(), "".join(traceback.format_stack())))
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        name=dict(type="str", required=True),
        state=dict(type="str", required=False, default="present"),
        type=dict(type="str", required=True),
        connection_args=dict(type="dict", default={}, required=False),
        set_encrypted_fields_at_creation_only=dict(type="bool",
                                                   default=False,
                                                   required=False),
        # params=dict(type='dict', default={}, required=False),
    )
    add_dss_connection_args(module_args)

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    args = MakeNamespace(module.params)
    if args.state not in ["present", "absent"]:
        module.fail_json(
            msg=
            "Invalid value '{}' for argument state : must be either 'present' or 'absent'"
            .format(args.source_type))
    type = args.type

    result = dict(
        changed=False,
        message="UNCHANGED",
    )

    try:
        client = get_client_from_parsed_args(module)
        exists = True
        create = False
        connection = client.get_connection(args.name)
        current_def = None
        try:
            current_def = connection.get_definition()
        except DataikuException as e:
            # if e.message.startswith("com.dataiku.dip.server.controllers.NotFoundException"):
            if str(
                    e
            ) == "java.lang.IllegalArgumentException: Connection '{}' does not exist".format(
                    args.name):
                exists = False
                if args.state == "present":
                    create = True
            else:
                raise
        except Exception as e:
            raise

        current_def = None
        encrypted_fields_before_change = {"params": {}}
        if exists:
            result[
                "previous_group_def"] = current_def = connection.get_definition(
                )
            # Check this is the same type
            if current_def["type"] != type:
                module.fail_json(
                    msg="Connection '{}' already exists but is of type '{}'".
                    format(args.name, current_def["type"]))
                return
            # Remove some values from the current def
            for field in encrypted_fields_list:
                encrypted_field_before_change = current_def["params"].get(
                    field, None)
                if encrypted_field_before_change is not None:
                    encrypted_fields_before_change["params"][
                        field] = encrypted_field_before_change
                    del current_def["params"][field]
        else:
            if args.state == "present":
                # for mandatory_create_param in ["user", "password", "database", "postgresql_host"]:
                # if module.params[mandatory_create_param] is None:
                # module.fail_json(msg="Connection '{}' does not exist and cannot be created without the '{}' parameter".format(args.name,mandatory_create_param))
                pass

        # Build the new definition
        new_def = copy.deepcopy(
            current_def
        ) if exists else connection_template  # Used for modification

        # Apply every attribute except the password for now
        new_def["name"] = args.name
        update(new_def, args.connection_args)

        # Extract args that may be encrypted
        encrypted_fields = {"params": {}}
        for field in encrypted_fields_list:
            value = new_def["params"].get(field, None)
            if value is not None:
                encrypted_fields["params"][field] = value
                del new_def["params"][field]

        # Prepare the result for dry-run mode
        result["changed"] = create or (exists and args.state == "absent") or (
            exists and current_def != new_def)
        if result["changed"]:
            if create:
                result["message"] = "CREATED"
            elif exists:
                if args.state == "absent":
                    result["message"] = "DELETED"
                elif current_def != new_def:
                    result["message"] = "MODIFIED"

        if args.state == "present":
            result["connection_def"] = new_def

        if module.check_mode:
            module.exit_json(**result)

        ## Apply the changes
        if result["changed"] or (0 < len(encrypted_fields["params"])
                                 and exists):
            if create:
                update(new_def, encrypted_fields)
                connection = client.create_connection(args.name, type,
                                                      new_def["params"])
                def_after_creation = connection.get_definition()
                update(def_after_creation, new_def)
                connection.set_definition(
                    def_after_creation
                )  # 2nd call to apply additional parameters
            elif exists:
                if args.state == "absent":
                    connection.delete()
                elif current_def != new_def or (
                        0 < len(encrypted_fields["params"])
                        and not args.set_encrypted_fields_at_creation_only):
                    for field in encrypted_fields_list:
                        new_def_value = encrypted_fields["params"].get(
                            field, None)
                        if new_def_value is not None:
                            new_def["params"][field] = new_def_value
                        else:
                            new_def["params"][
                                field] = encrypted_fields_before_change.get(
                                    field)
                    result["message"] = str(connection.set_definition(new_def))
                    if 0 < len(encrypted_fields["params"]):
                        # no need to compare, encrypted fields change value if reset
                        result["changed"] = True
                        result["message"] = "MODIFIED"

        module.exit_json(**result)
    except Exception as e:
        module.fail_json(msg="{}\n\n{}\n\n{}".format(
            str(e), traceback.format_exc(), "".join(traceback.format_stack())))
예제 #4
0
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        state=dict(type="str", required=False, default="present"),
        plugin_id=dict(type="str", required=True),
        zip_file=dict(type="str", required=False, default=None),
        git_repository_url=dict(type="str", required=False, default=None),
        git_checkout=dict(type="str", required=False, default="master"),
        git_subpath=dict(type="str", required=False, default=None),
        settings=dict(type="dict", required=False, default={}),
        force=dict(type="bool", required=False, default=False),
        install_code_env=dict(type="bool", required=False, default=True),
    )
    add_dss_connection_args(module_args)

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    args = MakeNamespace(module.params)

    result = dict(changed=False, message="UNCHANGED",)

    client = None
    exists = False
    create = False
    plugin = None
    create_code_env = False
    current_settings = {}
    try:
        client = get_client_from_parsed_args(module)
        plugins = client.list_plugins()
        plugin_dict = { plugin['id']: plugin for plugin in plugins }

        # Check existence
        if args.plugin_id in plugin_dict:
            exists = True

        if not exists and args.state == "present":
            create = True

        if exists:
            plugin = client.get_plugin(args.plugin_id)
            current_settings = copy.deepcopy(plugin.get_settings().get_raw())

        # Prepare the result for dry-run mode
        new_settings = copy.deepcopy(current_settings)
        if args.settings is not None:
            update(new_settings, args.settings)
        
        result["changed"] = create or (exists and (args.state == "absent" or (args.settings is not None and new_settings != current_settings) or (create_code_env and "codeEnvName" not in current_settings)))
        if result["changed"]:
            if create:
                result["message"] = "CREATED"
            elif exists:
                if args.state == "absent":
                    result["message"] = "DELETED"
                elif args.settings is not None:
                    result["message"] = "MODIFIED"
                else:
                    result["message"] = "UNMODIFIED"

        result["job_results"] = []
        result["dss_plugin"] = {
            "id": args.plugin_id,
        }
        if exists:
            result["dss_plugin"]["settings"] = new_settings
            update(result["dss_plugin"], plugin_dict[args.plugin_id])

        if module.check_mode:
            module.exit_json(**result)

        # Apply the changes
        if args.state == "present":
            plugin_desc = {}
            if not exists:
                future = None
                if args.zip_file is not None:
                    future = client.install_plugin_from_archive(args.zip_file)
                elif args.git_repository_url is not None:
                    future = client.install_plugin_from_git(args.git_repository_url, args.git_checkout, args.git_subpath)
                else:
                    # Install from store
                    future = client.install_plugin_from_store(args.plugin_id)
                result["job_results"].append(future.wait_for_result())
                plugin_desc = result["job_results"][-1].get("pluginDesc")

                # Required to relist for the meta
                plugins = client.list_plugins()
                plugin_dict = { plugin['id']: plugin for plugin in plugins }
                plugin = client.get_plugin(args.plugin_id)
                update(result["dss_plugin"], plugin_dict[args.plugin_id])

            elif args.force:
                future = None
                if args.zip_file is not None:
                    future = plugin.update_from_zip(args.zip_file)
                elif args.git_repository_url is not None:
                    future = plugin.update_from_git(args.git_repository_url, args.git_checkout, args.git_subpath)
                else:
                    # Install from store
                    future = plugin.update_from_store()
                result["job_results"].append(future.wait_for_result())
                plugin_desc = result["job_results"][-1].get("pluginDesc")

            # Force refetch settings
            current_settings = copy.deepcopy(plugin.get_settings().get_raw())
            new_settings = copy.deepcopy(current_settings)
            if args.settings is not None:
                update(new_settings, args.settings)

            if "codeEnvSpec" in plugin_desc and args.install_code_env:
                create_code_env = True
            result["dss_plugin"]["settings"] = new_settings

        code_env_install_result = None
        if args.state == "present" and create_code_env and "codeEnvName" not in new_settings:
            future = plugin.create_code_env()
            code_env_install_result = future.wait_for_result()
            new_settings["codeEnvName"] = code_env_install_result.get("envName")
            result["job_results"].append(code_env_install_result)

        if (args.settings is not None or code_env_install_result is not None) and args.state == "present" and new_settings != current_settings:
            settings_handle = plugin.get_settings()
            update(settings_handle.settings, new_settings)
            settings_handle.save()
            result["dss_plugin"]["settings"] = new_settings

        if args.state == "absent" and exists:
            future = plugin.delete(force=args.force)
            if future.job_id is not None:
                result["job_results"].append(future.wait_for_result())

        module.exit_json(**result)
    except Exception as e:
        module.fail_json(msg="{}\n\n{}\n\n{}".format(str(e), traceback.format_exc(), "".join(traceback.format_stack())))
예제 #5
0
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module

    #     Fields that can be updated in design node:

    #     * env.permissions, env.usableByAll, env.desc.owner
    #     * env.specCondaEnvironment, env.specPackageList, env.externalCondaEnvName, env.desc.installCorePackages,
    #       env.desc.installJupyterSupport, env.desc.yarnPythonBin

    #     Fields that can be updated in automation node (where {version} is the updated version):

    #     * env.permissions, env.usableByAll, env.owner
    #     * env.{version}.specCondaEnvironment, env.{version}.specPackageList, env.{version}.externalCondaEnvName,
    #       env.{version}.desc.installCorePackages, env.{version}.desc.installJupyterSupport, env.{version}.desc.yarnPythonBin

    # [ "version" { ]
    #   permissions, usableByAll, owner, specCondaEnvironement, specPackageList, externalCondaEnvName
    # desc(installCorePackages,installJupyterSupport, yarnPythonbin)
    # [ } ]
    module_args = dict(
        state=dict(type="str", required=False, default="present"),
        name=dict(type="str", required=True),
        lang=dict(type="str", required=True),
        deployment_mode=dict(type="str", required=False, default=None),
        version=dict(type="str", required=False, default=None),
        core_packages=dict(type="bool", required=False, default=True),
        jupyter_support=dict(type="bool", required=False, default=True),
        update=dict(type="bool", required=False, default=True),
        permissions=dict(type="list", required=False, default=None),
        usable_by_all=dict(type="bool", required=False, default=None),
        owner=dict(type="str", required=False, default=None),
        conda_environment=dict(type="str", required=False, default=None),
        package_list=dict(type="list", required=False, default=None),
        external_conda_env_name=dict(type="str", required=False, default=None),
        python_interpreter=dict(type="str", required=False, default=None),
        desc=dict(type="dict", required=False, default=None),
    )
    add_dss_connection_args(module_args)

    module = AnsibleModule(argument_spec=module_args, supports_check_mode=True)

    args = MakeNamespace(module.params)

    if args.lang not in ["PYTHON", "R"]:
        module.fail_json(
            msg=
            "The lang attribute has invalid value '{}'. Must be either 'PYTHON' or 'R'."
            .format(args.lang))

    result = dict(
        changed=False,
        message="UNCHANGED",
    )

    client = None
    exists = False
    create = False
    code_env = None

    code_env_def = {}

    required_code_env_def = {}
    versioned_required_code_env_def = required_code_env_def
    if args.version is not None:
        required_code_env_def[args.version] = {"desc": {}}
        versioned_required_code_env_def = required_code_env_def[args.version]
    else:
        required_code_env_def["desc"] = {}
    if args.permissions is not None:
        required_code_env_def["permissions"] = args.permissions
    if args.usable_by_all is not None:
        required_code_env_def["usableByAll"] = args.usable_by_all
    if args.conda_environment is not None:
        versioned_required_code_env_def[
            "specCondaEnvironment"] = args.conda_environment
    if args.package_list is not None:
        versioned_required_code_env_def["specPackageList"] = "\n".join(
            args.package_list)
    if args.external_conda_env_name is not None:
        versioned_required_code_env_def[
            "externalCondaEnvName"] = args.external_conda_env_name
    if args.owner is not None:
        if args.deployment_mode in [
                "DESIGN_MANAGED", "DESIGN_MANAGED", "PLUGIN_MANAGED",
                "PLUGIN_NON_MANAGED"
        ]:
            versioned_required_code_env_def["desc"]["owner"] = args.owner
        else:
            versioned_required_code_env_def["owner"] = args.owner
    if args.desc is not None:
        update(versioned_required_code_env_def["desc"], args.desc)

    if args.core_packages and "installCorePackages" not in versioned_required_code_env_def[
            "desc"]:
        versioned_required_code_env_def["desc"][
            "installCorePackages"] = args.core_packages

    if args.jupyter_support and "installJupyterSupport" not in versioned_required_code_env_def[
            "desc"]:
        versioned_required_code_env_def["desc"][
            "installJupyterSupport"] = args.jupyter_support

    update_packages = False

    try:
        client = get_client_from_parsed_args(module)
        code_envs = client.list_code_envs()

        # Check existence
        for env in code_envs:
            if env["envName"] == args.name and env["envLang"] == args.lang:
                exists = True
                break

        if not exists and args.state == "present":
            create = True

        if exists:
            code_env = client.get_code_env(args.lang, args.name)
            code_env_def = code_env.get_definition()
            if args.deployment_mode is None:
                args.deployment_mode = code_env_def["deploymentMode"]
            if "NON_MANAGED" not in args.deployment_mode:
                if args.version is not None:
                    if "specPackageList" in versioned_required_code_env_def and args.version in code_env_def and "specPackageList" in code_env_def[
                            args.version] and versioned_required_code_env_def[
                                "specPackageList"] != code_env_def[
                                    args.version]["specPackageList"]:
                        update_packages = True
                    if "installJupyterSupport" in versioned_required_code_env_def[
                            "desc"] and "installJupyterSupport" in code_env_def[
                                args.version][
                                    "desc"] and versioned_required_code_env_def[
                                        "desc"][
                                            "installJupyterSupport"] != code_env_def[
                                                args.version]["desc"][
                                                    "installJupyterSupport"]:
                        update_packages = True
                else:
                    if "specPackageList" in required_code_env_def and "specPackageList" in code_env_def and required_code_env_def[
                            "specPackageList"] != code_env_def[
                                "specPackageList"]:
                        update_packages = True
                    if "installJupyterSupport" in required_code_env_def[
                            "desc"] and "installJupyterSupport" in code_env_def[
                                "desc"] and required_code_env_def["desc"][
                                    "installJupyterSupport"] != code_env_def[
                                        "desc"]["installJupyterSupport"]:
                        update_packages = True

        new_code_env_def = copy.deepcopy(code_env_def)
        update(new_code_env_def, required_code_env_def)

        # Prepare the result for dry-run mode
        result["changed"] = create or (exists and args.state == "absent") or (
            args.state == "present" and new_code_env_def != code_env_def)
        if result["changed"]:
            if create:
                result["message"] = "CREATED"
            elif exists:
                if args.state == "absent":
                    result["message"] = "DELETED"
                else:
                    if code_env_def != new_code_env_def:
                        result["message"] = "MODIFIED"
                    else:
                        result["message"] = "UNMODIFIED"

        if module.check_mode:
            module.exit_json(**result)

        # Apply the changes
        if args.state == "present":
            if create:
                if args.deployment_mode is None:
                    raise Exception(
                        "The argument deployment_mode is mandatory to create a code env"
                    )
                if args.python_interpreter is not None:
                    versioned_required_code_env_def[
                        "pythonInterpreter"] = args.python_interpreter
                code_env = client.create_code_env(args.lang, args.name,
                                                  args.deployment_mode,
                                                  required_code_env_def)
                code_env_def = code_env.get_definition()
                new_code_env_def = copy.deepcopy(code_env_def)
                update(new_code_env_def, required_code_env_def)

            if new_code_env_def != code_env_def:
                code_env.set_definition(new_code_env_def)

            if (args.update or create or update_packages
                ) and "NON_MANAGED" not in args.deployment_mode:
                code_env.update_packages()

            if args.jupyter_support:
                code_env.set_jupyter_support(args.jupyter_support)

            code_env_def = code_env.get_definition()
            result["dss_code_env"] = code_env_def

            if new_code_env_def != code_env_def:
                result["changed"] = True

        if args.state == "absent" and exists:
            if exists:
                code_env.delete()

        module.exit_json(**result)
    except Exception as e:
        module.fail_json(msg="{}\n\n{}\n\n{}".format(
            str(e), traceback.format_exc(), "".join(traceback.format_stack())))