Exemplo n.º 1
0
    def run(self, progress_callback):
        client = DSSClient('http://localhost:%s' % os.environ.get('DKU_BACKEND_PORT'), internal_ticket = os.environ.get('DKU_API_TICKET'))

        rt = ResultTable()
        rt.set_name("Killed sessions")

        rt.add_column("session_id", "Session id", "STRING")
        rt.add_column("notebook_project", "Notebook project key", "STRING")
        rt.add_column("notebook_project", "Notebook name", "STRING")

        simulate = self.config.get('simulate', True)

        max_idle = float(self.config.get('maxIdleTimeHours', 0))
        max_age = float(self.config.get('maxSessionAgeHours', 0))

        dont_kill_busy = self.config.get('dontKillBusyKernels', True)
        dont_kill_connected = self.config.get('dontKillConnectedKernels', True)

        now = get_epochtime_ms()

        logging.info("Listing notebooks max_age_ms=%s max_idle_ms=%s" % (max_age * 1000 * 3600, max_idle * 1000 * 3600))

        for nbk in client.list_running_notebooks():
            state = nbk.get_state()

            for session in state["activeSessions"]:
                logging.info("Check kill of %s session_age=%s kernel_idle=%s" % (
                    session, (now - session["sessionStartTime"]), (now - session["kernelLastActivityTime"])))

                kill = False

                if max_age > 0 and (now - session["sessionStartTime"]) > max_age * 1000 * 3600:
                    logging.info( " -> Will kill on max_age")
                    kill = True

                if max_idle > 0 and (now - session["kernelLastActivityTime"]) > max_idle * 1000 * 3600:
                    logging.info( " -> Will kill on max_idle")
                    kill = True

                if dont_kill_busy and session["kernelExecutionState"] == "busy":
                    logging.info(" -> Don't kill (busy)")
                    kill = False

                if dont_kill_connected and session["kernelConnections"] > 0:
                    logging.info(" -> Don't kill (connected)")
                    kill = False

                if kill:
                    logging.info("Unloading session %s" % session["sessionId"])
                    rt.add_record([session["sessionId"], session.get("projectKey", "?"), session.get("notebookName", "?")])

                    if not simulate:
                        nbk.unload(session["sessionId"])
                else:
                    logging.info("Don't kill %s" % session["sessionId"])
        return rt
Exemplo n.º 2
0
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        connect_to=dict(type='dict', required=False, default={}, no_log=True),
        host=dict(type='str', required=False, default="127.0.0.1"),
        port=dict(type='str', required=False, default=None),
        api_key=dict(type='str', required=False, default=None),
        settings=dict(type='dict', required=False, default={}),
    )

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

    args = MakeNamespace(module.params)
    api_key = args.api_key if args.api_key is not None else args.connect_to.get(
        "api_key", None)
    if api_key is None:
        module.fail_json(
            msg=
            "Missing an API Key, either from 'api_key' or 'connect_to' parameters"
            .format(args.state))
    port = args.port if args.port is not None else args.connect_to.get(
        "port", "80")
    host = args.host

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

    client = None
    general_settings = None
    try:
        client = DSSClient("http://{}:{}".format(args.host, port),
                           api_key=api_key)
        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="{}: {}".format(type(e).__name__, str(e)))
Exemplo n.º 3
0
class MyRunnable(Runnable):
    def __init__(self, project_key, config, plugin_config):
        self.project_key = project_key
        self.config = config
        self.plugin_config = plugin_config
        self.client = DSSClient('http://localhost:%s' % os.environ.get('DKU_BACKEND_PORT'), internal_ticket = os.environ.get('DKU_API_TICKET'))
        
    def get_progress_target(self):
        return None
    
    def run(self, progress_callback):
        included = self.config.get('includedTags', '')
        excluded = self.config.get('excludedTags', '')
        included_or = self.config.get('includedTagsCombine', 'OR') == 'OR'
        excluded_or = self.config.get('excludedTagsCombine', 'OR') == 'OR'
        included_set = set(included.split(','))
        excluded_set = set(excluded.split(','))

        project = self.client.get_project(self.project_key)
        to_delete = []
        for dataset in project.list_datasets():
            tags = dataset.get('tags', [])
            included = apply(tags, included_set, included_or)
            excluded = apply(tags, excluded_set, excluded_or)
            if included and not excluded:
                to_delete.append(dataset)

        rt = ResultTable()
        rt.set_name("Delete datasets by tag")

        simulate = self.config.get('simulate', True)

        rt.add_column("dataset", simulate and "Dataset to delete" or "Deleted dataset", "LOCAL_DATASET_WITH_TYPE")
        if not simulate:
            rt.add_column("result", "Result", "STRING")

        if not simulate:
            for dataset in to_delete:
                try:
                    project.get_dataset(dataset.get('name')).delete(drop_data=self.config.get("drop_data", True))
                    rt.add_record(["%s:%s" % (dataset.get("type"), dataset.get("name")), "SUCCESS"])
                except Exception as e:
                    rt.add_record(["%s:%s" % (dataset.get("type"), dataset.get("name")), "FAILED: %s" % str(e)])
            return rt
        else:
            rows = []
            for dataset in to_delete:
                rt.add_record(["%s:%s" % (dataset.get("type"), dataset.get("name"))])
            return rt
