MrMurano 1.6.3 → 1.7.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/.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 :
|