Skip to content

Commit 67375c2

Browse files
authored
Merge pull request #22 from rdytech/NEP-17834-setup-for-multi-env-configs
Nep 17834 setup for multi env configs
2 parents c8554f7 + 07fdbb7 commit 67375c2

File tree

10 files changed

+343
-10
lines changed

10 files changed

+343
-10
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
superset-*.gem
1414

1515
# ignore local .env variables
16-
.env
16+
.env*
1717

1818
# ignore local log file
1919
log/superset-client.log

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
## Change Log
22

3+
## 0.1.5 - 2024-05-10
4+
5+
* add multi config for multi env creds https://github.com/rdytech/superset-client/pull/22
6+
* add endpoint for sqllab/execute https://github.com/rdytech/superset-client/pull/22
7+
* add endpoint for database/list https://github.com/rdytech/superset-client/pull/22
8+
* add delete cascade endpoint by @jbat in https://github.com/rdytech/superset-client/pull/21
9+
10+
## 0.1.4 - 2024-05-01
11+
12+
* Filter dashboards by array of tags by @jbat in https://github.com/rdytech/superset-client/pull/20
13+
* adds endpoints for Delete of dashboards, charts, datasets @jbat in https://github.com/rdytech/superset-client/pull/20
14+
* adds endpoints for BulkDelete of dashboards, charts, datasets @jbat in https://github.com/rdytech/superset-client/pull/20
15+
316
## 0.1.3 - 2024-04-23
417

518
* duplicate dashboard should also create embedded setting by @jbat in https://github.com/rdytech/superset-client/pull/14

bin/console

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,35 @@ Dir["./lib/**/*.rb"].each { |f| require f }
1818

1919
require "pry"
2020

21+
# if accessing multiple supeset host environments regularly you can optionally
22+
# setup multiple env files, see ./doc/setting_up_personal_api_credentials.md for more info
23+
if ENV['SUPERSET_ENVIRONMENT']
24+
env_file = ".env-#{ENV['SUPERSET_ENVIRONMENT']}"
25+
if File.exist?(env_file)
26+
Dotenv.overload(env_file)
27+
puts "ENV configuration loaded from from #{env_file}"
28+
else
29+
puts "Environment file #{env_file} not found"
30+
exit
31+
end
32+
end
33+
34+
35+
# Add the SUPERSET_ENVIRONMENT to the PRY prompt if it exists
36+
if ENV['SUPERSET_ENVIRONMENT']
37+
Pry.config.prompt = Pry::Prompt.new('custom', 'Custom Pry prompt with suffix', [proc do |target_self, nest_level, pry|
38+
"[#{pry.input_ring.size}] (#{":#{nest_level}" unless nest_level.zero?}ENV:#{ENV['SUPERSET_ENVIRONMENT'].upcase})> "
39+
end,
40+
proc do |target_self, nest_level, pry|
41+
"[#{pry.input_ring.size}] (#{":#{nest_level}" unless nest_level.zero?}ENV:#{ENV['SUPERSET_ENVIRONMENT'].upcase})* "
42+
end])
43+
end
44+
45+
unless ENV['SUPERSET_HOST'] && ENV['SUPERSET_API_USERNAME'] && ENV['SUPERSET_API_PASSWORD']
46+
puts "Missing environment variables. Check your .env file"
47+
puts "Please set each value for SUPERSET_HOST, SUPERSET_API_USERNAME, and SUPERSET_API_PASSWORD values"
48+
puts "Refer to ./doc/setting_up_personal_api_credentials.md for more info"
49+
exit
50+
end
51+
2152
Pry.start(__FILE__)

doc/setting_up_personal_api_credentials.md

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ Create your own .env file with
99

1010
Adjust .env as required.
1111
```
12-
ENV['SUPERSET_HOST'] = "https://your-superset-host.com"
13-
ENV['SUPERSET_API_USERNAME']="your-username"
14-
ENV['SUPERSET_API_PASSWORD']="your-password"
12+
SUPERSET_HOST="https://your-superset-host.com"
13+
SUPERSET_API_USERNAME="your-username"
14+
SUPERSET_API_PASSWORD="your-password"
1515
```
1616