Exemplo n.º 4
0
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        connect_to=dict(type='dict', required=False, default={}, no_log=True),
        host=dict(type='str', required=False, default="127.0.0.1"),
        port=dict(type='str', required=False, default=None),
        api_key=dict(type='str', required=False, default=None),
        state=dict(type='str', required=False, default="present"),
        id=dict(type='str', required=True),
        stage=dict(type='str', required=True),
        type=dict(type='str', required=True),
        api_nodes=dict(type='list', required=True),
        permissions=dict(type='list', required=False, default=[]),
        carbonapi_url=dict(type='str', required=False, default=None),
    )

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

    args = MakeNamespace(module.params)
    api_key = args.api_key if args.api_key is not None else args.connect_to.get(
        "api_key", None)
    if api_key is None:
        module.fail_json(
            msg=
            "Missing an API Key, either from 'api_key' or 'connect_to' parameters"
            .format(args.state))
    port = args.port if args.port is not None else args.connect_to.get(
        "port", "80")
    host = args.host

    result = dict(
        changed=False,
        message='UNCHANGED',
        id=args.id,
    )

    client = None
    exists = True
    create = False
    infra = None
    try:
        client = DSSClient("http://{}:{}".format(args.host, port),
                           api_key=api_key)
        api_deployer = client.get_apideployer()
        infras_status = api_deployer.list_infras(as_objects=False)
        infras_id = []
        for infra_status in infras_status:
            infras_id.append(infra_status["infraBasicInfo"]["id"])
        exists = args.id in infras_id
        if not exists and args.state == "present":
            create = True

        result["changed"] = create or (exists and args.state == "absent")
        if result["changed"]:
            if create:
                result["message"] = "CREATED"
            elif exists:
                if args.state == "absent":
                    result["message"] = "DELETED"
                elif current != new_def:
                    result["message"] = "MODIFIED"

        # Prepare the result for dry-run mode
        if module.check_mode:
            module.exit_json(**result)

        # Apply the changes
        if args.state == "present":
            if create:
                infra = api_deployer.create_infra(args.id, args.stage,
                                                  args.type)
            else:
                infra = api_deployer.get_infra(args.id)
            infra_settings = infra.get_settings()
            previous_settings = copy.deepcopy(infra_settings.get_raw())

            # Remove all / push all
            infra_settings.get_raw()["permissions"] = args.permissions
            infra_settings.get_raw()["apiNodes"] = []
            for api_node in args.api_nodes:
                infra_settings.add_apinode(
                    api_node["url"], api_node["admin_api_key"],
                    api_node.get("graphite_prefix", None))
            if args.carbonapi_url is not None:
                infra_settings.get_raw().update({
                    "carbonAPISettings": {
                        "carbonAPIURL": args.carbonapi_url
                    }
                })
            infra_settings.save()
            if infra_settings.get_raw(
            ) != previous_settings and not result["changed"]:
                result["changed"] = True
                result["message"] = "MODIFIED"

        if args.state == "absent" and exits:
            # TODO implement
            pass

        module.exit_json(**result)
    except Exception as e:
        module.fail_json(msg="{}: {}".format(type(e).__name__, str(e)))
