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,47 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'yaml'
|
|
4
|
+
require 'MrMurano/verbosing'
|
|
5
|
+
require 'MrMurano/Account'
|
|
6
|
+
require 'MrMurano/Config'
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module MrMurano
|
|
10
|
+
class ConfigMigrate
|
|
11
|
+
include Verbose
|
|
12
|
+
|
|
13
|
+
def import_secret
|
|
14
|
+
solsecret = Pathname.new($cfg['location.base']) + '.Solutionfile.secret'
|
|
15
|
+
if solsecret.exist? then
|
|
16
|
+
# Is in JSON, which as a subset of YAML, so use YAML parser
|
|
17
|
+
solsecret.open do |io|
|
|
18
|
+
ss = YAML.load(io)
|
|
19
|
+
|
|
20
|
+
pff = $cfg.file_at('passwords', :user)
|
|
21
|
+
pwd = MrMurano::Passwords.new(pff)
|
|
22
|
+
pwd.load
|
|
23
|
+
ps = pwd.get($cfg['net.host'], ss['email'])
|
|
24
|
+
if ps.nil? then
|
|
25
|
+
pwd.set($cfg['net.host'], ss['email'], ss['password'])
|
|
26
|
+
pwd.save
|
|
27
|
+
elsif ps != ss['password'] then
|
|
28
|
+
y = ask("A different password for this account already exists. Overwrite? N/y")
|
|
29
|
+
if y =~ /^y/i then
|
|
30
|
+
pwd.set($cfg['net.host'], ss['email'], ss['password'])
|
|
31
|
+
pwd.save
|
|
32
|
+
end
|
|
33
|
+
else
|
|
34
|
+
# already set, nothing to do.
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
$cfg.set('user.name', ss['email'])
|
|
38
|
+
$cfg.set('solution.id', ss['solution_id']) if ss.has_key? 'solution_id'
|
|
39
|
+
$cfg.set('product.id', ss['product_id']) if ss.has_key? 'product_id'
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# vim: set ai et sw=2 ts=2 :
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
require 'pathname'
|
|
2
|
+
require 'inifile'
|
|
3
|
+
require 'highline'
|
|
4
|
+
|
|
5
|
+
module MrMurano
|
|
6
|
+
class Config
|
|
7
|
+
#
|
|
8
|
+
# internal transient this-run-only things (also -c options)
|
|
9
|
+
# specified from --configfile
|
|
10
|
+
# env from ENV['MURANO_CONFIGFILE']
|
|
11
|
+
# project .murano/config at project dir
|
|
12
|
+
# user .murano/config at $HOME
|
|
13
|
+
# defaults Internal hardcoded defaults
|
|
14
|
+
#
|
|
15
|
+
ConfigFile = Struct.new(:kind, :path, :data) do
|
|
16
|
+
def load()
|
|
17
|
+
return if kind == :internal
|
|
18
|
+
return if kind == :defaults
|
|
19
|
+
self[:path] = Pathname.new(path) unless path.kind_of? Pathname
|
|
20
|
+
self[:data] = IniFile.new(:filename=>path.to_s) if self[:data].nil?
|
|
21
|
+
self[:data].restore
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def write()
|
|
25
|
+
return if kind == :internal
|
|
26
|
+
return if kind == :defaults
|
|
27
|
+
self[:path] = Pathname.new(path) unless path.kind_of? Pathname
|
|
28
|
+
self[:data] = IniFile.new(:filename=>path.to_s) if self[:data].nil?
|
|
29
|
+
self[:data].save
|
|
30
|
+
path.chmod(0600)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
attr :paths
|
|
35
|
+
attr_reader :projectDir
|
|
36
|
+
|
|
37
|
+
CFG_SCOPES=%w{internal specified env project user defaults}.map{|i| i.to_sym}.freeze
|
|
38
|
+
|
|
39
|
+
CFG_ENV_NAME=%{MURANO_CONFIGFILE}.freeze
|
|
40
|
+
CFG_FILE_NAME=%[.murano/config].freeze
|
|
41
|
+
CFG_DIR_NAME=%[.murano].freeze
|
|
42
|
+
|
|
43
|
+
CFG_OLD_ENV_NAME=%[MR_CONFIGFILE].freeze
|
|
44
|
+
CFG_OLD_DIR_NAME=%[.mrmurano].freeze
|
|
45
|
+
CFG_OLD_FILE_NAME=%[.mrmuranorc].freeze
|
|
46
|
+
|
|
47
|
+
def warning(msg)
|
|
48
|
+
$stderr.puts HighLine.color(msg, :yellow)
|
|
49
|
+
end
|
|
50
|
+
def error(msg)
|
|
51
|
+
$stderr.puts HighLine.color(msg, :red)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def migrateOldEnv
|
|
55
|
+
unless ENV[CFG_OLD_ENV_NAME].nil? then
|
|
56
|
+
warning %{ENV "#{CFG_OLD_ENV_NAME}" is no longer supported. Rename it to "#{CFG_ENV_NAME}"}
|
|
57
|
+
unless ENV[CFG_ENV_NAME].nil? then
|
|
58
|
+
error %{Both "#{CFG_ENV_NAME}" and "#{CFG_OLD_ENV_NAME}" defined, please remove "#{CFG_OLD_ENV_NAME}".}
|
|
59
|
+
end
|
|
60
|
+
ENV[CFG_ENV_NAME] = ENV[CFG_OLD_ENV_NAME]
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def migrateOldConfig(where)
|
|
65
|
+
# Check for dir.
|
|
66
|
+
if (where + CFG_OLD_DIR_NAME).exist? then
|
|
67
|
+
warning %{Moving old directory "#{CFG_OLD_DIR_NAME}" to "#{CFG_DIR_NAME}" in "#{where}"}
|
|
68
|
+
(where + CFG_OLD_DIR_NAME).rename(where + CFG_DIR_NAME)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# check for cfg.
|
|
72
|
+
if (where + CFG_OLD_FILE_NAME).exist? then
|
|
73
|
+
warning %{Moving old config "#{CFG_OLD_FILE_NAME}" to "#{CFG_FILE_NAME}" in "#{where}"}
|
|
74
|
+
(where + CFG_DIR_NAME).mkpath
|
|
75
|
+
(where + CFG_OLD_FILE_NAME).rename(where + CFG_FILE_NAME)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def initialize
|
|
80
|
+
@paths = []
|
|
81
|
+
@paths << ConfigFile.new(:internal, nil, IniFile.new())
|
|
82
|
+
# :specified --configfile FILE goes here. (see load_specific)
|
|
83
|
+
|
|
84
|
+
migrateOldEnv
|
|
85
|
+
unless ENV[CFG_ENV_NAME].nil? then
|
|
86
|
+
# if it exists, must be a file
|
|
87
|
+
# if it doesn't exist, that's ok
|
|
88
|
+
ep = Pathname.new(ENV[CFG_ENV_NAME])
|
|
89
|
+
if ep.file? or not ep.exist? then
|
|
90
|
+
@paths << ConfigFile.new(:env, ep)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
@projectDir = findProjectDir()
|
|
95
|
+
migrateOldConfig(@projectDir)
|
|
96
|
+
@paths << ConfigFile.new(:project, @projectDir + CFG_FILE_NAME)
|
|
97
|
+
(@projectDir + CFG_DIR_NAME).mkpath
|
|
98
|
+
fixModes(@projectDir + CFG_DIR_NAME)
|
|
99
|
+
|
|
100
|
+
migrateOldConfig(Pathname.new(Dir.home))
|
|
101
|
+
@paths << ConfigFile.new(:user, Pathname.new(Dir.home) + CFG_FILE_NAME)
|
|
102
|
+
(Pathname.new(Dir.home) + CFG_DIR_NAME).mkpath
|
|
103
|
+
fixModes(Pathname.new(Dir.home) + CFG_DIR_NAME)
|
|
104
|
+
|
|
105
|
+
@paths << ConfigFile.new(:defaults, nil, IniFile.new())
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
set('tool.verbose', false, :defaults)
|
|
109
|
+
set('tool.debug', false, :defaults)
|
|
110
|
+
set('tool.dry', false, :defaults)
|
|
111
|
+
set('tool.fullerror', false, :defaults)
|
|
112
|
+
set('tool.outformat', 'best', :defaults)
|
|
113
|
+
|
|
114
|
+
set('net.host', 'bizapi.hosted.exosite.io', :defaults)
|
|
115
|
+
|
|
116
|
+
set('location.base', @projectDir, :defaults) unless @projectDir.nil?
|
|
117
|
+
set('location.files', 'files', :defaults)
|
|
118
|
+
set('location.endpoints', 'routes', :defaults)
|
|
119
|
+
set('location.modules', 'modules', :defaults)
|
|
120
|
+
set('location.eventhandlers', 'services', :defaults)
|
|
121
|
+
set('location.specs', 'specs/resources.yaml', :defaults)
|
|
122
|
+
set('location.cors', 'cors.yaml', :defaults)
|
|
123
|
+
|
|
124
|
+
set('sync.bydefault', SyncRoot.bydefault.join(' '), :defaults) if defined? SyncRoot
|
|
125
|
+
|
|
126
|
+
set('files.default_page', 'index.html', :defaults)
|
|
127
|
+
set('files.searchFor', '**/*', :defaults)
|
|
128
|
+
set('files.ignoring', '', :defaults)
|
|
129
|
+
|
|
130
|
+
set('endpoints.searchFor', '{,../endpoints}/*.lua {,../endpoints}s/*/*.lua', :defaults)
|
|
131
|
+
set('endpoints.ignoring', '*_test.lua *_spec.lua .*', :defaults)
|
|
132
|
+
|
|
133
|
+
set('eventhandler.searchFor', '*.lua */*.lua {../eventhandlers,../event_handler}/*.lua {../eventhandlers,../event_handler}/*/*.lua', :defaults)
|
|
134
|
+
set('eventhandler.ignoring', '*_test.lua *_spec.lua .*', :defaults)
|
|
135
|
+
set('eventhandler.skiplist', 'websocket webservice device.service_call', :defaults)
|
|
136
|
+
|
|
137
|
+
set('modules.searchFor', '*.lua */*.lua', :defaults)
|
|
138
|
+
set('modules.ignoring', '*_test.lua *_spec.lua .*', :defaults)
|
|
139
|
+
|
|
140
|
+
if Gem.win_platform? then
|
|
141
|
+
set('diff.cmd', 'fc', :defaults)
|
|
142
|
+
else
|
|
143
|
+
set('diff.cmd', 'diff -u', :defaults)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
## Find the root of this project Directory.
|
|
148
|
+
#
|
|
149
|
+
# The Project dir is the directory between PWD and HOME that has one of (in
|
|
150
|
+
# order of preference):
|
|
151
|
+
# - .murano/config
|
|
152
|
+
# - .mrmuranorc
|
|
153
|
+
# - .murano/
|
|
154
|
+
# - .mrmurano/
|
|
155
|
+
def findProjectDir()
|
|
156
|
+
result=nil
|
|
157
|
+
fileNames=[CFG_FILE_NAME, CFG_OLD_FILE_NAME]
|
|
158
|
+
dirNames=[CFG_DIR_NAME, CFG_OLD_DIR_NAME]
|
|
159
|
+
home = Pathname.new(Dir.home).realpath
|
|
160
|
+
pwd = Pathname.new(Dir.pwd).realpath
|
|
161
|
+
return home if home == pwd
|
|
162
|
+
pwd.ascend do |i|
|
|
163
|
+
break unless result.nil?
|
|
164
|
+
break if i == home
|
|
165
|
+
fileNames.each do |f|
|
|
166
|
+
if (i + f).exist? then
|
|
167
|
+
result = i
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
dirNames.each do |f|
|
|
171
|
+
if (i + f).directory? then
|
|
172
|
+
result = i
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Now if nothing found, assume it will live in pwd.
|
|
178
|
+
result = Pathname.new(Dir.pwd) if result.nil?
|
|
179
|
+
return result
|
|
180
|
+
end
|
|
181
|
+
private :findProjectDir
|
|
182
|
+
|
|
183
|
+
def fixModes(path)
|
|
184
|
+
if path.directory? then
|
|
185
|
+
path.chmod(0700)
|
|
186
|
+
elsif path.file? then
|
|
187
|
+
path.chmod(0600)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def file_at(name, scope=:project)
|
|
192
|
+
case scope
|
|
193
|
+
when :internal
|
|
194
|
+
root = nil
|
|
195
|
+
when :specified
|
|
196
|
+
root = nil
|
|
197
|
+
when :project
|
|
198
|
+
root = @projectDir + CFG_DIR_NAME
|
|
199
|
+
when :user
|
|
200
|
+
root = Pathname.new(Dir.home) + CFG_DIR_NAME
|
|
201
|
+
when :defaults
|
|
202
|
+
root = nil
|
|
203
|
+
end
|
|
204
|
+
return nil if root.nil?
|
|
205
|
+
root.mkpath
|
|
206
|
+
root + name
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
## Load all of the potential config files
|
|
210
|
+
def load()
|
|
211
|
+
# - read/write config file in [Project, User, System] (all are optional)
|
|
212
|
+
@paths.each { |cfg| cfg.load }
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
## Load specified file into the config stack
|
|
216
|
+
# This can be called multiple times and each will get loaded into the config
|
|
217
|
+
def load_specific(file)
|
|
218
|
+
spc = ConfigFile.new(:specified, Pathname.new(file))
|
|
219
|
+
spc.load
|
|
220
|
+
@paths.insert(1, spc)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
## Get a value for key, looking at the specificed scopes
|
|
224
|
+
# key is <section>.<key>
|
|
225
|
+
def get(key, scope=CFG_SCOPES)
|
|
226
|
+
scope = [scope] unless scope.kind_of? Array
|
|
227
|
+
paths = @paths.select{|p| scope.include? p.kind}
|
|
228
|
+
|
|
229
|
+
section, ikey = key.split('.')
|
|
230
|
+
paths.each do |path|
|
|
231
|
+
if path.data.has_section?(section) then
|
|
232
|
+
sec = path.data[section]
|
|
233
|
+
return sec if ikey.nil?
|
|
234
|
+
if sec.has_key?(ikey) then
|
|
235
|
+
return sec[ikey]
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
return nil
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
## Dump out a combined config
|
|
243
|
+
def dump()
|
|
244
|
+
# have a fake, merge all into it, then dump it.
|
|
245
|
+
base = IniFile.new()
|
|
246
|
+
@paths.reverse.each do |ini|
|
|
247
|
+
base.merge! ini.data
|
|
248
|
+
end
|
|
249
|
+
base.to_s
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def set(key, value, scope=:project)
|
|
253
|
+
section, ikey = key.split('.', 2)
|
|
254
|
+
raise "Invalid key" if section.nil?
|
|
255
|
+
if not section.nil? and ikey.nil? then
|
|
256
|
+
# If key isn't dotted, then assume the tool section.
|
|
257
|
+
ikey = section
|
|
258
|
+
section = 'tool'
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
paths = @paths.select{|p| scope == p.kind}
|
|
262
|
+
raise "Unknown scope" if paths.empty?
|
|
263
|
+
cfg = paths.first
|
|
264
|
+
data = cfg.data
|
|
265
|
+
tomod = data[section]
|
|
266
|
+
tomod[ikey] = value unless value.nil?
|
|
267
|
+
tomod.delete(ikey) if value.nil?
|
|
268
|
+
data[section] = tomod
|
|
269
|
+
cfg.write
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# key is <section>.<key>
|
|
273
|
+
def [](key)
|
|
274
|
+
get(key)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# For setting internal, this-run-only values
|
|
278
|
+
def []=(key, value)
|
|
279
|
+
set(key, value, :internal)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
# vim: set ai et sw=2 ts=2 :
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
require 'erb'
|
|
2
|
+
require 'securerandom'
|
|
3
|
+
|
|
4
|
+
module MrMurano
|
|
5
|
+
class Mock
|
|
6
|
+
attr_accessor :uuid, :testpoint_file
|
|
7
|
+
|
|
8
|
+
def initialize
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def show
|
|
12
|
+
file = Pathname.new(get_testpoint_path)
|
|
13
|
+
if file.exist? then
|
|
14
|
+
authorization = %{if request.headers["authorization"] == "}
|
|
15
|
+
file.open('rb') do |io|
|
|
16
|
+
io.each_line do |line|
|
|
17
|
+
auth_line = line.include?(authorization)
|
|
18
|
+
if auth_line then
|
|
19
|
+
capture = /\=\= "(.*)"/.match(line)
|
|
20
|
+
return capture.captures[0]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
return false
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def get_mock_template
|
|
29
|
+
path = get_mock_template_path()
|
|
30
|
+
return ::File.read(path)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def get_testpoint_path
|
|
34
|
+
file_name = 'testpoint.post.lua'
|
|
35
|
+
path = %{#{$cfg['location.endpoints']}/#{file_name}}
|
|
36
|
+
return path
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def get_mock_template_path
|
|
40
|
+
return ::File.join(::File.dirname(__FILE__), 'template', 'mock.erb')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def create_testpoint
|
|
44
|
+
uuid = SecureRandom.uuid
|
|
45
|
+
template = ERB.new(get_mock_template)
|
|
46
|
+
endpoint = template.result(binding)
|
|
47
|
+
|
|
48
|
+
Pathname.new(get_testpoint_path).open('wb') do |io|
|
|
49
|
+
io << endpoint
|
|
50
|
+
end
|
|
51
|
+
return uuid
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def remove_testpoint
|
|
55
|
+
file = Pathname.new(get_testpoint_path)
|
|
56
|
+
if file.exist? then
|
|
57
|
+
file.unlink
|
|
58
|
+
return true
|
|
59
|
+
end
|
|
60
|
+
return false
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
require 'MrMurano/Product'
|
|
2
|
+
|
|
3
|
+
module MrMurano
|
|
4
|
+
class Product1PDevice < ProductBase
|
|
5
|
+
include ProductOnePlatformRpcShim
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
super
|
|
9
|
+
@uriparts << :proxy
|
|
10
|
+
@uriparts << 'onep:v1'
|
|
11
|
+
@uriparts << :rpc
|
|
12
|
+
@uriparts << :process
|
|
13
|
+
@model_rid = nil
|
|
14
|
+
@sn_rid = nil
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
## Get the internal protocol identifier for a device
|
|
18
|
+
# +sn+:: Identifier for a device
|
|
19
|
+
def sn_rid(sn)
|
|
20
|
+
return @sn_rid unless @sn_rid.nil?
|
|
21
|
+
prd = Product.new()
|
|
22
|
+
found = []
|
|
23
|
+
|
|
24
|
+
offset = 0
|
|
25
|
+
loop do
|
|
26
|
+
listing = prd.list(offset)
|
|
27
|
+
break if listing.empty?
|
|
28
|
+
found = listing.select{|item| item[:sn] == sn}
|
|
29
|
+
break unless found.empty?
|
|
30
|
+
|
|
31
|
+
offset += 50
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
raise "Identifier Not Found: #{sn}" if found.empty?
|
|
35
|
+
|
|
36
|
+
@sn_rid = found.first[:rid]
|
|
37
|
+
@sn_rid
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
## Get information about a device
|
|
41
|
+
# +sn+:: Identifier for a device
|
|
42
|
+
def info(sn)
|
|
43
|
+
do_rpc({:id=>1,
|
|
44
|
+
:procedure=>:info,
|
|
45
|
+
:arguments=>[sn_rid(sn), {}]
|
|
46
|
+
}, sn_rid(sn))
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
## List resources on a device
|
|
50
|
+
# +sn+:: Identifier for a device
|
|
51
|
+
def list(sn)
|
|
52
|
+
data = info(sn)
|
|
53
|
+
dt = {}
|
|
54
|
+
data[:aliases].each{|k,v| v.each{|a| dt[a] = k.to_s}}
|
|
55
|
+
dt
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def listing(sn)
|
|
59
|
+
do_rpc({:id=>1,
|
|
60
|
+
:procedure=>:listing,
|
|
61
|
+
:arguments=>[sn_rid(sn), [:dataport], {}]
|
|
62
|
+
}, sn_rid(sn))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
## Read the last value for resources on a device
|
|
66
|
+
# +sn+:: Identifier for a device
|
|
67
|
+
# +aliases+:: Array of resource names
|
|
68
|
+
def read(sn, aliases)
|
|
69
|
+
aliases = [aliases] unless aliases.kind_of? Array
|
|
70
|
+
calls = aliases.map do |a|
|
|
71
|
+
{
|
|
72
|
+
:procedure=>:read,
|
|
73
|
+
:arguments=>[ {:alias=>a}, {} ]
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
do_mrpc(calls, sn_rid(sn)).map do |i|
|
|
77
|
+
if i.has_key?(:result) and i[:result].count > 0 and i[:result][0].count > 1 then
|
|
78
|
+
i[:result][0][1]
|
|
79
|
+
else
|
|
80
|
+
nil
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
## Completely remove an identifier from the product
|
|
86
|
+
# +sn+:: Identifier for a device
|
|
87
|
+
def remove(sn)
|
|
88
|
+
# First drop it from the 1P database
|
|
89
|
+
do_rpc({:id=>1, :procedure=>:drop, :arguments=>[sn_rid(sn)]}, nil)
|
|
90
|
+
# Then remove it from the provisioning databases
|
|
91
|
+
psn = ProductSerialNumber.new
|
|
92
|
+
psn.remove_sn(sn)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
## Get a tree of info for a device and its resources.
|
|
96
|
+
# @param sn [String] Identifier for a device
|
|
97
|
+
# @return [Hash]
|
|
98
|
+
def twee(sn)
|
|
99
|
+
inf = info(sn)
|
|
100
|
+
return {} if inf.nil?
|
|
101
|
+
return {} unless inf.kind_of? Hash
|
|
102
|
+
return {} unless inf.has_key? :aliases
|
|
103
|
+
return {} unless inf[:aliases].kind_of? Hash
|
|
104
|
+
aliases = inf[:aliases].keys
|
|
105
|
+
# information for all
|
|
106
|
+
info_calls = aliases.map do |rid|
|
|
107
|
+
{:procedure=>:info, :arguments=>[rid, {}]}
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
limitkeys = [:basic, :description, :usage, :children, :storage]
|
|
111
|
+
|
|
112
|
+
isubs = do_mrpc(info_calls, sn_rid(sn))
|
|
113
|
+
children = isubs.map{|i| i[:result].select{|k,v| limitkeys.include? k} }
|
|
114
|
+
|
|
115
|
+
# most current value
|
|
116
|
+
read_calls = aliases.map do |rid|
|
|
117
|
+
{:procedure=>:read, :arguments=>[rid, {}]}
|
|
118
|
+
end
|
|
119
|
+
ivalues = do_mrpc(read_calls, sn_rid(sn))
|
|
120
|
+
|
|
121
|
+
rez = aliases.zip(children, ivalues).map do |d|
|
|
122
|
+
dinf = d[1]
|
|
123
|
+
dinf[:rid] = d[0]
|
|
124
|
+
dinf[:alias] = inf[:aliases][d[0]].first
|
|
125
|
+
|
|
126
|
+
iv = d[2]
|
|
127
|
+
if iv.has_key?(:result) and iv[:result].count > 0 and iv[:result][0].count > 1 then
|
|
128
|
+
dinf[:value] = iv[:result][0][1]
|
|
129
|
+
else
|
|
130
|
+
dinf[:value] = nil
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
dinf
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
inf[:children] = rez
|
|
137
|
+
inf.select!{|k,v| limitkeys.include? k }
|
|
138
|
+
inf
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# vim: set ai et sw=2 ts=2 :
|