"No DSS URL or API key found from any location" when using dataiku.api_client() in plugin

Solved!
jarchen
Level 1
"No DSS URL or API key found from any location" when using dataiku.api_client() in plugin

Hi,

 

I am updating an in-house plugin where we want to access a login and password that are stored in an arbitrary project's variables. The plugin is a connector to read data from InfluxDB.

I first tested my code in a notebook, and the following does execute without error:

 

client = dataiku.api_client()
project = client.get_default_project()
project_variables = project.get_variables()
username = project_variables['standard']['influxdb_username']
password = project_variables['standard']['influxdb_password']
print("username: ", username)
print("password: ", password)

 

However when I put the same code (minus the two print statements) inside the plugin and then try to run it (i.e. create a new dataset, fill in the plugin-specific form and hit "TEST & GET SCHEMA"), I get the following error:

Test failed: Failed to initialize kernel : <class 'Exception'> : No DSS URL or API key found from any location

This error is caused by the line "dataiku.api_client()", however, as I understand it, it's supposed to inherit its API key from the user executing the plugin.

What am I doing wrong?

0 Kudos
1 Solution
VitaliyD
Dataiker

Hi,

It is not possible to call internal Dataiku API from the connector.py as the required context is not available there. Instead, you can move the credentials retrieval from project variables to the UI where it is available, and then you can set them as config params in the connector.json and access it from connector.py.

For this, you can utilise the python function used to get select params dynamically. Please refer to the example below:

1) Create resource folder under plugin root and a file(for example, helper.py) where the function will reside:

Screenshot 2021-10-29 at 13.52.11.png

Sample function code for the file below:

import dataiku
client = dataiku.api_client()
project = client.get_default_project()
project_variables = project.get_variables()

def do(payload, config, plugin_config, inputs):
    if payload.get('parameterName') == 'influxdb_username':
        print(project_variables['standard']['influxdb_username'])
        result =  [{ "value" : project_variables['standard']['influxdb_username'], "label" : project_variables['standard']['influxdb_username']}]
    if payload.get('parameterName') == 'influxdb_password':
        print(project_variables['standard']['influxdb_password'])
        result =  [{ "value" : project_variables['standard']['influxdb_password'], "label" : project_variables['standard']['influxdb_password']}]
    return {"choices": result}

2) Specify a SELECT params with "getChoicesFromPython: true" and point to the python file created earlier in the connector.json file:

"paramsPythonSetup": "helper.py",
    "params": [
        {
            "name": "influxdb_username",
            "label": "influxdb_username",
            "type": "SELECT",
            "getChoicesFromPython": true
        },
        {
            "name": "influxdb_password",
            "label": "influxdb_password",
            "type": "SELECT",
            "getChoicesFromPython": true
        }
    ]

3) Then get the credentials from the config params in the connector.py file:

class MyConnector(Connector):

    def __init__(self, config, plugin_config):
        Connector.__init__(self, config, plugin_config)  # pass the parameters to the base class
        self.username = self.config.get("influxdb_username", "defaultValue")
        self.password = self.config.get("influxdb_password", "defaultValue")

Now the credentials will be loaded from project variables and you will be able to select them on the connector page:

Screenshot 2021-10-29 at 14.04.15.png

Unfortunately, you will still need to select the credentials manually. To fill them dynamically and make them hidden, you will need to use a fully custom form.

Hope this helps.

View solution in original post

4 Replies
VitaliyD
Dataiker

Hi,

From the description, it looks like you are using the Dataset plugin component, but I can be wrong. Could you provide more details like what plugin component you are using, the full or at least the relevant part of the code where you are trying to use Dataiku API, what is the DSS version, and whether your DSS instance has UIF enabled to understand the context better?

0 Kudos
jarchen
Level 1
Author

Hi,


Thank you for the quick reply. Yes I am using the Dataset plugin component, i.e. I am writing in connector.py. I am on a DSS 8.0.1 instance and User Isolation is set to "no" in Administration > License.
This is the beginning of connector.py:

# This file is the actual code for the custom Python dataset first-plugin_influxdb
from six.moves import xrange
from dataiku.connector import Connector,CustomDatasetWriter
from influxdb import InfluxDBClient,DataFrameClient
import requests
import dataiku

"""
A custom Python dataset is a subclass of Connector.
The parameters it expects and some flags to control its handling by DSS are
specified in the connector.json file.
Note: the name of the class itself is not relevant.
"""
class MyConnector(Connector):

    def __init__(self, config, plugin_config):

        Connector.__init__(self, config, plugin_config)  # pass the parameters to the base class
        
        client = dataiku.api_client()
        project = client.get_default_project()
        project_variables = project.get_variables()
        self.username = project_variables['standard']['influxdb_username']
        self.password = project_variables['standard']['influxdb_password']
		#self.username=plugin_config.get("username", None)
		#self.password = plugin_config.get("password",None)

With this code, if I then go to Datasets > + New Dataset > influxdb-plugin > influxdb read dataset, I then land on the configuration/test page for the dataset, and clicking on "Test & Get Schema" gives me the error listed in my previous post.

0 Kudos
VitaliyD
Dataiker

Hi,

It is not possible to call internal Dataiku API from the connector.py as the required context is not available there. Instead, you can move the credentials retrieval from project variables to the UI where it is available, and then you can set them as config params in the connector.json and access it from connector.py.

For this, you can utilise the python function used to get select params dynamically. Please refer to the example below:

1) Create resource folder under plugin root and a file(for example, helper.py) where the function will reside:

Screenshot 2021-10-29 at 13.52.11.png

Sample function code for the file below:

import dataiku
client = dataiku.api_client()
project = client.get_default_project()
project_variables = project.get_variables()

def do(payload, config, plugin_config, inputs):
    if payload.get('parameterName') == 'influxdb_username':
        print(project_variables['standard']['influxdb_username'])
        result =  [{ "value" : project_variables['standard']['influxdb_username'], "label" : project_variables['standard']['influxdb_username']}]
    if payload.get('parameterName') == 'influxdb_password':
        print(project_variables['standard']['influxdb_password'])
        result =  [{ "value" : project_variables['standard']['influxdb_password'], "label" : project_variables['standard']['influxdb_password']}]
    return {"choices": result}

2) Specify a SELECT params with "getChoicesFromPython: true" and point to the python file created earlier in the connector.json file:

"paramsPythonSetup": "helper.py",
    "params": [
        {
            "name": "influxdb_username",
            "label": "influxdb_username",
            "type": "SELECT",
            "getChoicesFromPython": true
        },
        {
            "name": "influxdb_password",
            "label": "influxdb_password",
            "type": "SELECT",
            "getChoicesFromPython": true
        }
    ]

3) Then get the credentials from the config params in the connector.py file:

class MyConnector(Connector):

    def __init__(self, config, plugin_config):
        Connector.__init__(self, config, plugin_config)  # pass the parameters to the base class
        self.username = self.config.get("influxdb_username", "defaultValue")
        self.password = self.config.get("influxdb_password", "defaultValue")

Now the credentials will be loaded from project variables and you will be able to select them on the connector page:

Screenshot 2021-10-29 at 14.04.15.png

Unfortunately, you will still need to select the credentials manually. To fill them dynamically and make them hidden, you will need to use a fully custom form.

Hope this helps.

jarchen
Level 1
Author

Thanks! This helped a lot.

0 Kudos