Exemplo n.º 5
0
 def __init__(self, project_key, config, plugin_config):
     self.project_key = project_key
     self.config = config
     self.plugin_config = plugin_config
     self.client = DSSClient('http://localhost:%s' % os.environ.get('DKU_BACKEND_PORT'), internal_ticket = os.environ.get('DKU_API_TICKET'))
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        connect_to=dict(type='dict', required=False, default={}, no_log=True),
        host=dict(type='str', required=False, default="127.0.0.1"),
        port=dict(type='str', required=False, default=None),
        api_key=dict(type='str', required=False, default=None),
        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),
    )

    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))
    api_key = args.api_key if args.api_key is not None else args.connect_to.get("api_key",None)
    if api_key is None:
        module.fail_json(msg="Missing an API Key, either from 'api_key' or 'connect_to' parameters".format(args.state))
    port = args.port if args.port is not None else args.connect_to.get("port","80")
    host = args.host

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

    try:
        client = DSSClient("http://{}:{}".format(args.host, port),api_key=api_key)
        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="{}: {}".format(type(e).__name__,str(e)))
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        connect_to=dict(type='dict', required=False, default={}, no_log=True),
        host=dict(type='str', required=False, default="127.0.0.1"),
        port=dict(type='str', required=False, default=None),
        api_key=dict(type='str', required=False, default=None),
        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),
        #params=dict(type='dict', default={}, required=False),
    )

    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))
    api_key = args.api_key if args.api_key is not None else args.connect_to.get("api_key",None)
    if api_key is None:
        module.fail_json(msg="Missing an API Key, either from 'api_key' or 'connect_to' parameters".format(args.state))
    port = args.port if args.port is not None else args.connect_to.get("port","80")
    host = args.host
    type = args.type

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

    try:
        client = DSSClient("http://{}:{}".format(args.host, port),api_key=api_key)
        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"]):
                    #for field in encrypted_fields_list:
                        #new_def_value = encrypted_fields.get(field, None)
                        ## TODO: Bugfix about password here
                        #del new_def["params"][field]
                        ##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"]):
                        ## Get again the definition to test again the encrypted fields
                        #new_def_after_submit = connection.get_definition()
                        #encrypted_fields_after_change = {"params":{}}
                        #for field in encrypted_fields_list:
                            #value = new_def_after_submit.get(field,None)
                            #if value is not None:
                                #encrypted_fields_after_change["params"][field] = value
                        #if encrypted_fields_before_change != encrypted_fields_after_change:
                            #result["changed"] = True
                            #result["message"] = "MODIFIED"

        module.exit_json(**result)
    except Exception as e:
        module.fail_json(msg="{}: {}".format(pytypefunc(e).__name__,str(e)))