17+
If you have multiple superset hosts across various environments you also have the option
18+
to create individual env files per environment. More details below.
19+
1720
## What is my user name?
1821

1922
If your Superset instance is setup to authenicate via SSO then your authenticating agent will most likely have provided a username for you in the form of a UUID value.
@@ -57,6 +60,59 @@ Edit the params to only consist of only the password field and the value of your
5760

5861
And click Execute.
5962

60-
Create your `.env`
61-
Add your username and password to the `.env` file.
63+
Within your `.env` now add your username and password.
64+
65+
# Accessing API across Multiple Environments
66+
67+
Given some local development requirements where you have to access multiple superset hosts across various environments with different credentials you can setup the env creds as follows.
68+
69+
Just set the overall superset environment in `.env`
70+
71+
```
72+
# .env file holding one setting for the overall superset environment
73+
SUPERSET_ENVIRONMENT='staging'
74+
```
75+
76+
Then create a new file called `.env-staging` that holds your superset staging host and credentials.
77+
78+
```
79+
# specific settings for the superset staging host
80+
SUPERSET_HOST="https://your-staging-superset-host.com"
81+
SUPERSET_API_USERNAME="staging-user-here"
82+
SUPERSET_API_PASSWORD="set-password-here"
83+
```
84+
85+
Do the same for production env.
86+
Create a new file called `.env-production` that holds your superset production host and credentials.
87+
88+
```
89+
# specific settings for the superset production host
90+
SUPERSET_HOST="https://your-production-superset-host.com"
91+
SUPERSET_API_USERNAME="production-user-here"
92+
SUPERSET_API_PASSWORD="set-password-here"
93+
```
94+
95+
The command `bin/console` will then load your env file depending on the value in ENV['SUPERSET_ENVIRONMENT'] from the primary `.env`.
96+
97+
When you need to switch envs, exit the console, edit the .env to your desired value, eg `production`, then open a console again.
98+
99+
Bonus is the Pry prompt will now also include the `SUPERSET_ENVIRONMENT` value.
100+
101+
```
102+
bin/console
103+
ENV configuration loaded from from .env-staging
104+
[1] (ENV:STAGING)> Superset::Dashboard::List.new(title_contains: 'video').list
105+
106+
Happi: GET https://your-staging-superset-host.com/api/v1/dashboard/?q=(filters:!((col:dashboard_title,opr:ct,value:'video')),page:0,page_size:100), {}
107+
+----+------------------+-----------+------------------------------------------------------------------+
108+
| Superset::Dashboard::List |
109+
+----+------------------+-----------+------------------------------------------------------------------+
110+
| Id | Dashboard title | Status | Url |
111+
+----+------------------+-----------+------------------------------------------------------------------+
112+
| 6 | Video Game Sales | published | https://your-staging-superset-host.com/superset/dashboard/6/ |
113+
+----+------------------+-----------+------------------------------------------------------------------+
114+
```
115+
116+
117+
62118

lib/superset/database/list.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Usage: Superset::Database::List.call
2+
# Usage: Superset::Dashboard::List.new(title_contains: 'test').list
3+
4+
module Superset
5+
module Database
6+
class List < Superset::Request
7+
attr_reader :title_contains
8+
9+
def initialize(page_num: 0, title_contains: '')
10+
@title_contains = title_contains
11+
super(page_num: page_num)
12+
end
13+
14+
def self.call
15+
self.new.list
16+
end
17+
18+
def response
19+
validate_constructor_args
20+
super
21+
end
22+
23+
def ids
24+
result.map { |d| d[:id] }
25+
end
26+
27+
private
28+
29+
def route
30+
"database/?q=(#{query_params})"
31+
end
32+
33+
def filters
34+
# TODO filtering across all list classes can be refactored to support multiple options in a more flexible way
35+
filter_set = []
36+
filter_set << "(col:database_name,opr:ct,value:'#{title_contains}')" if title_contains.present?
37+
unless filter_set.empty?
38+
"filters:!(" + filter_set.join(',') + "),"
39+
end
40+
end
41+
42+
def list_attributes
43+
[:id, :database_name, :backend, :expose_in_sqllab]
44+
end
45+
46+
def validate_constructor_args
47+
raise InvalidParameterError, "title_contains must be a String type" unless title_contains.is_a?(String)
48+
end
49+
end
50+
end
51+
end

