MrMurano 1.3.1 → 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/TODO.taskpaper +9 -1
- data/lib/MrMurano/Account.rb +24 -69
- data/lib/MrMurano/Solution-Endpoint.rb +6 -2
- data/lib/MrMurano/Solution-File.rb +2 -1
- data/lib/MrMurano/Solution-ServiceConfig.rb +43 -34
- data/lib/MrMurano/Solution-Services.rb +5 -1
- data/lib/MrMurano/Solution.rb +7 -88
- data/lib/MrMurano/http.rb +103 -0
- data/lib/MrMurano/keystore.rb +1 -0
- data/lib/MrMurano/logs.rb +33 -17
- data/lib/MrMurano/timeseries.rb +15 -3
- data/lib/MrMurano/version.rb +1 -1
- data/lib/MrMurano.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02d6e091a69dd09c071539a97a2b9d3755ad9202
|
4
|
+
data.tar.gz: 46f2c3f6836c39648de3c08beef0eaf7c4ceb54b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa6b24a0ce013cb732a5563efbe86c54bbeb2cb9264cf69cc0dd1a7a43528f3fb22ef005af188ce7400ac2a7be40a9f716d850b395a24076edd550d8faf47d5c
|
7
|
+
data.tar.gz: 2633547b8be35f46ee9239b3092f8d6ebb7242fea6e8c62c53bdf9df93c461b57c22945a8fbabc556d054d64d85208052b8545d8a59bae85c464532e2b9ab389
|
data/TODO.taskpaper
CHANGED
@@ -2,12 +2,13 @@ Readme:
|
|
2
2
|
- Add more walk-thrus of common actions. (create new solution, …)
|
3
3
|
|
4
4
|
Commands:
|
5
|
-
- Status will show
|
5
|
+
- Status will show {modules,eventhandlers} have changes when they don’t.
|
6
6
|
- First time run needs to be smoothed out. @done(2016-08-09)
|
7
7
|
- Default for most commands should be -same @done(2016-08-02)
|
8
8
|
- Add Diff Command @done(2016-07-27)
|
9
9
|
|
10
10
|
Account:
|
11
|
+
- token is refetched many times. Do this once per run. @done(2016-09-12)
|
11
12
|
- Netrc library (or the netrc format) doesn't allow '#' in passwords. @done(2016-08-10)
|
12
13
|
|
13
14
|
Endpoints:
|
@@ -31,9 +32,15 @@ CORS:
|
|
31
32
|
- Get working with sync up/down.
|
32
33
|
- GET&PUT /cors data @done(2016-09-08)
|
33
34
|
|
35
|
+
Timeseries:
|
36
|
+
- Add CSV output option. @done(2016-09-09)
|
37
|
+
|
34
38
|
Product:
|
35
39
|
- Need to add way to set the product ID on a device eventhandler. @done(2016-08-01)
|
36
40
|
|
41
|
+
Service Device:
|
42
|
+
- When listing and bussiness.id is missing, gracefully fall back to --idonly @done(2016-09-12)
|
43
|
+
|
37
44
|
Config:
|
38
45
|
- Think about adding dev,staging,prod system; how would that work?
|
39
46
|
Would it work ok to just use the --configfile option?
|
@@ -43,6 +50,7 @@ Config:
|
|
43
50
|
- Maybe add dotenv support.
|
44
51
|
|
45
52
|
SolutionBase:
|
53
|
+
- Errors from the server should be displayed prettier.
|
46
54
|
- All network traffic is serialized. Make some parallel.
|
47
55
|
- JSON parse should use symbols for keys. @done(2016-09-01)
|
48
56
|
- Add the --curl verbose option. @done(2016-08-12)
|
data/lib/MrMurano/Account.rb
CHANGED
@@ -35,10 +35,10 @@ module MrMurano
|
|
35
35
|
end
|
36
36
|
hd = @data[host]
|
37
37
|
if hd.nil? or not hd.kind_of?(Hash) then
|
38
|
-
|
38
|
+
@data[host] = {user=>pass}
|
39
39
|
return
|
40
40
|
end
|
41
|
-
|
41
|
+
@data[host][user] = pass
|
42
42
|
return
|
43
43
|
end
|
44
44
|
def get(host, user)
|
@@ -51,14 +51,7 @@ module MrMurano
|
|
51
51
|
end
|
52
52
|
|
53
53
|
class Account
|
54
|
-
|
55
|
-
@json_opts = {
|
56
|
-
:allow_nan => true,
|
57
|
-
:symbolize_names => true,
|
58
|
-
:create_additions => false
|
59
|
-
}
|
60
|
-
end
|
61
|
-
|
54
|
+
include Http
|
62
55
|
|
63
56
|
def endPoint(path)
|
64
57
|
URI('https://' + $cfg['net.host'] + '/api:1/' + path.to_s)
|
@@ -86,84 +79,46 @@ module MrMurano
|
|
86
79
|
}
|
87
80
|
end
|
88
81
|
|
82
|
+
# Store the token in a class variable so that we only fetch it once per run
|
83
|
+
# session of this tool
|
84
|
+
@@token = nil
|
89
85
|
def token
|
90
|
-
if
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
#request.basic_auth(username(), password())
|
96
|
-
request.body = JSON.generate(_loginInfo)
|
97
|
-
|
98
|
-
response = http.request(request)
|
99
|
-
case response
|
100
|
-
when Net::HTTPSuccess
|
101
|
-
token = JSON.parse(response.body, @json_opts)
|
102
|
-
@token = token[:token]
|
103
|
-
else
|
104
|
-
say_error "No token! because: #{response}"
|
105
|
-
@token = nil
|
106
|
-
raise response
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
@token
|
111
|
-
end
|
86
|
+
if @@token.nil? then
|
87
|
+
# Cannot have token call token, so cannot use workit.
|
88
|
+
uri = endPoint('token/')
|
89
|
+
request = Net::HTTP::Post.new(uri)
|
90
|
+
curldebug(request)
|
112
91
|
|
113
|
-
def businesses
|
114
|
-
r = endPoint('user/' + $cfg['user.name'] + '/membership/')
|
115
|
-
Net::HTTP.start(r.host, r.port, :use_ssl=>true) do |http|
|
116
|
-
request = Net::HTTP::Get.new(r)
|
117
92
|
request.content_type = 'application/json'
|
118
|
-
request
|
93
|
+
#request.basic_auth(username(), password())
|
94
|
+
request.body = JSON.generate(_loginInfo)
|
119
95
|
|
120
96
|
response = http.request(request)
|
121
97
|
case response
|
122
98
|
when Net::HTTPSuccess
|
123
|
-
|
124
|
-
|
99
|
+
token = JSON.parse(response.body, json_opts)
|
100
|
+
@@token = token[:token]
|
125
101
|
else
|
102
|
+
say_error "No token! because: #{response}"
|
103
|
+
@@token = nil
|
126
104
|
raise response
|
127
105
|
end
|
128
106
|
end
|
107
|
+
@@token
|
108
|
+
end
|
109
|
+
|
110
|
+
def businesses
|
111
|
+
get('user/' + $cfg['user.name'] + '/membership/')
|
129
112
|
end
|
130
113
|
|
131
114
|
def products
|
132
115
|
raise "Missing Bussiness ID" if $cfg['business.id'].nil?
|
133
|
-
|
134
|
-
Net::HTTP.start(r.host, r.port, :use_ssl=>true) do |http|
|
135
|
-
request = Net::HTTP::Get.new(r)
|
136
|
-
request.content_type = 'application/json'
|
137
|
-
request['authorization'] = 'token ' + token
|
138
|
-
|
139
|
-
response = http.request(request)
|
140
|
-
case response
|
141
|
-
when Net::HTTPSuccess
|
142
|
-
busy = JSON.parse(response.body, @json_opts)
|
143
|
-
return busy
|
144
|
-
else
|
145
|
-
raise response
|
146
|
-
end
|
147
|
-
end
|
116
|
+
get('business/' + $cfg['business.id'] + '/product/')
|
148
117
|
end
|
149
118
|
|
150
119
|
def solutions
|
151
120
|
raise "Missing Bussiness ID" if $cfg['business.id'].nil?
|
152
|
-
|
153
|
-
Net::HTTP.start(r.host, r.port, :use_ssl=>true) do |http|
|
154
|
-
request = Net::HTTP::Get.new(r)
|
155
|
-
request.content_type = 'application/json'
|
156
|
-
request['authorization'] = 'token ' + token
|
157
|
-
|
158
|
-
response = http.request(request)
|
159
|
-
case response
|
160
|
-
when Net::HTTPSuccess
|
161
|
-
busy = JSON.parse(response.body, @json_opts)
|
162
|
-
return busy
|
163
|
-
else
|
164
|
-
raise response
|
165
|
-
end
|
166
|
-
end
|
121
|
+
get('business/' + $cfg['business.id'] + '/solution/')
|
167
122
|
end
|
168
123
|
|
169
124
|
end
|
@@ -20,7 +20,7 @@ module MrMurano
|
|
20
20
|
|
21
21
|
def fetch(id)
|
22
22
|
ret = get('/' + id.to_s)
|
23
|
-
aheader = ret[:script].lines.first.chomp
|
23
|
+
aheader = (ret[:script].lines.first or "").chomp
|
24
24
|
dheader = /^--#ENDPOINT (?i:#{ret[:method]}) #{ret[:path]}$/
|
25
25
|
rheader = %{--#ENDPOINT #{ret[:method]} #{ret[:path]}\n}
|
26
26
|
if block_given? then
|
@@ -86,7 +86,11 @@ module MrMurano
|
|
86
86
|
path = Pathname.new(path) unless path.kind_of? Pathname
|
87
87
|
aheader = path.readlines().first
|
88
88
|
md = /--#ENDPOINT (\S+) (.*)/.match(aheader)
|
89
|
-
|
89
|
+
if md.nil? then
|
90
|
+
rp = path.relative_path_from(Pathname.new(Dir.pwd))
|
91
|
+
say_warning "Not an Endpoint: #{rp.to_s}"
|
92
|
+
return nil
|
93
|
+
end
|
90
94
|
{:method=>md[1], :path=>md[2]}
|
91
95
|
end
|
92
96
|
|
@@ -125,12 +125,13 @@ module MrMurano
|
|
125
125
|
#sha1 = Digest::SHA1.file(path.to_s).hexdigest
|
126
126
|
def hexit(str)
|
127
127
|
ret=''
|
128
|
+
# TODO: find a faster way to do this.
|
128
129
|
str.each_byte{|b| ret << "%02x" % b}
|
129
130
|
ret
|
130
131
|
end
|
131
132
|
sha1 = Digest::SHA1.new
|
132
133
|
path.open('rb:ASCII-8BIT') do |io|
|
133
|
-
while chunk = io.read(
|
134
|
+
while chunk = io.read(1048576) do
|
134
135
|
sha1 << hexit(chunk)
|
135
136
|
end
|
136
137
|
end
|
@@ -25,23 +25,23 @@ module MrMurano
|
|
25
25
|
return @scid unless @scid.nil?
|
26
26
|
@scid = scid_for_name(@serviceName)
|
27
27
|
end
|
28
|
+
end
|
28
29
|
|
29
|
-
|
30
|
+
class SC_Device < ServiceConfig
|
31
|
+
def initialize
|
32
|
+
super
|
33
|
+
@serviceName = 'device'
|
34
|
+
end
|
30
35
|
|
31
36
|
def assignTriggers(products)
|
32
|
-
scid = scid_for_name('device')
|
33
|
-
|
34
37
|
details = fetch(scid)
|
35
38
|
products = [products] unless products.kind_of? Array
|
36
|
-
details[:triggers] = {:pid=>products}
|
39
|
+
details[:triggers] = {:pid=>products, :vendor=>products}
|
37
40
|
|
38
41
|
put('/'+scid, details)
|
39
|
-
|
40
42
|
end
|
41
43
|
|
42
44
|
def showTriggers
|
43
|
-
scid = scid_for_name('device')
|
44
|
-
|
45
45
|
details = fetch(scid)
|
46
46
|
|
47
47
|
return [] if details[:triggers].nil?
|
@@ -51,46 +51,55 @@ module MrMurano
|
|
51
51
|
end
|
52
52
|
end
|
53
53
|
|
54
|
-
command
|
55
|
-
c.syntax = 'mr assign [
|
56
|
-
c.description = '
|
57
|
-
|
58
|
-
c.option '--list', %{List assigned products}
|
54
|
+
command 'assign list' do |c|
|
55
|
+
c.syntax = 'mr assign list [options]'
|
56
|
+
c.description = 'List the products that are assigned'
|
59
57
|
c.option '--idonly', 'Only return the ids'
|
60
|
-
|
61
58
|
c.action do |args, options|
|
62
|
-
sol = MrMurano::
|
59
|
+
sol = MrMurano::SC_Device.new
|
63
60
|
|
64
|
-
|
65
|
-
|
66
|
-
|
61
|
+
trigs = sol.showTriggers()
|
62
|
+
if options.idonly or $cfg['business.id'].nil? then
|
63
|
+
say trigs.join(' ')
|
64
|
+
else
|
65
|
+
acc = MrMurano::Account.new
|
66
|
+
products = acc.products
|
67
|
+
products.select!{|p| trigs.include? p[:modelId] }
|
68
|
+
if products.empty? then
|
67
69
|
say trigs.join(' ')
|
68
70
|
else
|
69
|
-
acc = MrMurano::Account.new
|
70
|
-
products = acc.products
|
71
|
-
products.select!{|p| trigs.include? p[:pid] }
|
72
71
|
busy = products.map{|r| [r[:label], r[:type], r[:pid], r[:modelId]]}
|
73
72
|
table = Terminal::Table.new :rows => busy, :headings => ['Label', 'Type', 'PID', 'ModelID']
|
74
73
|
say table
|
75
74
|
end
|
76
|
-
|
77
|
-
else
|
78
|
-
prname = args.shift
|
79
|
-
if prname.nil? then
|
80
|
-
prid = $cfg['product.id']
|
81
|
-
else
|
82
|
-
acc = MrMurano::Account.new
|
83
|
-
products = acc.products
|
84
|
-
products.select!{|p| p[:label] == prname or p[:pid] == prname }
|
85
|
-
prid = products.map{|p| p[:pid]}
|
86
|
-
end
|
87
|
-
raise "No product ID!" if prid.nil?
|
88
|
-
say "Assigning #{prid} to solution" if $cfg['tool.verbose']
|
89
|
-
sol.assignTriggers(prid) unless $cfg['tool.dry']
|
90
75
|
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
alias_command :assign, 'assign list'
|
91
79
|
|
80
|
+
command 'assign set' do |c|
|
81
|
+
c.syntax = 'mr assign set [product]'
|
82
|
+
c.description = 'Assign a product to a eventhandler'
|
92
83
|
|
84
|
+
c.action do |args, options|
|
85
|
+
sol = MrMurano::SC_Device.new
|
86
|
+
|
87
|
+
prname = args.shift
|
88
|
+
if prname.nil? then
|
89
|
+
prid = $cfg['product.id']
|
90
|
+
else
|
91
|
+
acc = MrMurano::Account.new
|
92
|
+
products = acc.products
|
93
|
+
products.select!{|p|
|
94
|
+
p[:label] == prname or p[:modelId] == prname or p[:pid] == prname
|
95
|
+
}
|
96
|
+
prid = products.map{|p| p[:modelId]}
|
97
|
+
end
|
98
|
+
raise "No product ID!" if prid.nil?
|
99
|
+
say "Assigning #{prid} to solution" if $cfg['tool.verbose']
|
100
|
+
sol.assignTriggers(prid) unless $cfg['tool.dry']
|
93
101
|
end
|
102
|
+
|
94
103
|
end
|
95
104
|
|
96
105
|
# vim: set ai et sw=2 ts=2 :
|
@@ -153,7 +153,11 @@ module MrMurano
|
|
153
153
|
path = Pathname.new(path) unless path.kind_of? Pathname
|
154
154
|
aheader = path.readlines().first
|
155
155
|
md = /--#EVENT (\S+) (\S+)/.match(aheader)
|
156
|
-
|
156
|
+
if md.nil? then
|
157
|
+
rp = path.relative_path_from(Pathname.new(Dir.pwd))
|
158
|
+
say_warning "Not an Event handler: #{rp}"
|
159
|
+
return nil
|
160
|
+
end
|
157
161
|
{:service=>md[1], :event=>md[2]}
|
158
162
|
end
|
159
163
|
|
data/lib/MrMurano/Solution.rb
CHANGED
@@ -9,110 +9,27 @@ module MrMurano
|
|
9
9
|
class SolutionBase
|
10
10
|
# This might also be a valid ProductBase.
|
11
11
|
def initialize
|
12
|
-
@token = Account.new.token
|
13
|
-
raise "Not logged in!" if @token.nil?
|
14
12
|
@sid = $cfg['solution.id']
|
15
13
|
raise "No solution!" if @sid.nil?
|
16
14
|
@uriparts = [:solution, @sid]
|
17
15
|
@itemkey = :id
|
18
16
|
@locationbase = $cfg['location.base']
|
19
17
|
@location = nil
|
20
|
-
@json_opts = {
|
21
|
-
:allow_nan => true,
|
22
|
-
:symbolize_names => true,
|
23
|
-
:create_additions => false
|
24
|
-
}
|
25
18
|
end
|
26
19
|
|
20
|
+
include Http
|
21
|
+
|
27
22
|
def verbose(msg)
|
28
23
|
if $cfg['tool.verbose'] then
|
29
24
|
say msg
|
30
25
|
end
|
31
26
|
end
|
32
27
|
|
33
|
-
def curldebug(request)
|
34
|
-
if $cfg['tool.curldebug'] then
|
35
|
-
a = []
|
36
|
-
a << %{curl -s -H 'Authorization: #{request['authorization']}'}
|
37
|
-
a << %{-H 'User-Agent: #{request['User-Agent']}'}
|
38
|
-
a << %{-H 'Content-Type: #{request.content_type}'}
|
39
|
-
a << %{-X #{request.method}}
|
40
|
-
a << %{'#{request.uri.to_s}'}
|
41
|
-
a << %{-d '#{request.body}'} unless request.body.nil?
|
42
|
-
puts a.join(' ')
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
28
|
def endPoint(path='')
|
47
29
|
parts = ['https:/', $cfg['net.host'], 'api:1'] + @uriparts
|
48
30
|
s = parts.map{|v| v.to_s}.join('/')
|
49
31
|
URI(s + path.to_s)
|
50
32
|
end
|
51
|
-
def http
|
52
|
-
uri = URI('https://' + $cfg['net.host'])
|
53
|
-
if @http.nil? then
|
54
|
-
@http = Net::HTTP.new(uri.host, uri.port)
|
55
|
-
@http.use_ssl = true
|
56
|
-
@http.start
|
57
|
-
end
|
58
|
-
@http
|
59
|
-
end
|
60
|
-
|
61
|
-
def set_req_defaults(request)
|
62
|
-
request.content_type = 'application/json'
|
63
|
-
request['authorization'] = 'token ' + @token
|
64
|
-
request['User-Agent'] = "MrMurano/#{MrMurano::VERSION}"
|
65
|
-
request
|
66
|
-
end
|
67
|
-
|
68
|
-
def workit(request, &block)
|
69
|
-
set_req_defaults(request)
|
70
|
-
curldebug(request)
|
71
|
-
if block_given? then
|
72
|
-
yield request, http()
|
73
|
-
else
|
74
|
-
response = http().request(request)
|
75
|
-
case response
|
76
|
-
when Net::HTTPSuccess
|
77
|
-
return {} if response.body.nil?
|
78
|
-
begin
|
79
|
-
return JSON.parse(response.body, @json_opts)
|
80
|
-
rescue
|
81
|
-
return response.body
|
82
|
-
end
|
83
|
-
else
|
84
|
-
say_error "got #{response} from #{request} #{request.uri.to_s}"
|
85
|
-
say_error ":: #{response.body}"
|
86
|
-
say_error '==='
|
87
|
-
raise response
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def get(path='', &block)
|
93
|
-
uri = endPoint(path)
|
94
|
-
workit(Net::HTTP::Get.new(uri), &block)
|
95
|
-
end
|
96
|
-
|
97
|
-
def post(path='', body={}, &block)
|
98
|
-
uri = endPoint(path)
|
99
|
-
req = Net::HTTP::Post.new(uri)
|
100
|
-
req.body = JSON.generate(body)
|
101
|
-
workit(req, &block)
|
102
|
-
end
|
103
|
-
|
104
|
-
def put(path='', body={}, &block)
|
105
|
-
uri = endPoint(path)
|
106
|
-
req = Net::HTTP::Put.new(uri)
|
107
|
-
req.body = JSON.generate(body)
|
108
|
-
workit(req, &block)
|
109
|
-
end
|
110
|
-
|
111
|
-
def delete(path='', &block)
|
112
|
-
uri = endPoint(path)
|
113
|
-
workit(Net::HTTP::Delete.new(uri), &block)
|
114
|
-
end
|
115
|
-
|
116
33
|
# …
|
117
34
|
|
118
35
|
##
|
@@ -215,9 +132,11 @@ module MrMurano
|
|
215
132
|
# sometimes this is a name, sometimes it is an item.
|
216
133
|
# do I want to keep that? NO.
|
217
134
|
name = toRemoteItem(from, path)
|
218
|
-
name
|
219
|
-
|
220
|
-
|
135
|
+
unless name.nil? then
|
136
|
+
name[:local_path] = path
|
137
|
+
name
|
138
|
+
end
|
139
|
+
end.flatten.compact
|
221
140
|
end
|
222
141
|
|
223
142
|
def synckey(item)
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module MrMurano
|
6
|
+
module Http
|
7
|
+
def token
|
8
|
+
return @token unless @token.nil?
|
9
|
+
@token = Account.new.token
|
10
|
+
raise "Not logged in!" if @token.nil?
|
11
|
+
@token
|
12
|
+
end
|
13
|
+
|
14
|
+
def json_opts
|
15
|
+
return @json_opts unless @json_opts.nil?
|
16
|
+
@json_opts = {
|
17
|
+
:allow_nan => true,
|
18
|
+
:symbolize_names => true,
|
19
|
+
:create_additions => false
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
def curldebug(request)
|
24
|
+
if $cfg['tool.curldebug'] then
|
25
|
+
a = []
|
26
|
+
a << %{curl -s -H 'Authorization: #{request['authorization']}'}
|
27
|
+
a << %{-H 'User-Agent: #{request['User-Agent']}'}
|
28
|
+
a << %{-H 'Content-Type: #{request.content_type}'}
|
29
|
+
a << %{-X #{request.method}}
|
30
|
+
a << %{'#{request.uri.to_s}'}
|
31
|
+
a << %{-d '#{request.body}'} unless request.body.nil?
|
32
|
+
puts a.join(' ')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def http
|
37
|
+
uri = URI('https://' + $cfg['net.host'])
|
38
|
+
if @http.nil? then
|
39
|
+
@http = Net::HTTP.new(uri.host, uri.port)
|
40
|
+
@http.use_ssl = true
|
41
|
+
@http.start
|
42
|
+
end
|
43
|
+
@http
|
44
|
+
end
|
45
|
+
|
46
|
+
def set_req_defaults(request)
|
47
|
+
request.content_type = 'application/json'
|
48
|
+
request['authorization'] = 'token ' + token
|
49
|
+
request['User-Agent'] = "MrMurano/#{MrMurano::VERSION}"
|
50
|
+
request
|
51
|
+
end
|
52
|
+
|
53
|
+
def workit(request, &block)
|
54
|
+
set_req_defaults(request)
|
55
|
+
curldebug(request)
|
56
|
+
if block_given? then
|
57
|
+
yield request, http()
|
58
|
+
else
|
59
|
+
response = http().request(request)
|
60
|
+
case response
|
61
|
+
when Net::HTTPSuccess
|
62
|
+
return {} if response.body.nil?
|
63
|
+
begin
|
64
|
+
return JSON.parse(response.body, json_opts)
|
65
|
+
rescue
|
66
|
+
return response.body
|
67
|
+
end
|
68
|
+
else
|
69
|
+
say_error "got #{response} from #{request} #{request.uri.to_s}"
|
70
|
+
say_error ":: #{response.body}"
|
71
|
+
say_error '==='
|
72
|
+
raise response
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def get(path='', &block)
|
78
|
+
uri = endPoint(path)
|
79
|
+
workit(Net::HTTP::Get.new(uri), &block)
|
80
|
+
end
|
81
|
+
|
82
|
+
def post(path='', body={}, &block)
|
83
|
+
uri = endPoint(path)
|
84
|
+
req = Net::HTTP::Post.new(uri)
|
85
|
+
req.body = JSON.generate(body)
|
86
|
+
workit(req, &block)
|
87
|
+
end
|
88
|
+
|
89
|
+
def put(path='', body={}, &block)
|
90
|
+
uri = endPoint(path)
|
91
|
+
req = Net::HTTP::Put.new(uri)
|
92
|
+
req.body = JSON.generate(body)
|
93
|
+
workit(req, &block)
|
94
|
+
end
|
95
|
+
|
96
|
+
def delete(path='', &block)
|
97
|
+
uri = endPoint(path)
|
98
|
+
workit(Net::HTTP::Delete.new(uri), &block)
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
end
|
103
|
+
# vim: set ai et sw=2 ts=2 :
|
data/lib/MrMurano/keystore.rb
CHANGED
@@ -87,6 +87,7 @@ alias_command 'keystore rm', 'keystore delete'
|
|
87
87
|
|
88
88
|
command 'keystore command' do |c|
|
89
89
|
c.syntax = %{mr keystore command <key> <command> <args...>}
|
90
|
+
c.summary = %{Call some Redis commands in the Keystore}
|
90
91
|
c.description = %{Call some Redis commands in the Keystore.
|
91
92
|
|
92
93
|
Only a subset of all Redis commands is supported.
|
data/lib/MrMurano/logs.rb
CHANGED
@@ -55,6 +55,9 @@ command :logs do |c|
|
|
55
55
|
elsif line.kind_of?(Hash) then
|
56
56
|
out=""
|
57
57
|
|
58
|
+
if line.has_key?(:type) then
|
59
|
+
out << "#{line[:type]} ".upcase.color(:red).background(:aliceblue)
|
60
|
+
end
|
58
61
|
out << "[#{line[:subject]}]".color(:red).background(:aliceblue)
|
59
62
|
out << " "
|
60
63
|
if options.localtime then
|
@@ -63,24 +66,37 @@ command :logs do |c|
|
|
63
66
|
curtime = Time.at(line[:timestamp]).to_datetime.iso8601(3)
|
64
67
|
end
|
65
68
|
out << curtime.color(:blue)
|
66
|
-
out << "
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
69
|
+
out << ":\n"
|
70
|
+
if line.has_key?(:data) then
|
71
|
+
data = line[:data]
|
72
|
+
|
73
|
+
if data.kind_of?(Hash) and data.has_key?(:request) and data.has_key?(:response) then
|
74
|
+
out << "---------\nrequest:"
|
75
|
+
if options.pretty then
|
76
|
+
ret = JSON.pretty_generate(data[:request]).to_s
|
77
|
+
ret[0] = ret[0].color(:magenta)
|
78
|
+
ret[-1] = ret[-1].color(:magenta)
|
79
|
+
out << ret
|
80
|
+
else
|
81
|
+
out << data[:request].to_json
|
82
|
+
end
|
83
|
+
|
84
|
+
out << "\n---------\nresponse:"
|
85
|
+
if options.pretty then
|
86
|
+
ret = JSON.pretty_generate(data[:response]).to_s
|
87
|
+
ret[0] = ret[0].color(:magenta)
|
88
|
+
ret[-1] = ret[-1].color(:magenta)
|
89
|
+
out << ret
|
90
|
+
else
|
91
|
+
out << data[:response].to_json
|
92
|
+
end
|
93
|
+
|
94
|
+
else
|
95
|
+
out << data.to_s
|
96
|
+
end
|
97
|
+
|
82
98
|
else
|
83
|
-
out << line
|
99
|
+
out << line.to_s
|
84
100
|
end
|
85
101
|
|
86
102
|
end
|
data/lib/MrMurano/timeseries.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'csv'
|
1
2
|
|
2
3
|
module MrMurano
|
3
4
|
class Timeseries < ServiceConfig
|
@@ -25,14 +26,25 @@ command 'timeseries query' do |c|
|
|
25
26
|
c.syntax = %{mr timeseries query <query string>}
|
26
27
|
c.description = %{Query the timeseries database}
|
27
28
|
c.option '--[no-]json', %{Display results as raw json}
|
28
|
-
|
29
|
-
|
29
|
+
c.option '--[no-]csv', %{Display results as CSV}
|
30
|
+
|
30
31
|
c.action do |args,options|
|
31
|
-
options.defalts :json=>false
|
32
|
+
options.defalts :json=>false, :csv=>false
|
32
33
|
sol = MrMurano::Timeseries.new
|
33
34
|
ret = sol.query args.join(' ')
|
34
35
|
if options.json then
|
35
36
|
puts ret.to_json
|
37
|
+
|
38
|
+
elsif options.csv then
|
39
|
+
(ret[:results] or []).each do |res|
|
40
|
+
(res[:series] or []).each do |ser|
|
41
|
+
cols = ser[:columns] #.map{|h| "#{ser[:name]}.#{h}"}
|
42
|
+
CSV($stdout, :headers=>cols, :write_headers=>true) do |csv|
|
43
|
+
ser[:values].each{|v| csv << v}
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
36
48
|
else
|
37
49
|
(ret[:results] or []).each do |res|
|
38
50
|
(res[:series] or []).each do |ser|
|
data/lib/MrMurano/version.rb
CHANGED
data/lib/MrMurano.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: MrMurano
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Conrad Tadpol Tilstra
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-09-
|
11
|
+
date: 2016-09-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: commander
|
@@ -179,6 +179,7 @@ files:
|
|
179
179
|
- lib/MrMurano/configFile.rb
|
180
180
|
- lib/MrMurano/cors.rb
|
181
181
|
- lib/MrMurano/hash.rb
|
182
|
+
- lib/MrMurano/http.rb
|
182
183
|
- lib/MrMurano/keystore.rb
|
183
184
|
- lib/MrMurano/logs.rb
|
184
185
|
- lib/MrMurano/shelledCommand.rb
|