Exemplo n.º 8
0
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        connect_to=dict(type='dict', required=False, default={}, no_log=True),
        host=dict(type='str', required=False, default="127.0.0.1"),
        port=dict(type='str', required=False, default=None),
        api_key=dict(type='str', required=False, default=None),
        login=dict(type='str', required=True),
        password=dict(type='str', required=False, default=None, no_log=True),
        set_password_at_creation_only=dict(type='bool', required=False, default=True),
        email=dict(type='str', required=False, default=None),
        display_name=dict(type='str', required=False, default=None),
        groups=dict(type='list', required=False, default=None),
        profile=dict(type='str', required=False, default=None),
        source_type=dict(type='str', required=False, default="LOCAL"),
        state=dict(type='str', required=False, default="present"),
        )

    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.state))
    api_key = args.api_key if args.api_key is not None else args.connect_to.get("api_key",None)
    if api_key is None:
        module.fail_json(msg="Missing an API Key, either from 'api_key' or 'connect_to' parameters".format(args.state))
    port = args.port if args.port is not None else args.connect_to.get("port","80")
    host = args.host

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

    client = DSSClient("http://{}:{}".format(args.host, port),api_key=api_key)
    user = DSSUser(client, args.login)
    try:
        user_exists = True
        create_user = False
        current_user = None
        try:
            current_user = user.get_definition()
        except DataikuException as e:
            if e.message.startswith("com.dataiku.dip.server.controllers.NotFoundException"):
                user_exists = False
                if args.state == "present":
                    create_user = True
            else:
                raise
        except:
            raise

        # Manage errors
        if args.source_type not in ["LOCAL","LDAP","LOCAL_NO_AUTH"]:
            module.fail_json(msg="Invalid value '{}' for source_type : must be either 'LOCAL', 'LDAP' or 'LOCAL_NO_AUTH'".format(args.source_type))
        if args.password is None and create_user and args.source_type not in ['LDAP','LOCAL_NO_AUTH']:
            module.fail_json(msg="The 'password' parameter is missing but is mandatory to create new local user '{}'.".format(args.login))
        if args.display_name is None and create_user:
            #module.fail_json(msg="The 'display_name' parameter is missing but is mandatory to create new user '{}'.".format(args.login))
            # TODO: shall we fail here or use a default to login ?
            args.display_name = module.params["display_name"] = args.login
        if args.groups is None and create_user:
            args.groups = module.params["groups"] = ["readers"]

        # Build the new user definition
        # TODO: be careful that the key names changes between creation and edition
        new_user_def = copy.deepcopy(current_user) if user_exists else {} # Used for modification
        result["previous_user_def"] = copy.deepcopy(new_user_def)
        for key, api_param in [("email","email"),("display_name","displayName"),("profile","userProfile"),("groups","groups"),("source_type","sourceType")]:
            if module.params.get(key,None) is not None:
                value = module.params[key]
                if isinstance(value,six.string_types):
                    value = value.decode("UTF-8")
                new_user_def[key if create_user else api_param] = value
        if user_exists and args.password is not None and not args.set_password_at_creation_only:
            new_user_def["password"] = args.password

        # Sort groups list before comparison as they should be considered sets
        new_user_def.get("groups",[]).sort()
        if user_exists:
            current_user.get("groups",[]).sort()

        # Prepare the result for dry-run mode
        result["changed"] = create_user or (user_exists and args.state == "absent") or (user_exists and current_user != new_user_def)
        if result["changed"]:
            if create_user:
                result["message"] = "CREATED"
            elif user_exists:
                if  args.state == "absent":
                    result["message"] = "DELETED"
                elif current_user != new_user_def:
                    result["message"] = "MODIFIED"

        # Can be useful to register info from a playbook and act on it
        if args.state == "present":
            result["user_def"] = new_user_def

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

        # Apply the changes
        if result["changed"]:
            if create_user:
                create_excluded_keys = ["email"]
                create_excluded_values = {}
                for create_excluded_key in create_excluded_keys:
                    if new_user_def.get(create_excluded_key,None) is not None:
                        create_excluded_values[create_excluded_key] = new_user_def[create_excluded_key]
                        del new_user_def[create_excluded_key]
                new_user = client.create_user(args.login, args.password, **new_user_def)
                if module.params.get("email",None) is not None:
                    new_user_def_mod = new_user.get_definition()
                    new_user_def_mod.update(create_excluded_values)
                    new_user.set_definition(new_user_def_mod)
            elif user_exists:
                if args.state == "absent":
                    user.delete()
                elif current_user != new_user_def:
                    result["message"] = str(user.set_definition(new_user_def))

        module.exit_json(**result)
    except Exception as e:
        module.fail_json(msg=str(e))
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        connect_to=dict(type='dict', required=False, default={}, no_log=True),
        host=dict(type='str', required=False, default="127.0.0.1"),
        port=dict(type='str', required=False, default=None),
        api_key=dict(type='str', required=False, default=None),
        name=dict(type='str', required=True),
        description=dict(type='str', required=False, default=None),
        source_type=dict(type='str', required=False, default=None),
        state=dict(type='str', required=False, default="present"),
        admin=dict(type='bool', required=False, default=None),
        ldap_group_names=dict(type='list', required=False, default=None),
        may_create_authenticated_connections=dict(type='bool', required=False, default=None),
        may_create_code_envs=dict(type='bool', required=False, default=None),
        may_create_projects=dict(type='bool', required=False, default=None),
        may_develop_plugins=dict(type='bool', required=False, default=None),
        may_edit_lib_folders=dict(type='bool', required=False, default=None),
        may_manage_code_envs=dict(type='bool', required=False, default=None),
        may_manage_u_d_m=dict(type='bool', required=False, default=None),
        may_view_indexed_hive_connections=dict(type='bool', required=False, default=None),
        may_write_safe_code=dict(type='bool', required=False, default=True),
        may_write_unsafe_code=dict(type='bool', required=False, default=None),
    )

    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))
    if args.source_type not in [None,"LOCAL","LDAP","SAAS"]:
        module.fail_json(msg="Invalid value '{}' for source_type : must be either 'LOCAL', 'LDAP' or 'SAAS'".format(args.state))
    api_key = args.api_key if args.api_key is not None else args.connect_to.get("api_key",None)
    if api_key is None:
        module.fail_json(msg="Missing an API Key, either from 'api_key' or 'connect_to' parameters".format(args.state))
    port = args.port if args.port is not None else args.connect_to.get("port","80")
    host = args.host

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

    client = DSSClient("http://{}:{}".format(args.host, port),api_key=api_key)
    group = DSSGroup(client, args.name)
    try:
        exists = True
        create = False
        current = None
        try:
            current = group.get_definition()
        except DataikuException as e:
            if e.message.startswith("com.dataiku.dip.server.controllers.NotFoundException"):
                exists = False
                if args.state == "present":
                    create = True
            else:
                raise
        except:
            raise


        # Sort groups list before comparison as they should be considered sets
        if exists:
            current["ldapGroupNames"]= ",".join(sorted(current.get("ldapGroupNames","").split(",")))
            result["previous_group_def"] = current
        # Build the new user definition
        new_def = copy.deepcopy(current) if exists else {} # Used for modification

        # Transform to camel case
        dict_args = {}
        if args.ldap_group_names is not None:
            dict_args["ldapGroupNames"] = ",".join(sorted(args.ldap_group_names))
        for key, value in module.params.items():
            if key not in ["connect_to","host","port","api_key","state","ldap_group_names"] and value is not None:
                camelKey = re.sub(r'_[a-z]', lambda x : x.group()[1:].upper(), key)
                dict_args[camelKey] = value
        new_def.update(dict_args)

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

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

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

        # Apply the changes
        if result["changed"]:
            if create:
                new_group = client.create_group(args.name, description = new_def.get("description",None), source_type=new_def.get("source_type","LOCAL"))
                # 2nd request mandatory for capabilites TODO: fix the API
                if "mayWriteSafeCode" not in new_def.keys():
                    new_def["mayWriteSafeCode"] = True
                new_group.set_definition(new_def)
                result["group_def"] = new_group.get_definition()
            elif exists:
                if args.state == "absent":
                    group.delete()
                elif current != new_def:
                    result["message"] = str(group.set_definition(new_def))

        module.exit_json(**result)
    except Exception as e:
        module.fail_json(msg="{}: {}".format(type(e).__name__,str(e)))
