MuranoCLI 2.0.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 +7 -0
- data/.gitignore +28 -0
- data/.rspec +2 -0
- data/.travis.yml +21 -0
- data/Gemfile +27 -0
- data/LICENSE.txt +19 -0
- data/MuranoCLI.gemspec +50 -0
- data/MuranoCLI.iss +50 -0
- data/README.markdown +208 -0
- data/Rakefile +188 -0
- data/TODO.taskpaper +122 -0
- data/bin/mr +8 -0
- data/bin/murano +84 -0
- data/docs/demo.md +109 -0
- data/lib/MrMurano/Account.rb +211 -0
- data/lib/MrMurano/Config-Migrate.rb +47 -0
- data/lib/MrMurano/Config.rb +286 -0
- data/lib/MrMurano/Mock.rb +63 -0
- data/lib/MrMurano/Product-1P-Device.rb +145 -0
- data/lib/MrMurano/Product-Resources.rb +195 -0
- data/lib/MrMurano/Product.rb +358 -0
- data/lib/MrMurano/ProjectFile.rb +349 -0
- data/lib/MrMurano/Solution-Cors.rb +46 -0
- data/lib/MrMurano/Solution-Endpoint.rb +177 -0
- data/lib/MrMurano/Solution-File.rb +150 -0
- data/lib/MrMurano/Solution-ServiceConfig.rb +140 -0
- data/lib/MrMurano/Solution-Services.rb +326 -0
- data/lib/MrMurano/Solution-Users.rb +129 -0
- data/lib/MrMurano/Solution.rb +59 -0
- data/lib/MrMurano/SubCmdGroupContext.rb +49 -0
- data/lib/MrMurano/SyncUpDown.rb +565 -0
- data/lib/MrMurano/commands/assign.rb +57 -0
- data/lib/MrMurano/commands/businessList.rb +45 -0
- data/lib/MrMurano/commands/completion.rb +152 -0
- data/lib/MrMurano/commands/config.rb +67 -0
- data/lib/MrMurano/commands/content.rb +130 -0
- data/lib/MrMurano/commands/cors.rb +30 -0
- data/lib/MrMurano/commands/domain.rb +17 -0
- data/lib/MrMurano/commands/gb.rb +33 -0
- data/lib/MrMurano/commands/init.rb +138 -0
- data/lib/MrMurano/commands/keystore.rb +157 -0
- data/lib/MrMurano/commands/logs.rb +78 -0
- data/lib/MrMurano/commands/mock.rb +63 -0
- data/lib/MrMurano/commands/password.rb +88 -0
- data/lib/MrMurano/commands/postgresql.rb +41 -0
- data/lib/MrMurano/commands/product.rb +14 -0
- data/lib/MrMurano/commands/productCreate.rb +39 -0
- data/lib/MrMurano/commands/productDelete.rb +33 -0
- data/lib/MrMurano/commands/productDevice.rb +84 -0
- data/lib/MrMurano/commands/productDeviceIdCmds.rb +86 -0
- data/lib/MrMurano/commands/productList.rb +45 -0
- data/lib/MrMurano/commands/productWrite.rb +27 -0
- data/lib/MrMurano/commands/show.rb +80 -0
- data/lib/MrMurano/commands/solution.rb +14 -0
- data/lib/MrMurano/commands/solutionCreate.rb +39 -0
- data/lib/MrMurano/commands/solutionDelete.rb +34 -0
- data/lib/MrMurano/commands/solutionList.rb +45 -0
- data/lib/MrMurano/commands/status.rb +92 -0
- data/lib/MrMurano/commands/sync.rb +60 -0
- data/lib/MrMurano/commands/timeseries.rb +115 -0
- data/lib/MrMurano/commands/tsdb.rb +271 -0
- data/lib/MrMurano/commands/usage.rb +23 -0
- data/lib/MrMurano/commands/zshcomplete.erb +112 -0
- data/lib/MrMurano/commands.rb +32 -0
- data/lib/MrMurano/hash.rb +20 -0
- data/lib/MrMurano/http.rb +153 -0
- data/lib/MrMurano/makePretty.rb +75 -0
- data/lib/MrMurano/schema/pf-v1.0.0.yaml +114 -0
- data/lib/MrMurano/schema/sf-v0.2.0.yaml +77 -0
- data/lib/MrMurano/schema/sf-v0.3.0.yaml +78 -0
- data/lib/MrMurano/template/mock.erb +9 -0
- data/lib/MrMurano/template/projectFile.murano.erb +81 -0
- data/lib/MrMurano/verbosing.rb +99 -0
- data/lib/MrMurano/version.rb +4 -0
- data/lib/MrMurano.rb +20 -0
- data/spec/Account-Passwords_spec.rb +242 -0
- data/spec/Account_spec.rb +272 -0
- data/spec/ConfigFile_spec.rb +50 -0
- data/spec/ConfigMigrate_spec.rb +89 -0
- data/spec/Config_spec.rb +409 -0
- data/spec/Http_spec.rb +204 -0
- data/spec/MakePretties_spec.rb +118 -0
- data/spec/Mock_spec.rb +53 -0
- data/spec/ProductBase_spec.rb +113 -0
- data/spec/ProductContent_spec.rb +162 -0
- data/spec/ProductResources_spec.rb +329 -0
- data/spec/Product_1P_Device_spec.rb +202 -0
- data/spec/Product_1P_RPC_spec.rb +175 -0
- data/spec/Product_spec.rb +153 -0
- data/spec/ProjectFile_spec.rb +324 -0
- data/spec/Solution-Cors_spec.rb +164 -0
- data/spec/Solution-Endpoint_spec.rb +581 -0
- data/spec/Solution-File_spec.rb +212 -0
- data/spec/Solution-ServiceConfig_spec.rb +202 -0
- data/spec/Solution-ServiceDevice_spec.rb +176 -0
- data/spec/Solution-ServiceEventHandler_spec.rb +385 -0
- data/spec/Solution-ServiceModules_spec.rb +465 -0
- data/spec/Solution-UsersRoles_spec.rb +207 -0
- data/spec/Solution_spec.rb +92 -0
- data/spec/SyncRoot_spec.rb +83 -0
- data/spec/SyncUpDown_spec.rb +495 -0
- data/spec/Verbosing_spec.rb +279 -0
- data/spec/_workspace.rb +27 -0
- data/spec/cmd_assign_spec.rb +51 -0
- data/spec/cmd_business_spec.rb +59 -0
- data/spec/cmd_common.rb +72 -0
- data/spec/cmd_config_spec.rb +68 -0
- data/spec/cmd_content_spec.rb +71 -0
- data/spec/cmd_cors_spec.rb +50 -0
- data/spec/cmd_device_spec.rb +96 -0
- data/spec/cmd_domain_spec.rb +32 -0
- data/spec/cmd_init_spec.rb +30 -0
- data/spec/cmd_keystore_spec.rb +97 -0
- data/spec/cmd_password_spec.rb +62 -0
- data/spec/cmd_status_spec.rb +239 -0
- data/spec/cmd_syncdown_spec.rb +86 -0
- data/spec/cmd_syncup_spec.rb +62 -0
- data/spec/cmd_usage_spec.rb +36 -0
- data/spec/fixtures/.mrmuranorc +9 -0
- data/spec/fixtures/ProjectFiles/invalid.yaml +9 -0
- data/spec/fixtures/ProjectFiles/only_meta.yaml +24 -0
- data/spec/fixtures/ProjectFiles/with_routes.yaml +27 -0
- data/spec/fixtures/SolutionFiles/0.2.0.json +20 -0
- data/spec/fixtures/SolutionFiles/0.2.0_invalid.json +18 -0
- data/spec/fixtures/SolutionFiles/0.2.json +21 -0
- data/spec/fixtures/SolutionFiles/0.3.0.json +20 -0
- data/spec/fixtures/SolutionFiles/0.3.0_invalid.json +19 -0
- data/spec/fixtures/SolutionFiles/0.3.json +20 -0
- data/spec/fixtures/SolutionFiles/basic.json +20 -0
- data/spec/fixtures/SolutionFiles/secret.json +6 -0
- data/spec/fixtures/configfile +9 -0
- data/spec/fixtures/dumped_config +42 -0
- data/spec/fixtures/mrmuranorc_deleted_bob +8 -0
- data/spec/fixtures/mrmuranorc_tool_bob +3 -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/fixtures/product_spec_files/lightbulb-no-state.yaml +11 -0
- data/spec/fixtures/product_spec_files/lightbulb.yaml +14 -0
- data/spec/fixtures/roles-three.yaml +11 -0
- data/spec/fixtures/syncable_content/assets/icon.png +0 -0
- data/spec/fixtures/syncable_content/assets/index.html +0 -0
- data/spec/fixtures/syncable_content/assets/js/script.js +0 -0
- data/spec/fixtures/syncable_content/modules/table_util.lua +58 -0
- data/spec/fixtures/syncable_content/routes/manyRoutes.lua +11 -0
- data/spec/fixtures/syncable_content/routes/singleRoute.lua +5 -0
- data/spec/fixtures/syncable_content/services/devdata.lua +18 -0
- data/spec/fixtures/syncable_content/services/timers.lua +4 -0
- data/spec/spec_helper.rb +119 -0
- metadata +498 -0
|
@@ -0,0 +1,195 @@
|
|
|
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
|
+
include ProductOnePlatformRpcShim
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
super
|
|
16
|
+
@uriparts << :proxy
|
|
17
|
+
@uriparts << 'onep:v1'
|
|
18
|
+
@uriparts << :rpc
|
|
19
|
+
@uriparts << :process
|
|
20
|
+
@model_rid = nil
|
|
21
|
+
|
|
22
|
+
@itemkey = :rid # this is the key that is the identifier used by murano
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
## Get 1P info about the prodcut
|
|
26
|
+
def info
|
|
27
|
+
do_rpc({:id=>1,
|
|
28
|
+
:procedure=>:info,
|
|
29
|
+
:arguments=>[model_rid, {}]
|
|
30
|
+
})
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
## Return a list of the product resources as items
|
|
34
|
+
def list()
|
|
35
|
+
data = info()
|
|
36
|
+
ret = []
|
|
37
|
+
data[:aliases].each do |rid, aliases|
|
|
38
|
+
aliases.each do |al|
|
|
39
|
+
ret << {
|
|
40
|
+
:alias => al,
|
|
41
|
+
:rid => rid
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
ret
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
## Fetch data from one resource
|
|
50
|
+
def fetch(rid)
|
|
51
|
+
do_rpc({:id=>1,
|
|
52
|
+
:procedure=>:info,
|
|
53
|
+
:arguments=>[rid, {}],
|
|
54
|
+
})
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
## Remove a resource by RID
|
|
58
|
+
def remove(rid)
|
|
59
|
+
do_rpc({:id=>1,
|
|
60
|
+
:procedure=>:drop,
|
|
61
|
+
:arguments=>[rid]
|
|
62
|
+
})
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
## Create a new resource in the prodcut
|
|
66
|
+
def create(alias_id, format=:string)
|
|
67
|
+
raise "Alias cannot be nil" if alias_id.nil?
|
|
68
|
+
# create then map.
|
|
69
|
+
rid = do_rpc({:id=>1,
|
|
70
|
+
:procedure=>:create,
|
|
71
|
+
:arguments=>[:dataport,
|
|
72
|
+
{:format=>format,
|
|
73
|
+
:name=>alias_id,
|
|
74
|
+
:retention=>{:count=>1,:duration=>:infinity}
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
})
|
|
78
|
+
return rid unless not rid.kind_of?(String) or rid.match(/\p{XDigit}{40}/)
|
|
79
|
+
|
|
80
|
+
do_rpc({:id=>1,
|
|
81
|
+
:procedure=>:map,
|
|
82
|
+
:arguments=>[:alias, rid, alias_id]
|
|
83
|
+
})
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
## Upload a resource.
|
|
87
|
+
# this is for SyncUpDown
|
|
88
|
+
# @param modify Bool: True if item exists already and this is changing it
|
|
89
|
+
def upload(src, item, modify)
|
|
90
|
+
if modify then
|
|
91
|
+
# this is usually a format change, which can only be set on create.
|
|
92
|
+
# So delete then create.
|
|
93
|
+
remove(item[:rid])
|
|
94
|
+
end
|
|
95
|
+
r = create(item[:alias], item[:format])
|
|
96
|
+
raise "Create Failed: #{r}" unless r.nil?
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
## Use alias for doing sync compares
|
|
100
|
+
# (The RID will change if destroyed and recreated.)
|
|
101
|
+
def synckey(item)
|
|
102
|
+
item[:alias]
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
##
|
|
106
|
+
#
|
|
107
|
+
def tolocalpath(into, item)
|
|
108
|
+
into
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
## Get a local list of items from the single file
|
|
112
|
+
def localitems(from)
|
|
113
|
+
from = Pathname.new(from) unless from.kind_of? Pathname
|
|
114
|
+
debug "#{self.class.to_s}: Getting local items from: #{from}"
|
|
115
|
+
if not from.exist? then
|
|
116
|
+
warning "Skipping missing #{from.to_s}"
|
|
117
|
+
return []
|
|
118
|
+
end
|
|
119
|
+
unless from.file? then
|
|
120
|
+
warning "Cannot read from #{from.to_s}"
|
|
121
|
+
return []
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
here = []
|
|
125
|
+
from.open {|io| here = YAML.load(io) }
|
|
126
|
+
return [] if here == false
|
|
127
|
+
|
|
128
|
+
if here.kind_of?(Hash) and here.has_key?('resources') then
|
|
129
|
+
here['resources'].map{|i| Hash.transform_keys_to_symbols(i)}
|
|
130
|
+
else
|
|
131
|
+
warning "Unexpected data in #{from.to_s}"
|
|
132
|
+
[]
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def download(local, item)
|
|
137
|
+
# needs to append/merge with file
|
|
138
|
+
# for now, we'll read, modify, write
|
|
139
|
+
data = fetch(item[:rid])
|
|
140
|
+
item[:format] = data[:description][:format]
|
|
141
|
+
|
|
142
|
+
here = []
|
|
143
|
+
if local.exist? then
|
|
144
|
+
local.open('rb') {|io| here = YAML.load(io)}
|
|
145
|
+
here = [] if here == false
|
|
146
|
+
if here.kind_of?(Hash) and here.has_key?('resources') then
|
|
147
|
+
here = here['resources'].map{|i| Hash.transform_keys_to_symbols(i)}
|
|
148
|
+
else
|
|
149
|
+
here = []
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
here.delete_if do |i|
|
|
153
|
+
i[:alias] == item[:alias]
|
|
154
|
+
end
|
|
155
|
+
here << item.reject{|k,v| k==:synckey or k==:rid}
|
|
156
|
+
here.map!{|i| Hash.transform_keys_to_strings(i)}
|
|
157
|
+
local.dirname.mkpath
|
|
158
|
+
local.open('wb') do |io|
|
|
159
|
+
io << {'resources'=>here}.to_yaml
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def removelocal(dest, item)
|
|
164
|
+
# needs to append/merge with file
|
|
165
|
+
# for now, we'll read, modify, write
|
|
166
|
+
here = []
|
|
167
|
+
if dest.exist? then
|
|
168
|
+
dest.open('rb') {|io| here = YAML.load(io)}
|
|
169
|
+
here = [] if here == false
|
|
170
|
+
if here.kind_of?(Hash) and here.has_key?('resources') then
|
|
171
|
+
here = here['resources'].map{|i| Hash.transform_keys_to_symbols(i)}
|
|
172
|
+
else
|
|
173
|
+
here = []
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
here.delete_if do |it|
|
|
177
|
+
it[:alias] == item[:alias]
|
|
178
|
+
end
|
|
179
|
+
here.map!{|i| Hash.transform_keys_to_strings(i)}
|
|
180
|
+
dest.open('wb') do|io|
|
|
181
|
+
io << {'resources'=>here}.to_yaml
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
##
|
|
186
|
+
# True if itemA and itemB are different
|
|
187
|
+
def docmp(itemA, itemB)
|
|
188
|
+
itemA[:alias] != itemB[:alias] or itemA[:format] != itemB[:format]
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
end
|
|
192
|
+
SyncRoot.add('specs', ProductResources, 'P', %{Product Specification})
|
|
193
|
+
|
|
194
|
+
end
|
|
195
|
+
# vim: set ai et sw=2 ts=2 :
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
require 'uri'
|
|
2
|
+
require 'mime/types'
|
|
3
|
+
require 'csv'
|
|
4
|
+
require 'pp'
|
|
5
|
+
require 'MrMurano/http'
|
|
6
|
+
require 'MrMurano/verbosing'
|
|
7
|
+
|
|
8
|
+
module MrMurano
|
|
9
|
+
class ProductBase
|
|
10
|
+
def initialize
|
|
11
|
+
@pid = $cfg['product.id']
|
|
12
|
+
raise "No Product ID!" if @pid.nil?
|
|
13
|
+
@uriparts = [:product, @pid]
|
|
14
|
+
@project_section = :resources
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
include Http
|
|
18
|
+
include Verbose
|
|
19
|
+
|
|
20
|
+
## Generate an endpoint in Murano
|
|
21
|
+
# Uses the uriparts and path
|
|
22
|
+
# @param path String: any additional parts for the URI
|
|
23
|
+
# @return URI: The full URI for this enpoint.
|
|
24
|
+
def endPoint(path='')
|
|
25
|
+
parts = ['https:/', $cfg['net.host'], 'api:1'] + @uriparts
|
|
26
|
+
s = parts.map{|v| v.to_s}.join('/')
|
|
27
|
+
URI(s + path.to_s)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
module ProductOnePlatformRpcShim
|
|
32
|
+
## The model RID for this product.
|
|
33
|
+
def model_rid
|
|
34
|
+
return @model_rid unless @model_rid.nil?
|
|
35
|
+
prd = Product.new
|
|
36
|
+
data = prd.info
|
|
37
|
+
if data.kind_of?(Hash) and data.has_key?(:modelrid) then
|
|
38
|
+
@model_rid = data[:modelrid]
|
|
39
|
+
else
|
|
40
|
+
raise "Bad info; #{data}"
|
|
41
|
+
end
|
|
42
|
+
@model_rid
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
## Do a 1P RPC call
|
|
46
|
+
#
|
|
47
|
+
# While this will take an array of calls, don't. Only pass one.
|
|
48
|
+
# This only returns the result of the first call. Results from other calls are
|
|
49
|
+
# dropped.
|
|
50
|
+
def do_rpc(calls, cid=model_rid)
|
|
51
|
+
calls = [calls] unless calls.kind_of?(Array)
|
|
52
|
+
r = do_mrpc(calls, cid)
|
|
53
|
+
return r if not r.kind_of?(Array) or r.count < 1
|
|
54
|
+
r = r[0]
|
|
55
|
+
return r if not r.kind_of?(Hash) or r[:status] != 'ok'
|
|
56
|
+
r[:result]
|
|
57
|
+
end
|
|
58
|
+
private :do_rpc
|
|
59
|
+
|
|
60
|
+
## Do many 1P RPC calls
|
|
61
|
+
def do_mrpc(calls, cid=model_rid)
|
|
62
|
+
calls = [calls] unless calls.kind_of?(Array)
|
|
63
|
+
maxid = ((calls.max_by{|c| c[:id] or 0 }[:id]) or 0)
|
|
64
|
+
calls.map!{|c| c[:id] = (maxid += 1) unless c.has_key?(:id); c}
|
|
65
|
+
post('', {
|
|
66
|
+
:auth=>(cid ? {:client_id=>cid} : {}),
|
|
67
|
+
:calls=>calls
|
|
68
|
+
})
|
|
69
|
+
end
|
|
70
|
+
private :do_mrpc
|
|
71
|
+
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
class Product < ProductBase
|
|
75
|
+
## Get info about the product
|
|
76
|
+
def info
|
|
77
|
+
get('/info')
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
## List enabled devices
|
|
81
|
+
def list(offset=0, limit=50)
|
|
82
|
+
get("/device/?offset=#{offset}&limit=#{limit}")
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
## Enable a serial number
|
|
86
|
+
# This creates the device and opens the activation window.
|
|
87
|
+
def enable(sn)
|
|
88
|
+
post("/device/#{sn.to_s}")
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
## Upload a spec file.
|
|
92
|
+
#
|
|
93
|
+
# Note that this will fail if any of the resources already exist.
|
|
94
|
+
def update(specFile)
|
|
95
|
+
specFile = Pathname.new(specFile) unless specFile.kind_of? Pathname
|
|
96
|
+
|
|
97
|
+
uri = endPoint('/definition')
|
|
98
|
+
request = Net::HTTP::Post.new(uri)
|
|
99
|
+
ret = nil
|
|
100
|
+
|
|
101
|
+
specFile.open do |io|
|
|
102
|
+
request.body_stream = io
|
|
103
|
+
request.content_length = specFile.size
|
|
104
|
+
set_def_headers(request)
|
|
105
|
+
request.content_type = 'text/yaml'
|
|
106
|
+
ret = workit(request)
|
|
107
|
+
end
|
|
108
|
+
ret
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
## Write a value to an alias on a device
|
|
112
|
+
def write(sn, values)
|
|
113
|
+
post("/write/#{sn}", values) unless $cfg['tool.dry']
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
## Converts an exoline style spec file into a Murano style one
|
|
117
|
+
# @param fin IO: IO Stream to read from
|
|
118
|
+
# @return String: Converted yaml data
|
|
119
|
+
def convertit(fin)
|
|
120
|
+
specOut = {'resources'=>[]}
|
|
121
|
+
spec = YAML.load(fin)
|
|
122
|
+
if spec.has_key?('dataports') and spec['dataports'].kind_of?(Array) then
|
|
123
|
+
dps = spec['dataports'].map do |dp|
|
|
124
|
+
dp.delete_if{|k,v| k != 'alias' and k != 'format' and k != 'initial'}
|
|
125
|
+
dp['format'] = 'string' if (dp['format']||'')[0..5] == 'string'
|
|
126
|
+
dp
|
|
127
|
+
end
|
|
128
|
+
specOut['resources'] = dps
|
|
129
|
+
else
|
|
130
|
+
raise "No dataports section found, or not an array"
|
|
131
|
+
end
|
|
132
|
+
specOut
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
## Converts an exoline style spec file into a Murano style one
|
|
136
|
+
# @param specFile String: Path to file or '-' for stdin
|
|
137
|
+
# @return String: Converted yaml data
|
|
138
|
+
def convert(specFile)
|
|
139
|
+
if specFile == '-' then
|
|
140
|
+
convertit($stdin).to_yaml
|
|
141
|
+
else
|
|
142
|
+
specFile = Pathname.new(specFile) unless specFile.kind_of? Pathname
|
|
143
|
+
out = ''
|
|
144
|
+
specFile.open() do |fin|
|
|
145
|
+
out = convertit(fin).to_yaml
|
|
146
|
+
end
|
|
147
|
+
out
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
##
|
|
153
|
+
# Manage the uploadable content for products.
|
|
154
|
+
class ProductContent < ProductBase
|
|
155
|
+
def initialize
|
|
156
|
+
super
|
|
157
|
+
@uriparts << :proxy
|
|
158
|
+
@uriparts << :provision
|
|
159
|
+
@uriparts << :manage
|
|
160
|
+
@uriparts << :content
|
|
161
|
+
@uriparts << @pid
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
## List all things in content area
|
|
165
|
+
def list
|
|
166
|
+
ret = get('/')
|
|
167
|
+
return [] if ret.kind_of?(Hash)
|
|
168
|
+
ret.lines.map{|i|i.chomp}
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
## List all contents allowed for sn
|
|
172
|
+
def list_for(sn)
|
|
173
|
+
ret = get("/?sn=#{sn}")
|
|
174
|
+
return [] if ret.kind_of?(Hash)
|
|
175
|
+
ret.lines.map{|i|i.chomp}
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
## Create a new content item
|
|
179
|
+
def create(id, meta='', protect=false)
|
|
180
|
+
http_reset
|
|
181
|
+
data = {:id=>id, :meta=>meta}
|
|
182
|
+
data[:protected] = true if protect
|
|
183
|
+
postf('/', data)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
## Remove Content item
|
|
187
|
+
def remove(id)
|
|
188
|
+
postf('/', {:id=>id, :delete=>true})
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
## Get info for content item
|
|
192
|
+
def info(id)
|
|
193
|
+
get("/#{id}") do |request, http|
|
|
194
|
+
http.request(request) do |resp|
|
|
195
|
+
case resp
|
|
196
|
+
when Net::HTTPSuccess
|
|
197
|
+
return CSV.parse(resp.body)
|
|
198
|
+
else
|
|
199
|
+
return nil
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
## Download data for content item
|
|
206
|
+
def download(id, &block)
|
|
207
|
+
get("/#{id}?download=true") do |request, http|
|
|
208
|
+
http.request(request) do |resp|
|
|
209
|
+
case resp
|
|
210
|
+
when Net::HTTPSuccess
|
|
211
|
+
if block_given? then
|
|
212
|
+
resp.read_body(&block)
|
|
213
|
+
else
|
|
214
|
+
resp.read_body do |chunk|
|
|
215
|
+
$stdout.write chunk
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
else
|
|
219
|
+
showHttpError(request, resp)
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
nil
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
## Upload data for content item
|
|
227
|
+
# TODO: add support for passing in IOStream
|
|
228
|
+
# @param modify Bool: True if item exists already and this is changing it
|
|
229
|
+
def upload(id, path, modify=false)
|
|
230
|
+
path = Pathname.new(path) unless path.kind_of? Pathname
|
|
231
|
+
|
|
232
|
+
mime = MIME::Types.type_for(path.to_s)[0] || MIME::Types["application/octet-stream"][0]
|
|
233
|
+
uri = endPoint("/#{id}")
|
|
234
|
+
request = Net::HTTP::Post.new(uri)
|
|
235
|
+
ret = nil
|
|
236
|
+
|
|
237
|
+
path.open do |io|
|
|
238
|
+
request.body_stream = io
|
|
239
|
+
set_def_headers(request)
|
|
240
|
+
request.content_length = path.size
|
|
241
|
+
request.content_type = mime.simplified
|
|
242
|
+
ret = workit(request)
|
|
243
|
+
end
|
|
244
|
+
ret
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
## Delete data for content item
|
|
248
|
+
# Note that the content item is still present and listed.
|
|
249
|
+
def remove_content(id)
|
|
250
|
+
delete("/#{id}")
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
##
|
|
256
|
+
# This is not applicable to Murano. Remove?
|
|
257
|
+
# :nocov:
|
|
258
|
+
class ProductModel < ProductBase
|
|
259
|
+
def initialize
|
|
260
|
+
super
|
|
261
|
+
@uriparts << :proxy
|
|
262
|
+
@uriparts << :provision
|
|
263
|
+
@uriparts << :manage
|
|
264
|
+
@uriparts << :model
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
# In Murano, there should only ever be one.
|
|
268
|
+
# AND it should be @pid
|
|
269
|
+
def list
|
|
270
|
+
get('/')
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def info(modelID=@pid)
|
|
274
|
+
get("/#{modelID}")
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def list_sn(modelID=@pid)
|
|
278
|
+
get("/#{modelID}/")
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
class ProductSerialNumber < ProductBase
|
|
283
|
+
def initialize
|
|
284
|
+
super
|
|
285
|
+
@uriparts << :proxy
|
|
286
|
+
@uriparts << :provision
|
|
287
|
+
@uriparts << :manage
|
|
288
|
+
@uriparts << :model
|
|
289
|
+
@uriparts << @pid
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def list(offset=0, limit=1000)
|
|
293
|
+
ret = get("/?offset=#{offset}&limit=#{limit}&status=true")
|
|
294
|
+
return [] if ret.kind_of?(Hash)
|
|
295
|
+
CSV.parse(ret)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def logs(sn)
|
|
299
|
+
get("/#{sn}?show=log") # results are empty
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def regen(sn)
|
|
303
|
+
postf("/#{sn}", {:enable=>true})
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
def disable(sn)
|
|
307
|
+
postf("/#{sn}", {:disable=>true})
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def activate(sn)
|
|
311
|
+
uri = URI("https://#{@pid}.m2.exosite.com/provision/activate")
|
|
312
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
313
|
+
http.use_ssl = true
|
|
314
|
+
http.start
|
|
315
|
+
request = Net::HTTP::Post.new(uri)
|
|
316
|
+
request.form_data = {
|
|
317
|
+
:vendor => @pid,
|
|
318
|
+
:model => @pid,
|
|
319
|
+
:sn => sn
|
|
320
|
+
}
|
|
321
|
+
request['User-Agent'] = "MrMurano/#{MrMurano::VERSION}"
|
|
322
|
+
request['Authorization'] = nil
|
|
323
|
+
request.content_type = 'application/x-www-form-urlencoded; charset=utf-8'
|
|
324
|
+
curldebug(request)
|
|
325
|
+
response = http.request(request)
|
|
326
|
+
case response
|
|
327
|
+
when Net::HTTPSuccess
|
|
328
|
+
return response.body
|
|
329
|
+
else
|
|
330
|
+
showHttpError(request, response)
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def add_sn(sn, extra='')
|
|
335
|
+
# this does add, but what does that mean?
|
|
336
|
+
# Still need to call …/device/<sn> to enable.
|
|
337
|
+
# How long is the activation window?
|
|
338
|
+
postf('/', {:sn=>sn,:extra=>extra})
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
def remove_sn(sn)
|
|
342
|
+
#postf('/', {:sn=>sn, :delete=>true})
|
|
343
|
+
delete("/#{sn}")
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def ranges
|
|
347
|
+
get('/?show=ranges')
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def add_range()
|
|
351
|
+
post('/', {:ranges=>[ ]})
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
end
|
|
355
|
+
# :nocov:
|
|
356
|
+
|
|
357
|
+
end
|
|
358
|
+
# vim: set ai et sw=2 ts=2 :
|