holistics 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/holistics/api_client.rb +133 -131
- data/lib/holistics/custom_logger.rb +31 -0
- data/lib/holistics/version.rb +1 -1
- data/lib/holistics.rb +15 -2
- data/lib/{holistics/tabular_formatter.rb → tabular_formatter.rb} +1 -2
- data/lib/{holistics/cucumber/vcr.rb → vcr.rb} +0 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61601d17f426d38122402a767f5b4534e6671b50
|
4
|
+
data.tar.gz: 0c533d1dcb1f12c193ebc79fb168db3524a2fde6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b77f45439562d748fd22fb498e5dc9f130f9d36e18cd67b2bdf05c5a1230e528d6bdba20e4cabd6135d3fe2364f0ac6a9012b8d824ac985ebd8a5827cd0aa6e
|
7
|
+
data.tar.gz: 9ae95aa35c514d7860963d07180d091d3f3b67a75a59e16bff113817e4e231865687accec89143688e7e6f33105a57750eec562d9cb09c5f7eb036735881f97a
|
data/lib/holistics/api_client.rb
CHANGED
@@ -1,169 +1,171 @@
|
|
1
1
|
require 'httparty'
|
2
|
-
require '
|
2
|
+
require 'tabular_formatter'
|
3
3
|
require 'yaml'
|
4
4
|
require 'json'
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
module Holistics
|
7
|
+
class ApiClient
|
8
|
+
SERVER_URL = 'https://secure.holistics.io/'
|
8
9
|
|
9
|
-
|
10
|
-
puts 'Logging in...'
|
11
|
-
response, ok = holistics_authenticate(token)
|
12
|
-
if ok
|
13
|
-
parsed = JSON.parse(response.body)
|
14
|
-
puts 'Authentication successful. Info:'
|
15
|
-
puts "- ID: #{parsed['id']}"
|
16
|
-
puts "- Email: #{parsed['email']}"
|
10
|
+
def initialize
|
17
11
|
|
18
|
-
write_token_to_gconfig(token)
|
19
|
-
else
|
20
|
-
puts 'Error logging in. Please check your token again.'
|
21
12
|
end
|
22
|
-
end
|
23
13
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
14
|
+
def login token
|
15
|
+
puts 'Logging in...'
|
16
|
+
response, ok = holistics_authenticate(token)
|
17
|
+
if ok
|
18
|
+
parsed = JSON.parse(response.body)
|
19
|
+
puts 'Authentication successful. Info:'
|
20
|
+
puts "- ID: #{parsed['id']}"
|
21
|
+
puts "- Email: #{parsed['email']}"
|
29
22
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
23
|
+
write_token_to_gconfig(token)
|
24
|
+
else
|
25
|
+
puts 'Error logging in. Please check your token again.'
|
26
|
+
end
|
27
|
+
end
|
34
28
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
29
|
+
def holistics_authenticate(token)
|
30
|
+
url = api_url_for('users/info.json', token)
|
31
|
+
response = HTTParty.get(url)
|
32
|
+
return response, (response.code == 200)
|
33
|
+
end
|
39
34
|
|
40
|
-
|
35
|
+
def job_show options
|
36
|
+
job_id = options[:job_id]
|
37
|
+
tail_job(job_id)
|
38
|
+
end
|
41
39
|
|
42
|
-
|
43
|
-
|
44
|
-
|
40
|
+
def ds_list
|
41
|
+
url = api_url_for('data_sources.json')
|
42
|
+
response = HTTParty.get(url)
|
43
|
+
err_and_exit('Error retrieving list of data sources', response) if response_has_error?(response)
|
45
44
|
|
46
|
-
|
47
|
-
end
|
45
|
+
parsed = JSON.parse(response.body)
|
48
46
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
response = submit_transport_job(params)
|
47
|
+
table = [%w(ID Type Name)]
|
48
|
+
rows = parsed.map { |record| [record['id'], record['dbtype'], record['name']] }
|
49
|
+
table.concat(rows)
|
53
50
|
|
54
|
-
|
51
|
+
puts TabularFormatter.new(table).to_pretty_table
|
52
|
+
end
|
55
53
|
|
56
|
-
|
57
|
-
|
54
|
+
def send_transport(options)
|
55
|
+
puts 'Submitting transport job ...'
|
56
|
+
params = build_submit_params(options)
|
57
|
+
response = submit_transport_job(params)
|
58
58
|
|
59
|
-
|
60
|
-
tail_job(job_id)
|
61
|
-
end
|
59
|
+
err_and_exit("Error submitting transport job", response) if response_has_error?(response)
|
62
60
|
|
63
|
-
def tail_job(job_id)
|
64
|
-
last_ts = ''
|
65
|
-
while true
|
66
|
-
response = fetch_job_status(job_id)
|
67
61
|
parsed = JSON.parse(response.body)
|
68
|
-
|
62
|
+
job_id = parsed['job_id']
|
69
63
|
|
70
|
-
|
71
|
-
|
72
|
-
print_log(log)
|
73
|
-
end
|
74
|
-
last_ts = logs.last['created_at'] if logs.size > 0
|
75
|
-
break unless has_more?(parsed['status'])
|
76
|
-
sleep 1
|
64
|
+
puts "Job submitted. Job ID: #{job_id}."
|
65
|
+
tail_job(job_id)
|
77
66
|
end
|
78
|
-
end
|
79
67
|
|
80
|
-
|
81
|
-
|
82
|
-
|
68
|
+
def tail_job(job_id)
|
69
|
+
last_id = 0
|
70
|
+
while true
|
71
|
+
response = fetch_job_details(job_id, last_id)
|
72
|
+
parsed = JSON.parse(response.body)
|
83
73
|
|
84
|
-
|
85
|
-
%w(running created).include?(status)
|
86
|
-
end
|
74
|
+
logs = parsed['logs']
|
87
75
|
|
88
|
-
|
89
|
-
HTTParty.post(server_url + 'transports/submit.json', body: params.to_json, headers: {'Content-Type' => 'application/json'})
|
90
|
-
end
|
76
|
+
logs.each { |log| print_log(log) }
|
91
77
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
elsif ENV['STAGING']
|
97
|
-
'https://staging.holistics.io'
|
98
|
-
elsif ENV['HOST']
|
99
|
-
ENV['HOST']
|
100
|
-
else
|
101
|
-
SERVER_URL
|
78
|
+
last_id = logs.last['id'] if logs.size > 0
|
79
|
+
break unless parsed['has_more']
|
80
|
+
|
81
|
+
sleep 0.5
|
102
82
|
end
|
103
|
-
|
104
|
-
host
|
105
|
-
end
|
83
|
+
end
|
106
84
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
params
|
111
|
-
end
|
85
|
+
def fetch_job_details(job_id, last_id = 0)
|
86
|
+
HTTParty.get(api_url_for("jobs/#{job_id}.json?last_id=#{last_id}"))
|
87
|
+
end
|
112
88
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
return JSON.parse(File.read(filepath))
|
117
|
-
elsif file_ext == '.yml'
|
118
|
-
return YAML.load(File.read(filepath))
|
119
|
-
else
|
120
|
-
raise StandardError.new 'Invalid config file extension. Please use either JSON or YML'
|
121
|
-
end
|
122
|
-
rescue StandardError => e
|
123
|
-
STDERR.puts "Error parsing transport config file: #{e.message}"
|
124
|
-
exit 1
|
125
|
-
end
|
89
|
+
def submit_transport_job(params)
|
90
|
+
HTTParty.post(server_url + 'transports/submit.json', body: params.to_json, headers: {'Content-Type' => 'application/json'})
|
91
|
+
end
|
126
92
|
|
127
|
-
|
128
|
-
|
129
|
-
|
93
|
+
def server_url
|
94
|
+
host =
|
95
|
+
if ENV['DEV'] || ENV['TEST']
|
96
|
+
'http://localhost:3000'
|
97
|
+
elsif ENV['STAGING']
|
98
|
+
'https://staging.holistics.io'
|
99
|
+
elsif ENV['HOST']
|
100
|
+
ENV['HOST']
|
101
|
+
else
|
102
|
+
SERVER_URL
|
103
|
+
end
|
104
|
+
host += '/' if host[-1] != '/'
|
105
|
+
host
|
106
|
+
end
|
130
107
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
else
|
136
|
-
raise StandardError.new 'Holistics config file not found'
|
108
|
+
def build_submit_params(options)
|
109
|
+
params = options.except(:config_path).merge(_utoken: get_token_from_gconfig)
|
110
|
+
params[:configs] = parse_transport_config(options[:config_path]).to_json if options[:config_path]
|
111
|
+
params
|
137
112
|
end
|
138
|
-
end
|
139
113
|
|
140
|
-
|
141
|
-
|
142
|
-
|
114
|
+
def parse_transport_config(filepath)
|
115
|
+
file_ext = File.extname(filepath).downcase
|
116
|
+
if file_ext == '.json'
|
117
|
+
return JSON.parse(File.read(filepath))
|
118
|
+
elsif file_ext == '.yml'
|
119
|
+
return YAML.load(File.read(filepath))
|
120
|
+
else
|
121
|
+
raise StandardError.new 'Invalid config file extension. Please use either JSON or YML'
|
122
|
+
end
|
123
|
+
rescue StandardError => e
|
124
|
+
STDERR.puts "Error parsing transport config file: #{e.message}"
|
125
|
+
exit 1
|
126
|
+
end
|
143
127
|
|
144
|
-
|
145
|
-
|
146
|
-
|
128
|
+
def authenticated?
|
129
|
+
File.exists?(get_gconfig_filepath)
|
130
|
+
end
|
147
131
|
|
148
|
-
|
149
|
-
|
150
|
-
|
132
|
+
def get_token_from_gconfig
|
133
|
+
if authenticated?
|
134
|
+
string = YAML.load_file(get_gconfig_filepath)
|
135
|
+
string['token']
|
136
|
+
else
|
137
|
+
raise StandardError.new 'Holistics config file not found'
|
138
|
+
end
|
139
|
+
end
|
151
140
|
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
STDERR.puts response.body
|
156
|
-
exit 1
|
157
|
-
end
|
141
|
+
def get_gconfig_filepath
|
142
|
+
File.expand_path('~/.holistics.yml', __FILE__)
|
143
|
+
end
|
158
144
|
|
159
|
-
|
160
|
-
|
161
|
-
|
145
|
+
def api_url_for(path, token = nil)
|
146
|
+
"#{server_url}#{path}?_utoken=#{token || get_token_from_gconfig}"
|
147
|
+
end
|
162
148
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
end
|
149
|
+
def print_log log
|
150
|
+
ts = Time.parse(log['created_at'])
|
151
|
+
Holistics.logger.log(log['level'], log['message'], timestamp: ts)
|
152
|
+
end
|
168
153
|
|
169
|
-
|
154
|
+
def err_and_exit(message, response)
|
155
|
+
STDERR.puts message
|
156
|
+
STDERR.puts "Error Response Code: #{response.code}"
|
157
|
+
STDERR.puts response.body
|
158
|
+
exit 1
|
159
|
+
end
|
160
|
+
|
161
|
+
def response_has_error?(response)
|
162
|
+
response.code != 200
|
163
|
+
end
|
164
|
+
|
165
|
+
def write_token_to_gconfig(token)
|
166
|
+
file_path = File.join(ENV['HOME'], '.holistics.yml')
|
167
|
+
h = {'token' => token}
|
168
|
+
File.write(file_path, h.to_yaml)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Custom logger class that allows
|
2
|
+
module Holistics
|
3
|
+
class CustomLogger
|
4
|
+
|
5
|
+
def initialize out
|
6
|
+
@out = out
|
7
|
+
end
|
8
|
+
|
9
|
+
def log(level, data, options = {})
|
10
|
+
t = options[:timestamp] || Time.now.utc
|
11
|
+
@out.puts "#{t} - #{level.to_s.upcase.ljust(5)} #{data}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def info data, options = {}
|
15
|
+
log('info', data, options)
|
16
|
+
end
|
17
|
+
|
18
|
+
def debug data, options = {}
|
19
|
+
log('debug', data, options)
|
20
|
+
end
|
21
|
+
|
22
|
+
def warn data, options = {}
|
23
|
+
log('warn', data, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def error data, options = {}
|
27
|
+
log('error', data, options)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
data/lib/holistics/version.rb
CHANGED
data/lib/holistics.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'holistics/api_client'
|
3
|
-
require '
|
3
|
+
require 'vcr'
|
4
4
|
|
5
|
-
|
5
|
+
module Holistics
|
6
6
|
def self.root
|
7
7
|
Pathname.new(__FILE__).parent.parent
|
8
8
|
end
|
9
|
+
|
10
|
+
def logger
|
11
|
+
@logger ||= CustomLogger.new(STDOUT)
|
12
|
+
end
|
13
|
+
|
9
14
|
end
|
10
15
|
|
11
16
|
# Right now we can't do `holistics ds:list`
|
@@ -13,6 +18,14 @@ end
|
|
13
18
|
# Either we use other libs, or figure out an elegant way to do it without
|
14
19
|
|
15
20
|
class HolisticsRunner < Thor
|
21
|
+
|
22
|
+
method_option :verbosity, aliases: '-v', type: :numeric, default: 2, required: false,
|
23
|
+
desc: 'Set the logging verbosity. Values range from 1 (log everything) to 6 (log nothing)'
|
24
|
+
|
25
|
+
def initialize(args=[], options={}, config={})
|
26
|
+
super(args, options, config)
|
27
|
+
end
|
28
|
+
|
16
29
|
desc 'login [auth_token]', 'Perform authentication'
|
17
30
|
|
18
31
|
def login token
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'csv'
|
2
2
|
require 'active_support/all'
|
3
3
|
|
4
|
-
|
5
4
|
class TabularFormatter
|
6
5
|
|
7
6
|
def initialize input_data, options = {}
|
@@ -39,7 +38,7 @@ class TabularFormatter
|
|
39
38
|
str << "-#{'-' * l}-+"
|
40
39
|
end.chomp!("+")
|
41
40
|
divider = divider[1..-1]
|
42
|
-
output.insert(1,divider)
|
41
|
+
output.insert(1, divider)
|
43
42
|
output.join("\n").concat("\n")
|
44
43
|
end
|
45
44
|
|
File without changes
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: holistics
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thanh Dinh Khac
|
@@ -80,9 +80,10 @@ files:
|
|
80
80
|
- holistics.gemspec
|
81
81
|
- lib/holistics.rb
|
82
82
|
- lib/holistics/api_client.rb
|
83
|
-
- lib/holistics/
|
84
|
-
- lib/holistics/tabular_formatter.rb
|
83
|
+
- lib/holistics/custom_logger.rb
|
85
84
|
- lib/holistics/version.rb
|
85
|
+
- lib/tabular_formatter.rb
|
86
|
+
- lib/vcr.rb
|
86
87
|
homepage: http://rubygems.org/gems/holistics-cli
|
87
88
|
licenses:
|
88
89
|
- GPL
|