Exemplo n.º 10
0
def run_module():
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        connect_to=dict(type='dict', required=False, default={}, no_log=True),
        host=dict(type='str', required=False, default="127.0.0.1"),
        port=dict(type='str', required=False, default=None),
        api_key=dict(type='str', required=False, default=None),
        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),
        jupyter_support=dict(type='bool', required=False, default=None),
        update=dict(type='bool', required=False, default=True),
        desc=dict(type='dict', required=False, default=None),
    )

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

    args = MakeNamespace(module.params)
    api_key = args.api_key if args.api_key is not None else args.connect_to.get("api_key",None)
    if api_key is None:
        module.fail_json(msg="Missing an API Key, either from 'api_key' or 'connect_to' parameters".format(args.state))
    port = args.port if args.port is not None else args.connect_to.get("port","80")
    host = args.host

    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 = {}
    try:
        client = DSSClient("http://{}:{}".format(args.host, port),api_key=api_key)
        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()

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

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

        # Apply the changes
        if args.state == "present":
            previous_code_env_def = copy.deepcopy(code_env_def)
            if create:
                if args.deployment_mode is None:
                    raise Exception("The argument deployment_mode is mandatory to create a code env")
                code_env = client.create_code_env(args.lang,args.name,args.deployment_mode,args.desc)
                code_env_def = code_env.get_definition()

            if args.desc is not None:
                update(code_env_def, args.desc)

            if args.jupyter_support is not None:
                code_env.set_jupyter_support(args.jupyter_support)

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

            if previous_code_env_def != code_env_def:
                if args.update and not create:
                    code_env.update_packages()
                result["changed"] = True
                result["message"] = "MODIFIED"

        if args.state == "absent" and exits:
            if exists:
                code_env.delete()
                result["message"] = "DELETED"
            
        module.exit_json(**result)
    except Exception as e:
        module.fail_json(msg="{}: {}".format(type(e).__name__,str(e)))