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.
Files changed (151) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +28 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +21 -0
  5. data/Gemfile +27 -0
  6. data/LICENSE.txt +19 -0
  7. data/MuranoCLI.gemspec +50 -0
  8. data/MuranoCLI.iss +50 -0
  9. data/README.markdown +208 -0
  10. data/Rakefile +188 -0
  11. data/TODO.taskpaper +122 -0
  12. data/bin/mr +8 -0
  13. data/bin/murano +84 -0
  14. data/docs/demo.md +109 -0
  15. data/lib/MrMurano/Account.rb +211 -0
  16. data/lib/MrMurano/Config-Migrate.rb +47 -0
  17. data/lib/MrMurano/Config.rb +286 -0
  18. data/lib/MrMurano/Mock.rb +63 -0
  19. data/lib/MrMurano/Product-1P-Device.rb +145 -0
  20. data/lib/MrMurano/Product-Resources.rb +195 -0
  21. data/lib/MrMurano/Product.rb +358 -0
  22. data/lib/MrMurano/ProjectFile.rb +349 -0
  23. data/lib/MrMurano/Solution-Cors.rb +46 -0
  24. data/lib/MrMurano/Solution-Endpoint.rb +177 -0
  25. data/lib/MrMurano/Solution-File.rb +150 -0
  26. data/lib/MrMurano/Solution-ServiceConfig.rb +140 -0
  27. data/lib/MrMurano/Solution-Services.rb +326 -0
  28. data/lib/MrMurano/Solution-Users.rb +129 -0
  29. data/lib/MrMurano/Solution.rb +59 -0
  30. data/lib/MrMurano/SubCmdGroupContext.rb +49 -0
  31. data/lib/MrMurano/SyncUpDown.rb +565 -0
  32. data/lib/MrMurano/commands/assign.rb +57 -0
  33. data/lib/MrMurano/commands/businessList.rb +45 -0
  34. data/lib/MrMurano/commands/completion.rb +152 -0
  35. data/lib/MrMurano/commands/config.rb +67 -0
  36. data/lib/MrMurano/commands/content.rb +130 -0
  37. data/lib/MrMurano/commands/cors.rb +30 -0
  38. data/lib/MrMurano/commands/domain.rb +17 -0
  39. data/lib/MrMurano/commands/gb.rb +33 -0
  40. data/lib/MrMurano/commands/init.rb +138 -0
  41. data/lib/MrMurano/commands/keystore.rb +157 -0
  42. data/lib/MrMurano/commands/logs.rb +78 -0
  43. data/lib/MrMurano/commands/mock.rb +63 -0
  44. data/lib/MrMurano/commands/password.rb +88 -0
  45. data/lib/MrMurano/commands/postgresql.rb +41 -0
  46. data/lib/MrMurano/commands/product.rb +14 -0
  47. data/lib/MrMurano/commands/productCreate.rb +39 -0
  48. data/lib/MrMurano/commands/productDelete.rb +33 -0
  49. data/lib/MrMurano/commands/productDevice.rb +84 -0
  50. data/lib/MrMurano/commands/productDeviceIdCmds.rb +86 -0
  51. data/lib/MrMurano/commands/productList.rb +45 -0
  52. data/lib/MrMurano/commands/productWrite.rb +27 -0
  53. data/lib/MrMurano/commands/show.rb +80 -0
  54. data/lib/MrMurano/commands/solution.rb +14 -0
  55. data/lib/MrMurano/commands/solutionCreate.rb +39 -0
  56. data/lib/MrMurano/commands/solutionDelete.rb +34 -0
  57. data/lib/MrMurano/commands/solutionList.rb +45 -0
  58. data/lib/MrMurano/commands/status.rb +92 -0
  59. data/lib/MrMurano/commands/sync.rb +60 -0
  60. data/lib/MrMurano/commands/timeseries.rb +115 -0
  61. data/lib/MrMurano/commands/tsdb.rb +271 -0
  62. data/lib/MrMurano/commands/usage.rb +23 -0
  63. data/lib/MrMurano/commands/zshcomplete.erb +112 -0
  64. data/lib/MrMurano/commands.rb +32 -0
  65. data/lib/MrMurano/hash.rb +20 -0
  66. data/lib/MrMurano/http.rb +153 -0
  67. data/lib/MrMurano/makePretty.rb +75 -0
  68. data/lib/MrMurano/schema/pf-v1.0.0.yaml +114 -0
  69. data/lib/MrMurano/schema/sf-v0.2.0.yaml +77 -0
  70. data/lib/MrMurano/schema/sf-v0.3.0.yaml +78 -0
  71. data/lib/MrMurano/template/mock.erb +9 -0
  72. data/lib/MrMurano/template/projectFile.murano.erb +81 -0
  73. data/lib/MrMurano/verbosing.rb +99 -0
  74. data/lib/MrMurano/version.rb +4 -0
  75. data/lib/MrMurano.rb +20 -0
  76. data/spec/Account-Passwords_spec.rb +242 -0
  77. data/spec/Account_spec.rb +272 -0
  78. data/spec/ConfigFile_spec.rb +50 -0
  79. data/spec/ConfigMigrate_spec.rb +89 -0
  80. data/spec/Config_spec.rb +409 -0
  81. data/spec/Http_spec.rb +204 -0
  82. data/spec/MakePretties_spec.rb +118 -0
  83. data/spec/Mock_spec.rb +53 -0
  84. data/spec/ProductBase_spec.rb +113 -0
  85. data/spec/ProductContent_spec.rb +162 -0
  86. data/spec/ProductResources_spec.rb +329 -0
  87. data/spec/Product_1P_Device_spec.rb +202 -0
  88. data/spec/Product_1P_RPC_spec.rb +175 -0
  89. data/spec/Product_spec.rb +153 -0
  90. data/spec/ProjectFile_spec.rb +324 -0
  91. data/spec/Solution-Cors_spec.rb +164 -0
  92. data/spec/Solution-Endpoint_spec.rb +581 -0
  93. data/spec/Solution-File_spec.rb +212 -0
  94. data/spec/Solution-ServiceConfig_spec.rb +202 -0
  95. data/spec/Solution-ServiceDevice_spec.rb +176 -0
  96. data/spec/Solution-ServiceEventHandler_spec.rb +385 -0
  97. data/spec/Solution-ServiceModules_spec.rb +465 -0
  98. data/spec/Solution-UsersRoles_spec.rb +207 -0
  99. data/spec/Solution_spec.rb +92 -0
  100. data/spec/SyncRoot_spec.rb +83 -0
  101. data/spec/SyncUpDown_spec.rb +495 -0
  102. data/spec/Verbosing_spec.rb +279 -0
  103. data/spec/_workspace.rb +27 -0
  104. data/spec/cmd_assign_spec.rb +51 -0
  105. data/spec/cmd_business_spec.rb +59 -0
  106. data/spec/cmd_common.rb +72 -0
  107. data/spec/cmd_config_spec.rb +68 -0
  108. data/spec/cmd_content_spec.rb +71 -0
  109. data/spec/cmd_cors_spec.rb +50 -0
  110. data/spec/cmd_device_spec.rb +96 -0
  111. data/spec/cmd_domain_spec.rb +32 -0
  112. data/spec/cmd_init_spec.rb +30 -0
  113. data/spec/cmd_keystore_spec.rb +97 -0
  114. data/spec/cmd_password_spec.rb +62 -0
  115. data/spec/cmd_status_spec.rb +239 -0
  116. data/spec/cmd_syncdown_spec.rb +86 -0
  117. data/spec/cmd_syncup_spec.rb +62 -0
  118. data/spec/cmd_usage_spec.rb +36 -0
  119. data/spec/fixtures/.mrmuranorc +9 -0
  120. data/spec/fixtures/ProjectFiles/invalid.yaml +9 -0
  121. data/spec/fixtures/ProjectFiles/only_meta.yaml +24 -0
  122. data/spec/fixtures/ProjectFiles/with_routes.yaml +27 -0
  123. data/spec/fixtures/SolutionFiles/0.2.0.json +20 -0
  124. data/spec/fixtures/SolutionFiles/0.2.0_invalid.json +18 -0
  125. data/spec/fixtures/SolutionFiles/0.2.json +21 -0
  126. data/spec/fixtures/SolutionFiles/0.3.0.json +20 -0
  127. data/spec/fixtures/SolutionFiles/0.3.0_invalid.json +19 -0
  128. data/spec/fixtures/SolutionFiles/0.3.json +20 -0
  129. data/spec/fixtures/SolutionFiles/basic.json +20 -0
  130. data/spec/fixtures/SolutionFiles/secret.json +6 -0
  131. data/spec/fixtures/configfile +9 -0
  132. data/spec/fixtures/dumped_config +42 -0
  133. data/spec/fixtures/mrmuranorc_deleted_bob +8 -0
  134. data/spec/fixtures/mrmuranorc_tool_bob +3 -0
  135. data/spec/fixtures/product_spec_files/example.exoline.spec.yaml +116 -0
  136. data/spec/fixtures/product_spec_files/example.murano.spec.yaml +14 -0
  137. data/spec/fixtures/product_spec_files/gwe.exoline.spec.yaml +21 -0
  138. data/spec/fixtures/product_spec_files/gwe.murano.spec.yaml +16 -0
  139. data/spec/fixtures/product_spec_files/lightbulb-no-state.yaml +11 -0
  140. data/spec/fixtures/product_spec_files/lightbulb.yaml +14 -0
  141. data/spec/fixtures/roles-three.yaml +11 -0
  142. data/spec/fixtures/syncable_content/assets/icon.png +0 -0
  143. data/spec/fixtures/syncable_content/assets/index.html +0 -0
  144. data/spec/fixtures/syncable_content/assets/js/script.js +0 -0
  145. data/spec/fixtures/syncable_content/modules/table_util.lua +58 -0
  146. data/spec/fixtures/syncable_content/routes/manyRoutes.lua +11 -0
  147. data/spec/fixtures/syncable_content/routes/singleRoute.lua +5 -0
  148. data/spec/fixtures/syncable_content/services/devdata.lua +18 -0
  149. data/spec/fixtures/syncable_content/services/timers.lua +4 -0
  150. data/spec/spec_helper.rb +119 -0
  151. 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 :