forj 1.0.1 → 1.0.2

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 (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +7 -0
  3. data/.gitreview +4 -0
  4. data/Gemfile +21 -19
  5. data/Gemfile.lock +71 -0
  6. data/bin/forj +126 -83
  7. data/forj.gemspec +64 -0
  8. data/{lib → forj}/defaults.yaml +23 -1
  9. data/lib/appinit.rb +5 -5
  10. data/lib/build_tmpl/build-env.py +293 -0
  11. data/lib/cloud_test.rb +121 -0
  12. data/lib/forj-settings.rb +52 -39
  13. data/lib/forj/ForjCli.rb +11 -10
  14. data/lib/forj/ForjCore.rb +8 -6
  15. data/lib/forj/process/ForjProcess.rb +345 -82
  16. data/lib/ssh.rb +81 -20
  17. metadata +110 -80
  18. data/lib/compute.rb +0 -36
  19. data/lib/connection.rb +0 -144
  20. data/lib/down.rb +0 -60
  21. data/lib/forj-account.rb +0 -294
  22. data/lib/forj-config.rb +0 -522
  23. data/lib/helpers.rb +0 -56
  24. data/lib/lib-forj/lib/core/core.rb +0 -1740
  25. data/lib/lib-forj/lib/core/definition.rb +0 -441
  26. data/lib/lib-forj/lib/core/definition_internal.rb +0 -306
  27. data/lib/lib-forj/lib/core_process/CloudProcess.rb +0 -334
  28. data/lib/lib-forj/lib/core_process/global_process.rb +0 -406
  29. data/lib/lib-forj/lib/core_process/network_process.rb +0 -603
  30. data/lib/lib-forj/lib/lib-forj.rb +0 -37
  31. data/lib/lib-forj/lib/providers/hpcloud/Hpcloud.rb +0 -419
  32. data/lib/lib-forj/lib/providers/hpcloud/compute.rb +0 -108
  33. data/lib/lib-forj/lib/providers/hpcloud/network.rb +0 -117
  34. data/lib/lib-forj/lib/providers/hpcloud/security_groups.rb +0 -67
  35. data/lib/lib-forj/lib/providers/templates/compute.rb +0 -42
  36. data/lib/lib-forj/lib/providers/templates/core.rb +0 -61
  37. data/lib/lib-forj/lib/providers/templates/network.rb +0 -33
  38. data/lib/log.rb +0 -162
  39. data/lib/network.rb +0 -365
  40. data/lib/repositories.rb +0 -222
  41. data/lib/security.rb +0 -207
  42. data/lib/ssh.sh +0 -185
  43. data/spec/connection_spec.rb +0 -52
  44. data/spec/forj-config_spec.rb +0 -237
  45. data/spec/repositories_spec.rb +0 -50
data/lib/helpers.rb DELETED
@@ -1,56 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- # (c) Copyright 2014 Hewlett-Packard Development Company, L.P.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
-
18
- require 'fileutils'
19
-
20
- module Helpers
21
- def get_home_path
22
- File.expand_path('~')
23
- end
24
-
25
- def create_directory(path)
26
- unless File.directory?(path)
27
- Dir.mkdir path
28
- end
29
- end
30
-
31
- def dir_exists?(path)
32
- if File.exists?(path)
33
- if not File.directory?(path)
34
- msg = "'%s' is not a directory. Please fix it." % path
35
- if $FORJ_LOGGER
36
- Logging.fatal(1, msg)
37
- else
38
- raise msg
39
- end
40
- end
41
- if not File.readable?(path) or not File.writable?(path) or not File.executable?(path)
42
- msg = "%s is not a valid directory. Check permissions and fix it." % path
43
- if $FORJ_LOGGER
44
- Logging.fatal(1, msg)
45
- else
46
- raise msg
47
- end
48
- end
49
- return true
50
- end
51
- false
52
- end
53
-
54
-
55
-
56
- end
@@ -1,1740 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # encoding: UTF-8
3
-
4
- # (c) Copyright 2014 Hewlett-Packard Development Company, L.P.
5
- #
6
- # Licensed under the Apache License, Version 2.0 (the "License");
7
- # you may not use this file except in compliance with the License.
8
- # You may obtain a copy of the License at
9
- #
10
- # http://www.apache.org/licenses/LICENSE-2.0
11
- #
12
- # Unless required by applicable law or agreed to in writing, software
13
- # distributed under the License is distributed on an "AS IS" BASIS,
14
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
- # See the License for the specific language governing permissions and
16
- # limitations under the License.
17
-
18
-
19
- # Those classes describes :
20
- # - processes (BaseProcess) : How to create/delete/edit/query object.
21
- # - controler (BaseControler) : If a provider is defined, define how will do object creation/etc...
22
- # - definition(BaseDefinition): Functions to declare objects, query/data mapping and setup
23
- # this task to make it to work.
24
-
25
- module ForjLib
26
- def ForjLib::debug(iLevel, sMsg)
27
- if iLevel <= $LIB_FORJ_DEBUG
28
- Logging.debug("-%s- %s" % [iLevel, sMsg])
29
- end
30
- end
31
- end
32
-
33
- module ForjLib
34
- class ForjLib::Data
35
-
36
- def initialize(oType = :object)
37
- # Support :data for single object data
38
- # :list for a list of object data
39
- oType = :data if not [:list, :object, :data].include?(oType)
40
- @oType = oType
41
- case oType
42
- when :data, :object
43
- @data = new_object
44
- when :list
45
- @data = new_object_list
46
- end
47
- end
48
-
49
- def type?()
50
- @oType
51
- end
52
-
53
- def object_type?()
54
- @data[:object_type]
55
- end
56
-
57
- def set(oObj, sObjType = nil, hQuery = {})
58
- if oObj.is_a?(ForjLib::Data)
59
- oType = oObj.type?
60
- case oType
61
- when :data, :object
62
- @data[:object_type] = ((sObjType.nil?)? (oObj.object_type?) : sObjType)
63
- @data[:object] = oObj.get(:object)
64
- @data[:attrs] = oObj.get(:attrs)
65
- when :list
66
- @data[:object_type] = ((sObjType.nil?)? (oObj.object_type?) : sObjType)
67
- @data[:object] = oObj.get(:object)
68
- @data[:list] = oObj.get(:list)
69
- @data[:query] = oObj.get(:query)
70
- end
71
- return self
72
- end
73
-
74
- # while saving the object, a mapping work is done?
75
- case @oType
76
- when :data, :object
77
- @data[:object_type] = sObjType
78
- @data[:object] = oObj
79
- @data[:attrs] = yield(sObjType, oObj)
80
- when :list
81
- @data[:object] = oObj
82
- @data[:object_type] = sObjType
83
- @data[:query] = hQuery
84
- unless oObj.nil?
85
- begin
86
- oObj.each { | oObject |
87
- next if oObject.nil?
88
- begin
89
- oDataObject = ForjLib::Data.new(:object)
90
-
91
- oDataObject.set(oObject, sObjType) { |sObjectType, oObject|
92
- yield(sObjectType, oObject)
93
- }
94
- @data[:list] << oDataObject
95
- rescue => e
96
- raise ForjError.new(), "'%s' Mapping attributes issue.\n%s" % [sObjType, e.message]
97
- end
98
- }
99
- rescue => e
100
- raise ForjError.new(), "each function is not supported by '%s'.\n%s" % [oObj.class, e.message]
101
- end
102
- end
103
- end
104
- self
105
- end
106
-
107
- def type=(sObjType)
108
- return self if self.empty?
109
- @data[:object_type] = sObjType
110
- self
111
- end
112
-
113
- def [](*key)
114
- get(*key)
115
- end
116
-
117
- def []=(*key, value)
118
- return false if @oType == :list
119
- rhSet(@data, value, :attrs, key)
120
- true
121
- end
122
-
123
- def get(*key)
124
- return @data if key.length == 0
125
- case @oType
126
- when :data, :object # Return only attrs or the real object.
127
- return @data[key[0]] if key[0] == :object
128
- return rhGet(@data, key) if key[0] == :attrs
129
- rhGet(@data, :attrs, key)
130
- when :list
131
- return @data[key[0]] if [:object, :query].include?(key[0])
132
- return @data[:list][key[0]] if key.length == 1
133
- @data[:list][key[0]][key[1..-1]] # can Return only attrs or the real object.
134
- end
135
- end
136
-
137
- def exist?(*key)
138
- case @oType
139
- when :data, :object
140
- return true if key[0] == :object and @data.key?(key[0])
141
- return true if key[0] == :attrs and rhExist?(@data, key)
142
- (rhExist?(@data, :attrs, key) == key.length+1)
143
- when :list
144
- return true if key[0] == :object and @data.key?(key[0])
145
- (rhExist?(@data[:list][key[0]], :attrs, key[1..-1]) == key.length)
146
- end
147
- end
148
-
149
- def empty?()
150
- @data[:object].nil?
151
- end
152
-
153
- def nil?()
154
- # Obsolete Use empty? instead.
155
- @data[:object].nil?
156
- end
157
-
158
- def length()
159
- case @oType
160
- when :data
161
- return 0 if self.nil?
162
- 1
163
- when :list
164
- @data[:list].length
165
- end
166
- end
167
-
168
- def each(sData = :list)
169
- to_remove = []
170
- return nil if @oType != :list or not [:object, :list].include?(sData)
171
-
172
- @data[:list].each { |elem|
173
- sAction = yield (elem)
174
- case sAction
175
- when :remove
176
- to_remove << elem
177
- end
178
- }
179
- if to_remove.length > 0
180
- to_remove.each { | elem |
181
- @data[:list].delete(elem)
182
- }
183
- end
184
- end
185
-
186
- def each_index(sData = :list)
187
- to_remove = []
188
- return nil if @oType != :list or not [:object, :list].include?(sData)
189
-
190
- @data[:list].each_index { |iIndex|
191
- sAction = yield (iIndex)
192
- case sAction
193
- when :remove
194
- to_remove << @data[:list][iIndex]
195
- end
196
- }
197
- if to_remove.length > 0
198
- to_remove.each { | elem |
199
- @data[:list].delete(elem)
200
- }
201
- end
202
- end
203
-
204
- def registered?()
205
- @bRegister
206
- end
207
-
208
- def register()
209
- @bRegister = true
210
- self
211
- end
212
-
213
- def unregister()
214
- @bRegister = false
215
- self
216
- end
217
- private
218
-
219
- def new_object_list
220
- {
221
- :object => nil,
222
- :object_type => nil,
223
- :list => [],
224
- :query => nil
225
- }
226
- end
227
-
228
- def new_object
229
- oCoreObject = {
230
- :object_type => nil,
231
- :attrs => {},
232
- :object => nil,
233
- }
234
- end
235
-
236
- end
237
- end
238
-
239
- class ForjError < RuntimeError
240
- attr_reader :ForjMsg
241
-
242
- def initialize(message = nil)
243
- @ForjMsg = message
244
- end
245
- end
246
-
247
- # Class to handle key or keypath on needs
248
- class KeyPath
249
-
250
- def initialize(sKeyPath = nil)
251
-
252
- @keypath = []
253
- self.set sKeyPath
254
- end
255
-
256
- def key=(sKeyPath)
257
- self.set(sKeyPath)
258
- end
259
-
260
- def set(sKeyPath)
261
-
262
- if sKeyPath.is_a?(Symbol)
263
- @keypath = [ sKeyPath]
264
- elsif sKeyPath.is_a?(Array)
265
- @keypath = sKeyPath
266
- elsif sKeyPath.is_a?(String)
267
- if /[^\\\/]?\/[^\/]/ =~ sKeyPath or /:[^:\/]/ =~ sKeyPath
268
- # keypath to interpret
269
- aResult = sKeyPath.split('/')
270
- aResult.each_index { | iIndex |
271
- next if not aResult[iIndex].is_a?(String)
272
- aResult[iIndex] = aResult[iIndex][1..-1].to_sym if aResult[iIndex][0] == ":"
273
- }
274
- @keypath = aResult
275
- else
276
- @keypath = [sKeyPath]
277
- end
278
- end
279
- end
280
-
281
- def aTree()
282
- @keypath
283
- end
284
-
285
- def sFullPath()
286
- return nil if @keypath.length == 0
287
- aKeyAccess = @keypath.clone
288
- aKeyAccess.each_index { |iIndex|
289
- next if not aKeyAccess[iIndex].is_a?(Symbol)
290
- aKeyAccess[iIndex] = ":" + aKeyAccess[iIndex].to_s
291
- }
292
- aKeyAccess.join('/')
293
- end
294
-
295
- def to_s
296
- return nil if @keypath.length == 0
297
- aKeyAccess = @keypath.clone
298
- aKeyAccess.each_index { |iIndex|
299
- next if not aKeyAccess[iIndex].is_a?(Symbol)
300
- aKeyAccess[iIndex] = aKeyAccess[iIndex].to_s
301
- }
302
- aKeyAccess.join('/')
303
- end
304
-
305
- def sKey(iIndex = -1)
306
- return nil if @keypath.length == 0
307
- @keypath[iIndex] if self.length >= 1
308
- end
309
-
310
- def length()
311
- @keypath.length
312
- end
313
- end
314
-
315
- # This is the main class definition.
316
- # It drives creation of High level cloud class object, like servers
317
- # Initialization requires a Configuration Object (ForjConfig) and the Account to load.
318
- # Account is loaded with ForjAccount Object.
319
- # During ForjCloud initialization, general options + account options are loaded.
320
-
321
- # For example, to create a server
322
-
323
- # oCloud = ForjCloud.new(oConfig, 'myhpcloud')
324
- # oConfig.set(:server_name,'myservername')
325
- # oCloud.Create(:server)
326
-
327
- # Most of data are predefined from account or general config.
328
- # If some required value are missing, an error is reported.
329
- # A Process Object can be defined, in order to add some process features, like :maestro_server
330
-
331
- # Based Forj Object to use, with a process and (or not) a controler.
332
- class ForjObject
333
-
334
- # ForjObject parameters are:
335
- # oForjConfig : Required. an instance of a configuration system which HAVE to provide
336
- # 2 kind of functions:
337
- # - set (key, value) and []=(key, value)
338
- # From processes, you can set a runtime data with:
339
- # config.set(key, value)
340
- # OR
341
- # config[key] = value
342
- #
343
- # - get (key, default) and [](key, default)
344
- # default is an optional value.
345
- # From processes, you can get a data (runtime/account/config.yaml or defaults.yaml) with:
346
- # config.get(key)
347
- # OR
348
- # config[key]
349
-
350
- # sProcessClass: Required. string or symbol. Is the name of ProcessClass to use.
351
- # This class is dynamically loaded and derived from BaseProcess class.
352
- # It loads the Process class content from a file '$CORE_PROCESS_PATH/<sProcessClass>.rb'
353
- # If sProcessClass is a file path, this file will be loaded as a ruby include.
354
-
355
- # <sProcessClass>.rb file name is case sensible and respect RUBY Class name convention
356
-
357
- # sControllerClass: Optional. string or symbol. Is the name of ControlerClass to use.
358
- # This class is dynamically loaded and derived from BaseControler class.
359
- # It loads the Controler class content from a file '$PROVIDER_PATH/<sControlerClass>.rb'
360
- #
361
- # The provider can redefine partially or totally some processes
362
- # ForjObject will load those redefinition from file:
363
- # '$PROVIDER_PATH/<sControlerClass>Process.rb'
364
-
365
- # <sControllerClass>.rb or <sControllerClass>Process.rb file name is case sensible and respect RUBY Class name convention
366
-
367
- attr_reader :config
368
-
369
-
370
- def initialize(oForjConfig, processesClass = nil, sControllerClass = nil)
371
- # Loading ProcessClass
372
- # Create Process derived from respectively BaseProcess
373
- @config = oForjConfig
374
-
375
- if processesClass.nil?
376
- aProcessesClass = []
377
- elsif not processesClass.is_a?(Array)
378
- aProcessesClass = [processesClass]
379
- else
380
- aProcessesClass = processesClass
381
- end
382
-
383
- cBaseProcess = BaseProcess
384
- cProcessClass = nil
385
-
386
- aProcessesClass.each { | sProcessClass |
387
- ForjLib.debug(1, "Loading Process '%s'" % sProcessClass)
388
-
389
- # And load the content from the <sProcessClass>.rb
390
- if sProcessClass.is_a?(Symbol)
391
- sFile = File.join($CORE_PROCESS_PATH, sProcessClass.to_s + '.rb')
392
- else
393
- if sProcessClass.include?('/')
394
- # Consider a path to the process file. File name is the name of the class.
395
- sPath = File.dirname(File.expand_path(sProcessClass))
396
- file = File.basename(sProcessClass)
397
- file['.rb'] = '' if file['.rb']
398
- sProcessClass = file
399
- sProcessClass = file.capitalize if (/[A-Z]/ =~ file) != 0
400
- else
401
- sPath = $CORE_PROCESS_PATH
402
- end
403
- sFile = File.join(sPath, sProcessClass + '.rb')
404
- end
405
- if File.exists?(sFile)
406
- cNewClass = Class.new(cBaseProcess)
407
- sProcessClass = "%sProcess" % sProcessClass if not /Process$/ =~ sProcessClass
408
- ForjLib.debug(1, "Declaring Process '%s'" % sProcessClass)
409
- cBaseProcess = Object.const_set(sProcessClass, cNewClass)
410
- cProcessClass = sProcessClass
411
- BaseDefinition.current_process(cBaseProcess)
412
- load sFile
413
- else
414
- Logging.warning("Process file definition '%s' is missing. " % sFile)
415
- end
416
- }
417
-
418
- if sControllerClass
419
- ForjLib.debug(1, "Loading Controler/definition '%s'" % sControllerClass)
420
- # Add Provider Object -------------
421
- sProviderClass = sControllerClass.capitalize
422
-
423
- # Initialize an empty class derived from BaseDefinition.
424
- # This to ensure provider Class will be derived from this Base Class
425
- # If this class is derived from a different Class, ruby will raise an error.
426
-
427
- # Create Definition and Controler derived from respectively BaseDefinition and BaseControler
428
- cBaseDefinition = Class.new(BaseDefinition)
429
- # Finally, name that class!
430
- Object.const_set sProviderClass, cBaseDefinition
431
-
432
- cBaseControler = Class.new(BaseController)
433
- Object.const_set sProviderClass + 'Controller', cBaseControler
434
-
435
- # Loading Provider base file. This file should load a class
436
- # which have the same name as the file.
437
- if sControllerClass.include?('/')
438
- # Consider a path to the process file. File name is the name of the class.
439
- sPath = File.dirname(File.expand_path(sControllerClass))
440
- file = File.basename(sControllerClass)
441
- file['.rb'] = '' if file['.rb']
442
- sControllerClass = file
443
- else
444
- sPath = File.join($PROVIDERS_PATH, sControllerClass)
445
- end
446
- sFile = File.join(sPath, sProviderClass + '.rb')
447
- if File.exists?(sFile)
448
- load sFile
449
- else
450
- raise ForjError.new(), "Provider file definition '%s' is missing. Cannot go on" % sFile
451
- end
452
-
453
- #cForjBaseCloud = Class.new(ForjBaseCloud)
454
- # Finally, name that class!
455
- #Object.const_set sProviderClass, cForjBaseCloud
456
-
457
- # Identify Provider Classes. Search for
458
- # - Definition Class (sProviderClass) - Contains ForjClass Object
459
- # - Controller Class (sProviderClass + 'Controller') - Provider Cloud controler object
460
-
461
- # Search for Definition Class
462
- begin
463
- # Get it from Objects
464
- oDefClass = Object.const_get(sProviderClass)
465
- rescue
466
- raise ForjError.new(), 'ForjCloud: Unable to find class "%s"' % sProviderClass
467
- end
468
-
469
- # Search for Controler Class
470
- # - Process Class (sProviderClass + 'Process') - Provider Process object if defined
471
- begin
472
- # Get the same one suffixed with 'Provider' from Objects
473
- oCoreObjectControllerClass = Object.const_get(sProviderClass + 'Controller')
474
- rescue
475
- raise ForjError.new(), 'ForjCloud: Unable to find class "%s"' % sProviderClass + 'Controller'
476
- end
477
-
478
- # Then, we create an BaseCloud Object with 2 objects joined:
479
- # ForjAccount and a BaseControler Object type
480
-
481
-
482
- else
483
- oCoreObjectControllerClass = nil
484
- end
485
-
486
- # Add Process management object ---------------
487
- unless cProcessClass.nil?
488
- begin
489
- oBaseProcessDefClass = Object.const_get(cProcessClass)
490
- rescue
491
- raise ForjError.new(), 'ForjCloud: Unable to find class "%s"' % cProcessClass
492
- end
493
- else
494
- raise ForjError.new(), 'ForjCloud: No valid process loaded. Aborting.'
495
- end
496
- # Ex: Hpcloud(ForjAccount, HpcloudProvider)
497
- if oCoreObjectControllerClass
498
- @oCoreObject = oDefClass.new(oForjConfig, oBaseProcessDefClass.new(), oCoreObjectControllerClass.new())
499
- else
500
- @oCoreObject = oDefClass.new(oForjConfig, oBaseProcessDefClass.new())
501
- end
502
-
503
- end
504
-
505
- def Connect(oCloudObj)
506
- return nil if not oCloudObj or not @oCoreObject
507
- @oCoreObject.Connect(oCloudObj)
508
- end
509
-
510
- def Create(oCloudObj)
511
- return nil if not oCloudObj or not @oCoreObject
512
- @oCoreObject.Create(oCloudObj)
513
- end
514
-
515
- def Delete(oCloudObj)
516
- return nil if not oCloudObj or not @oCoreObject
517
-
518
- @oCoreObject.Delete(oCloudObj)
519
- end
520
-
521
- def Query(oCloudObj, sQuery)
522
- return nil if not oCloudObj or not @oCoreObject
523
-
524
- @oCoreObject.Query(oCloudObj, sQuery)
525
- end
526
-
527
- def Get(oCloudObj, sId)
528
- return nil if not oCloudObj or not @oCoreObject or sId.nil?
529
-
530
- @oCoreObject.Get(oCloudObj, sId)
531
- end
532
-
533
- def Update(oCloudObj)
534
- return nil if not oCloudObj or not @oCoreObject
535
-
536
- @oCoreObject.Update(oCloudObj)
537
- end
538
-
539
- # Function used to ask users about setting up his account.
540
- def Setup(oCloudObj, sAccountName = nil)
541
- return nil if not oCloudObj or not @oCoreObject
542
- @oCoreObject.Setup(oCloudObj, sAccountName)
543
- end
544
- end
545
-
546
- # This class based on generic ForjObject, defines a Cloud Process to use.
547
- class ForjCloud < ForjObject
548
- def initialize(oConfig, sAccount = nil, aProcesses = [])
549
-
550
- unless oConfig.is_a?(ForjAccount)
551
- oForjAccount = ForjAccount.new(oConfig)
552
- unless sAccount.nil?
553
- oForjAccount.ac_load(sAccount)
554
- end
555
- else
556
- oForjAccount = oConfig
557
- end
558
- aProcessList = [:CloudProcess]
559
-
560
- sControllerMod = oForjAccount.get(:provider_name)
561
- raise ForjError.new(), "Provider_name not set. Unable to create instance ForjCloud." if sControllerMod.nil?
562
-
563
- sControllerProcessMod = File.join($PROVIDERS_PATH, sControllerMod, sControllerMod.capitalize + "Process.rb")
564
- if File.exist?(sControllerProcessMod)
565
- aProcessList << sControllerProcessMod
566
- else
567
- ForjLib.debug(1, "No Provider process defined. File '%s' not found." % sControllerProcessMod)
568
- end
569
-
570
- super(oForjAccount, aProcessList.concat(aProcesses), sControllerMod)
571
- end
572
- end
573
-
574
-
575
- # class describing generic Object Process
576
- # Ex: How to get a Network Object (ie: get a network or create it if missing)
577
- class BaseProcess
578
- def initialize()
579
- @oDefinition = nil
580
- end
581
-
582
- def set_BaseObject(oDefinition)
583
- @oDefinition = oDefinition
584
- end
585
- private
586
-
587
- def query_cache_cleanup(sObjectType)
588
- raise ForjError.new(), "No Base object loaded." if not @oDefinition
589
- @oDefinition.query_cleanup(sObjectType)
590
- end
591
-
592
- def object_cache_cleanup(sObjectType)
593
- raise ForjError.new(), "No Base object loaded." if not @oDefinition
594
- @oDefinition.object_cleanup(sObjectType)
595
- end
596
-
597
- def controler
598
- raise ForjError.new(), "No Controler object loaded." if not @oDefinition
599
- @oDefinition
600
- end
601
-
602
- def object
603
- raise ForjError.new(), "No Base object loaded." if not @oDefinition
604
- @oDefinition
605
- end
606
-
607
- def format_object(sObjectType, oMiscObj)
608
-
609
- raise ForjError.new(), "No Base object loaded." if not @oDefinition
610
- @oDefinition.format_object(sObjectType, oMiscObj)
611
- end
612
-
613
- def format_query(sObjectType, oMiscObj, hQuery)
614
-
615
- raise ForjError.new(), "No Base object loaded." if not @oDefinition
616
- @oDefinition.format_list(sObjectType, oMiscObj, hQuery)
617
- end
618
-
619
- def DataObjects(sObjectType, *key)
620
- raise ForjError.new(), "No Base object loaded." if not @oDefinition
621
- @oDefinition.DataObjects(sObjectType, *key)
622
- end
623
-
624
- def get_data(oObj, *key)
625
-
626
- raise ForjError.new(), "No Base object loaded." if not @oDefinition
627
- @oDefinition.get_data(oObj, :attrs, key)
628
- end
629
-
630
- def register(oObject, sObjectType = nil)
631
-
632
- raise ForjError.new(), "No Base object loaded." if not @oDefinition
633
- @oDefinition.register(oObject, sObjectType)
634
- end
635
-
636
- def config
637
- raise ForjError.new(), "No Base object loaded." if not @oDefinition
638
- @oDefinition.config
639
- end
640
-
641
- def query_single(sCloudObj, oList, sQuery, name, sInfoMsg = {})
642
- oList = controler.query(sCloudObj, sQuery)
643
- sInfo = {
644
- :notfound => "No %s '%s' found",
645
- :checkmatch => "Found 1 %s. checking exact match for '%s'.",
646
- :nomatch => "No %s '%s' match",
647
- :found => "Found %s '%s'.",
648
- :more => "Found several %s. Searching for '%s'.",
649
- :items_form => "%s",
650
- :items => [:name]
651
- }
652
- sInfo[:notfound] = sInfoMsg[:notfound] if sInfoMsg.key?(:notfound)
653
- sInfo[:checkmatch] = sInfoMsg[:checkmatch] if sInfoMsg.key?(:checkmatch)
654
- sInfo[:nomatch] = sInfoMsg[:nomatch] if sInfoMsg.key?(:nomatch)
655
- sInfo[:found] = sInfoMsg[:found] if sInfoMsg.key?(:found)
656
- sInfo[:more] = sInfoMsg[:more] if sInfoMsg.key?(:more)
657
- sInfo[:items] = sInfoMsg[:items] if sInfoMsg.key?(:items)
658
- sInfo[:items_form] = sInfoMsg[:items_form] if sInfoMsg.key?(:items_form)
659
- case oList.length()
660
- when 0
661
- Logging.info( sInfo[:notfound] % [sCloudObj, name] )
662
- oList
663
- when 1
664
- ForjLib.debug(2, sInfo[:checkmatch] % [sCloudObj, name])
665
- element = nil
666
- oList.each { | oElem |
667
- bFound = true
668
- sQuery.each { | key, value |
669
- if oElem[key] != value
670
- bFound = false
671
- break
672
- end
673
- }
674
- :remove if not bFound
675
- }
676
- if oList.length == 0
677
- Logging.info(sInfo[:nomatch] % [sCloudObj, name])
678
- else
679
- sItems = []
680
- if sInfo[:items].is_a?(Array)
681
- sInfo[:items].each { | key |
682
- sItems << oList[0, key]
683
- }
684
- else
685
- sItems << oList[0, sInfo[:items]]
686
- end
687
- sItem = sInfo[:items_form] % sItems
688
- Logging.info(sInfo[:found] % [sCloudObj, sItem])
689
- end
690
- oList
691
- else
692
- ForjLib.debug(2, sInfo[:more] % [sCloudObj, name])
693
- # Looping to find the one corresponding
694
- element = nil
695
- oList.each { | oElem |
696
- bFound = true
697
- sQuery.each { | key, value |
698
- if oElem[key] != value
699
- bFound = false
700
- break
701
- end
702
- }
703
- :remove if not bFound
704
- }
705
- if oList.length == 0
706
- Logging.info(sInfo[:notfound] % [sCloudObj, name])
707
- else
708
- sItems = []
709
- if sInfo[:items].is_a?(Array)
710
- sInfo[:items].each { | key |
711
- sItems << oList[0, key]
712
- }
713
- else
714
- sItems << oList[0, sInfo[:items]]
715
- end
716
- sItem = sInfo[:items_form] % sItems
717
- Logging.info(sInfo[:found] % [sCloudObj, sItem])
718
- end
719
- oList
720
- end
721
- end
722
- end
723
-
724
-
725
- class BaseController
726
- # Default handlers which needs to be defined by the cloud controller,
727
- # called by BaseDefinition Create, Delete, Get, Query and Update functions.
728
- def connect(sObjectType, hParams)
729
- raise ForjError.new(), "connect has not been redefined by the controller '%s'" % self.class
730
- end
731
-
732
- def create(sObjectType, hParams)
733
- raise ForjError.new(), "create_object has not been redefined by the controller '%s'" % self.class
734
- end
735
-
736
- def delete(sObjectType, hParams)
737
- raise ForjError.new(), "delete_object has not been redefined by the controller '%s'" % self.class
738
- end
739
-
740
- def get(sObjectType, sUniqId, hParams)
741
- raise ForjError.new(), "get_object has not been redefined by the controller '%s'" % self.class
742
- end
743
-
744
- def query(sObjectType, sQuery, hParams)
745
- raise ForjError.new(), "query_object has not been redefined by the controller '%s'" % self.class
746
- end
747
-
748
- def update(sObjectType, oObject, hParams)
749
- raise ForjError.new(), "update_object has not been redefined by the controller '%s'" % self.class
750
- end
751
-
752
- def forjError(msg)
753
- raise ForjError.new(), "%s: %s" % [self.class, msg]
754
- end
755
-
756
- def required?(oParams, key)
757
- raise ForjError.new(), "%s: %s is not set." % [self.class, key] if not oParams.exist?(key)
758
- end
759
- end
760
-
761
- # represent an object or a list of object
762
-
763
- # Collection of DataObject
764
- # This class represents Object Parameters
765
- class ObjectData
766
- def initialize(bInternal = false)
767
-
768
- @hParams = {}
769
- @hParams[:hdata] = {} unless bInternal
770
- @bInternal = bInternal
771
- end
772
-
773
- def [] (*key)
774
-
775
- key = key.flatten
776
- # Return ObjectData Element if asked. Ignore additional keys.
777
- return @hParams[key[0]] if key[1] == :ObjectData
778
-
779
- return @hParams if key.length == 0
780
-
781
- oObject = rhGet(@hParams, key[0])
782
- return nil if oObject.nil?
783
-
784
- # Return attributes if asked
785
- return oObject[:attrs, key[2..-1]] if key[1] == :attrs
786
-
787
- if oObject.is_a?(ForjLib::Data)
788
- if @bInternal
789
- # params are retrieved in process context
790
- # By default, if key is detected as a framework object, return its data.
791
- return oObject[:attrs, key[1..-1]]
792
- else
793
- # params are retrieved in controller context
794
- # By default, if key is detected as a controller object, return its data.
795
- return oObject[:object, key[1..-1]]
796
- end
797
- end
798
-
799
- # otherwise, simply return what is found in keys hierarchy.
800
- rhGet(@hParams, key)
801
- end
802
-
803
- # Functions used to set simple data/Object for controller/process function call.
804
- # TODO: to revisit this function, as we may consider simple data, as ForjLib::Data object
805
- def []= (*key, value)
806
- return nil if [:object, :query].include?(key[0])
807
- rhSet(@hParams, value, key)
808
- end
809
-
810
- def add(oDataObject)
811
- # Requires to be a valid framework object.
812
- raise ForjError.new, "Invalid Framework object type '%s'." % oDataObject.class unless oDataObject.is_a?(ForjLib::Data)
813
-
814
- sObjectType = oDataObject.object_type?
815
-
816
- if oDataObject.type? == :list
817
- oOldDataObject = rhGet(@hParams, :query, sObjectType)
818
- oOldDataObject.unregister if oOldDataObject
819
- rhSet(@hParams, oDataObject, :query, sObjectType)
820
- else
821
- oOldDataObject = rhGet(@hParams, sObjectType)
822
- oOldDataObject.unregister if oOldDataObject
823
- @hParams[sObjectType] = oDataObject
824
- end
825
- oDataObject.register
826
- end
827
-
828
- def delete(oObj)
829
- if oObj.is_a?(Symbol)
830
- sObjectType = oObj
831
- @hParams[sObjectType] = nil
832
- else
833
- raise ForjError.new(), "ObjectData: delete error. oObj is not a framework data Object." unless oObj.is_a?(ForjLib::Data)
834
- if oObj[:object_type] == :object_list
835
- rhSet(@hParams, nil, :query, sObjectType)
836
- else
837
- sObjectType = oObj[:object_type]
838
- @hParams[sObjectType] = nil
839
- end
840
- end
841
- oObj.unregister
842
- end
843
-
844
- def << (hHash)
845
- @hParams.merge!(hHash)
846
- end
847
-
848
- def exist?(*key)
849
- raise ForjError.new, "ObjectData: key is not list of values (string/symbol or array)" if not [Array, String, Symbol].include?(key.class)
850
-
851
- key = [key] if key.is_a?(Symbol) or key.is_a?(String)
852
-
853
- key = key.flatten
854
-
855
- oObject = rhGet(@hParams, key[0])
856
- return false if oObject.nil?
857
-
858
- if oObject.is_a?(ForjLib::Data)
859
- # Return true if ObjectData Element is found when asked.
860
- return true if key[1] == :ObjectData and oObject.type?(key[0]) == :object
861
-
862
- # Return true if attritutes or controller object attributes found when asked.
863
- return oObject.exist?(key[2..-1]) if key[1] == :attrs
864
- return oObject.exist?(key[1..-1]) if key.length > 1
865
- true
866
- else
867
- # By default true if found key hierarchy
868
- (rhExist?(@hParams, key) == key.length)
869
- end
870
- end
871
-
872
- #~ def get(*key)
873
- #~ rhGet(@hParams, key)
874
- #~ end
875
-
876
- def type?(key)
877
- return nil if rhExist?(@hParams, key) != 1
878
- :data
879
- :DataObject if @hParams[key].type?() == :object
880
- end
881
-
882
- def cObj(*key)
883
- rhGet(@hParams, key, :object) if rhExist?(@hParams, key, :object) == 2
884
- end
885
-
886
- end
887
-
888
- # Following class defines class levels function to
889
- # declare framework objects.
890
- # As each process needs to define new object to deal with
891
- # require that process to define it with definition functions
892
- # See definition.rb for functions to use.
893
-
894
- class BaseDefinition
895
- # Capitalized function are called to start a process. It is done by ForjObject.
896
-
897
- # BaseCloud Object available functions.
898
- def Create(sCloudObj)
899
- return nil if not sCloudObj
900
- raise ForjError.new(), "%s.Create: '%s' is not a known object type." % [self.class, sCloudObj] if rhExist?(@@meta_obj, sCloudObj) != 1
901
-
902
- pProc = rhGet(@@meta_obj, sCloudObj, :lambdas, :create_e)
903
-
904
- # Check required parameters
905
- oObjMissing = _check_required(sCloudObj, :create_e, pProc).reverse
906
-
907
- while oObjMissing.length >0
908
- sElem = oObjMissing.pop
909
-
910
- raise ForjError.new(),"Unable to create Object '%s'" % sElem if not Create(sElem)
911
- oObjMissing = _check_required(sCloudObj, :create_e, pProc).reverse
912
-
913
- raise ForjError.new(), "loop detection: '%s' is required but Create(%s) did not loaded it." % [sElem, sElem] if oObjMissing.include?(sElem)
914
- end
915
- @RuntimeContext[:oCurrentObj] = sCloudObj # Context: Default object used.
916
-
917
- if pProc.nil?
918
- # This object is a meta object, without any data.
919
- # Used to build other kind of objects.
920
- oObject = ForjLib::Data.new
921
- oObject.set({}, sCloudObj) {}
922
- else
923
- # build Function params to pass to the event handler.
924
- aParams = _get_object_params(sCloudObj, :create_e, pProc,)
925
- ForjLib.debug(2, "Create Object '%s' - Running '%s'" % [sCloudObj, pProc])
926
-
927
- # Call the process function.
928
- # At some point, the process will call the controller, via the framework.
929
- # This controller call via the framework has the role to
930
- # create an ObjectData well formatted, with _return_map function
931
- # See Definition.connect/create/update/query/get functions (lowercase)
932
- oObject = @oForjProcess.method(pProc).call(sCloudObj, aParams)
933
- # return usually is the main object that the process called should provide.
934
- # Save Object if the object has been created by the process, without controller
935
- end
936
-
937
- unless oObject.nil?
938
- @ObjectData.add(oObject)
939
- end
940
- end
941
-
942
- def Delete(sCloudObj)
943
- return nil if not sCloudObj
944
-
945
- raise ForjError.new(), "%s.Delete: '%s' is not a known object type." % [self.class, sCloudObj] if rhExist?(@@meta_obj, sCloudObj) != 1
946
-
947
- pProc = rhGet(@@meta_obj, sCloudObj, :lambdas, :delete_e)
948
-
949
- return nil if pProc.nil?
950
-
951
- # Check required parameters
952
- oObjMissing = _check_required(sCloudObj, :delete_e, pProc).reverse
953
-
954
- while oObjMissing.length >0
955
- sElem = oObjMissing.pop
956
- raise ForjError.new(),"Unable to create Object '%s'" % sElem if not Create(sElem)
957
- oObjMissing = _check_required(sCloudObj, :delete_e, pProc).reverse
958
- raise ForjError.new(), "loop detection: '%s' is required but Delete(%s) did not loaded it." % [sElem, sElem] if oObjMissing.include?(sElem)
959
- end
960
- @RuntimeContext[:oCurrentObj] = sCloudObj # Context: Default object used.
961
-
962
- # build Function params to pass to the event handler.
963
- aParams = _get_object_params(sCloudObj, :delete_e, pProc)
964
-
965
- bState = @oForjProcess.method(pProc).call(sCloudObj, aParams)
966
- # return usually is the main object that the process called should provide.
967
- if bState
968
- @ObjectData.del(sCloudObj)
969
- end
970
-
971
- end
972
-
973
- def query_cleanup(sCloudObj)
974
- oList = @ObjectData[:query, sCloudObj]
975
- unless oList.nil?
976
- @ObjectData.delete(oList)
977
- end
978
- end
979
-
980
- def object_cleanup(sCloudObj)
981
- oObject = @ObjectData[sCloudObj, :ObjectData]
982
- unless oObject.nil?
983
- @ObjectData.delete(oObject)
984
- end
985
- end
986
-
987
-
988
- # This function returns a list of objects
989
- def Query(sCloudObj, hQuery)
990
-
991
- return nil if not sCloudObj
992
-
993
- raise ForjError.new(), "$s.Get: '%s' is not a known object type." % [self.class, sCloudObj] if rhExist?(@@meta_obj, sCloudObj) != 1
994
-
995
- # Check if we can re-use a previous query
996
- oList = @ObjectData[:query, sCloudObj]
997
- unless oList.nil?
998
- if oList[:query] == hQuery
999
- ForjLib.debug(3, "Using Object '%s' query cache : %s" % [sCloudObj, hQuery])
1000
- return oList
1001
- end
1002
- end
1003
-
1004
- pProc = rhGet(@@meta_obj, sCloudObj, :lambdas, :query_e)
1005
-
1006
- return nil if pProc.nil?
1007
-
1008
- # Check required parameters
1009
- oObjMissing = _check_required(sCloudObj, :query_e, pProc).reverse
1010
-
1011
- while oObjMissing.length >0
1012
- sElem = oObjMissing.pop
1013
- raise ForjError.new(),"Unable to create Object '%s'" % sElem if not Create(sElem)
1014
- oObjMissing = _check_required(sCloudObj, :query_e, pProc).reverse
1015
- raise ForjError.new(), "loop detection: '%s' is required but Query(%s) did not loaded it." % [sElem, sElem] if oObjMissing.include?(sElem)
1016
- end
1017
- @RuntimeContext[:oCurrentObj] = sCloudObj # Context: Default object used.
1018
-
1019
- # build Function params to pass to the Process Event handler.
1020
- aParams = _get_object_params(sCloudObj, :query_e, pProc)
1021
-
1022
- # Call the process function.
1023
- # At some point, the process will call the controller, via the framework.
1024
- # This controller call via the framework has the role to
1025
- # create an ObjectData well formatted, with _return_map function
1026
- # See Definition.connect/create/update/query/get functions (lowercase)
1027
- oObject = @oForjProcess.method(pProc).call(sCloudObj, hQuery, aParams)
1028
- # return usually is the main object that the process called should provide.
1029
- unless oObject.nil?
1030
- # Save Object if the object has been created by the process, without controller
1031
- @ObjectData.add(oObject)
1032
- end
1033
- end
1034
-
1035
- def Get(sCloudObj, sUniqId)
1036
-
1037
- return nil if not sCloudObj
1038
-
1039
- raise ForjError.new(), "$s.Get: '%s' is not a known object type." % [self.class, sCloudObj] if rhExist?(@@meta_obj, sCloudObj) != 1
1040
-
1041
- pProc = rhGet(@@meta_obj, sCloudObj, :lambdas, :get_e)
1042
-
1043
- return nil if pProc.nil?
1044
-
1045
- # Check required parameters
1046
- oObjMissing = _check_required(sCloudObj, :get_e, pProc).reverse
1047
-
1048
- while oObjMissing.length >0
1049
- sElem = oObjMissing.pop
1050
- raise ForjError.new(),"Unable to create Object '%s'" % sElem if not Create(sElem)
1051
- oObjMissing = _check_required(sCloudObj, :get_e, pProc).reverse
1052
- raise ForjError.new(), "loop detection: '%s' is required but Get(%s) did not loaded it." % [sElem, sElem] if oObjMissing.include?(sElem)
1053
- end
1054
- @RuntimeContext[:oCurrentObj] = sCloudObj # Context: Default object used.
1055
-
1056
- # build Function params to pass to the Process Event handler.
1057
- aParams = _get_object_params(sCloudObj, :get_e, pProc)
1058
-
1059
- # Call the process function.
1060
- # At some point, the process will call the controller, via the framework.
1061
- # This controller call via the framework has the role to
1062
- # create an ObjectData well formatted, with _return_map function
1063
- # See Definition.connect/create/update/query/get functions (lowercase)
1064
- oObject = @oForjProcess.method(pProc).call(sCloudObj, sUniqId, aParams)
1065
- # return usually is the main object that the process called should provide.
1066
- unless oObject.nil?
1067
- # Save Object if the object has been created by the process, without controller
1068
- @ObjectData.add(oObject)
1069
- end
1070
- end
1071
-
1072
- def Update(sCloudObj)
1073
-
1074
- return nil if not sCloudObj
1075
-
1076
- raise ForjError.new(), "$s.Update: '%s' is not a known object type." % [self.class, sCloudObj] if rhExist?(@@meta_obj, sCloudObj) != 1
1077
-
1078
- pProc = rhGet(@@meta_obj, sCloudObj, :lambdas, :update_e)
1079
-
1080
- return nil if pProc.nil?
1081
-
1082
- # Check required parameters
1083
- oObjMissing = _check_required(sCloudObj, :update_e, pProc).reverse
1084
-
1085
- while oObjMissing.length >0
1086
- sElem = oObjMissing.pop
1087
- raise ForjError.new(),"Unable to create Object '%s'" % sElem if not Create(sElem)
1088
- oObjMissing = _check_required(sCloudObj, :update_e, pProc).reverse
1089
- raise ForjError.new(), "loop detection: '%s' is required but Update(%s) did not loaded it." % [sElem, sElem] if oObjMissing.include?(sElem)
1090
- end
1091
- @RuntimeContext[:oCurrentObj] = sCloudObj # Context: Default object used.
1092
-
1093
- # build Function params to pass to the event handler.
1094
- aParams = _get_object_params(sCloudObj, :update_e, pProc)
1095
-
1096
- oObject = @oForjProcess.method(pProc).call(sCloudObj, aParams)
1097
- # return usually is the main object that the process called should provide.
1098
- unless oObject.nil?
1099
- # Save Object if the object has been created by the process, without controller
1100
- @ObjectData.add(oObject)
1101
- end
1102
- end
1103
-
1104
- def Setup(sObjectType, sAccountName)
1105
- # Loop in dependencies to get list of data object to setup
1106
- raise ForjError,new(), "Setup: '%s' not a valid object type." if rhExist?(@@meta_obj, sObjectType) != 1
1107
-
1108
- hAskStep = ForjDefault.get(:ask_step, :setup)
1109
- aSetup = []
1110
- hAskStep.each{ | value |
1111
- aSetup << {
1112
- :desc => value[:desc],
1113
- :explanation => value[:explanation],
1114
- :pre_step_handler => value[:pre_step_function],
1115
- :order => [[]],
1116
- :post_step_handler => value[:post_step_function]
1117
- }
1118
-
1119
- }
1120
- oInspectedObjects = []
1121
- oInspectObj = [sObjectType]
1122
-
1123
- @oForjConfig.ac_load(sAccountName) if sAccountName
1124
-
1125
- ForjLib.debug(2, "Setup is identifying account data to ask for '%s'" % sObjectType)
1126
- while oInspectObj.length() >0
1127
- # Identify data to ask
1128
- # A data to ask is a data needs from an object type
1129
- # which is declared in section of defaults.yaml
1130
- # and is declared :account to true (in defaults.yaml or in process declaration - define_data)
1131
-
1132
- sObjectType = oInspectObj.pop
1133
- sAsk_step = 0
1134
- ForjLib.debug(1, "Checking '%s'" % sObjectType)
1135
- hTopParams = rhGet(@@meta_obj,sObjectType, :params)
1136
- if hTopParams[:keys].nil?
1137
- ForjLib.debug(1, "Warning! Object '%s' has no data/object needs. Check the process" % sObjectType)
1138
- next
1139
- end
1140
- hTopParams[:keys].each { |sKeypath, hParams|
1141
- oKeyPath = KeyPath.new(sKeypath)
1142
- sKey = oKeyPath.sKey
1143
- case hParams[:type]
1144
- when :data
1145
- hMeta = _get_meta_data(sKey)
1146
- next if hMeta.nil?
1147
- sAsk_step = hMeta[:ask_step] if rhExist?(hMeta, :ask_step) == 1 and hMeta[:ask_step].is_a?(Fixnum)
1148
- ForjLib.debug(3, "#{sKey} is part of setup step #{sAsk_step}")
1149
- aOrder = aSetup[sAsk_step][:order]
1150
-
1151
- if oInspectedObjects.include?(sKey)
1152
- ForjLib.debug(2, "#{sKey} is already asked. Ignored.")
1153
- next
1154
- end
1155
- if hMeta[:account].is_a?(TrueClass)
1156
- if not hMeta[:depends_on].is_a?(Array)
1157
- Logging.warning("'%s' depends_on definition have to be an array." % oKeyPath.sFullPath) unless hMeta[:depends_on].nil?
1158
- iLevel = 0
1159
- bFound = true
1160
- else
1161
- # Searching highest level from dependencies.
1162
- bFound = false
1163
- iLevel = 0
1164
- hMeta[:depends_on].each { |depend_key|
1165
- aOrder.each_index { |iCurLevel|
1166
- if aOrder[iCurLevel].include?(depend_key)
1167
- bFound = true
1168
- iLevel = [iLevel, iCurLevel + 1].max
1169
- end
1170
- }
1171
- aOrder[iLevel] = [] if aOrder[iLevel].nil?
1172
- }
1173
- end
1174
- if bFound
1175
- if not aOrder[iLevel].include?(sKey)
1176
- if hMeta[:ask_sort].is_a?(Fixnum)
1177
- iOrder = hMeta[:ask_sort]
1178
- if aOrder[iLevel][iOrder].nil?
1179
- aOrder[iLevel][iOrder] = sKey
1180
- else
1181
- aOrder[iLevel].insert(iOrder, sKey)
1182
- end
1183
- ForjLib.debug(3, "S%s/L%s/O%s: '%s' added in setup list. " % [sAsk_step, iLevel, iOrder, sKey])
1184
- else
1185
- aOrder[iLevel] << sKey
1186
- ForjLib.debug(3, "S%s/L%s/Last: '%s' added in setup list." % [sAsk_step, iLevel, sKey])
1187
- end
1188
- end
1189
- end
1190
- oInspectedObjects << sKey
1191
- else
1192
- ForjLib.debug(2, "#{sKey} used by #{sObjectType} won't be asked during setup. :account = true not set.")
1193
- end
1194
- when :CloudObject
1195
- oInspectObj << sKey if not oInspectObj.include?(sKey) and not oInspectedObjects.include?(sKey)
1196
- end
1197
- }
1198
- oInspectedObjects << sObjectType
1199
- end
1200
- ForjLib.debug(2, "Setup check if needs to add unrelated data in the process")
1201
- hAskStep.each_index{ | iStep |
1202
- value = hAskStep[iStep]
1203
- if rhExist?(value, :add) == 1
1204
- sKeysToAdd = rhGet(value, :add)
1205
- sKeysToAdd.each { | sKeyToAdd |
1206
- bFound = false
1207
- aSetup[iStep][:order].each_index { | iOrder |
1208
- sKeysToAsk = aSetup[iStep][:order][iOrder]
1209
- unless sKeysToAsk.index(sKeyToAdd).nil?
1210
- bFound = true
1211
- break
1212
- end
1213
- }
1214
- next if bFound
1215
- iLevel = 0
1216
- iOrder = aSetup[iStep][:order].length
1217
- iAtStep = iStep
1218
- hMeta = _get_meta_data(sKeyToAdd)
1219
- if rhExist?(hMeta, :after) == 1
1220
- sAfterKeys = hMeta[:after]
1221
- sAfterKeys = [ sAfterKeys ] if not sAfterKeys.is_a?(Array)
1222
- sAfterKeys.each{ |sAfterKey |
1223
- bFound = false
1224
- aSetup.each_index { |iStepToCheck|
1225
- aSetup[iStepToCheck][:order].each_index { | iLevelToCheck |
1226
- sKeysToAsk = aSetup[iStepToCheck][:order][iLevelToCheck]
1227
- iOrderToCheck = sKeysToAsk.index(sAfterKey)
1228
- unless iOrderToCheck.nil?
1229
- iAtStep = iStepToCheck if iStepToCheck > iAtStep
1230
- iLevel = iLevelToCheck if iLevelToCheck > iLevel
1231
- iOrder = iOrderToCheck + 1 if iOrderToCheck + 1 > iOrder
1232
- bFound = true
1233
- break
1234
- end
1235
- }
1236
- }
1237
- }
1238
- end
1239
- aSetup[iAtStep][:order][iLevel].insert(iOrder, sKeyToAdd)
1240
- ForjLib.debug(3, "S%s/L%s/O%s: '%s' added in setup list at position." % [iAtStep, iLevel, iOrder, sKeyToAdd])
1241
- }
1242
- end
1243
- }
1244
-
1245
- ForjLib.debug(2, "Setup will ask for :\n %s" % aSetup.to_yaml)
1246
-
1247
- Logging.info("Configuring account : '#{config[:account_name]}', provider '#{config[:provider_name]}'")
1248
-
1249
- # Ask for user input
1250
- aSetup.each_index { | iStep |
1251
- ForjLib.debug(2, "Ask step %s:" % iStep)
1252
- puts "%s%s%s" % [ANSI.bold, aSetup[iStep][:desc], ANSI.clear] unless aSetup[iStep][:desc].nil?
1253
- puts "%s\n\n" % ANSI.yellow(aSetup[iStep][:explanation]) unless aSetup[iStep][:explanation].nil?
1254
- aOrder = aSetup[iStep][:order]
1255
- aOrder.each_index { | iIndex |
1256
- ForjLib.debug(2, "Ask order %s:" % iIndex)
1257
- aOrder[iIndex].each { | sKey |
1258
- hParam = _get_meta_data(sKey)
1259
- hParam = {} if hParam.nil?
1260
-
1261
- bOk = false
1262
-
1263
- if hParam[:pre_step_function]
1264
- pProc = hParam[:pre_step_function]
1265
- bOk = not(@oForjProcess.method(pProc).call(sKey))
1266
- end
1267
-
1268
-
1269
- sDesc = "'%s' value" % sKey
1270
- puts "#{sKey}: %s" % [hParam[:explanation]] unless rhGet(hParam, :explanation).nil?
1271
- sDesc = hParam[:desc] unless hParam[:desc].nil?
1272
- sDefault = @oForjConfig.get(sKey, hParam[:default_value])
1273
- rValidate = nil
1274
-
1275
- rValidate = hParam[:validate] unless hParam[:validate].nil?
1276
- bRequired = (hParam[:required] == true)
1277
- while not bOk
1278
- bOk = true
1279
- if not hParam[:list_values].nil?
1280
- hValues = hParam[:list_values]
1281
- sObjectToLoad = hValues[:object]
1282
-
1283
- bListStrict = (hValues[:validate] == :list_strict)
1284
-
1285
- case hValues[:query_type]
1286
- when :controller_call
1287
- oObject = @ObjectData[sObjectToLoad, :ObjectData]
1288
- Logging.state("Loading #{sObjectToLoad}.")
1289
- oObject = Create(sObjectToLoad) if oObject.nil?
1290
- return nil if oObject.nil?
1291
- oParams = ObjectData.new
1292
- oParams.add(oObject)
1293
- oParams << hValues[:query_params]
1294
- raise ForjError.new(), "#{sKey}: query_type => :controller_call requires missing :query_call declaration (Controller function)" if hValues[:query_call].nil?
1295
- pProc = hValues[:query_call]
1296
- begin
1297
- aList = @oProvider.method(pProc).call(sObjectToLoad, oParams)
1298
- rescue => e
1299
- raise ForjError.new(), "Error during call of '%s':\n%s" % [pProc, e.message]
1300
- end
1301
- when :query_call
1302
- sQuery = {}
1303
- sQuery = hValues[:query_params] unless hValues[:query_params].nil?
1304
- Logging.state("Querying #{sObjectToLoad}.")
1305
- oObjectList = Query(sObjectToLoad, sQuery)
1306
- aList = []
1307
- oObjectList.each { | oElem |
1308
- aList << oElem[hValues[:value]]
1309
- }
1310
- aList.sort!
1311
- when :process_call
1312
- raise ForjError.new(), "#{sKey}: query_type => :process_call requires missing :query_call declaration (Provider function)" if hValues[:query_call].nil?
1313
- pProc = hValues[:query_call]
1314
- sObjectToLoad = hValues[:object]
1315
- oParams = ObjectData.new
1316
- oParams.add(oObject)
1317
- oParams << hValues[:query_params]
1318
- begin
1319
- aList = @oForjProcess.method(pProc).call(sObjectToLoad, oParams)
1320
- rescue => e
1321
- raise ForjError.new(), "Error during call of '%s':\n%s" % [pProc, e.message]
1322
- end
1323
- else
1324
- raise ForjError.new, "'%s' invalid. %s/list_values/values_type supports %s. " % [hValues[:values_type], sKey, [:provider_function]]
1325
- end
1326
- Logging.fatal(1, "%s requires a value from the '%s' query which is empty." % [sKey, sObjectToLoad])if aList.nil? and bListStrict
1327
- aList = [] if aList.nil?
1328
- if not bListStrict
1329
- aList << "other"
1330
- end
1331
- say("Enter %s" % ((sDefault.nil?)? sDesc : sDesc + " |%s|" % sDefault))
1332
- value = choose { | q |
1333
- q.choices(*aList)
1334
- q.default = sDefault if sDefault
1335
- }
1336
- if not bListStrict and value == "other"
1337
- value = _ask(sDesc, sDefault, rValidate, hParam[:encrypted], bRequired)
1338
- end
1339
- else
1340
- pValidateProc = hParam[:validate_function]
1341
- pAskProc = hParam[:ask_function]
1342
-
1343
- if pAskProc.nil?
1344
- unless pValidateProc.nil?
1345
- value = _ask(sDesc, sDefault, rValidate, hParam[:encrypted], bRequired)
1346
- while not @oForjProcess.method(pValidateProc).call(value)
1347
- value = _ask(sDesc, sDefault, rValidate, hParam[:encrypted], bRequired)
1348
- end
1349
- else
1350
- value = _ask(sDesc, sDefault, rValidate, hParam[:encrypted], bRequired)
1351
- end
1352
- else
1353
- unless pValidateProc.nil?
1354
- value = @oForjProcess.method(pAskProc).call(sDesc, sDefault, rValidate, hParam[:encrypted], bRequired)
1355
- while not @oForjProcess.method(pValidateProc).call(value)
1356
- value = @oForjProcess.method(pAskProc).call(sDesc, sDefault, rValidate, hParam[:encrypted], bRequired)
1357
- end
1358
- else
1359
- value = @oForjProcess.method(pAskProc).call(sDesc, sDefault, rValidate, hParam[:encrypted], bRequired)
1360
- end
1361
- end
1362
- end
1363
-
1364
- @oForjConfig.set(sKey, value)
1365
- if hParam[:post_step_function]
1366
- pProc = hParam[:post_step_function]
1367
- bOk = @oForjProcess.method(pProc).call()
1368
- end
1369
- end
1370
- }
1371
- }
1372
- }
1373
- end
1374
-
1375
- # Initialize Cloud object Data
1376
-
1377
- def initialize(oForjConfig, oForjProcess, oForjProvider = nil)
1378
- # Object Data object. Contains all loaded object data.
1379
- # This object is used to build hParams as well.
1380
- @ObjectData = ObjectData.new(true)
1381
- #
1382
- @RuntimeContext = {
1383
- :oCurrentObj => nil
1384
- }
1385
-
1386
- @oForjConfig = oForjConfig
1387
- raise ForjError.new(), "'%s' is not a valid ForjAccount or ForjConfig Object." % [oForjConfig.class] if not oForjConfig.is_a?(ForjAccount) and not oForjConfig.is_a?(ForjConfig)
1388
-
1389
- @oProvider = oForjProvider
1390
- if oForjProvider
1391
- raise ForjError.new(), "'%s' is not a valid ForjProvider Object type." % [oForjProvider.class] if not oForjProvider.is_a?(BaseController)
1392
- end
1393
-
1394
- @oForjProcess = oForjProcess
1395
- raise ForjError.new(), "'%s' is not a valid BaseProcess Object type." % [oForjProcess.class] if not oForjProcess.is_a?(BaseProcess)
1396
-
1397
- @oForjProcess.set_BaseObject(self)
1398
- end
1399
-
1400
- # ------------------------------------------------------
1401
- # Functions used by processes functions
1402
- # ------------------------------------------------------
1403
- # Ex: object.set_data(...)
1404
- # config
1405
-
1406
-
1407
- # Function to manipulate the config object.
1408
- # 2 kind of functions:
1409
- # - set (key, value) and []=(key, value)
1410
- # From processes, you can set a runtime data with:
1411
- # config.set(key, value)
1412
- # OR
1413
- # config[key] = value
1414
- #
1415
- # - get (key, default) and [](key, default)
1416
- # default is an optional value.
1417
- # From processes, you can get a data (runtime/account/config.yaml or defaults.yaml) with:
1418
- # config.get(key)
1419
- # OR
1420
- # config[key]
1421
-
1422
- def config
1423
- raise ForjError.new(), "No config object loaded." if not @oForjConfig
1424
- @oForjConfig
1425
- end
1426
-
1427
- def format_query(sObjectType, oControlerObject, hQuery)
1428
- {
1429
- :object => oControlerObject,
1430
- :object_type => :object_list,
1431
- :list_type => sObjectType,
1432
- :list => [],
1433
- :query => hQuery
1434
- }
1435
- end
1436
-
1437
- def format_object(sCloudObj, oMiscObject)
1438
- return nil if not sCloudObj or not [String, Symbol].include?(sCloudObj.class)
1439
-
1440
- sCloudObj = sCloudObj.to_sym if sCloudObj.class == String
1441
-
1442
- oCoreObject = {
1443
- :object_type => sCloudObj,
1444
- :attrs => {},
1445
- :object => oMiscObject,
1446
- }
1447
- end
1448
-
1449
- def get_data_metadata(sKey)
1450
- _get_meta_data(sKey)
1451
- end
1452
-
1453
- # Before doing a query, mapping fields
1454
- # Transform Object query field to Provider query Fields
1455
- def query_map(sCloudObj, hParams)
1456
- return nil if not sCloudObj or not [String, Symbol].include?(sCloudObj.class)
1457
- return {} if not hParams
1458
-
1459
- sCloudObj = sCloudObj.to_sym if sCloudObj.class == String
1460
-
1461
- hReturn = {}
1462
- hMap = rhGet(@@meta_obj, sCloudObj, :query_mapping)
1463
- hParams.each { |key, value|
1464
- oKeyPath = KeyPath.new(key)
1465
- sKeyPath = oKeyPath.sFullPath
1466
- raise ForjError.new(), "Forj query field '%s.%s' not defined by class '%s'" % [sCloudObj, oKeyPath.sKey, self.class] if not hMap.key?(oKeyPath.sFullPath)
1467
- oMapPath = KeyPath.new(hMap[oKeyPath.sFullPath])
1468
- hValueMapping = rhGet(@@meta_obj, sCloudObj, :value_mapping, sKeyPath)
1469
- if hValueMapping
1470
- raise ForjError.new(), "'%s.%s': No value mapping for '%s'" % [sCloudObj, oKeyPath.sKey, value] if rhExist?(hValueMapping, value) != 1
1471
-
1472
- rhSet(hReturn, hValueMapping[value], oMapPath.aTree)
1473
- else
1474
- rhSet(hReturn, value, oMapPath.aTree)
1475
- end
1476
- }
1477
- hReturn
1478
- end
1479
-
1480
- # Used by the Process.
1481
- # Ask controller get_attr to get a data
1482
- # The result is the data of a defined data attribute.
1483
- # If the value is normally mapped (value mapped), the value is
1484
- # returned as a recognized data attribute value.
1485
- def get_attr(oObject, key)
1486
-
1487
- raise ForjError.new(), "'%s' is not a valid Object type. " % [oObject.class] if not oObject.is_a?(Hash) and rhExist?(oObject, :object_type) != 1
1488
- sCloudObj = oObject[:object_type]
1489
- oKeyPath = KeyPath.new(key)
1490
- raise ForjError.new(), "'%s' key is not declared as data of '%s' CloudObject. You may need to add obj_needs..." % [oKeyPath.sKey, sCloudObj] if rhExist?(@@meta_obj, sCloudObj, :returns, oKeyPath.sFullPath) != 3
1491
- begin
1492
- oMapPath = KeyPath.new(rhGet(@@meta_obj, sCloudObj, :returns, oKeyPath.sFullPath))
1493
- hMap = oMapPath.sFullPath
1494
- value = @oProvider.get_attr(get_cObject(oObject), hMap)
1495
-
1496
- hValueMapping = rhGet(@@meta_obj, sCloudObj, :value_mapping, oKeyPath.sFullPath)
1497
-
1498
- if hValueMapping
1499
- hValueMapping.each { | found_key, found_value |
1500
- if found_value == value
1501
- value = found_key
1502
- break
1503
- end
1504
- }
1505
- end
1506
- rescue => e
1507
- raise ForjError.new(), "'%s.get_attr' fails to provide value of '%s'" % [oProvider.class, key]
1508
- end
1509
- end
1510
-
1511
- # Register the object to the internal @ObjectData instance
1512
- def register(oObject, sObjectType = nil, sDataType = :object)
1513
- if oObject.is_a?(ForjLib::Data)
1514
- oDataObject = oObject
1515
- else
1516
- raise ForjError.new(), "Unable to register an object '%s' as ForjLib::Data object if ObjectType is not given." % [ oObject.class ] if not sObjectType
1517
- oDataObject = ForjLib::Data.new(sDataType)
1518
- oDataObject.set(oObject, sObjectType) { | sObjType, oControlerObject |
1519
- _return_map(sObjType, oControlerObject)
1520
- }
1521
- end
1522
- @ObjectData.add oDataObject
1523
- end
1524
-
1525
- def DataObjects(sObjectType, *key)
1526
- @ObjectData[sObjectType, key]
1527
- end
1528
-
1529
- # get an attribute/object/... from an object.
1530
- def get_data(oObj, *key)
1531
- if oObj.is_a?(Hash) and oObj.key?(:object_type)
1532
- oObjData = ObjectData.new
1533
- oObjData << oObj
1534
- else
1535
- oObjData = @ObjectData
1536
- end
1537
- oObjData[oObj, *key]
1538
- end
1539
-
1540
- #~ def hParams(sCloudObj, hParams)
1541
- #~ aParams = _get_object_params(sCloudObj, ":ObjectData.hParams")
1542
- #~ end
1543
-
1544
- def get_cObject(oObject)
1545
- return nil if rhExist?(oObject, :object) != 1
1546
- rhGet(oObject, :object)
1547
- end
1548
-
1549
- # a Process can execute any kind of predefined controler task.
1550
- # Those function build hParams with Provider compliant data (mapped)
1551
- # Results are formatted as usual framework Data object and stored.
1552
- def connect(sObjectType)
1553
-
1554
- hParams = _get_object_params(sObjectType, :create_e, :connect, true)
1555
- oControlerObject = @oProvider.connect(sObjectType, hParams)
1556
- oDataObject = ForjLib::Data.new
1557
- oDataObject.set(oControlerObject, sObjectType) { | sObjType, oObject |
1558
- begin
1559
- _return_map(sObjType, oObject)
1560
- rescue => e
1561
- raise ForjError.new(), "connect %s.%s : %s" % [@oForjProcess.class, sObjectType, e.message]
1562
- end
1563
- }
1564
- @ObjectData.add oDataObject
1565
- oDataObject
1566
- end
1567
-
1568
- def create(sObjectType)
1569
- # The process ask the controller to create the object.
1570
- # hParams have to be fully readable by the controller.
1571
- hParams = _get_object_params(sObjectType, :create_e, :create, true)
1572
- oControlerObject = @oProvider.create(sObjectType, hParams)
1573
- oDataObject = ForjLib::Data.new
1574
- oDataObject.set(oControlerObject, sObjectType) { | sObjType, oObject |
1575
- begin
1576
- _return_map(sObjType, oObject)
1577
- rescue => e
1578
- raise ForjError.new(), "create %s.%s : %s" % [@oForjProcess.class, sObjectType, e.message]
1579
- end
1580
- }
1581
- @ObjectData.add oDataObject
1582
-
1583
- oDataObject
1584
- end
1585
-
1586
- # The controller must return true to inform about the real deletion
1587
- def delete(sObjectType)
1588
- hParams = _get_object_params(sObjectType, :delete_e, :delete, true)
1589
- bState = @oProvider.delete(sObjectType, hParams)
1590
- @ObjectData.delete(sCloudObj) if bState
1591
- bState
1592
- end
1593
-
1594
- def get(sObjectType, sUniqId)
1595
-
1596
- hParams = _get_object_params(sObjectType, :get_e, :get, true)
1597
-
1598
- oControlerObject = @oProvider.get(sObjectType, sUniqId, hParams)
1599
- oDataObject = ForjLib::Data.new
1600
- oDataObject.set(oControlerObject, sObjectType) { | sObjType, oObject |
1601
- begin
1602
- _return_map(sObjType, oObject)
1603
- rescue => e
1604
- raise ForjError.new(), "get %s.%s : %s" % [@oForjProcess.class, sObjectType, e.message]
1605
- end
1606
- }
1607
- @ObjectData.add oDataObject
1608
-
1609
- oDataObject
1610
- end
1611
-
1612
- def query(sObjectType, hQuery)
1613
-
1614
- # Check if we can re-use a previous query
1615
- oList = @ObjectData[:query, sObjectType]
1616
- unless oList.nil?
1617
- if oList[:query] == hQuery
1618
- ForjLib.debug(3, "Using Object '%s' query cache : %s" % [sObjectType, hQuery])
1619
- return oList
1620
- end
1621
- end
1622
-
1623
-
1624
- hParams = _get_object_params(sObjectType, :query_e, :query, true)
1625
- sProviderQuery = query_map(sObjectType, hQuery)
1626
-
1627
- oControlerObject = @oProvider.query(sObjectType, sProviderQuery, hParams)
1628
-
1629
- oDataObjects = ForjLib::Data.new :list
1630
- oDataObjects.set(oControlerObject, sObjectType, hQuery) { | sObjType, key |
1631
- begin
1632
- _return_map(sObjType, key)
1633
- rescue => e
1634
- raise ForjError.new(), "query %s.%s : %s" % [@oForjProcess.class, sObjectType, e.message]
1635
- end
1636
- }
1637
-
1638
- ForjLib.debug(2, "Object %s - queried. Found %s object(s)." % [sObjectType, oDataObjects.length()])
1639
-
1640
- @ObjectData.add oDataObjects
1641
- oDataObjects
1642
- end
1643
-
1644
- def update(sObjectType)
1645
- # Need to detect data updated and update the Controler object with the controler
1646
-
1647
- hParams = _get_object_params(sObjectType, :update_e, :update, true)
1648
-
1649
- oObject = @ObjectData[sObjectType, :ObjectData]
1650
- oControlerObject = oObject[:object]
1651
-
1652
- bUpdated = false
1653
- oObject[:attrs].each { |key, value |
1654
- oKeyPath = KeyPath.new(key)
1655
- oMapPath = KeyPath.new(rhGet(@@meta_obj, sObjectType, :returns, oKeyPath.sFullPath))
1656
- old_value = @oProvider.get_attr(oControlerObject, oMapPath.aTree)
1657
- if value != old_value
1658
- bUpdated = true
1659
- @oProvider.set_attr(oControlerObject, oMapPath.aTree, value)
1660
- ForjLib.debug(2, "%s.%s - Updating: %s = %s (old : %s)" % [@oForjProcess.class, sObjectType, key, value, old_value])
1661
- end
1662
- }
1663
-
1664
- bDone = @oProvider.update(sObjectType, oObject, hParams) if bUpdated
1665
-
1666
- raise ForjError.new, "Controller function 'update' must return True or False. Class returned: '%s'" % bDone.class if not [TrueClass, FalseClass].include?(bDone.class)
1667
-
1668
- ForjLib.debug(1, "%s.%s - updated." % [@oForjProcess.class, sObjectType]) if bDone
1669
- oObject.set(oControlerObject, sObjectType) { | sObjType, oObject |
1670
- begin
1671
- _return_map(sObjType, oObject)
1672
- rescue => e
1673
- raise ForjError.new(), "update %s.%s : %s" % [@oForjProcess.class, sObjectType, e.message]
1674
- end
1675
- }
1676
- bDone
1677
- end
1678
-
1679
-
1680
- private
1681
-
1682
- # -------------------------------------------------------------------------
1683
- # Functions available for Process to communicate with the controler Object
1684
- # -------------------------------------------------------------------------
1685
- def cloud_obj_requires(sCloudObj, res = {})
1686
- aCaller = caller
1687
- aCaller.pop
1688
-
1689
- return res if @ObjectData.exist?(sCloudObj)
1690
- #~ return res if rhExist?(@CloudData, sCloudObj) == 1
1691
-
1692
- rhGet(@@meta_obj,sCloudObj, :params).each { |key, hParams|
1693
- case hParams[:type]
1694
- when :data
1695
- if hParams.key?(:array)
1696
- hParams[:array].each{ | aElem |
1697
- aElem = aElem.clone
1698
- aElem.pop # Do not go until last level, as used to loop next.
1699
- rhGet(hParams, aElem).each { | subkey, hSubParam |
1700
- next if aElem.length == 0 and [:array, :type].include?(subkey)
1701
- if hSubParams[:required] and @oForjConfig.get(subkey).nil?
1702
- res[subkey] = hSubParams
1703
- end
1704
- }
1705
- }
1706
- else
1707
- if hParams[:required] and @oForjConfig.get(key).nil?
1708
- res[key] = hParams
1709
- end
1710
- end
1711
- when :CloudObject
1712
- #~ if hParams[:required] and rhExist?(@CloudData, sCloudObj) != 1
1713
- if hParams[:required] and not @ObjectData.exist?(sCloudObj)
1714
- res[key] = hParams
1715
- cloud_obj_requires(key, res)
1716
- end
1717
- end
1718
- }
1719
- res
1720
- end
1721
-
1722
- def get_object(sCloudObj)
1723
- #~ return nil if rhExist?(@CloudData, sCloudObj) != 1
1724
- return nil if not @ObjectData.exist?(sCloudObj)
1725
- @ObjectData[sCloudObj, :ObjectData]
1726
- #~ rhGet(@CloudData, sCloudObj)
1727
- end
1728
-
1729
- def objectExist?(sCloudObj)
1730
- @ObjectData.exist?(sCloudObj)
1731
- #~ (rhExist?(@CloudData, sCloudObj) != 1)
1732
- end
1733
-
1734
- def get_forjKey(oCloudData, key)
1735
- return nil if not @ObjectData.exist?(sCloudObj)
1736
- @ObjectData[sCloudObj, :attrs, key]
1737
- #~ return nil if rhExist?(oCloudData, sCloudObj) != 1
1738
- #~ rhGet(oCloudData, sCloudObj, :attrs, key)
1739
- end
1740
- end