lib/superset/sqllab/execute.rb

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
module Superset
2+
module Sqllab
3+
class Execute < Superset::Request
4+
class InvalidParameterError < StandardError; end
5+
6+
attr_reader :database_id, :query, :schema
7+
8+
def initialize(database_id: , query: , schema: 'public')
9+
@database_id = database_id
10+
@query = query
11+
@schema = schema
12+
end
13+
14+
def perform
15+
validate_constructor_args
16+
response
17+
data
18+
end
19+
20+
def response
21+
@response ||= client.post(route, query_params)
22+
end
23+
24+
def data
25+
response["data"]
26+
end
27+
28+
private
29+
30+
def route
31+
"sqllab/execute/"
32+
end
33+
34+
def query_params
35+
{
36+
database_id: database_id,
37+
sql: query,
38+
schema: schema,
39+
queryLimit: 1000,
40+
runAsync: false,
41+
}
42+
end
43+
44+
def validate_constructor_args
45+
raise InvalidParameterError, "database_id integer is required" unless database_id.present? && database_id.is_a?(Integer)
46+
raise InvalidParameterError, "query string is required" unless query.present? && query.is_a?(String)
47+
raise InvalidParameterError, "schema must be a String type" unless schema.is_a?(String)
48+
end
49+
end
50+
end
51+
end

lib/superset/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# frozen_string_literal: true
22

33
module Superset
4-
VERSION = "0.1.4"
4+
VERSION = "0.1.5"
55
end

spec/superset/dashboard/list_spec.rb

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,5 @@
108108
"),page:3,page_size:100")
109109
end
110110
end
111-
112-
113111
end
114-
115112
end
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
require 'spec_helper'
2+
3+
RSpec.describe Superset::Database::List do
4+
subject { described_class.new }
5+
let(:result) do
6+
[
7+
{
8+
id: 1,
9+
database_name: 'Test 1',
10+
backend: 'postgres',
11+
expose_in_sqllab: 'true'
12+
},
13+
{
14+
id: 2,
15+
database_name: 'Test 2',
16+
backend: 'mysql',
17+
expose_in_sqllab: 'false'
18+
}
19+
]
20+
end
21+
22+
before do
23+
allow(subject).to receive(:result).and_return(result)
24+
end
25+
26+
describe '#rows' do
27+
specify do
28+
expect(subject.rows).to match_array(
29+
[
30+
['1', "Test 1", "postgres", "true"],
31+
['2', 'Test 2', 'mysql', "false"]
32+
]
33+
)
34+
end
35+
end
36+
37+
describe '#query_params' do
38+
context 'for pagination' do
39+
context 'with defaults' do
40+
specify do
41+
expect(subject.query_params).to eq("page:0,page_size:100")
42+
end
43+
end
44+
45+
context 'with specifiec page' do
46+
subject { described_class.new(page_num: 5) }
47+
48+
specify do
49+
expect(subject.query_params).to eq("page:5,page_size:100")
50+
end
51+
end
52+
end
53+
54+
context 'with title_contains filters' do
55+
subject { described_class.new(title_contains: 'acme') }
56+
57+
specify do
58+
expect(subject.query_params).to eq("filters:!((col:database_name,opr:ct,value:'acme')),page:0,page_size:100")
59+
end
60+
end
61+
end
62+
end

0 commit comments

Comments
 (0)