MuranoCLI 2.2.4 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.agignore +3 -0
- data/.gitignore +18 -1
- data/.rubocop.yml +222 -0
- data/.trustme.sh +185 -0
- data/.trustme.vim +24 -0
- data/Gemfile +23 -4
- data/LICENSE.txt +1 -1
- data/MuranoCLI.gemspec +43 -8
- data/README.markdown +9 -11
- data/Rakefile +187 -143
- data/TODO.taskpaper +2 -2
- data/bin/murano +51 -52
- data/docs/basic_example.rst +436 -0
- data/docs/completions/murano_completion-bash +3484 -0
- data/docs/demo.md +32 -32
- data/docs/develop.rst +391 -0
- data/lib/MrMurano.rb +21 -7
- data/lib/MrMurano/Account.rb +159 -174
- data/lib/MrMurano/Business.rb +381 -0
- data/lib/MrMurano/Config-Migrate.rb +32 -26
- data/lib/MrMurano/Config.rb +407 -128
- data/lib/MrMurano/Content.rb +191 -0
- data/lib/MrMurano/Gateway.rb +489 -0
- data/lib/MrMurano/Keystore.rb +48 -0
- data/lib/MrMurano/Passwords.rb +103 -0
- data/lib/MrMurano/ProjectFile.rb +121 -79
- data/lib/MrMurano/ReCommander.rb +114 -10
- data/lib/MrMurano/Setting.rb +90 -0
- data/lib/MrMurano/Solution-ServiceConfig.rb +89 -45
- data/lib/MrMurano/Solution-Services.rb +461 -166
- data/lib/MrMurano/Solution-Users.rb +70 -31
- data/lib/MrMurano/Solution.rb +372 -13
- data/lib/MrMurano/SolutionId.rb +73 -0
- data/lib/MrMurano/SyncRoot.rb +137 -0
- data/lib/MrMurano/SyncUpDown.rb +594 -284
- data/lib/MrMurano/Webservice-Cors.rb +71 -0
- data/lib/MrMurano/Webservice-Endpoint.rb +234 -0
- data/lib/MrMurano/Webservice-File.rb +193 -0
- data/lib/MrMurano/Webservice.rb +51 -0
- data/lib/MrMurano/commands.rb +18 -15
- data/lib/MrMurano/commands/business.rb +300 -6
- data/lib/MrMurano/commands/completion-bash.erb +166 -0
- data/lib/MrMurano/commands/{zshcomplete.erb → completion-zsh.erb} +0 -0
- data/lib/MrMurano/commands/completion.rb +76 -39
- data/lib/MrMurano/commands/config.rb +108 -44
- data/lib/MrMurano/commands/content.rb +115 -72
- data/lib/MrMurano/commands/cors.rb +29 -14
- data/lib/MrMurano/commands/devices.rb +286 -0
- data/lib/MrMurano/commands/domain.rb +52 -12
- data/lib/MrMurano/commands/gb.rb +24 -9
- data/lib/MrMurano/commands/globals.rb +64 -0
- data/lib/MrMurano/commands/init.rb +377 -155
- data/lib/MrMurano/commands/keystore.rb +92 -82
- data/lib/MrMurano/commands/link.rb +300 -0
- data/lib/MrMurano/commands/login.rb +74 -11
- data/lib/MrMurano/commands/logs.rb +63 -32
- data/lib/MrMurano/commands/mock.rb +57 -29
- data/lib/MrMurano/commands/password.rb +57 -39
- data/lib/MrMurano/commands/postgresql.rb +127 -94
- data/lib/MrMurano/commands/settings.rb +203 -0
- data/lib/MrMurano/commands/show.rb +79 -38
- data/lib/MrMurano/commands/solution.rb +423 -5
- data/lib/MrMurano/commands/solution_picker.rb +547 -0
- data/lib/MrMurano/commands/status.rb +195 -61
- data/lib/MrMurano/commands/sync.rb +78 -39
- data/lib/MrMurano/commands/timeseries.rb +71 -55
- data/lib/MrMurano/commands/tsdb.rb +113 -87
- data/lib/MrMurano/commands/usage.rb +57 -15
- data/lib/MrMurano/hash.rb +100 -10
- data/lib/MrMurano/http.rb +187 -43
- data/lib/MrMurano/makePretty.rb +16 -14
- data/lib/MrMurano/optparse.rb +2178 -0
- data/lib/MrMurano/progress.rb +138 -0
- data/lib/MrMurano/schema/resource-v1.0.0.yaml +32 -0
- data/lib/MrMurano/template/projectFile.murano.erb +16 -13
- data/lib/MrMurano/verbosing.rb +166 -29
- data/lib/MrMurano/version.rb +30 -1
- data/spec/Account-Passwords_spec.rb +21 -4
- data/spec/Account_spec.rb +69 -146
- data/spec/Business_spec.rb +290 -0
- data/spec/ConfigFile_spec.rb +1 -0
- data/spec/ConfigMigrate_spec.rb +12 -8
- data/spec/Config_spec.rb +40 -34
- data/spec/Content_spec.rb +363 -0
- data/spec/GatewayBase_spec.rb +54 -0
- data/spec/GatewayDevice_spec.rb +321 -0
- data/spec/GatewayResource_spec.rb +266 -0
- data/spec/GatewaySettings_spec.rb +120 -0
- data/spec/Http_spec.rb +18 -8
- data/spec/Mock_spec.rb +2 -2
- data/spec/ProjectFile_spec.rb +25 -14
- data/spec/Setting_spec.rb +110 -0
- data/spec/Solution-ServiceConfig_spec.rb +44 -5
- data/spec/Solution-ServiceEventHandler_spec.rb +23 -14
- data/spec/Solution-ServiceModules_spec.rb +47 -37
- data/spec/Solution-UsersRoles_spec.rb +10 -8
- data/spec/Solution_spec.rb +17 -8
- data/spec/SyncRoot_spec.rb +46 -20
- data/spec/SyncUpDown_spec.rb +437 -201
- data/spec/Verbosing_spec.rb +12 -4
- data/spec/{Solution-Cors_spec.rb → Webservice-Cors_spec.rb} +23 -20
- data/spec/{Solution-Endpoint_spec.rb → Webservice-Endpoint_spec.rb} +43 -41
- data/spec/{Solution-File_spec.rb → Webservice-File_spec.rb} +44 -33
- data/spec/Webservice-Setting_spec.rb +89 -0
- data/spec/_workspace.rb +4 -4
- data/spec/cmd_business_spec.rb +9 -4
- data/spec/cmd_common.rb +44 -1
- data/spec/cmd_content_spec.rb +43 -17
- data/spec/cmd_cors_spec.rb +4 -4
- data/spec/cmd_device_spec.rb +61 -16
- data/spec/cmd_domain_spec.rb +29 -6
- data/spec/cmd_init_spec.rb +281 -126
- data/spec/cmd_keystore_spec.rb +3 -3
- data/spec/cmd_link_spec.rb +98 -0
- data/spec/cmd_password_spec.rb +1 -1
- data/spec/cmd_setting_application_spec.rb +260 -0
- data/spec/cmd_setting_product_spec.rb +220 -0
- data/spec/cmd_status_spec.rb +223 -114
- data/spec/cmd_syncdown_spec.rb +115 -35
- data/spec/cmd_syncup_spec.rb +68 -15
- data/spec/cmd_usage_spec.rb +35 -8
- data/spec/fixtures/dumped_config +6 -4
- data/spec/fixtures/gateway_resource_files/resources.notyaml +12 -0
- data/spec/fixtures/gateway_resource_files/resources.yaml +13 -0
- data/spec/fixtures/gateway_resource_files/resources_invalid.yaml +13 -0
- data/spec/fixtures/mrmuranorc_deleted_bob +0 -2
- data/spec/fixtures/product_spec_files/lightbulb.yaml +20 -13
- data/spec/fixtures/{syncable_content → syncable_conflict}/services/devdata.lua +1 -1
- data/spec/fixtures/{syncable_content → syncable_conflict}/services/timers.lua +0 -0
- data/spec/spec_helper.rb +5 -0
- metadata +262 -171
- data/bin/mr +0 -8
- data/lib/MrMurano/Product-1P-Device.rb +0 -145
- data/lib/MrMurano/Product-Resources.rb +0 -205
- data/lib/MrMurano/Product.rb +0 -358
- data/lib/MrMurano/Solution-Cors.rb +0 -47
- data/lib/MrMurano/Solution-Endpoint.rb +0 -191
- data/lib/MrMurano/Solution-File.rb +0 -166
- data/lib/MrMurano/commands/assign.rb +0 -57
- data/lib/MrMurano/commands/businessList.rb +0 -45
- data/lib/MrMurano/commands/product.rb +0 -14
- data/lib/MrMurano/commands/productCreate.rb +0 -39
- data/lib/MrMurano/commands/productDelete.rb +0 -33
- data/lib/MrMurano/commands/productDevice.rb +0 -87
- data/lib/MrMurano/commands/productDeviceIdCmds.rb +0 -89
- data/lib/MrMurano/commands/productList.rb +0 -45
- data/lib/MrMurano/commands/productWrite.rb +0 -27
- data/lib/MrMurano/commands/solutionCreate.rb +0 -41
- data/lib/MrMurano/commands/solutionDelete.rb +0 -34
- data/lib/MrMurano/commands/solutionList.rb +0 -45
- data/spec/ProductBase_spec.rb +0 -113
- data/spec/ProductContent_spec.rb +0 -162
- data/spec/ProductResources_spec.rb +0 -329
- data/spec/Product_1P_Device_spec.rb +0 -202
- data/spec/Product_1P_RPC_spec.rb +0 -175
- data/spec/Product_spec.rb +0 -153
- data/spec/Solution-ServiceDevice_spec.rb +0 -176
- data/spec/cmd_assign_spec.rb +0 -51
@@ -1,13 +1,23 @@
|
|
1
|
+
# Last Modified: 2017.08.16 /coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright © 2016-2017 Exosite LLC.
|
5
|
+
# License: MIT. See LICENSE.txt.
|
6
|
+
# vim:tw=0:ts=2:sw=2:et:ai
|
7
|
+
|
1
8
|
require 'date'
|
9
|
+
require 'MrMurano/ReCommander'
|
2
10
|
require 'MrMurano/Solution-ServiceConfig'
|
3
11
|
require 'MrMurano/SubCmdGroupContext'
|
4
12
|
|
5
13
|
module MrMurano
|
6
14
|
module ServiceConfigs
|
7
15
|
class Tsdb < ServiceConfig
|
8
|
-
def initialize
|
16
|
+
def initialize(sid=nil)
|
17
|
+
# FIXME/2017-07-03: What soln types have TSDBs?
|
18
|
+
@solntype = 'application.id'
|
9
19
|
super
|
10
|
-
@
|
20
|
+
@service_name = 'tsdb'
|
11
21
|
end
|
12
22
|
|
13
23
|
def write(data)
|
@@ -18,6 +28,8 @@ module MrMurano
|
|
18
28
|
call(:query, :post, query)
|
19
29
|
end
|
20
30
|
|
31
|
+
# FIXME/2017-08-16: Convert to snake_case. Or is this method name magical?
|
32
|
+
# rubocop:disable Style/MethodName: Use snake_case for method names.
|
21
33
|
def listTags
|
22
34
|
call(:listTags)
|
23
35
|
end
|
@@ -26,34 +38,54 @@ module MrMurano
|
|
26
38
|
call(:listMetrics)
|
27
39
|
end
|
28
40
|
|
29
|
-
|
30
41
|
def str_to_timestamp(str)
|
31
|
-
if str =~ /^\d+(u|ms|s)?$/
|
42
|
+
if str =~ /^\d+(u|ms|s)?$/
|
32
43
|
str
|
33
44
|
else
|
34
45
|
dt = DateTime.parse(str)
|
35
|
-
(dt.to_time.to_f *
|
46
|
+
(dt.to_time.to_f * 1_000_000).to_i
|
36
47
|
end
|
37
48
|
end
|
38
49
|
end
|
39
50
|
end
|
40
51
|
end
|
41
52
|
|
53
|
+
command :tsdb do |c|
|
54
|
+
c.syntax = %(murano tsdb)
|
55
|
+
c.summary = %(Show list of TSDB commands)
|
56
|
+
c.description = %(
|
57
|
+
The tsdb sub-commands let you interact directly with the TSDB instance in a
|
58
|
+
solution. This allows for easier debugging, being able to quickly try out
|
59
|
+
different queries or write test data.
|
60
|
+
).strip
|
61
|
+
c.project_not_required = true
|
62
|
+
|
63
|
+
c.action do |_args, _options|
|
64
|
+
::Commander::UI.enable_paging
|
65
|
+
say MrMurano::SubCmdGroupHelp.new(c).get_help
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
42
69
|
command 'tsdb write' do |c|
|
43
|
-
c.syntax = %
|
44
|
-
c.summary = %
|
45
|
-
c.description = %
|
70
|
+
c.syntax = %(murano tsdb write [--options] <metric=value>|@<tag=value> … )
|
71
|
+
c.summary = %(Write data to the TSDB)
|
72
|
+
c.description = %(
|
73
|
+
Write data to the time series database (TSDB).
|
46
74
|
|
47
75
|
TIMESTAMP is microseconds since unix epoch, or can be suffixed with units.
|
48
76
|
Units are u (microseconds), ms (milliseconds), s (seconds)
|
49
77
|
|
50
78
|
Also, many date-time formats can be parsed and will be converted to microseconds
|
51
|
-
|
52
|
-
|
79
|
+
).strip
|
80
|
+
|
81
|
+
c.option '--when TIMESTAMP', %(When this data happened (default: now))
|
53
82
|
# TODO: add option to take data from STDIN.
|
54
|
-
|
83
|
+
|
84
|
+
c.example 'murano tsdb write hum=45 lux=12765 @sn=44', %(Write two metrics (hum and lux) with a tag (sn))
|
55
85
|
|
56
86
|
c.action do |args, options|
|
87
|
+
# SKIP: c.verify_arg_count!(args)
|
88
|
+
|
57
89
|
sol = MrMurano::ServiceConfigs::Tsdb.new
|
58
90
|
|
59
91
|
# we have hash of tags, hash of metrics, optional timestamp.
|
@@ -61,32 +93,31 @@ Also, many date-time formats can be parsed and will be converted to microseconds
|
|
61
93
|
tags = {}
|
62
94
|
args.each do |item|
|
63
95
|
key, value = item.split('=', 2)
|
64
|
-
if key[0] == '@'
|
65
|
-
tags[key[1..-1]] = value.to_s
|
96
|
+
if key[0] == '@'
|
97
|
+
tags[key[1..-1]] = value.to_s # tags are always strings.
|
66
98
|
else
|
67
99
|
value = value.to_i if value == value.to_i.to_s
|
68
100
|
metrics[key] = value
|
69
101
|
end
|
70
102
|
end
|
71
103
|
|
72
|
-
data = {:tags
|
73
|
-
if
|
104
|
+
data = { tags: tags, metrics: metrics }
|
105
|
+
if !options.when.nil? && options.when != 'now'
|
74
106
|
data[:ts] = sol.str_to_timestamp(options.when)
|
75
107
|
end
|
76
108
|
|
77
109
|
ret = sol.write(data)
|
78
|
-
if ret != {}
|
79
|
-
sol.error ret
|
80
|
-
end
|
110
|
+
sol.error ret if ret != {}
|
81
111
|
end
|
82
112
|
end
|
83
113
|
|
84
114
|
command 'tsdb query' do |c|
|
85
|
-
c.syntax = %
|
86
|
-
c.summary = %
|
87
|
-
c.description
|
115
|
+
c.syntax = %(murano tsdb query [--options] <metric>|@<tag=value> …)
|
116
|
+
c.summary = %(Query data from the TSDB)
|
117
|
+
c.description = %(
|
118
|
+
Query data from the time series database (TSDB).
|
88
119
|
|
89
|
-
FUNCS is a comma
|
120
|
+
FUNCS is a comma separated list of the aggregate functions.
|
90
121
|
Currently: avg, min, max, count, sum. For string metrics, only count.
|
91
122
|
|
92
123
|
FILL is null, none, any integer, previous
|
@@ -99,20 +130,21 @@ TIMESTAMP is microseconds since unix epoch, or can be suffixed with units.
|
|
99
130
|
Units are u (microseconds), ms (milliseconds), s (seconds)
|
100
131
|
|
101
132
|
Also, many date-time formats can be parsed and will be converted to microseconds
|
102
|
-
|
103
|
-
|
104
|
-
c.option '--
|
105
|
-
c.option '--
|
106
|
-
c.option '--
|
107
|
-
c.option '--
|
108
|
-
c.option '--
|
109
|
-
c.option '--
|
110
|
-
c.option '--
|
111
|
-
c.option '--
|
112
|
-
c.option '--
|
113
|
-
c.option '--
|
114
|
-
|
115
|
-
|
133
|
+
).strip
|
134
|
+
|
135
|
+
c.option '--start_time TIMESTAMP', %(Start time range)
|
136
|
+
c.option '--end_time TIMESTAMP', %(End time range; defaults to now)
|
137
|
+
c.option '--relative_start DURATION', %(Start time relative from now)
|
138
|
+
c.option '--relative_end DURATION', %(End time relative from now)
|
139
|
+
c.option '--sampling_size DURATION', %(The size of time slots used for downsampling)
|
140
|
+
c.option '--limit NUM', Integer, %(Limit number of data points returned)
|
141
|
+
c.option '--epoch UNIT', %w[u ms s], %(Set size of returned timestamps)
|
142
|
+
c.option '--mode MODE', %w[merge split], %(Merge or split each returned metric)
|
143
|
+
c.option '--fill FILL', %(Value to fill for time slots with no data points exist in merge mode)
|
144
|
+
c.option '--order_by ORDER', %w[desc asc], %(Return results in ascending or descending time order)
|
145
|
+
c.option '--aggregate FUNCS', %(Aggregation functions to apply)
|
146
|
+
|
147
|
+
c.option '-o', '--output FILE', %(Download to file instead of STDOUT)
|
116
148
|
|
117
149
|
c.example 'murano tsdb query hum', 'Get all hum metric entries'
|
118
150
|
c.example 'murano tsdb query hum @sn=45', 'Get all hum metric entries for tag sn=45'
|
@@ -123,17 +155,18 @@ Also, many date-time formats can be parsed and will be converted to microseconds
|
|
123
155
|
c.example 'murano tsdb query hum --sampling_size 30m', 'Get one hum entry from each 30 minute chunk of time'
|
124
156
|
c.example 'murano tsdb query hum --sampling_size 30m --aggregate avg', 'Get average hum entry from each 30 minute chunk of time'
|
125
157
|
|
126
|
-
|
127
158
|
c.action do |args, options|
|
159
|
+
# SKIP: c.verify_arg_count!(args)
|
160
|
+
|
128
161
|
sol = MrMurano::ServiceConfigs::Tsdb.new
|
129
162
|
|
130
163
|
query = {}
|
131
164
|
tags = {}
|
132
165
|
metrics = []
|
133
166
|
args.each do |arg|
|
134
|
-
if arg =~ /=/
|
167
|
+
if arg =~ /=/
|
135
168
|
# a tag.
|
136
|
-
k,v = arg.split('=', 2)
|
169
|
+
k, v = arg.split('=', 2)
|
137
170
|
k = k[1..-1] if k[0] == '@'
|
138
171
|
tags[k] = v
|
139
172
|
else
|
@@ -145,24 +178,24 @@ Also, many date-time formats can be parsed and will be converted to microseconds
|
|
145
178
|
|
146
179
|
# A query without any metrics is invalid. So if the user didn't provide any,
|
147
180
|
# look up all of them (well, frist however many) and use that list.
|
148
|
-
if query[:metrics].
|
181
|
+
if query[:metrics].to_s.empty?
|
149
182
|
ret = sol.listMetrics
|
150
183
|
query[:metrics] = ret[:metrics]
|
151
184
|
end
|
152
185
|
|
153
|
-
unless options.start_time.nil?
|
186
|
+
unless options.start_time.nil?
|
154
187
|
query[:start_time] = sol.str_to_timestamp(options.start_time)
|
155
188
|
end
|
156
|
-
unless options.end_time.nil?
|
189
|
+
unless options.end_time.nil?
|
157
190
|
query[:end_time] = sol.str_to_timestamp(options.end_time)
|
158
191
|
end
|
159
192
|
|
160
|
-
unless options.relative_start.nil?
|
193
|
+
unless options.relative_start.nil?
|
161
194
|
o = options.relative_start
|
162
195
|
o = "-#{o}" unless o[0] == '-'
|
163
196
|
query[:relative_start] = o
|
164
197
|
end
|
165
|
-
unless options.relative_end.nil?
|
198
|
+
unless options.relative_end.nil?
|
166
199
|
o = options.relative_end
|
167
200
|
o = "-#{o}" unless o[0] == '-'
|
168
201
|
query[:relative_end] = o
|
@@ -175,79 +208,86 @@ Also, many date-time formats can be parsed and will be converted to microseconds
|
|
175
208
|
query[:order_by] = options.order_by unless options.order_by.nil?
|
176
209
|
|
177
210
|
query[:fill] = options.fill unless options.fill.nil?
|
178
|
-
unless options.aggregate.nil?
|
211
|
+
unless options.aggregate.nil?
|
179
212
|
query[:aggregate] = options.aggregate.split(',')
|
180
213
|
end
|
181
214
|
|
182
|
-
io=
|
183
|
-
if options.output then
|
184
|
-
io = File.open(options.output, 'w')
|
185
|
-
end
|
215
|
+
io = File.open(options.output, 'w') if options.output
|
186
216
|
sol.outf sol.query(query) do |dd, ios|
|
187
217
|
# If aggregated, then we need to break up the columns. since each is now a
|
188
218
|
# hash of the aggregated functions
|
189
|
-
unless options.aggregate.nil?
|
219
|
+
unless options.aggregate.nil?
|
190
220
|
dd[:values].map! do |row|
|
191
221
|
row.map do |value|
|
192
|
-
if value.
|
193
|
-
query[:aggregate].map{|qa| value[qa.to_sym]}
|
222
|
+
if value.is_a? Hash
|
223
|
+
query[:aggregate].map { |qa| value[qa.to_sym] }
|
194
224
|
else
|
195
225
|
value
|
196
226
|
end
|
197
227
|
end.flatten
|
198
228
|
end
|
199
229
|
dd[:columns].map! do |col|
|
200
|
-
if col == 'time'
|
230
|
+
if col == 'time'
|
201
231
|
col
|
202
232
|
else
|
203
|
-
query[:aggregate].map{|qa| "#{col}.#{qa
|
233
|
+
query[:aggregate].map { |qa| "#{col}.#{qa}" }
|
204
234
|
end
|
205
235
|
end.flatten!
|
206
236
|
end
|
207
|
-
sol.tabularize(
|
208
|
-
|
209
|
-
|
210
|
-
|
237
|
+
sol.tabularize(
|
238
|
+
{
|
239
|
+
headers: dd[:columns],
|
240
|
+
rows: dd[:values],
|
241
|
+
},
|
242
|
+
ios
|
243
|
+
)
|
211
244
|
end
|
212
245
|
io.close unless io.nil?
|
213
246
|
end
|
214
247
|
end
|
215
248
|
|
216
249
|
command 'tsdb list tags' do |c|
|
217
|
-
c.syntax = %
|
218
|
-
c.summary = %
|
219
|
-
c.
|
250
|
+
c.syntax = %(murano tsdb list tags [--options])
|
251
|
+
c.summary = %(List tags)
|
252
|
+
c.description = %(
|
253
|
+
List tags.
|
254
|
+
).strip
|
255
|
+
|
256
|
+
c.option '--values', %(Include the known tag values)
|
220
257
|
|
221
258
|
c.action do |args, options|
|
222
|
-
|
259
|
+
c.verify_arg_count!(args)
|
260
|
+
options.default(values: false)
|
223
261
|
|
224
262
|
sol = MrMurano::ServiceConfigs::Tsdb.new
|
225
263
|
ret = sol.listTags
|
226
264
|
# TODO: handle looping if :next != nil
|
227
265
|
|
228
|
-
if options.values
|
266
|
+
if options.values
|
229
267
|
sol.outf(ret[:tags]) do |dd, ios|
|
230
|
-
data={}
|
268
|
+
data = {}
|
231
269
|
data[:headers] = dd.keys
|
232
|
-
data[:rows] = dd.keys.map{|k| dd[k]}
|
233
|
-
len = data[:rows].map
|
234
|
-
data[:rows].each{|r| r.fill(nil, r.length, len - r.length)}
|
270
|
+
data[:rows] = dd.keys.map { |k| dd[k] }
|
271
|
+
len = data[:rows].map(&:length).max
|
272
|
+
data[:rows].each { |r| r.fill(nil, r.length, len - r.length) }
|
235
273
|
data[:rows] = data[:rows].transpose
|
236
274
|
sol.tabularize(data, ios)
|
237
275
|
end
|
238
276
|
else
|
239
277
|
sol.outf ret[:tags].keys
|
240
278
|
end
|
241
|
-
|
242
|
-
|
243
279
|
end
|
244
280
|
end
|
245
281
|
|
246
282
|
command 'tsdb list metrics' do |c|
|
247
|
-
c.syntax = %
|
248
|
-
c.summary = %
|
249
|
-
|
250
|
-
|
283
|
+
c.syntax = %(murano tsdb list metrics)
|
284
|
+
c.summary = %(List metrics)
|
285
|
+
c.description = %(
|
286
|
+
List metrics.
|
287
|
+
).strip
|
288
|
+
|
289
|
+
c.action do |args, _options|
|
290
|
+
c.verify_arg_count!(args)
|
251
291
|
sol = MrMurano::ServiceConfigs::Tsdb.new
|
252
292
|
ret = sol.listMetrics
|
253
293
|
# TODO: handle looping if :next != nil
|
@@ -255,17 +295,3 @@ command 'tsdb list metrics' do |c|
|
|
255
295
|
end
|
256
296
|
end
|
257
297
|
|
258
|
-
command :tsdb do |c|
|
259
|
-
c.syntax = %{murano tsdb}
|
260
|
-
c.summary = %{About TSDB}
|
261
|
-
c.description = %{The tsdb sub-commands let you interact directly with the TSDB instance in a
|
262
|
-
solution. This allows for easier debugging, being able to quickly try out
|
263
|
-
different queries or write test data.}
|
264
|
-
|
265
|
-
c.action do |args, options|
|
266
|
-
::Commander::UI.enable_paging
|
267
|
-
say MrMurano::SubCmdGroupHelp.new(c).get_help
|
268
|
-
end
|
269
|
-
end
|
270
|
-
|
271
|
-
# vim: set ai et sw=2 ts=2 :
|
@@ -1,23 +1,65 @@
|
|
1
|
+
# Last Modified: 2017.08.16 /coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright © 2016-2017 Exosite LLC.
|
5
|
+
# License: MIT. See LICENSE.txt.
|
6
|
+
# vim:tw=0:ts=2:sw=2:et:ai
|
7
|
+
|
8
|
+
require 'MrMurano/ReCommander'
|
1
9
|
require 'MrMurano/Solution'
|
2
10
|
|
3
11
|
command :usage do |c|
|
4
|
-
c.syntax = %
|
5
|
-
c.summary = %
|
6
|
-
c.description = %
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
12
|
+
c.syntax = %(murano usage)
|
13
|
+
c.summary = %(Get usage info for solution(s))
|
14
|
+
c.description = %(
|
15
|
+
Get usage info for solution(s).
|
16
|
+
).strip
|
17
|
+
|
18
|
+
# Add flag: --type [application|product|all].
|
19
|
+
cmd_add_solntype_pickers(c)
|
20
|
+
|
21
|
+
c.option '--[no-]all', 'Show usage for all Solutions in Business, not just Project'
|
22
|
+
c.option(
|
23
|
+
'--[no-]header', %(Output solution descriptions (default: true))
|
24
|
+
)
|
25
|
+
|
26
|
+
c.action do |args, options|
|
27
|
+
c.verify_arg_count!(args)
|
28
|
+
options.default(all: false, header: true)
|
29
|
+
cmd_defaults_solntype_pickers(options)
|
30
|
+
|
31
|
+
solz = must_fetch_solutions!(options)
|
32
|
+
|
33
|
+
solsages = []
|
34
|
+
MrMurano::Verbose.whirly_start('Fetching usage...')
|
35
|
+
solz.each do |sol|
|
36
|
+
solsages += [[sol, sol.usage]]
|
37
|
+
end
|
38
|
+
MrMurano::Verbose.whirly_stop
|
39
|
+
|
40
|
+
solsages.each do |sol, usage|
|
41
|
+
sol.outf(usage) do |dd, ios|
|
42
|
+
ios.puts(sol.pretty_desc(add_type: true)) if options.header
|
43
|
+
headers = ['', :Quota, :Daily, :Monthly, :Total]
|
44
|
+
rows = []
|
45
|
+
dd.each_pair do |key, value|
|
46
|
+
quota = value[:quota] || {}
|
47
|
+
usage = value[:usage] || {}
|
48
|
+
rows << [
|
49
|
+
key,
|
50
|
+
quota[:daily],
|
51
|
+
usage[:calls_daily],
|
52
|
+
usage[:calls_monthly],
|
53
|
+
usage[:calls_total],
|
54
|
+
]
|
55
|
+
end
|
56
|
+
sol.tabularize({ headers: headers, rows: rows }, ios)
|
17
57
|
end
|
18
|
-
sol.tabularize({:headers=>headers,:rows=>rows}, ios)
|
19
58
|
end
|
20
59
|
end
|
21
60
|
end
|
61
|
+
alias_command 'usage application', 'usage', '--type', 'application'
|
62
|
+
alias_command 'usage product', 'usage', '--type', 'product'
|
63
|
+
alias_command 'application usage', 'usage', '--type', 'application'
|
64
|
+
alias_command 'product usage', 'usage', '--type', 'product'
|
22
65
|
|
23
|
-
# vim: set ai et sw=2 ts=2 :
|
data/lib/MrMurano/hash.rb
CHANGED
@@ -1,20 +1,110 @@
|
|
1
|
+
# Last Modified: 2017.08.16 /coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Copyright © 2016-2017 Exosite LLC.
|
5
|
+
# License: MIT. See LICENSE.txt.
|
6
|
+
# vim:tw=0:ts=2:sw=2:et:ai
|
7
|
+
|
8
|
+
require 'orderedhash'
|
1
9
|
|
2
|
-
# from: http://www.any-where.de/blog/ruby-hash-convert-string-keys-to-symbols/
|
3
10
|
class Hash
|
4
|
-
#
|
11
|
+
# From:
|
12
|
+
# http://www.any-where.de/blog/ruby-hash-convert-string-keys-to-symbols/
|
13
|
+
#
|
14
|
+
# Take keys of hash and transform those to symbols.
|
5
15
|
def self.transform_keys_to_symbols(value)
|
6
|
-
return value.map{|v| Hash.transform_keys_to_symbols(v)} if value.is_a?(Array)
|
16
|
+
return value.map { |v| Hash.transform_keys_to_symbols(v) } if value.is_a?(Array)
|
7
17
|
return value if not value.is_a?(Hash)
|
8
|
-
|
9
|
-
return hash
|
18
|
+
value.inject({}) { |memo, (k,v)| memo[k.to_sym] = Hash.transform_keys_to_symbols(v); memo }
|
10
19
|
end
|
11
|
-
|
20
|
+
|
21
|
+
# From:
|
22
|
+
# http://www.any-where.de/blog/ruby-hash-convert-string-keys-to-symbols/
|
23
|
+
#
|
24
|
+
# Take keys of hash and transform those to strings.
|
12
25
|
def self.transform_keys_to_strings(value)
|
13
|
-
return value.map{|v| Hash.transform_keys_to_strings(v)} if value.is_a?(Array)
|
26
|
+
return value.map { |v| Hash.transform_keys_to_strings(v) } if value.is_a?(Array)
|
14
27
|
return value if not value.is_a?(Hash)
|
15
|
-
|
16
|
-
|
28
|
+
value.inject({}) { |memo, (k,v)| memo[k.to_s] = Hash.transform_keys_to_strings(v); memo }
|
29
|
+
end
|
30
|
+
|
31
|
+
# From Rails.
|
32
|
+
def deep_merge!(other_hash, &block)
|
33
|
+
other_hash.each_pair do |current_key, other_value|
|
34
|
+
this_value = self[current_key]
|
35
|
+
if this_value.is_a?(Hash) && other_value.is_a?(Hash)
|
36
|
+
self[current_key] = this_value.deep_merge(other_value, &block)
|
37
|
+
elsif block_given? && key?(current_key)
|
38
|
+
self[current_key] = block.call(current_key, this_value, other_value)
|
39
|
+
else
|
40
|
+
self[current_key] = other_value
|
41
|
+
end
|
42
|
+
end
|
43
|
+
self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def ordered_hash(dict)
|
48
|
+
ohash = OrderedHash.new
|
49
|
+
dict.keys.sort.each do |key|
|
50
|
+
value = dict[key]
|
51
|
+
if value.is_a? Hash
|
52
|
+
ohash[key] = ordered_hash(value)
|
53
|
+
else
|
54
|
+
ohash[key] = value
|
55
|
+
end
|
56
|
+
end
|
57
|
+
ohash
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# Take a hash or something (a Commander::Command::Options) and return a hash
|
62
|
+
#
|
63
|
+
# @param hsh [Hash, Commander::Command::Options] Thing we want to be a Hash
|
64
|
+
# @return [Hash] an actual Hash with default value of false
|
65
|
+
def elevate_hash(hsh)
|
66
|
+
# Commander::Command::Options stripped all of the methods from parent
|
67
|
+
# objects. I have not nice thoughts about that.
|
68
|
+
begin
|
69
|
+
hsh = hsh.__hash__
|
70
|
+
# rubocop:disable Lint/HandleExceptions: Do not suppress exceptions.
|
71
|
+
rescue NoMethodError
|
72
|
+
# swallow this.
|
73
|
+
end
|
74
|
+
# build a hash where the default is 'false' instead of 'nil'
|
75
|
+
Hash.new(false).merge(Hash.transform_keys_to_symbols(hsh))
|
76
|
+
# 2017-08-16: Weird: [lb] seeing the Hash behave differently
|
77
|
+
# after feeding through this function. Unknown keys would
|
78
|
+
# return nil before, but after, return false.
|
79
|
+
#
|
80
|
+
# (byeebug) options
|
81
|
+
# {:delete=>false, :create=>true, :update=>false}
|
82
|
+
# (byeebug) options[:fff]
|
83
|
+
# false
|
84
|
+
# (byeebug) options[:fff] = nil
|
85
|
+
# nil
|
86
|
+
# (byeebug) options[:fff]
|
87
|
+
# nil
|
88
|
+
# (byeebug) options[:fffd]
|
89
|
+
# false
|
90
|
+
# (byeebug) options
|
91
|
+
# {:delete=>false, :create=>true, :update=>false, :fff=>nil}
|
92
|
+
#
|
93
|
+
# Work around is to test with hash.key?
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
# Array-ify the given item, if not already an array.
|
98
|
+
#
|
99
|
+
# NOTE/2017-08-15: This fcn. is not hash-related, but this file is the
|
100
|
+
# closest we've got to a generic utility method dumping ground.
|
101
|
+
def ensure_array(item)
|
102
|
+
if item.nil?
|
103
|
+
[]
|
104
|
+
elsif !item.is_a?(Array)
|
105
|
+
[item]
|
106
|
+
else
|
107
|
+
item
|
17
108
|
end
|
18
109
|
end
|
19
110
|
|
20
|
-
# vim: set ai et sw=2 ts=2 :
|