-
Notifications
You must be signed in to change notification settings - Fork 0
Snowflake plugin #40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
richbenwell
wants to merge
4
commits into
main
Choose a base branch
from
work/rb/snowflake
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+359
−0
Open
Snowflake plugin #40
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # Snowflake plugin | ||
|
|
||
| A simple data source for Snowflake that supports Snowflake SQL queries. Requires an OAuth connection. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| { | ||
| "steps": [ | ||
| { | ||
| "displayName": "API access", | ||
| "dataStream": { | ||
| "name": "sqlQuery", | ||
| "config": { | ||
| "query": "show databases" | ||
| } | ||
| }, | ||
| "success": "User credentials has Snowflake query permissions.", | ||
| "error": "User does not have permission to access the Snowflake API (query 'SHOW DATABASES' failed).", | ||
| "required": true | ||
| }, | ||
| { | ||
| "displayName": "Compute access", | ||
| "dataStream": { | ||
| "name": "sqlQuery", | ||
| "config": { | ||
| "query": "select 1/1", | ||
| "errorOnEmptyResults": true | ||
| } | ||
| }, | ||
| "success": "User has access to warehouse.", | ||
| "error": "User does not have access to a warehouse (query 'SELECT 1/1' failed). Check user's role is configured with a default warehouse and has warehouse permissions.", | ||
| "required": true | ||
| }, | ||
| { | ||
| "displayName": "Database access", | ||
| "dataStream": { | ||
| "name": "sqlQuery", | ||
| "config": { | ||
| "query": "show databases", | ||
| "errorOnEmptyResults": true | ||
| } | ||
| }, | ||
| "success": "User has access to at least one database.", | ||
| "error": "User does not have permission to access any databases. Check user's default role or specify a role.", | ||
| "required": false | ||
| } | ||
| ] | ||
| } | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| result = data.data.map( r => r.reduce((obj, value, i) => { | ||
| const columnName = data.resultSetMetaData.rowType[i].name; | ||
| obj[columnName] = value; | ||
| return obj; | ||
| }, {})); | ||
|
|
||
| // support value column for autoComplete queries | ||
| if (context.config.valueColumn) { | ||
| metadata = [ | ||
| { | ||
| name: context.config.valueColumn, | ||
| role: "value" | ||
| } | ||
| ] | ||
| } else { | ||
| const typeMapping = { | ||
| "text": "string", | ||
| "fixed": "number", | ||
| "real": "number", | ||
| "varchar": "string", | ||
| "date": "date", | ||
| "timestamp": "date" | ||
| }; | ||
|
|
||
| metadata = data.resultSetMetaData.rowType.map( c => { | ||
| return { | ||
| name: c.name, | ||
| shape: typeMapping[c.type] || "string" | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| // used for validation queries | ||
| if (context.config.errorOnEmptyResults === true && data.data.length === 0) { | ||
| throw new Error("No results"); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| { | ||
| "name": "sqlQuery", | ||
| "displayName": "SQL Query", | ||
| "baseDataSourceName": "httpRequestUnscoped", | ||
| "config": { | ||
| "httpMethod": "post", | ||
| "paging": { | ||
| "mode": "none" | ||
| }, | ||
| "expandInnerObjects": true, | ||
| "endpointPath": "/v2/statements/", | ||
| "postBody": { | ||
| "database": "{{typeof database !== 'undefined' ? database : undefined}}", | ||
| "schema": "{{typeof schema !== 'undefined' ? schema : undefined}}", | ||
| "statement": "{{query}}" | ||
| }, | ||
| "postRequestScript": "sqlQuery-post.js", | ||
| "getArgs": [], | ||
| "headers": [] | ||
| }, | ||
| "ui": [ | ||
| { | ||
| "name": "database", | ||
| "type": "autocomplete", | ||
| "label": "Database", | ||
| "validation": { | ||
| "required": false | ||
| }, | ||
| "isMulti": false, | ||
| "allowCustomValues": true, | ||
| "data": { | ||
| "source": "dataStream", | ||
| "dataStreamName": "sqlQuery", | ||
| "dataSourceConfig": { | ||
| "valueColumn": "name", | ||
| "query": "show databases" | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| "name": "schema", | ||
| "type": "autocomplete", | ||
| "label": "Schema", | ||
| "validation": { | ||
| "required": false | ||
| }, | ||
| "isMulti": false, | ||
| "allowCustomValues": true, | ||
| "data": { | ||
| "source": "dataStream", | ||
| "dataStreamName": "sqlQuery", | ||
| "dataSourceConfig": { | ||
| "valueColumn": "name", | ||
| "database": { | ||
| "fieldName": "database", | ||
| "required": true | ||
| }, | ||
| "query": "show schemas" | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| "help": "Enter a query using Snowflake SQL syntax. You can also use parameters like {{timeframe.start}}, e.g. event_time BETWEEN '{{timeframe.start}}' AND '{{timeframe.end}}'", | ||
| "name": "query", | ||
| "language": "sql", | ||
| "label": "SQL query", | ||
| "type": "code", | ||
| "validation": { | ||
| "required": true | ||
| } | ||
| } | ||
| ], | ||
| "manualConfigApply": true, | ||
| "supportsNoneTimeframe": true, | ||
| "requiresParameterTimeframe": true, | ||
| "defaultTimeframe": "none" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,99 @@ | ||
| # Before you start | ||
|
|
||
| ## Creating an OAuth integration in Snowflake | ||
|
|
||
| The Snowflake data source authenticates using OAuth. | ||
|
|
||
| Before configuring the data source you will need to register SquaredUp with your Snowflake account by creating a custom integration. | ||
|
|
||
| Sample Snowflake commands for creating the integration are provided below. | ||
|
|
||
| For more information on creating a Snowflake integration see: | ||
| https://docs.snowflake.com/en/sql-reference/sql/create-security-integration-oauth-snowflake | ||
|
|
||
|
|
||
| If your SquaredUp account is in the US region (default): | ||
|
|
||
| ``` | ||
| CREATE SECURITY INTEGRATION oauth_squaredup | ||
| TYPE = oauth | ||
| OAUTH_CLIENT = custom | ||
| OAUTH_CLIENT_TYPE = 'CONFIDENTIAL' | ||
| OAUTH_REDIRECT_URI = 'https://app.squaredup.com/settings/pluginsoauth2' | ||
| COMMENT = 'Used by SquaredUp to connect to this Snowflake account' | ||
| ``` | ||
|
|
||
| If your SquaredUp account is in the EU region: | ||
|
|
||
| ``` | ||
| CREATE SECURITY INTEGRATION oauth_squaredup | ||
| TYPE = oauth | ||
|
richbenwell marked this conversation as resolved.
|
||
| OAUTH_CLIENT = custom | ||
| OAUTH_CLIENT_TYPE = 'CONFIDENTIAL' | ||
| OAUTH_REDIRECT_URI = 'https://eu.app.squaredup.com/settings/pluginsoauth2' | ||
| COMMENT = 'Used by SquaredUp to connect to this Snowflake account' | ||
| ``` | ||
|
|
||
| Once your integration is created, run: | ||
|
|
||
| ``` | ||
| SELECT | ||
| oauth:OAUTH_CLIENT_SECRET::STRING AS OAUTH_CLIENT_SECRET, | ||
| oauth:OAUTH_CLIENT_ID::STRING AS OAUTH_CLIENT_ID | ||
| FROM (SELECT PARSE_JSON(SYSTEM$SHOW_OAUTH_CLIENT_SECRETS('oauth_squaredup')) AS oauth) | ||
|
|
||
| ``` | ||
|
|
||
| Use the values of the `OAUTH_CLIENT_ID` and `OAUTH_CLIENT_SECRET` columns in your configuration below. | ||
|
|
||
|
|
||
| ## Creating a read-only user | ||
|
|
||
| To connect to Snowflake you will need the credentials for a Snowflake user. | ||
|
|
||
| By default, it is NOT possible to connect via OAuth using an ACCOUNTADMIN role. Snowflake automatically adds privileged roles to the blocked role list used for OAuth authorization, see https://docs.snowflake.com/en/sql-reference/parameters#oauth-add-privileged-roles-to-blocked-list | ||
|
|
||
| We recommend a dedicated 'squaredup' user account that is assigned read only role. For more information on Snowflake users and roles, see https://docs.snowflake.com/en/user-guide/security-access-control-configure. | ||
|
|
||
| Ensure the user has a default role set, or specify the role when configuring the data source (see below). If the user does not have a default role and no role is specified, the connection will use the PUBLIC role, which typically does not have any permissions to databases. | ||
|
|
||
|
|
||
| # Configuration | ||
|
|
||
| ## Snowflake account identifier | ||
|
|
||
| Enter your Snowflake account identifier. | ||
|
|
||
| This can be found in the Snowflake portal under 'Your Username' > Account > Account Identifier. | ||
|
richbenwell marked this conversation as resolved.
|
||
|
|
||
| The account identifier is in the format <org_name>-<account_name>. | ||
|
|
||
| For example: `ABCDEFG-XYZ12345` | ||
|
|
||
| Alternatively, run the following Snowflake query: | ||
|
|
||
| ``` | ||
| SELECT CURRENT_ORGANIZATION_NAME() || '-' || CURRENT_ACCOUNT_NAME(); | ||
| ``` | ||
|
|
||
| ## Snowflake OAuth client ID | ||
|
|
||
| The client ID for your Snowflake OAuth application. | ||
|
|
||
| Enter the `OAUTH_CLIENT_ID` value from the integration you created above. | ||
|
|
||
| ## Snowflake OAuth client secret | ||
|
|
||
| The client secret for your Snowflake OAuth application. | ||
|
|
||
| Enter the `OAUTH_CLIENT_SECRET` value from the integration you created above. | ||
|
|
||
| ## Role (optional) | ||
|
|
||
| Restrict OAuth connection to a specific role. If not specified, the user's default role is used. | ||
|
|
||
| If you have created a custom role for your database, for example a read-only role, enter its name here. | ||
|
|
||
| ## Authorize | ||
|
|
||
| Click the Sign-in button to authorize SquaredUp to access Snowflake. | ||
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| { | ||
| "name": "snowflake", | ||
| "displayName": "Snowflake", | ||
| "version": "1.0.0", | ||
| "author": { | ||
| "name": "SquaredUp Labs", | ||
| "type": "labs" | ||
| }, | ||
| "description": "Query data from Snowflake.", | ||
| "category": "Database", | ||
| "type": "hybrid", | ||
| "schemaVersion": "2.0", | ||
| "base": { | ||
| "plugin": "WebAPI", | ||
| "majorVersion": "1", | ||
| "config": { | ||
| "queryArgs": [], | ||
| "headers": [], | ||
| "oauth2TokenExtraArgs": [], | ||
| "oauth2ClientSecret": "{{oauth2ClientSecret}}", | ||
| "oauth2ClientSecretLocationDuringAuth": "header", | ||
| "oauth2AuthUrl": "https://{{accountId}}.snowflakecomputing.com/oauth/authorize", | ||
| "authMode": "oauth2", | ||
| "oauth2GrantType": "authCode", | ||
| "baseUrl": "https://{{accountId}}.snowflakecomputing.com/api", | ||
| "oauth2TokenExtraHeaders": [ | ||
| { | ||
| "value": "application/x-www-form-urlencoded", | ||
| "key": "Content-Type" | ||
| } | ||
| ], | ||
| "oauth2ClientId": "{{oauth2ClientId}}", | ||
| "oauth2TokenUrl": "https://{{accountId}}.snowflakecomputing.com/oauth/token-request", | ||
| "oauth2AuthExtraArgs": [], | ||
| "oauth2Scope": "refresh_token {{oauth2Role? 'session:role:' + oauth2Role : ''}}" | ||
| } | ||
| }, | ||
| "links": [ | ||
| { | ||
| "category": "documentation", | ||
| "url": "https://github.com/squaredup/plugins/blob/main/plugins/Snowflake/v1/docs/setup.md", | ||
| "label": "Help adding this plugin" | ||
| }, | ||
| { | ||
| "category": "source", | ||
| "url": "https://github.com/squaredup/plugins/tree/main/plugins/Snowflake/v1", | ||
| "label": "Repository" | ||
| } | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| [ | ||
| { | ||
| "type": "text", | ||
| "name": "accountId", | ||
| "label": "Snowflake account identifier", | ||
| "help": "Enter your Snowflake account identifier. Find this in the portal under Your Username > Account > Account Identifier. It is in the format <org_name>-<account_name>, e.g. ABCDEFG-XYZ12345", | ||
| "validation": { | ||
| "required": true | ||
| }, | ||
| "placeholder": "<org_name>-<account_name>, e.g. ABCDEFG-XYZ12345" | ||
| }, | ||
| { | ||
| "type": "text", | ||
| "name": "oauth2ClientId", | ||
| "label": "Snowflake OAuth client ID", | ||
| "help": "The client ID for your Snowflake OAuth application. See documentation for details on how to set up an OAuth application in Snowflake and obtain the client ID.", | ||
| "validation": { | ||
| "required": true | ||
| }, | ||
| "placeholder": "Enter your Snowflake OAuth client ID" | ||
| }, | ||
| { | ||
| "type": "password", | ||
| "name": "oauth2ClientSecret", | ||
| "label": "Snowflake OAuth secret", | ||
| "help": "The client secret for your Snowflake OAuth application. See documentation for details on how to set up an OAuth application in Snowflake and obtain the client secret.", | ||
| "validation": { | ||
| "required": true | ||
| }, | ||
| "placeholder": "Enter your Snowflake OAuth secret" | ||
| }, | ||
| { | ||
| "type": "text", | ||
| "name": "oauth2Role", | ||
| "label": "Role (optional)", | ||
| "help": "Scope OAuth connection to a specific role. If not specified, the user's default role is used.", | ||
| "validation": { | ||
| "required": false | ||
| }, | ||
| "placeholder": "Enter your Snowflake OAuth role" | ||
| }, | ||
| { | ||
| "type": "oAuth2", | ||
| "name": "oauth2AuthCodeSignIn", | ||
| "label": "Authorize", | ||
| "validation": { | ||
| "required": true | ||
| } | ||
| } | ||
| ] |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.