MrMurano 1.7.4 → 1.8.0
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/README.markdown +33 -19
- data/TODO.taskpaper +22 -2
- data/lib/MrMurano/Config.rb +6 -2
- data/lib/MrMurano/Product-Resources.rb +3 -1
- data/lib/MrMurano/Solution-Endpoint.rb +33 -12
- data/lib/MrMurano/Solution-ServiceConfig.rb +1 -0
- data/lib/MrMurano/SubCmdGroupContext.rb +45 -0
- data/lib/MrMurano/SyncUpDown.rb +27 -12
- data/lib/MrMurano/commands.rb +2 -0
- data/lib/MrMurano/commands/assign.rb +6 -3
- data/lib/MrMurano/commands/content.rb +14 -1
- data/lib/MrMurano/commands/keystore.rb +12 -1
- data/lib/MrMurano/commands/product.rb +14 -0
- data/lib/MrMurano/commands/productList.rb +28 -5
- data/lib/MrMurano/commands/productSpec.rb +14 -4
- data/lib/MrMurano/commands/serialNumberCmds.rb +12 -1
- data/lib/MrMurano/commands/solution.rb +14 -0
- data/lib/MrMurano/commands/solutionList.rb +27 -5
- data/lib/MrMurano/commands/status.rb +5 -1
- data/lib/MrMurano/commands/timeseries.rb +13 -0
- data/lib/MrMurano/commands/tsdb.rb +35 -6
- data/lib/MrMurano/version.rb +1 -1
- data/spec/ProductResources_spec.rb +32 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 18a4696a79038b6f17c3a43cf1253edf00945062
|
4
|
+
data.tar.gz: aab88cf46593211db7207e8759e31f52a407a7c2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e88eb9c42ddfda7599c5be3f53cfec180f1faadb5fdc83a0d2f784401ba11eab1f54b5db69ac4d517f07a9284f1706502bbc7701989bcf8b52df5d39d4ecdff
|
7
|
+
data.tar.gz: 20751f37d098dbc3f547518c80a9a465eaa62b9850b60ce12089f1b661c7ded530f68391e537994513cd0762d292b45c6277b11e078069d0bcce92b10b5f4c59
|
data/README.markdown
CHANGED
@@ -5,6 +5,13 @@
|
|
5
5
|
|
6
6
|
Do more from the command line with [Murano](https://exosite.com/platform/)
|
7
7
|
|
8
|
+
MrMurano is the command-line tool that interacts with Murano and makes different
|
9
|
+
tasks easier. MrMurano makes it easy to deploy code to a solution, import many
|
10
|
+
product definitions at once, set up endpoints and APIs, and more.
|
11
|
+
|
12
|
+
MrMurano works around the idea of syncing, much like rsync. Files from your working
|
13
|
+
directory are synced up (or down) from Murano.
|
14
|
+
|
8
15
|
## Usage
|
9
16
|
|
10
17
|
### To start from an existing project in Murano
|
@@ -26,11 +33,13 @@ running in Murano. Here is the list.
|
|
26
33
|
- Set it: `mr config business.id ZZZZZZZZZ`
|
27
34
|
- Create a product: `mr product create myawesomeproduct`
|
28
35
|
- Save the result: `mr config product.id YYYYYYYYY`
|
29
|
-
-
|
36
|
+
- Set the product definition: `mr config product.spec prd.spec`
|
37
|
+
- Add resource aliases to specs/prd.spec
|
38
|
+
- Sync the product definition up: `mr syncup -V --specs`
|
30
39
|
- Create a solution: `mr solution create myawesomesolution`
|
31
40
|
- Save the result: `mr config solution.id XXXXXX`
|
32
41
|
- Sync solution code up: `mr syncup -V`
|
33
|
-
- Assign the
|
42
|
+
- Assign the product to the solution: `mr assign set`
|
34
43
|
|
35
44
|
Do stuff, see what changed: `mr status` or `mr diff`.
|
36
45
|
Then deploy with `mr syncup`
|
@@ -105,15 +114,29 @@ EOF
|
|
105
114
|
This also allows for keeping private things in a seperate config file and having
|
106
115
|
the shared things checked into source control.
|
107
116
|
|
108
|
-
###
|
117
|
+
### Direct Service Access
|
118
|
+
|
119
|
+
To aid with debugging, MrMurano has direct access to some of the services in a
|
120
|
+
solution.
|
109
121
|
|
110
|
-
|
122
|
+
Currently these are:
|
123
|
+
- Keystore: `mr keystore`
|
124
|
+
- Timeseries: `mr timeseries`
|
125
|
+
- TSDB: `mr tsdb`
|
111
126
|
|
112
|
-
|
127
|
+
### Output Format
|
113
128
|
|
114
|
-
|
129
|
+
Many sub-commands respect the `outformat` setting. This lets you switch the output
|
130
|
+
between YAML, JSON, Ruby, CSV, and pretty tables. Not all formats work with all
|
131
|
+
commands.
|
115
132
|
|
116
|
-
|
133
|
+
```
|
134
|
+
mr tsdb product list
|
135
|
+
mr tsdb product list -c outformat=csv
|
136
|
+
mr tsdb product list -c outformat=json
|
137
|
+
mr tsdb product list -c outformat=yaml
|
138
|
+
mr tsdb product list -c outformat=pp
|
139
|
+
```
|
117
140
|
|
118
141
|
### Product Content Area
|
119
142
|
|
@@ -183,18 +206,9 @@ spec
|
|
183
206
|
spec/cico.murano.spec
|
184
207
|
```
|
185
208
|
|
209
|
+
## Developing
|
186
210
|
|
187
|
-
|
188
|
-
|
189
|
-
MrMuanro allows adding bundles of resources to your project.
|
190
|
-
|
191
|
-
A Bundle is a group of modules, endpoints, and static files.
|
192
|
-
|
193
|
-
Bundles live in the 'bundle' directory. Each bundle is a directory that matches
|
194
|
-
the layout of a project. (with directories for endpoints, modules, files, etc)
|
195
|
-
|
196
|
-
The items in bundles are layered by sorting the bundle names. Then your project's
|
197
|
-
items are layered on top. This builds the list of what is synced. It also allows
|
198
|
-
you to override things that are in a bundle from you project.
|
211
|
+
MrMurano uses git flow for managing branches.
|
199
212
|
|
213
|
+
MrMurano also uses [bunder](http://bundler.io).
|
200
214
|
|
data/TODO.taskpaper
CHANGED
@@ -3,6 +3,12 @@ Readme:
|
|
3
3
|
- Look into using VCR for testing. @pri(low)
|
4
4
|
|
5
5
|
Commands:
|
6
|
+
- Init command.
|
7
|
+
- Empty sub-commands should return help. @done(2016-11-21)
|
8
|
+
There are a bunch of empty sub-commands that prefix another layer. Such as
|
9
|
+
assign, content, product, and others. Those should be impemented as a ‘help’
|
10
|
+
only command. That is they should return help like the plain `mr` command, but
|
11
|
+
just for their sub-section of things
|
6
12
|
- Errors and Warnings should get sent to STDERR @done(2016-11-03)
|
7
13
|
- Need a more consistent output format. 'pp' is still used in many places. @done(2016-11-03)
|
8
14
|
Maybe have a tool setting for output format? json, yaml, pp, csv, table ?
|
@@ -17,7 +23,7 @@ Account:
|
|
17
23
|
- Netrc library (or the netrc format) doesn't allow '#' in passwords. @done(2016-08-10)
|
18
24
|
|
19
25
|
Endpoints:
|
20
|
-
- Add support for multiple endpoints in one file (
|
26
|
+
- Add support for multiple endpoints in one file @pri(high) @done(2016-11-18)
|
21
27
|
- Add directory support like in modules @done(2016-07-26)
|
22
28
|
|
23
29
|
Files:
|
@@ -39,12 +45,18 @@ CORS:
|
|
39
45
|
- GET&PUT /cors data @done(2016-09-08)
|
40
46
|
|
41
47
|
TSDB:
|
42
|
-
-
|
48
|
+
- For query, if no metrics on cmdline, then do listMetrics and use all. @done(2016-11-21)
|
49
|
+
well, the first 1000 or whatever we get from a single call to listMetrics
|
50
|
+
- Query should handle tags prefixed with @ to match write. @done(2016-11-21)
|
51
|
+
- Add support for new TSDB service. @pri(high) @done(2016-11-03)
|
43
52
|
|
44
53
|
Timeseries:
|
45
54
|
- Add CSV output option. @done(2016-09-09)
|
46
55
|
|
47
56
|
Product:
|
57
|
+
- Support multiple products.
|
58
|
+
Think about how this would work. There is the syncing of the resoruces, and then
|
59
|
+
some of the commands that use product.id.
|
48
60
|
- Auto convert exoline spec files into murano spec files on upload? @done(2016-10-27)
|
49
61
|
Not doing this. Convert is there if you need it.
|
50
62
|
- write alias command @done(2016-09-26)
|
@@ -54,12 +66,20 @@ Service Device:
|
|
54
66
|
- When listing and bussiness.id is missing, gracefully fall back to --idonly @done(2016-09-12)
|
55
67
|
|
56
68
|
Config:
|
69
|
+
- Add config tool.default_sync to set which things sync{up,down} by default
|
70
|
+
It is internally hardcoded to be -s, -a, -m, -e right now.
|
57
71
|
- Add ENV['MR_CONFIGFILE'] path to file to load like --configfile @done(2016-09-22)
|
58
72
|
- Maybe add dotenv support. @done(2016-09-22)
|
59
73
|
- Think about adding dev,staging,prod system; how would that work? @done(2016-09-16)
|
60
74
|
|
75
|
+
SyncUpDown:
|
76
|
+
- Document the hash keys for an item. @pri(high)
|
77
|
+
Also consider turning that hash into a Struct
|
78
|
+
- Allow specifying local files to limit actions to.
|
79
|
+
|
61
80
|
SolutionBase:
|
62
81
|
- All network traffic is serialized. Make some parallel.
|
82
|
+
This might break some things.
|
63
83
|
- Errors from the server should be displayed prettier. @done(2016-09-26)
|
64
84
|
- JSON parse should use symbols for keys. @done(2016-09-01)
|
65
85
|
- Add the --curl verbose option. @done(2016-08-12)
|
data/lib/MrMurano/Config.rb
CHANGED
@@ -39,7 +39,7 @@ module MrMurano
|
|
39
39
|
CFG_PRVT_NAME = '.mrmuranorc.private'.freeze # Going away.
|
40
40
|
CFG_DIR_NAME = '.mrmurano'.freeze
|
41
41
|
CFG_ALTRC_NAME = '.mrmurano/config'.freeze
|
42
|
-
CFG_SYS_NAME = '/etc/mrmuranorc'.freeze
|
42
|
+
CFG_SYS_NAME = '/etc/mrmuranorc'.freeze # Going away.
|
43
43
|
|
44
44
|
def initialize
|
45
45
|
@paths = []
|
@@ -64,7 +64,10 @@ module MrMurano
|
|
64
64
|
end
|
65
65
|
@paths << ConfigFile.new(:user, Pathname.new(Dir.home) + CFG_FILE_NAME)
|
66
66
|
fixModes(Pathname.new(Dir.home) + CFG_DIR_NAME)
|
67
|
-
|
67
|
+
if Pathname.new(CFG_SYS_NAME).exist? then
|
68
|
+
say_warning "!!! Using #{CFG_SYS_NAME} is deprecated"
|
69
|
+
@paths << ConfigFile.new(:system, Pathname.new(CFG_SYS_NAME))
|
70
|
+
end
|
68
71
|
@paths << ConfigFile.new(:defaults, nil, IniFile.new())
|
69
72
|
|
70
73
|
|
@@ -83,6 +86,7 @@ module MrMurano
|
|
83
86
|
set('location.roles', 'roles.yaml', :defaults)
|
84
87
|
set('location.users', 'users.yaml', :defaults)
|
85
88
|
set('location.cors', 'cors.yaml', :defaults)
|
89
|
+
set('location.specs', 'specs', :defaults)
|
86
90
|
|
87
91
|
set('files.default_page', 'index.html', :defaults)
|
88
92
|
|
@@ -33,10 +33,12 @@ module MrMurano
|
|
33
33
|
name = $cfg['product.spec']
|
34
34
|
prid = $cfg['product.id']
|
35
35
|
name = $cfg["p-#{prid}.spec"] unless prid.nil? or $cfg["p-#{prid}.spec"].nil?
|
36
|
+
raise "No spec file named; run `mr config prodcut.spec <specfile>`" if name.nil?
|
36
37
|
|
37
38
|
unless $cfg['location.specs'].nil? then
|
38
|
-
name = File.join($cfg['location.specs'], name)
|
39
|
+
name = ::File.join($cfg['location.specs'], name)
|
39
40
|
end
|
41
|
+
debug " spec file name => #{name}"
|
40
42
|
name
|
41
43
|
end
|
42
44
|
|
@@ -16,11 +16,15 @@ module MrMurano
|
|
16
16
|
##
|
17
17
|
# This gets all data about all endpoints
|
18
18
|
def list
|
19
|
-
get()
|
19
|
+
get().map do |item|
|
20
|
+
item[:content_type] = 'application/json' if item[:content_type].empty?
|
21
|
+
item
|
22
|
+
end
|
20
23
|
end
|
21
24
|
|
22
25
|
def fetch(id)
|
23
26
|
ret = get('/' + id.to_s)
|
27
|
+
ret[:content_type] = 'application/json' if ret[:content_type].empty?
|
24
28
|
aheader = (ret[:script].lines.first or "").chomp
|
25
29
|
dheader = /^--#ENDPOINT (?i:#{ret[:method]}) #{ret[:path]}$/
|
26
30
|
rheader = %{--#ENDPOINT #{ret[:method]} #{ret[:path]}\n}
|
@@ -45,10 +49,12 @@ module MrMurano
|
|
45
49
|
raise "no file" unless local.exist?
|
46
50
|
|
47
51
|
# we assume these are small enough to slurp.
|
48
|
-
script
|
52
|
+
unless remote.has_key? :script then
|
53
|
+
script = local.read
|
54
|
+
remote[:script] = script
|
55
|
+
end
|
49
56
|
limitkeys = [:method, :path, :script, @itemkey]
|
50
57
|
remote = remote.select{|k,v| limitkeys.include? k }
|
51
|
-
remote[:script] = script
|
52
58
|
# post('', remote)
|
53
59
|
if remote.has_key? @itemkey then
|
54
60
|
put('/' + remote[@itemkey], remote) do |request, http|
|
@@ -84,16 +90,31 @@ module MrMurano
|
|
84
90
|
end
|
85
91
|
|
86
92
|
def toRemoteItem(from, path)
|
87
|
-
#
|
93
|
+
# Path could be have multiple endpoints in side, so a loop.
|
94
|
+
items = []
|
88
95
|
path = Pathname.new(path) unless path.kind_of? Pathname
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
96
|
+
cur = nil
|
97
|
+
lineno=0
|
98
|
+
path.readlines().each do |line|
|
99
|
+
md = /--#ENDPOINT (?<method>\S+) (?<path>\S+)( (?<ctype>.*))?/.match(line)
|
100
|
+
if not md.nil? then
|
101
|
+
# header line.
|
102
|
+
cur[:line_end] = lineno unless cur.nil?
|
103
|
+
items << cur unless cur.nil?
|
104
|
+
cur = {:method=>md[:method],
|
105
|
+
:path=>md[:path],
|
106
|
+
:content_type=> (md[:ctype] or 'application/json'),
|
107
|
+
:local_path=>path,
|
108
|
+
:line=>lineno,
|
109
|
+
:script=>line}
|
110
|
+
elsif not cur.nil? and not cur[:script].nil? then
|
111
|
+
cur[:script] << line
|
112
|
+
end
|
113
|
+
lineno += 1
|
95
114
|
end
|
96
|
-
|
115
|
+
cur[:line_end] = lineno unless cur.nil?
|
116
|
+
items << cur unless cur.nil?
|
117
|
+
items
|
97
118
|
end
|
98
119
|
|
99
120
|
def synckey(item)
|
@@ -107,7 +128,7 @@ module MrMurano
|
|
107
128
|
if itemB[:script].nil? and itemB[:local_path] then
|
108
129
|
itemB[:script] = itemB[:local_path].read
|
109
130
|
end
|
110
|
-
return itemA[:script] != itemB[:script]
|
131
|
+
return (itemA[:script] != itemB[:script] or itemA[:content_type] != itemB[:content_type])
|
111
132
|
end
|
112
133
|
|
113
134
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
module MrMurano
|
3
|
+
class SubCmdGroupHelp
|
4
|
+
attr :name, :description
|
5
|
+
|
6
|
+
def initialize(command)
|
7
|
+
@name = command.syntax.to_s
|
8
|
+
@description = command.description.to_s
|
9
|
+
@runner = ::Commander::Runner.instance
|
10
|
+
prefix = /^#{command.name.to_s} /
|
11
|
+
cmds = @runner.instance_variable_get(:@commands).select{|n,_| n.to_s =~ prefix}
|
12
|
+
@commands = cmds
|
13
|
+
als = @runner.instance_variable_get(:@aliases).select{|n,_| n.to_s =~ prefix}
|
14
|
+
@aliases = als
|
15
|
+
|
16
|
+
@options = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def program(key)
|
20
|
+
case key
|
21
|
+
when :name
|
22
|
+
@name
|
23
|
+
when :description
|
24
|
+
@description
|
25
|
+
when :help
|
26
|
+
nil
|
27
|
+
else
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def alias?(name)
|
33
|
+
@aliases.include? name.to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_help
|
37
|
+
hf = @runner.program(:help_formatter).new(self)
|
38
|
+
pc = Commander::HelpFormatter::ProgramContext.new(self).get_binding
|
39
|
+
hf.template(:help).result(pc)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# vim: set ai et sw=2 ts=2 :
|
data/lib/MrMurano/SyncUpDown.rb
CHANGED
@@ -5,6 +5,7 @@ require 'MrMurano/Config'
|
|
5
5
|
require 'MrMurano/hash'
|
6
6
|
|
7
7
|
module MrMurano
|
8
|
+
## Track what things are syncable.
|
8
9
|
class SyncRoot
|
9
10
|
Syncable = Struct.new(:name, :class, :type, :desc, :bydefault) do
|
10
11
|
end
|
@@ -258,16 +259,18 @@ module MrMurano
|
|
258
259
|
path
|
259
260
|
end
|
260
261
|
end.flatten.compact.reject do |path|
|
262
|
+
# TODO: These globs should be in $cfg.
|
261
263
|
path.fnmatch('*_test.lua') or path.basename.fnmatch('.*')
|
262
264
|
end.select do |path|
|
265
|
+
# TODO: These globs should be in $cfg.
|
263
266
|
path.extname == '.lua'
|
264
267
|
end.map do |path|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
268
|
+
item = toRemoteItem(from, path)
|
269
|
+
if item.kind_of?(Array) then
|
270
|
+
item.compact.map{|i| i[:local_path] = path; i}
|
271
|
+
elsif not item.nil? then
|
272
|
+
item[:local_path] = path
|
273
|
+
item
|
271
274
|
end
|
272
275
|
end.flatten.compact
|
273
276
|
end
|
@@ -368,19 +371,31 @@ module MrMurano
|
|
368
371
|
# @param item Hash: The item to get a diff of
|
369
372
|
# @return String: The diff output
|
370
373
|
def dodiff(item)
|
371
|
-
|
374
|
+
trmt = Tempfile.new([tolocalname(item, @itemkey)+'_remote_', '.lua'])
|
375
|
+
tlcl = Tempfile.new([tolocalname(item, @itemkey)+'_local_', '.lua'])
|
376
|
+
if item.has_key? :script then
|
377
|
+
Pathname.new(tlcl.path).open('wb') do |io|
|
378
|
+
io << item[:script]
|
379
|
+
end
|
380
|
+
else
|
381
|
+
Pathname.new(tlcl.path).open('wb') do |io|
|
382
|
+
io << item[:local_path].read
|
383
|
+
end
|
384
|
+
end
|
372
385
|
df = ""
|
373
386
|
begin
|
374
|
-
download(Pathname.new(
|
387
|
+
download(Pathname.new(trmt.path), item)
|
375
388
|
|
376
389
|
cmd = $cfg['diff.cmd'].shellsplit
|
377
|
-
cmd <<
|
378
|
-
cmd <<
|
390
|
+
cmd << trmt.path
|
391
|
+
cmd << tlcl.path
|
379
392
|
|
380
393
|
IO.popen(cmd) {|io| df = io.read }
|
381
394
|
ensure
|
382
|
-
|
383
|
-
|
395
|
+
trmt.close
|
396
|
+
trmt.unlink
|
397
|
+
tlcl.close
|
398
|
+
tlcl.unlink
|
384
399
|
end
|
385
400
|
df
|
386
401
|
end
|
data/lib/MrMurano/commands.rb
CHANGED
@@ -7,12 +7,14 @@ require 'MrMurano/commands/domain'
|
|
7
7
|
require 'MrMurano/commands/exportImport'
|
8
8
|
require 'MrMurano/commands/keystore'
|
9
9
|
require 'MrMurano/commands/logs'
|
10
|
+
require 'MrMurano/commands/product'
|
10
11
|
require 'MrMurano/commands/productCreate'
|
11
12
|
require 'MrMurano/commands/productDelete'
|
12
13
|
require 'MrMurano/commands/productList'
|
13
14
|
require 'MrMurano/commands/productSpec'
|
14
15
|
require 'MrMurano/commands/productWrite'
|
15
16
|
require 'MrMurano/commands/serialNumberCmds'
|
17
|
+
require 'MrMurano/commands/solution'
|
16
18
|
require 'MrMurano/commands/solutionCreate'
|
17
19
|
require 'MrMurano/commands/solutionDelete'
|
18
20
|
require 'MrMurano/commands/solutionList'
|
@@ -4,11 +4,14 @@ command 'assign list' do |c|
|
|
4
4
|
c.syntax = 'mr assign list [options]'
|
5
5
|
c.description = 'List the products that are assigned'
|
6
6
|
c.option '--idonly', 'Only return the ids'
|
7
|
+
|
7
8
|
c.action do |args, options|
|
8
9
|
sol = MrMurano::SC_Device.new
|
9
10
|
|
10
11
|
trigs = sol.showTriggers()
|
11
|
-
|
12
|
+
options.idonly = true if $cfg['business.id'].nil?
|
13
|
+
|
14
|
+
if options.idonly then
|
12
15
|
say trigs.join(' ')
|
13
16
|
else
|
14
17
|
acc = MrMurano::Account.new
|
@@ -17,8 +20,8 @@ command 'assign list' do |c|
|
|
17
20
|
if products.empty? then
|
18
21
|
say trigs.join(' ')
|
19
22
|
else
|
20
|
-
busy = products.map{|r| [r[:label], r[:
|
21
|
-
table = Terminal::Table.new :rows => busy, :headings => ['Label', '
|
23
|
+
busy = products.map{|r| [r[:label], r[:modelId]]}
|
24
|
+
table = Terminal::Table.new :rows => busy, :headings => ['Label', 'ModelID']
|
22
25
|
say table
|
23
26
|
end
|
24
27
|
end
|
@@ -1,5 +1,19 @@
|
|
1
1
|
require 'MrMurano/Product'
|
2
2
|
|
3
|
+
command :content do |c|
|
4
|
+
c.syntax = %{mr content}
|
5
|
+
c.summary = %{About Content Area}
|
6
|
+
c.description = %{This set of commands let you interact with the content area for a product.
|
7
|
+
|
8
|
+
This is where OTA data can be stored so that devices can easily download it.
|
9
|
+
}
|
10
|
+
|
11
|
+
c.action do |args, options|
|
12
|
+
::Commander::UI.enable_paging
|
13
|
+
say MrMurano::SubCmdGroupHelp.new(c).get_help
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
3
17
|
command 'content list' do |c|
|
4
18
|
c.syntax = %{mr content list}
|
5
19
|
c.summary = %{List downloadable content for a product}
|
@@ -13,7 +27,6 @@ command 'content list' do |c|
|
|
13
27
|
prd.outf prd.list
|
14
28
|
end
|
15
29
|
end
|
16
|
-
alias_command :content, 'content list'
|
17
30
|
|
18
31
|
command 'content info' do |c|
|
19
32
|
c.syntax = %{mr content info <content id>}
|
@@ -36,6 +36,18 @@ module MrMurano
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
command :keystore do |c|
|
40
|
+
c.syntax = %{mr keystore}
|
41
|
+
c.summary = %{About Keystore}
|
42
|
+
c.description = %{The Keystore sub-commands let you interact directly with the Keystore instance
|
43
|
+
in a solution. This allows for easier debugging, being able to quickly get and
|
44
|
+
set data. As well as calling any of the other supported REDIS commands.}
|
45
|
+
c.action do |args, options|
|
46
|
+
::Commander::UI.enable_paging
|
47
|
+
say MrMurano::SubCmdGroupHelp.new(c).get_help
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
39
51
|
command 'keystore info' do |c|
|
40
52
|
c.syntax = %{mr keystore info}
|
41
53
|
c.description = %{Show info about the Keystore}
|
@@ -53,7 +65,6 @@ command 'keystore list' do |c|
|
|
53
65
|
sol.outf sol.listkeys
|
54
66
|
end
|
55
67
|
end
|
56
|
-
alias_command :keystore, 'keystore list'
|
57
68
|
|
58
69
|
command 'keystore get' do |c|
|
59
70
|
c.syntax = %{mr keystore get <key>}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'MrMurano/SubCmdGroupContext'
|
2
|
+
|
3
|
+
command :product do |c|
|
4
|
+
c.syntax = %{mr product}
|
5
|
+
c.summary = %{About Product}
|
6
|
+
c.description = %{Sub-commands for working with Products}
|
7
|
+
|
8
|
+
c.action do |args, options|
|
9
|
+
::Commander::UI.enable_paging
|
10
|
+
say MrMurano::SubCmdGroupHelp.new(c).get_help
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# vim: set ai et sw=2 ts=2 :
|
@@ -5,19 +5,42 @@ command 'product list' do |c|
|
|
5
5
|
c.syntax = %{mr product list [options]}
|
6
6
|
c.description = %{List products}
|
7
7
|
c.option '--idonly', 'Only return the ids'
|
8
|
+
c.option '--[no-]all', 'Show all fields'
|
9
|
+
c.option '-o', '--output FILE', %{Download to file instead of STDOUT}
|
8
10
|
|
9
11
|
c.action do |args, options|
|
10
12
|
acc = MrMurano::Account.new
|
11
13
|
data = acc.products
|
14
|
+
|
15
|
+
io=nil
|
16
|
+
if options.output then
|
17
|
+
io = File.open(options.output, 'w')
|
18
|
+
end
|
19
|
+
|
12
20
|
if options.idonly then
|
13
|
-
|
21
|
+
headers = [:modelId]
|
22
|
+
data = data.map{|row| [row[:modelId]]}
|
23
|
+
elsif not options.all then
|
24
|
+
headers = [:label, :modelId]
|
25
|
+
data = data.map{|r| [r[:label], r[:modelId]]}
|
14
26
|
else
|
15
|
-
|
16
|
-
|
17
|
-
say table
|
27
|
+
headers = data[0].keys
|
28
|
+
data = data.map{|r| headers.map{|h| r[h]}}
|
18
29
|
end
|
30
|
+
|
31
|
+
acc.outf(data, io) do |dd, ios|
|
32
|
+
if options.idonly then
|
33
|
+
ios.puts dd.join(' ')
|
34
|
+
else
|
35
|
+
acc.tabularize({
|
36
|
+
:headers=>headers.map{|h| h.to_s},
|
37
|
+
:rows=>dd
|
38
|
+
}, ios)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
io.close unless io.nil?
|
42
|
+
|
19
43
|
end
|
20
44
|
end
|
21
|
-
alias_command :product, 'product list'
|
22
45
|
|
23
46
|
# vim: set ai et sw=2 ts=2 :
|
@@ -4,6 +4,17 @@ require 'MrMurano/hash'
|
|
4
4
|
require 'yaml'
|
5
5
|
require 'terminal-table'
|
6
6
|
|
7
|
+
command 'product spec' do |c|
|
8
|
+
c.syntax = %{mr product spec}
|
9
|
+
c.summary = %{About Product Specs}
|
10
|
+
c.description = %{Some utility for working with prodcut specification files.}
|
11
|
+
|
12
|
+
c.action do |args, options|
|
13
|
+
::Commander::UI.enable_paging
|
14
|
+
say MrMurano::SubCmdGroupHelp.new(c).get_help
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
7
18
|
command 'product spec convert' do |c|
|
8
19
|
c.syntax = %{mr product spec convert FILE}
|
9
20
|
c.summary = %{Convert exoline spec file into Murano format}
|
@@ -72,11 +83,11 @@ command 'product spec pull' do |c|
|
|
72
83
|
end
|
73
84
|
|
74
85
|
prd.outf(ret, io) do |dd, ios|
|
75
|
-
if
|
76
|
-
ios.puts
|
86
|
+
if dd.kind_of? Array then
|
87
|
+
ios.puts dd.join(' ')
|
77
88
|
else
|
78
89
|
prd.tabularize({
|
79
|
-
:rows =>
|
90
|
+
:rows => dd[:resources].map{|r| [r[:alias], r[:format], r[:rid]]},
|
80
91
|
:headers => ['Alias', 'Format', 'RID']
|
81
92
|
}, ios)
|
82
93
|
end
|
@@ -84,7 +95,6 @@ command 'product spec pull' do |c|
|
|
84
95
|
io.close unless io.nil?
|
85
96
|
end
|
86
97
|
end
|
87
|
-
alias_command 'product spec', 'product spec pull'
|
88
98
|
alias_command 'product spec list', 'product spec pull', '--astable'
|
89
99
|
|
90
100
|
# vim: set ai et sw=2 ts=2 :
|
@@ -1,6 +1,18 @@
|
|
1
1
|
require 'MrMurano/Product'
|
2
2
|
require 'terminal-table'
|
3
3
|
|
4
|
+
command :sn do |c|
|
5
|
+
c.syntax = %{mr sn}
|
6
|
+
c.summary = %{About Serial Numbers}
|
7
|
+
c.description = %{The sn sub-commands allow for managing the identifiers (or Serial Numbers) on
|
8
|
+
a product.}
|
9
|
+
|
10
|
+
c.action do |args, options|
|
11
|
+
::Commander::UI.enable_paging
|
12
|
+
say MrMurano::SubCmdGroupHelp.new(c).get_help
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
4
16
|
command 'sn list' do |c|
|
5
17
|
c.syntax = %{mr sn list [options]}
|
6
18
|
c.summary = %{List serial numbers for a product}
|
@@ -18,7 +30,6 @@ command 'sn list' do |c|
|
|
18
30
|
say table
|
19
31
|
end
|
20
32
|
end
|
21
|
-
alias_command :sn, 'sn list'
|
22
33
|
|
23
34
|
command 'sn enable' do |c|
|
24
35
|
c.syntax = %{mr sn enable [<sn>|--file <sns>]}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'MrMurano/SubCmdGroupContext'
|
2
|
+
|
3
|
+
command :solution do |c|
|
4
|
+
c.syntax = %{mr solution}
|
5
|
+
c.summary = %{About Solution}
|
6
|
+
c.description = %{Sub-commands for working with solutions}
|
7
|
+
|
8
|
+
c.action do |args, options|
|
9
|
+
::Commander::UI.enable_paging
|
10
|
+
say MrMurano::SubCmdGroupHelp.new(c).get_help
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# vim: set ai et sw=2 ts=2 :
|
@@ -5,19 +5,41 @@ command 'solution list' do |c|
|
|
5
5
|
c.syntax = %{mr solution list [options]}
|
6
6
|
c.description = %{List solutions}
|
7
7
|
c.option '--idonly', 'Only return the ids'
|
8
|
+
c.option '--[no-]all', 'Show all fields'
|
9
|
+
c.option '-o', '--output FILE', %{Download to file instead of STDOUT}
|
8
10
|
|
9
11
|
c.action do |args, options|
|
10
12
|
acc = MrMurano::Account.new
|
11
13
|
data = acc.solutions
|
14
|
+
|
15
|
+
io=nil
|
16
|
+
if options.output then
|
17
|
+
io = File.open(options.output, 'w')
|
18
|
+
end
|
19
|
+
|
12
20
|
if options.idonly then
|
13
|
-
|
21
|
+
headers = [:apiId]
|
22
|
+
data = data.map{|row| [row[:apiId]]}
|
23
|
+
elsif not options.all then
|
24
|
+
headers = [:apiId, :domain]
|
25
|
+
data = data.map{|r| [r[:apiId], r[:domain]]}
|
14
26
|
else
|
15
|
-
|
16
|
-
|
17
|
-
|
27
|
+
headers = data[0].keys
|
28
|
+
data = data.map{|r| headers.map{|h| r[h]}}
|
29
|
+
end
|
30
|
+
|
31
|
+
acc.outf(data, io) do |dd, ios|
|
32
|
+
if options.idonly then
|
33
|
+
ios.puts dd.join(' ')
|
34
|
+
else
|
35
|
+
acc.tabularize({
|
36
|
+
:headers=>headers.map{|h| h.to_s},
|
37
|
+
:rows=>dd
|
38
|
+
}, ios)
|
39
|
+
end
|
18
40
|
end
|
41
|
+
io.close unless io.nil?
|
19
42
|
end
|
20
43
|
end
|
21
|
-
alias_command :solution, 'solution list'
|
22
44
|
|
23
45
|
# vim: set ai et sw=2 ts=2 :
|
@@ -20,7 +20,11 @@ command :status do |c|
|
|
20
20
|
|
21
21
|
def fmtr(item)
|
22
22
|
if item.has_key? :local_path then
|
23
|
-
item[:local_path].relative_path_from(Pathname.pwd()).to_s
|
23
|
+
lp = item[:local_path].relative_path_from(Pathname.pwd()).to_s
|
24
|
+
if item.has_key?(:line) and item[:line] > 0 then
|
25
|
+
return "#{lp}:#{item[:line]}"
|
26
|
+
end
|
27
|
+
lp
|
24
28
|
else
|
25
29
|
item[:synckey]
|
26
30
|
end
|
@@ -22,6 +22,19 @@ module MrMurano
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
command :timeseries do |c|
|
26
|
+
c.syntax = %{mr timeseries}
|
27
|
+
c.summary = %{About Timeseries}
|
28
|
+
c.description = %{The timeseries sub-commands let you interact directly with the Timeseries
|
29
|
+
instance in a solution. This allows for easier debugging, being able to
|
30
|
+
quickly try out different queries or write test data.}
|
31
|
+
|
32
|
+
c.action do |args, options|
|
33
|
+
::Commander::UI.enable_paging
|
34
|
+
say MrMurano::SubCmdGroupHelp.new(c).get_help
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
25
38
|
command 'timeseries query' do |c|
|
26
39
|
c.syntax = %{mr timeseries query <query string>}
|
27
40
|
c.description = %{Query the timeseries database}
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'date'
|
2
2
|
require 'MrMurano/Solution-ServiceConfig'
|
3
|
+
require 'MrMurano/SubCmdGroupContext'
|
3
4
|
|
4
5
|
module MrMurano
|
5
6
|
module ServiceConfigs
|
@@ -50,6 +51,7 @@ Also, many date-time formats can be parsed and will be converted to microseconds
|
|
50
51
|
}
|
51
52
|
c.option '--when TIMESTAMP', %{When this data happened. (defaults to now)}
|
52
53
|
# TODO: add option to take data from STDIN.
|
54
|
+
c.example 'mr tsdb write hum=45 lux=12765 @sn=44', %{Write two metrics (hum and lux) with a tag (sn)}
|
53
55
|
|
54
56
|
c.action do |args, options|
|
55
57
|
sol = MrMurano::ServiceConfigs::Tsdb.new
|
@@ -80,15 +82,13 @@ Also, many date-time formats can be parsed and will be converted to microseconds
|
|
80
82
|
end
|
81
83
|
|
82
84
|
command 'tsdb query' do |c|
|
83
|
-
c.syntax = %{mr tsdb query [options] }
|
85
|
+
c.syntax = %{mr tsdb query [options] <metric>|@<tag=value> …}
|
84
86
|
c.summary = %{query data}
|
85
|
-
c.description =%{
|
86
|
-
|
87
|
-
list metrics to return
|
88
|
-
list tag=value to match
|
89
|
-
|
87
|
+
c.description =%{Query data from the TSDB.
|
90
88
|
|
91
89
|
FUNCS is a comma seperated list of the aggregate functions.
|
90
|
+
Currently: avg, min, max, count, sum. For string metrics, only count.
|
91
|
+
|
92
92
|
FILL is null, none, any integer, previous
|
93
93
|
|
94
94
|
DURATION is an integer with time unit to indicate relative time before now.
|
@@ -114,6 +114,16 @@ Also, many date-time formats can be parsed and will be converted to microseconds
|
|
114
114
|
|
115
115
|
c.option '-o', '--output FILE', %{Download to file instead of STDOUT}
|
116
116
|
|
117
|
+
c.example 'mr tsdb query hum', 'Get all hum metric entries'
|
118
|
+
c.example 'mr tsdb query hum @sn=45', 'Get all hum metric entries for tag sn=45'
|
119
|
+
c.example 'mr tsdb query hum --limit 1', 'Get just the most recent entry'
|
120
|
+
c.example 'mr tsdb query hum --relative_start 1h', 'Get last hour of hum entries'
|
121
|
+
c.example 'mr tsdb query hum --relative_start -1h', 'Get last hour of hum entries'
|
122
|
+
c.example 'mr tsdb query hum --relative_start 2h --relative_end 1h', 'Get hum entries of two hours ago, but not the last hours'
|
123
|
+
c.example 'mr tsdb query hum --sampling_size 30m', 'Get one hum entry from each 30 minute chunk of time'
|
124
|
+
c.example 'mr tsdb query hum --sampling_size 30m --aggregate avg', 'Get average hum entry from each 30 minute chunk of time'
|
125
|
+
|
126
|
+
|
117
127
|
c.action do |args, options|
|
118
128
|
sol = MrMurano::ServiceConfigs::Tsdb.new
|
119
129
|
|
@@ -124,6 +134,7 @@ Also, many date-time formats can be parsed and will be converted to microseconds
|
|
124
134
|
if arg =~ /=/ then
|
125
135
|
# a tag.
|
126
136
|
k,v = arg.split('=', 2)
|
137
|
+
k = k[1..-1] if k[0] == '@'
|
127
138
|
tags[k] = v
|
128
139
|
else
|
129
140
|
metrics << arg
|
@@ -132,6 +143,11 @@ Also, many date-time formats can be parsed and will be converted to microseconds
|
|
132
143
|
query[:tags] = tags unless tags.empty?
|
133
144
|
query[:metrics] = metrics unless metrics.empty?
|
134
145
|
|
146
|
+
# A query without any metrics is invalid. So if the user didn't provide any,
|
147
|
+
# look up all of them (well, frist however many) and use that list.
|
148
|
+
ret = sol.listMetrics
|
149
|
+
query[:metrics] = ret[:metrics]
|
150
|
+
|
135
151
|
unless options.start_time.nil? then
|
136
152
|
query[:start_time] = sol.str_to_timestamp(options.start_time)
|
137
153
|
end
|
@@ -199,4 +215,17 @@ command 'tsdb list metrics' do |c|
|
|
199
215
|
end
|
200
216
|
end
|
201
217
|
|
218
|
+
command :tsdb do |c|
|
219
|
+
c.syntax = %{mr tsdb}
|
220
|
+
c.summary = %{About TSDB}
|
221
|
+
c.description = %{The tsdb sub-commands let you interact directly with the TSDB instance in a
|
222
|
+
solution. This allows for easier debugging, being able to quickly try out
|
223
|
+
different queries or write test data.}
|
224
|
+
|
225
|
+
c.action do |args, options|
|
226
|
+
::Commander::UI.enable_paging
|
227
|
+
say MrMurano::SubCmdGroupHelp.new(c).get_help
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
202
231
|
# vim: set ai et sw=2 ts=2 :
|
data/lib/MrMurano/version.rb
CHANGED
@@ -8,6 +8,7 @@ RSpec.describe MrMurano::ProductResources do
|
|
8
8
|
$cfg.load
|
9
9
|
$cfg['net.host'] = 'bizapi.hosted.exosite.io'
|
10
10
|
$cfg['product.id'] = 'XYZ'
|
11
|
+
$cfg['product.spec'] = 'XYZ.yaml'
|
11
12
|
|
12
13
|
@prd = MrMurano::ProductResources.new
|
13
14
|
allow(@prd).to receive(:token).and_return("TTTTTTTTTT")
|
@@ -19,6 +20,37 @@ RSpec.describe MrMurano::ProductResources do
|
|
19
20
|
expect(uri.to_s).to eq("https://bizapi.hosted.exosite.io/api:1/product/XYZ/proxy/onep:v1/rpc/process")
|
20
21
|
end
|
21
22
|
|
23
|
+
context "location" do
|
24
|
+
it "Gets a product.spec, with location.specs" do
|
25
|
+
loc = @prd.location
|
26
|
+
expect(loc).to eq("specs/XYZ.yaml")
|
27
|
+
end
|
28
|
+
it "Gets a product.spec, without location.specs" do
|
29
|
+
$cfg.set('location.specs', nil, :defaults)
|
30
|
+
loc = @prd.location
|
31
|
+
expect(loc).to eq("XYZ.yaml")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "Gets a p-FOO.spec, with location.specs" do
|
35
|
+
$cfg['p-XYZ.spec'] = 'magical.file'
|
36
|
+
loc = @prd.location
|
37
|
+
expect(loc).to eq("specs/magical.file")
|
38
|
+
end
|
39
|
+
|
40
|
+
it "Gets a p-FOO.spec, without location.specs" do
|
41
|
+
$cfg['p-XYZ.spec'] = 'magical.file'
|
42
|
+
$cfg.set('location.specs', nil, :defaults)
|
43
|
+
loc = @prd.location
|
44
|
+
expect(loc).to eq("magical.file")
|
45
|
+
end
|
46
|
+
|
47
|
+
it "raises when no spec name" do
|
48
|
+
$cfg['product.spec'] = nil
|
49
|
+
$cfg['product.id'] = nil
|
50
|
+
expect { @prd.location }.to raise_error("No spec file named; run `mr config prodcut.spec <specfile>`")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
22
54
|
context "do_rpc" do
|
23
55
|
# Note, do_rpc is private.
|
24
56
|
it "Accepts an object" do
|
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.
|
4
|
+
version: 1.8.0
|
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-11-
|
11
|
+
date: 2016-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: commander
|
@@ -209,6 +209,7 @@ files:
|
|
209
209
|
- lib/MrMurano/Solution-Services.rb
|
210
210
|
- lib/MrMurano/Solution-Users.rb
|
211
211
|
- lib/MrMurano/Solution.rb
|
212
|
+
- lib/MrMurano/SubCmdGroupContext.rb
|
212
213
|
- lib/MrMurano/SyncUpDown.rb
|
213
214
|
- lib/MrMurano/commands.rb
|
214
215
|
- lib/MrMurano/commands/account.rb
|
@@ -221,12 +222,14 @@ files:
|
|
221
222
|
- lib/MrMurano/commands/exportImport.rb
|
222
223
|
- lib/MrMurano/commands/keystore.rb
|
223
224
|
- lib/MrMurano/commands/logs.rb
|
225
|
+
- lib/MrMurano/commands/product.rb
|
224
226
|
- lib/MrMurano/commands/productCreate.rb
|
225
227
|
- lib/MrMurano/commands/productDelete.rb
|
226
228
|
- lib/MrMurano/commands/productList.rb
|
227
229
|
- lib/MrMurano/commands/productSpec.rb
|
228
230
|
- lib/MrMurano/commands/productWrite.rb
|
229
231
|
- lib/MrMurano/commands/serialNumberCmds.rb
|
232
|
+
- lib/MrMurano/commands/solution.rb
|
230
233
|
- lib/MrMurano/commands/solutionCreate.rb
|
231
234
|
- lib/MrMurano/commands/solutionDelete.rb
|
232
235
|
- lib/MrMurano/commands/solutionList.rb
|