MrMurano 1.6.3 → 1.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -2
- data/Gemfile +1 -1
- data/MrMurano.gemspec +1 -1
- data/README.markdown +4 -0
- data/TODO.taskpaper +17 -4
- data/lib/MrMurano/Account.rb +5 -1
- data/lib/MrMurano/Config.rb +3 -1
- data/lib/MrMurano/Product-Resources.rb +239 -0
- data/lib/MrMurano/Product.rb +51 -2
- data/lib/MrMurano/Solution-Cors.rb +81 -0
- data/lib/MrMurano/Solution-Endpoint.rb +8 -4
- data/lib/MrMurano/Solution-File.rb +4 -2
- data/lib/MrMurano/Solution-ServiceConfig.rb +74 -1
- data/lib/MrMurano/Solution-Services.rb +4 -2
- data/lib/MrMurano/Solution-Users.rb +6 -3
- data/lib/MrMurano/Solution.rb +6 -274
- data/lib/MrMurano/SyncUpDown.rb +433 -0
- data/lib/MrMurano/commands/completion.rb +152 -0
- data/lib/MrMurano/commands/content.rb +15 -14
- data/lib/MrMurano/commands/cors.rb +11 -38
- data/lib/MrMurano/commands/exportImport.rb +4 -3
- data/lib/MrMurano/commands/keystore.rb +15 -16
- data/lib/MrMurano/commands/logs.rb +2 -2
- data/lib/MrMurano/commands/productCreate.rb +4 -4
- data/lib/MrMurano/commands/productDelete.rb +6 -8
- data/lib/MrMurano/commands/productSpec.rb +31 -36
- data/lib/MrMurano/commands/productWrite.rb +9 -7
- data/lib/MrMurano/commands/serialNumberCmds.rb +4 -4
- data/lib/MrMurano/commands/solutionCreate.rb +4 -4
- data/lib/MrMurano/commands/solutionDelete.rb +5 -5
- data/lib/MrMurano/commands/status.rb +9 -42
- data/lib/MrMurano/commands/sync.rb +15 -71
- data/lib/MrMurano/commands/timeseries.rb +23 -29
- data/lib/MrMurano/commands/tsdb.rb +202 -0
- data/lib/MrMurano/commands/zshcomplete.erb +112 -0
- data/lib/MrMurano/commands.rb +4 -1
- data/lib/MrMurano/http.rb +4 -3
- data/lib/MrMurano/makePretty.rb +15 -6
- data/lib/MrMurano/verbosing.rb +71 -0
- data/lib/MrMurano/version.rb +1 -1
- data/lib/MrMurano.rb +1 -0
- data/spec/ConfigFile_spec.rb +3 -3
- data/spec/ProductContent_spec.rb +2 -2
- data/spec/ProductResources_spec.rb +152 -0
- data/spec/Product_spec.rb +38 -1
- data/spec/Solution-Cors_spec.rb +134 -0
- data/spec/Solution-ServiceConfig_spec.rb +198 -0
- data/spec/SyncRoot_spec.rb +74 -0
- data/spec/cmd_config_spec.rb +51 -0
- data/spec/fixtures/.mrmuranorc +9 -0
- data/spec/{testfiles → fixtures}/configfile +0 -0
- data/spec/fixtures/mrmuranorc_deleted_bob +8 -0
- data/spec/fixtures/product_spec_files/example.exoline.spec.yaml +116 -0
- data/spec/fixtures/product_spec_files/example.murano.spec.yaml +14 -0
- data/spec/fixtures/product_spec_files/gwe.exoline.spec.yaml +21 -0
- data/spec/fixtures/product_spec_files/gwe.murano.spec.yaml +16 -0
- data/spec/{lightbulb.yaml → fixtures/product_spec_files/lightbulb.yaml} +0 -0
- data/spec/spec_helper.rb +4 -4
- metadata +47 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 08052f794adafafd1df94b8ddb72a1b604ead821
|
4
|
+
data.tar.gz: 4554d9ecf88eacc3af079263f10046b882fc4aa4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbc7d9cabe0efaf8a613b39dc636c353aec46ec5d3bf6de7761be4f810b96ae547d4490b6e077c4c586999a00fff88da44111c8a04f51cd618ad746bcc90a8e7
|
7
|
+
data.tar.gz: fe92deb1e28bb05c11e7a5b274b89afe90b9c8ef1935c6f105cc842e36f657ec3776eb2d3101d4756997f1ae5d8523d575c65dc568675fc68377e08efd07f05a
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -3,12 +3,12 @@ source 'http://rubygems.org'
|
|
3
3
|
#gemspec
|
4
4
|
|
5
5
|
gem 'commander', '~> 4.4.0'
|
6
|
+
gem 'highline', '~> 1.7.8'
|
6
7
|
gem 'terminal-table', '~> 1.4.5'
|
7
8
|
gem 'mime-types', '~> 1.25.1'
|
8
9
|
gem 'mime-types-data', '~> 3.2016'
|
9
10
|
gem 'inifile', '~> 3.0'
|
10
11
|
gem 'http-form_data', '~> 1.0.1'
|
11
|
-
gem 'rainbow', '~> 2.1.0'
|
12
12
|
gem 'dotenv', '~> 2.1.1'
|
13
13
|
|
14
14
|
group :test do
|
data/MrMurano.gemspec
CHANGED
@@ -25,12 +25,12 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.require_paths = ['lib']
|
26
26
|
|
27
27
|
s.add_runtime_dependency('commander', '~> 4.4.0')
|
28
|
+
s.add_runtime_dependency('highline', '~> 1.7.8')
|
28
29
|
s.add_runtime_dependency('terminal-table', '~> 1.4.5')
|
29
30
|
s.add_runtime_dependency('mime-types', '~> 1.25.1')
|
30
31
|
s.add_runtime_dependency('mime-types-data', '~> 3.2016')
|
31
32
|
s.add_runtime_dependency('inifile', '~> 3.0')
|
32
33
|
s.add_runtime_dependency('http-form_data', '~> 1.0.1')
|
33
|
-
s.add_runtime_dependency('rainbow', '~> 2.1.0')
|
34
34
|
s.add_runtime_dependency('dotenv', '~> 2.1.1')
|
35
35
|
|
36
36
|
s.add_development_dependency('bundler', '~> 1.7.6')
|
data/README.markdown
CHANGED
@@ -134,6 +134,10 @@ following commands:
|
|
134
134
|
|
135
135
|
Call them with `--help` for details.
|
136
136
|
|
137
|
+
### ZSH tab completion
|
138
|
+
|
139
|
+
Basic completion support for zsh.
|
140
|
+
|
137
141
|
### Sub-directories
|
138
142
|
|
139
143
|
For the endpoints, modules, and eventhandlers directories. The can contain both
|
data/TODO.taskpaper
CHANGED
@@ -1,8 +1,12 @@
|
|
1
1
|
Readme:
|
2
2
|
- Add more walk-thrus of common actions. (create new solution, …)
|
3
|
-
- Look into using VCR for testing.
|
3
|
+
- Look into using VCR for testing. @pri(low)
|
4
4
|
|
5
5
|
Commands:
|
6
|
+
- Errors and Warnings should get sent to STDERR @done(2016-11-03)
|
7
|
+
- Need a more consistent output format. 'pp' is still used in many places. @done(2016-11-03)
|
8
|
+
Maybe have a tool setting for output format? json, yaml, pp, csv, table ?
|
9
|
+
- Do we need rainbow since highline does ANSI color too? @done(2016-11-02)
|
6
10
|
- Status will show {modules,eventhandlers} have changes when they don’t. @done(2016-09-23)
|
7
11
|
- First time run needs to be smoothed out. @done(2016-08-09)
|
8
12
|
- Default for most commands should be -same @done(2016-08-02)
|
@@ -18,7 +22,7 @@ Endpoints:
|
|
18
22
|
|
19
23
|
Files:
|
20
24
|
- Add ignore patterns to config
|
21
|
-
- Switch to mime-types v3
|
25
|
+
- Switch to mime-types v3 @pri(low)
|
22
26
|
- Figure out how to make the hexed-sha checksum faster. @done(2016-09-23)
|
23
27
|
- Fix upload. @done(2016-08-01)
|
24
28
|
- Files won't update, they always delete then add. @done(2016-07-28)
|
@@ -31,14 +35,18 @@ Users and Roles:
|
|
31
35
|
- Have hash keys in the yaml be strings not symbols. (don't start with colon) @done(2016-07-27)
|
32
36
|
|
33
37
|
CORS:
|
34
|
-
- Get working with sync up/down.
|
38
|
+
- Get working with sync up/down. @done(2016-10-28)
|
35
39
|
- GET&PUT /cors data @done(2016-09-08)
|
36
40
|
|
41
|
+
TSDB:
|
42
|
+
- Add support for new TSDB service. @pri(high)
|
43
|
+
|
37
44
|
Timeseries:
|
38
45
|
- Add CSV output option. @done(2016-09-09)
|
39
46
|
|
40
47
|
Product:
|
41
|
-
- Auto convert exoline spec files into murano spec files on upload?
|
48
|
+
- Auto convert exoline spec files into murano spec files on upload? @done(2016-10-27)
|
49
|
+
Not doing this. Convert is there if you need it.
|
42
50
|
- write alias command @done(2016-09-26)
|
43
51
|
- Need to add way to set the product ID on a device eventhandler. @done(2016-08-01)
|
44
52
|
|
@@ -57,7 +65,12 @@ SolutionBase:
|
|
57
65
|
- Add the --curl verbose option. @done(2016-08-12)
|
58
66
|
- Rebuild how local names and paths are computed from remote items. @done(2016-07-27)
|
59
67
|
|
68
|
+
Windows:
|
69
|
+
- Need to test with http://rubyinstaller.org on Windows. @pri(high)
|
70
|
+
- Look into http://ocra.rubyforge.org for building an exec. @pri(high)
|
71
|
+
|
60
72
|
Bundles:
|
73
|
+
- Revisit this idea. Its complexity may not be worth its value.
|
61
74
|
- Test syncdown behavor.
|
62
75
|
- Work on design @done(2016-08-09)
|
63
76
|
Thinking of something like VIM bundles. A directory of directories. Each with a
|
data/lib/MrMurano/Account.rb
CHANGED
@@ -6,6 +6,7 @@ require 'pathname'
|
|
6
6
|
require 'yaml'
|
7
7
|
require 'MrMurano/Config'
|
8
8
|
require 'MrMurano/http'
|
9
|
+
require 'MrMurano/verbosing'
|
9
10
|
|
10
11
|
module MrMurano
|
11
12
|
class Passwords
|
@@ -53,6 +54,7 @@ module MrMurano
|
|
53
54
|
|
54
55
|
class Account
|
55
56
|
include Http
|
57
|
+
include Verbose
|
56
58
|
|
57
59
|
def endPoint(path)
|
58
60
|
URI('https://' + $cfg['net.host'] + '/api:1/' + path.to_s)
|
@@ -62,7 +64,8 @@ module MrMurano
|
|
62
64
|
host = $cfg['net.host']
|
63
65
|
user = $cfg['user.name']
|
64
66
|
if user.nil? then
|
65
|
-
user
|
67
|
+
say_error("No Murano user account found; please login")
|
68
|
+
user = ask("User name: ")
|
66
69
|
$cfg.set('user.name', user, :user)
|
67
70
|
end
|
68
71
|
pff = $cfg.file_at('passwords', :user)
|
@@ -70,6 +73,7 @@ module MrMurano
|
|
70
73
|
pf.load
|
71
74
|
pws = pf.get(host, user)
|
72
75
|
if pws.nil? then
|
76
|
+
say_error("Couldn't find password for #{user}")
|
73
77
|
pws = ask("Password: ") { |q| q.echo = "*" }
|
74
78
|
pf.set(host, user, pws)
|
75
79
|
pf.save
|
data/lib/MrMurano/Config.rb
CHANGED
@@ -71,6 +71,7 @@ module MrMurano
|
|
71
71
|
set('tool.verbose', false, :defaults)
|
72
72
|
set('tool.debug', false, :defaults)
|
73
73
|
set('tool.dry', false, :defaults)
|
74
|
+
set('tool.outformat', 'best', :defaults)
|
74
75
|
|
75
76
|
set('net.host', 'bizapi.hosted.exosite.io', :defaults)
|
76
77
|
|
@@ -81,6 +82,7 @@ module MrMurano
|
|
81
82
|
set('location.eventhandlers', 'eventhandlers', :defaults)
|
82
83
|
set('location.roles', 'roles.yaml', :defaults)
|
83
84
|
set('location.users', 'users.yaml', :defaults)
|
85
|
+
set('location.cors', 'cors.yaml', :defaults)
|
84
86
|
|
85
87
|
set('files.default_page', 'index.html', :defaults)
|
86
88
|
|
@@ -244,7 +246,7 @@ module MrMurano
|
|
244
246
|
# IF none of -same, then -same; else just the ones listed.
|
245
247
|
def self.checkSAME(opt)
|
246
248
|
unless opt.files or opt.endpoints or opt.modules or
|
247
|
-
opt.eventhandlers or opt.roles or opt.users then
|
249
|
+
opt.eventhandlers or opt.roles or opt.users or opt.spec then
|
248
250
|
opt.files = true
|
249
251
|
opt.endpoints = true
|
250
252
|
opt.modules = true
|
@@ -0,0 +1,239 @@
|
|
1
|
+
require 'MrMurano/Product'
|
2
|
+
require 'MrMurano/SyncUpDown'
|
3
|
+
|
4
|
+
module MrMurano
|
5
|
+
|
6
|
+
## Manage the resources on a Product
|
7
|
+
#
|
8
|
+
# There isn't an okami-shim for most of this, it maps right over to 1P-RPC.
|
9
|
+
# Or better stated, that's all okami-shim is.
|
10
|
+
class ProductResources < ProductBase
|
11
|
+
include SyncUpDown
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
super
|
15
|
+
@uriparts << :proxy
|
16
|
+
@uriparts << 'onep:v1'
|
17
|
+
@uriparts << :rpc
|
18
|
+
@uriparts << :process
|
19
|
+
@model_rid = nil
|
20
|
+
|
21
|
+
@itemkey = :rid # this is the key that is the identifier used by murano
|
22
|
+
@location = location
|
23
|
+
end
|
24
|
+
|
25
|
+
## Get the location of the product spec file
|
26
|
+
def location
|
27
|
+
# If location.specs is defined, then all spec files are assume to be relative
|
28
|
+
# to that and location.base, otherwise they're relative to only location.base
|
29
|
+
#
|
30
|
+
# If there is a p-<product.id>.spec key, then that is the file name.
|
31
|
+
# Otherwise use product.spec
|
32
|
+
|
33
|
+
name = $cfg['product.spec']
|
34
|
+
prid = $cfg['product.id']
|
35
|
+
name = $cfg["p-#{prid}.spec"] unless prid.nil? or $cfg["p-#{prid}.spec"].nil?
|
36
|
+
|
37
|
+
unless $cfg['location.specs'].nil? then
|
38
|
+
name = File.join($cfg['location.specs'], name)
|
39
|
+
end
|
40
|
+
name
|
41
|
+
end
|
42
|
+
|
43
|
+
## The model RID for this product.
|
44
|
+
def model_rid
|
45
|
+
return @model_rid unless @model_rid.nil?
|
46
|
+
prd = Product.new
|
47
|
+
data = prd.info
|
48
|
+
if data.kind_of?(Hash) and data.has_key?(:modelrid) then
|
49
|
+
@model_rid = data[:modelrid]
|
50
|
+
else
|
51
|
+
raise "Bad info; #{data}"
|
52
|
+
end
|
53
|
+
@model_rid
|
54
|
+
end
|
55
|
+
|
56
|
+
## Do a 1P RPC call
|
57
|
+
#
|
58
|
+
# While this will take an array of calls, don't. Only pass one.
|
59
|
+
def do_rpc(calls)
|
60
|
+
calls = [calls] unless calls.kind_of?(Array)
|
61
|
+
r = post('', {
|
62
|
+
:auth=>{:client_id=>model_rid},
|
63
|
+
:calls=>calls
|
64
|
+
})
|
65
|
+
return r if not r.kind_of?(Array) or r.count < 1
|
66
|
+
r = r[0]
|
67
|
+
return r if not r.kind_of?(Hash) or r[:status] != 'ok'
|
68
|
+
r[:result]
|
69
|
+
end
|
70
|
+
private :do_rpc
|
71
|
+
|
72
|
+
## Get 1P info about the prodcut
|
73
|
+
def info
|
74
|
+
do_rpc({:id=>1,
|
75
|
+
:procedure=>:info,
|
76
|
+
:arguments=>[model_rid, {}]
|
77
|
+
})
|
78
|
+
end
|
79
|
+
|
80
|
+
## Return a list of the product resources as items
|
81
|
+
def list()
|
82
|
+
data = info()
|
83
|
+
ret = []
|
84
|
+
data[:aliases].each do |rid, aliases|
|
85
|
+
aliases.each do |al|
|
86
|
+
ret << {
|
87
|
+
:alias => al,
|
88
|
+
:rid => rid
|
89
|
+
}
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
ret
|
94
|
+
end
|
95
|
+
|
96
|
+
## Fetch data from one resource
|
97
|
+
def fetch(rid)
|
98
|
+
do_rpc({:id=>1,
|
99
|
+
:procedure=>:info,
|
100
|
+
:arguments=>[rid, {}],
|
101
|
+
})
|
102
|
+
end
|
103
|
+
|
104
|
+
## Remove a resource by RID
|
105
|
+
def remove(rid)
|
106
|
+
do_rpc({:id=>1,
|
107
|
+
:procedure=>:drop,
|
108
|
+
:arguments=>[rid]
|
109
|
+
})
|
110
|
+
end
|
111
|
+
|
112
|
+
## Create a new resource in the prodcut
|
113
|
+
def create(alias_id, format=:string)
|
114
|
+
raise "Alias cannot be nil" if alias_id.nil?
|
115
|
+
# create then map.
|
116
|
+
rid = do_rpc({:id=>1,
|
117
|
+
:procedure=>:create,
|
118
|
+
:arguments=>[:dataport,
|
119
|
+
{:format=>format,
|
120
|
+
:name=>alias_id,
|
121
|
+
:retention=>{:count=>1,:duration=>:infinity}
|
122
|
+
}
|
123
|
+
]
|
124
|
+
})
|
125
|
+
return rid unless not rid.kind_of?(String) or rid.match(/\p{XDigit}{40}/)
|
126
|
+
|
127
|
+
do_rpc({:id=>1,
|
128
|
+
:procedure=>:map,
|
129
|
+
:arguments=>[:alias, rid, alias_id]
|
130
|
+
})
|
131
|
+
end
|
132
|
+
|
133
|
+
## Upload a resource.
|
134
|
+
# this is for SyncUpDown
|
135
|
+
# @param modify Bool: True if item exists already and this is changing it
|
136
|
+
def upload(src, item, modify)
|
137
|
+
if modify then
|
138
|
+
# this is usually a format change, which can only be set on create.
|
139
|
+
# So delete then create.
|
140
|
+
remove(item[:rid])
|
141
|
+
end
|
142
|
+
r = create(item[:alias], item[:format])
|
143
|
+
raise "Create Failed: #{r}" unless r.nil?
|
144
|
+
end
|
145
|
+
|
146
|
+
## Use alias for doing sync compares
|
147
|
+
# (The RID will change if destroyed and recreated.)
|
148
|
+
def synckey(item)
|
149
|
+
item[:alias]
|
150
|
+
end
|
151
|
+
|
152
|
+
##
|
153
|
+
#
|
154
|
+
def tolocalpath(into, item)
|
155
|
+
into
|
156
|
+
end
|
157
|
+
|
158
|
+
## Get a local list of items from the single file
|
159
|
+
def localitems(from)
|
160
|
+
from = Pathname.new(from) unless from.kind_of? Pathname
|
161
|
+
if not from.exist? then
|
162
|
+
say_warning "Skipping missing #{from.to_s}"
|
163
|
+
return []
|
164
|
+
end
|
165
|
+
unless from.file? then
|
166
|
+
say_warning "Cannot read from #{from.to_s}"
|
167
|
+
return []
|
168
|
+
end
|
169
|
+
|
170
|
+
here = []
|
171
|
+
from.open {|io| here = YAML.load(io) }
|
172
|
+
return [] if here == false
|
173
|
+
|
174
|
+
if here.kind_of?(Hash) and here.has_key?('resources') then
|
175
|
+
here['resources'].map{|i| Hash.transform_keys_to_symbols(i)}
|
176
|
+
else
|
177
|
+
[]
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def download(local, item)
|
182
|
+
# needs to append/merge with file
|
183
|
+
# for now, we'll read, modify, write
|
184
|
+
data = fetch(item[:rid])
|
185
|
+
item[:format] = data[:description][:format]
|
186
|
+
|
187
|
+
here = []
|
188
|
+
if local.exist? then
|
189
|
+
local.open('rb') {|io| here = YAML.load(io)}
|
190
|
+
here = [] if here == false
|
191
|
+
if here.kind_of?(Hash) and here.has_key?('resources') then
|
192
|
+
here = here['resources'].map{|i| Hash.transform_keys_to_symbols(i)}
|
193
|
+
else
|
194
|
+
here = []
|
195
|
+
end
|
196
|
+
end
|
197
|
+
here.delete_if do |i|
|
198
|
+
i[:alias] == item[:alias]
|
199
|
+
end
|
200
|
+
here << item.reject{|k,v| k==:synckey or k==:rid}
|
201
|
+
here.map!{|i| Hash.transform_keys_to_strings(i)}
|
202
|
+
local.open('wb') do |io|
|
203
|
+
io << {'resources'=>here}.to_yaml
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def removelocal(dest, item)
|
208
|
+
# needs to append/merge with file
|
209
|
+
# for now, we'll read, modify, write
|
210
|
+
here = []
|
211
|
+
if dest.exist? then
|
212
|
+
dest.open('rb') {|io| here = YAML.load(io)}
|
213
|
+
here = [] if here == false
|
214
|
+
if here.kind_of?(Hash) and here.has_key?('resources') then
|
215
|
+
here = here['resources'].map{|i| Hash.transform_keys_to_symbols(i)}
|
216
|
+
else
|
217
|
+
here = []
|
218
|
+
end
|
219
|
+
end
|
220
|
+
here.delete_if do |it|
|
221
|
+
it[:alias] == item[:alias]
|
222
|
+
end
|
223
|
+
here.map!{|i| Hash.transform_keys_to_strings(i)}
|
224
|
+
dest.open('wb') do|io|
|
225
|
+
io << {'resources'=>here}.to_yaml
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
##
|
230
|
+
# True if itemA and itemB are different
|
231
|
+
def docmp(itemA, itemB)
|
232
|
+
itemA[:alias] == itemB[:alias] and itemA[:format] == itemB[:format]
|
233
|
+
end
|
234
|
+
|
235
|
+
end
|
236
|
+
SyncRoot.add('specs', ProductResources, 'P', %{Product Specification})
|
237
|
+
|
238
|
+
end
|
239
|
+
# vim: set ai et sw=2 ts=2 :
|
data/lib/MrMurano/Product.rb
CHANGED
@@ -11,11 +11,17 @@ module MrMurano
|
|
11
11
|
@pid = $cfg['product.id']
|
12
12
|
raise "No Product ID!" if @pid.nil?
|
13
13
|
@uriparts = [:product, @pid]
|
14
|
+
@locationbase = $cfg['location.base']
|
15
|
+
@location = nil
|
14
16
|
end
|
15
17
|
|
16
18
|
include Http
|
17
19
|
include Verbose
|
18
20
|
|
21
|
+
## Generate an endpoint in Murano
|
22
|
+
# Uses the uriparts and path
|
23
|
+
# @param path String: any additional parts for the URI
|
24
|
+
# @return URI: The full URI for this enpoint.
|
19
25
|
def endPoint(path='')
|
20
26
|
parts = ['https:/', $cfg['net.host'], 'api:1'] + @uriparts
|
21
27
|
s = parts.map{|v| v.to_s}.join('/')
|
@@ -24,18 +30,25 @@ module MrMurano
|
|
24
30
|
end
|
25
31
|
|
26
32
|
class Product < ProductBase
|
33
|
+
## Get info about the product
|
27
34
|
def info
|
28
35
|
get('/info')
|
29
36
|
end
|
30
37
|
|
38
|
+
## List enabled devices
|
31
39
|
def list(offset=0, limit=50)
|
32
40
|
get("/device/?offset=#{offset}&limit=#{limit}")
|
33
41
|
end
|
34
42
|
|
43
|
+
## Enable a serial number
|
44
|
+
# This creates the device and opens the activation window.
|
35
45
|
def enable(sn)
|
36
46
|
post("/device/#{sn.to_s}")
|
37
47
|
end
|
38
48
|
|
49
|
+
## Upload a spec file.
|
50
|
+
#
|
51
|
+
# Note that this will fail if any of the resources already exist.
|
39
52
|
def update(specFile)
|
40
53
|
specFile = Pathname.new(specFile) unless specFile.kind_of? Pathname
|
41
54
|
|
@@ -53,10 +66,45 @@ module MrMurano
|
|
53
66
|
ret
|
54
67
|
end
|
55
68
|
|
69
|
+
## Write a value to an alias on a device
|
56
70
|
def write(sn, values)
|
57
71
|
post("/write/#{sn}", values)
|
58
72
|
end
|
59
73
|
|
74
|
+
## Converts an exoline style spec file into a Murano style one
|
75
|
+
# @param fin IO: IO Stream to read from
|
76
|
+
# @return String: Converted yaml data
|
77
|
+
def convertit(fin)
|
78
|
+
specOut = {'resources'=>[]}
|
79
|
+
spec = YAML.load(fin)
|
80
|
+
if spec.has_key?('dataports') and spec['dataports'].kind_of?(Array) then
|
81
|
+
dps = spec['dataports'].map do |dp|
|
82
|
+
dp.delete_if{|k,v| k != 'alias' and k != 'format' and k != 'initial'}
|
83
|
+
dp['format'] = 'string' if (dp['format']||'')[0..5] == 'string'
|
84
|
+
dp
|
85
|
+
end
|
86
|
+
specOut['resources'] = dps
|
87
|
+
else
|
88
|
+
raise "No dataports section found, or not an array"
|
89
|
+
end
|
90
|
+
specOut
|
91
|
+
end
|
92
|
+
|
93
|
+
## Converts an exoline style spec file into a Murano style one
|
94
|
+
# @param specFile String: Path to file or '-' for stdin
|
95
|
+
# @return String: Converted yaml data
|
96
|
+
def convert(specFile)
|
97
|
+
if specFile == '-' then
|
98
|
+
convertit($stdin).to_yaml
|
99
|
+
else
|
100
|
+
specFile = Pathname.new(specFile) unless specFile.kind_of? Pathname
|
101
|
+
out = ''
|
102
|
+
specFile.open() do |fin|
|
103
|
+
out = convertit(fin).to_yaml
|
104
|
+
end
|
105
|
+
out
|
106
|
+
end
|
107
|
+
end
|
60
108
|
end
|
61
109
|
|
62
110
|
##
|
@@ -119,7 +167,7 @@ module MrMurano
|
|
119
167
|
case resp
|
120
168
|
when Net::HTTPSuccess
|
121
169
|
if block_given? then
|
122
|
-
resp.read_body
|
170
|
+
resp.read_body(&block)
|
123
171
|
else
|
124
172
|
resp.read_body do |chunk|
|
125
173
|
$stdout.write chunk
|
@@ -136,7 +184,8 @@ module MrMurano
|
|
136
184
|
|
137
185
|
## Upload data for content item
|
138
186
|
# TODO: add support for passing in IOStream
|
139
|
-
|
187
|
+
# @param modify Bool: True if item exists already and this is changing it
|
188
|
+
def upload(id, path, modify=false)
|
140
189
|
path = Pathname.new(path) unless path.kind_of? Pathname
|
141
190
|
|
142
191
|
mime = MIME::Types.type_for(path.to_s)[0] || MIME::Types["application/octet-stream"][0]
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'json'
|
3
|
+
require 'MrMurano/Solution'
|
4
|
+
|
5
|
+
module MrMurano
|
6
|
+
class Cors < SolutionBase
|
7
|
+
def initialize
|
8
|
+
super
|
9
|
+
@uriparts << 'cors'
|
10
|
+
@location = $cfg['location.cors']
|
11
|
+
end
|
12
|
+
|
13
|
+
def list()
|
14
|
+
data = fetch()
|
15
|
+
data[:id] = 'cors'
|
16
|
+
[data]
|
17
|
+
end
|
18
|
+
|
19
|
+
def fetch(id=nil, &block)
|
20
|
+
ret = get()
|
21
|
+
data = JSON.parse(ret[:cors], @json_opts)
|
22
|
+
# XXX cors is a JSON encoded string. That seems weird. keep an eye on this.
|
23
|
+
if block_given? then
|
24
|
+
yield Hash.transform_keys_to_strings(data).to_yaml
|
25
|
+
else
|
26
|
+
data
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def remove(id)
|
31
|
+
# Not really anything to do here. Return to defaults? maybe?
|
32
|
+
end
|
33
|
+
|
34
|
+
##
|
35
|
+
# Upload CORS
|
36
|
+
# :local path to file to push
|
37
|
+
# :remote hash of method and endpoint path (ignored for now)
|
38
|
+
# @param modify Bool: True if item exists already and this is changing it
|
39
|
+
def upload(local, remote, modify=false)
|
40
|
+
remote.reject!{|k,v| k==:synckey or k==:bundled or k==:id}
|
41
|
+
put('', remote)
|
42
|
+
end
|
43
|
+
|
44
|
+
def tolocalpath(into, item)
|
45
|
+
into
|
46
|
+
end
|
47
|
+
|
48
|
+
def removelocal(dest, item)
|
49
|
+
# this is a nop.
|
50
|
+
end
|
51
|
+
#
|
52
|
+
def localitems(from)
|
53
|
+
from = Pathname.new(from) unless from.kind_of? Pathname
|
54
|
+
if not from.exist? then
|
55
|
+
warning "Skipping missing #{from.to_s}"
|
56
|
+
return []
|
57
|
+
end
|
58
|
+
unless from.file? then
|
59
|
+
warning "Cannot read from #{from.to_s}"
|
60
|
+
return []
|
61
|
+
end
|
62
|
+
|
63
|
+
here = {}
|
64
|
+
from.open {|io| here = YAML.load(io) }
|
65
|
+
return [] if here == false
|
66
|
+
|
67
|
+
here[:id] = 'cors'
|
68
|
+
[ Hash.transform_keys_to_symbols(here) ]
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# True if itemA and itemB are different
|
73
|
+
def docmp(itemA, itemB)
|
74
|
+
itemA != itemB
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
SyncRoot.add('cors', Cors, 'Z', %{CORS settings})
|
79
|
+
end
|
80
|
+
|
81
|
+
# vim: set ai et sw=2 ts=2 :
|
@@ -39,7 +39,8 @@ module MrMurano
|
|
39
39
|
# Upload endpoint
|
40
40
|
# :local path to file to push
|
41
41
|
# :remote hash of method and endpoint path
|
42
|
-
|
42
|
+
# @param modify Bool: True if item exists already and this is changing it
|
43
|
+
def upload(local, remote, modify)
|
43
44
|
local = Pathname.new(local) unless local.kind_of? Pathname
|
44
45
|
raise "no file" unless local.exist?
|
45
46
|
|
@@ -75,9 +76,10 @@ module MrMurano
|
|
75
76
|
end
|
76
77
|
|
77
78
|
def tolocalname(item, key)
|
78
|
-
name =
|
79
|
-
name << '
|
80
|
-
name <<
|
79
|
+
name = ''
|
80
|
+
name << item[:path].split('/').reject{|i|i.empty?}.join('-')
|
81
|
+
name << '.'
|
82
|
+
name << item[:method].downcase
|
81
83
|
name << '.lua'
|
82
84
|
end
|
83
85
|
|
@@ -109,5 +111,7 @@ module MrMurano
|
|
109
111
|
end
|
110
112
|
|
111
113
|
end
|
114
|
+
|
115
|
+
SyncRoot.add('endpoints', Endpoint, 'A', %{Endpoints}, true)
|
112
116
|
end
|
113
117
|
# vim: set ai et sw=2 ts=2 :
|
@@ -30,7 +30,7 @@ module MrMurano
|
|
30
30
|
case resp
|
31
31
|
when Net::HTTPSuccess
|
32
32
|
if block_given? then
|
33
|
-
resp.read_body
|
33
|
+
resp.read_body(&block)
|
34
34
|
else
|
35
35
|
resp.read_body do |chunk|
|
36
36
|
$stdout.write chunk
|
@@ -62,7 +62,8 @@ module MrMurano
|
|
62
62
|
|
63
63
|
##
|
64
64
|
# Upload a file
|
65
|
-
|
65
|
+
# @param modify Bool: True if item exists already and this is changing it
|
66
|
+
def upload(local, remote, modify)
|
66
67
|
local = Pathname.new(local) unless local.kind_of? Pathname
|
67
68
|
|
68
69
|
uri = endPoint('upload' + remote[:path])
|
@@ -161,5 +162,6 @@ module MrMurano
|
|
161
162
|
end
|
162
163
|
|
163
164
|
end
|
165
|
+
SyncRoot.add('files', File, 'S', %{Static Files}, true)
|
164
166
|
end
|
165
167
|
# vim: set ai et sw=2 ts=2 :
|