sfpagent 0.3.10 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sfpagent might be problematic. Click here for more details.

@@ -25,5 +25,5 @@ matrix:
25
25
  - rvm: jruby-19mode
26
26
  gemfile: Gemfile.1.8.7
27
27
 
28
- notification:
28
+ notifications:
29
29
  - email: false
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.10
1
+ 0.4.0
@@ -9,7 +9,7 @@ end
9
9
  opts = Trollop::options do
10
10
  version "sfpagent #{version?} (c) 2013 Herry"
11
11
  banner <<-EOS
12
- SFP Agent that provides a Ruby framework for managing system configurations. The configurations are modelled in SFP language.
12
+ Agent for Nuri configuration management tool.
13
13
 
14
14
  Usage:
15
15
  sfpagent [options] [model-file] [plan-file]
@@ -20,12 +20,14 @@ EOS
20
20
  opt :start, "Start the agent. If --daemon option is set true, then the agent will start as a daemon.", :short => '-s'
21
21
  opt :stop, "Stop the daemon agent.", :short => '-t'
22
22
  opt :restart, "Restart the daemon agent.", :short => '-r'
23
+ opt :no_daemon, "start agent non-daemon process", :default => false
23
24
  opt :status, "Print the status of the daemon agent.", :short => '-a'
24
25
  opt :port, "Port number of the daemon agent should listen to.", :short => '-p', :default => Sfp::Agent::DefaultPort
25
26
  opt :ssl, "Set the agent to use HTTPS instead of HTTP.", :default => false
26
27
  opt :certfile, "Certificate file for HTTPS.", :default => ''
27
28
  opt :keyfile, "Private key file for HTTPS.", :default => ''
28
29
  opt :modules_dir, "A directory that holds all SFP modules.", :default => ''
30
+ opt :resolve, "get current state of given reference", :default => ''
29
31
  end
30
32
 
31
33
  def parse(filepath)
@@ -54,6 +56,11 @@ elsif opts[:restart]
54
56
  Sfp::Agent.stop if Sfp::Agent.pid.to_i > 0
55
57
  Sfp::Agent.start(opts)
56
58
 
59
+ elsif opts[:no_daemon]
60
+ puts "no-daemon"
61
+ opts[:daemon] = false
62
+ Sfp::Agent.start(opts)
63
+
57
64
  elsif opts[:status]
58
65
  Sfp::Agent.status
59
66
 
@@ -80,6 +87,15 @@ elsif opts[:execute]
80
87
  runtime.get_state
81
88
  puts (runtime.execute_plan(File.read(plan_file)) ? "Success!" : "Failed!")
82
89
 
90
+ elsif opts[:resolve].to_s.strip.length > 0
91
+ path = opts[:resolve].to_s.strip.sub(/^\$\./, '').gsub(/\./, '/')
92
+ path = "/state/" + path
93
+ http = Object.new.extend(Sfp::Helper::Net)
94
+ code, state = http.get_data('localhost', Sfp::Agent::DefaultPort, path)
95
+ if code == '200'
96
+ puts state
97
+ end
98
+
83
99
  else
84
100
  Trollop::help
85
101
 
@@ -13,21 +13,21 @@ module Sfp
13
13
  module Agent
14
14
  NetHelper = Object.new.extend(Sfp::Helper::Net)
15
15
 
16
- CacheDir = (Process.euid == 0 ? '/var/sfpagent' : File.expand_path(Dir.home + '/.sfpagent'))
17
- Dir.mkdir(CacheDir, 0700) if not File.exist?(CacheDir)
16
+ Home = ((Process.euid == 0 and File.directory?('/var')) ? '/var/sfpagent' : File.expand_path(Dir.home + '/.sfpagent'))
17
+ Dir.mkdir(Home, 0700) if not File.exist?(Home)
18
18
 
19
19
  DefaultPort = 1314
20
20
 
21
- PIDFile = "#{CacheDir}/sfpagent.pid"
22
- LogFile = "#{CacheDir}/sfpagent.log"
23
- ModelFile = "#{CacheDir}/sfpagent.model"
24
- AgentsDataFile = "#{CacheDir}/sfpagent.agents"
21
+ PIDFile = "#{Home}/sfpagent.pid"
22
+ LogFile = "#{Home}/sfpagent.log"
23
+ ModelFile = "#{Home}/sfpagent.model"
24
+ AgentsDataFile = "#{Home}/sfpagent.agents"
25
25
 
26
- CacheModelFile = "#{CacheDir}/cache.model"
26
+ CacheModelFile = "#{Home}/cache.model"
27
27
 
28
- BSigFile = "#{CacheDir}/bsig.model"
29
- BSigPIDFile = "#{CacheDir}/bsig.pid"
30
- BSigThreadsLockFile = "#{CacheDir}/bsig.threads.lock.#{Time.now.to_i}"
28
+ BSigFile = "#{Home}/bsig.model"
29
+ BSigPIDFile = "#{Home}/bsig.pid"
30
+ BSigThreadsLockFile = "#{Home}/bsig.threads.lock.#{Time.now.to_i}"
31
31
 
32
32
  @@logger = WEBrick::Log.new(LogFile, WEBrick::BasicLog::INFO ||
33
33
  WEBrick::BasicLog::ERROR ||
@@ -78,7 +78,7 @@ module Sfp
78
78
 
79
79
  begin
80
80
  # check modules directory, and create it if it's not exist
81
- opts[:modules_dir] = File.expand_path(opts[:modules_dir].to_s.strip != '' ? opts[:modules_dir].to_s : "#{CacheDir}/modules")
81
+ opts[:modules_dir] = File.expand_path(opts[:modules_dir].to_s.strip != '' ? opts[:modules_dir].to_s : "#{Home}/modules")
82
82
  Dir.mkdir(opts[:modules_dir], 0700) if not File.exist?(opts[:modules_dir])
83
83
 
84
84
  # load modules from cached directory
@@ -108,20 +108,22 @@ module Sfp
108
108
  # create maintenance object
109
109
  maintenance = Maintenance.new(opts)
110
110
 
111
- # trap signal
112
- ['INT', 'KILL', 'HUP'].each { |signal|
113
- trap(signal) {
114
- maintenance.stop
115
-
116
- Sfp::Agent.logger.info "Shutting down web server and BSig engine..."
117
- bsig_engine.stop
118
- loop do
119
- break if bsig_engine.status == :stopped
120
- sleep 1
121
- end
122
- server.shutdown
123
- }
124
- }
111
+ if not is_windows
112
+ # trap signal
113
+ ['INT', 'KILL', 'HUP'].each do |signal|
114
+ trap(signal) {
115
+ maintenance.stop
116
+
117
+ Sfp::Agent.logger.info "Shutting down web server and BSig engine..."
118
+ bsig_engine.stop
119
+ loop do
120
+ break if bsig_engine.status == :stopped
121
+ sleep 1
122
+ end
123
+ server.shutdown
124
+ }
125
+ end
126
+ end
125
127
 
126
128
  File.open(PIDFile, 'w', 0644) { |f| f.write($$.to_s) }
127
129
 
@@ -197,6 +199,10 @@ module Sfp
197
199
  nil
198
200
  end
199
201
 
202
+ def self.is_windows
203
+ (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
204
+ end
205
+
200
206
  def self.set_cache_model(p={})
201
207
  File.open(CacheModelFile, File::RDWR|File::CREAT, 0600) do |f|
202
208
  f.flock(File::LOCK_EX)
@@ -414,31 +420,51 @@ module Sfp
414
420
  false
415
421
  end
416
422
 
417
- # Load all modules in given directory.
423
+ ###############
424
+ #
425
+ # Load all modules in given agent's module directory.
418
426
  #
419
427
  # options:
420
- # :dir => directory that holds all modules
428
+ # :dir => directory that contains all modules
421
429
  #
430
+ ###############
422
431
  def self.load_modules(p={})
423
432
  dir = p[:modules_dir]
424
433
 
425
- @@modules = []
434
+ @@modules = {}
426
435
  counter = 0
427
- if dir != '' and File.exist?(dir)
436
+ if dir != '' and File.directory?(dir)
428
437
  Sfp::Agent.logger.info "Modules directory: #{dir}"
429
- Dir.entries(dir).each { |name|
430
- next if name == '.' or name == '..' or File.file?("#{dir}/#{name}")
431
- module_file = "#{dir}/#{name}/#{name}.rb"
432
- next if not File.exist?(module_file)
433
- begin
434
- load module_file # use 'load' than 'require'
435
- Sfp::Agent.logger.info "Loading module #{dir}/#{name} [OK]"
438
+ Dir.entries(dir).each do |name|
439
+ module_dir = "#{dir}/#{name}"
440
+ next if name == '.' or name == '..' or not File.directory?(module_dir)
441
+ module_file = "#{module_dir}/#{name}.rb"
442
+ if File.exist?(module_file)
443
+ begin
444
+ ### use 'load' than 'require' to rewrite previous definitions
445
+ load module_file
446
+ Sfp::Agent.logger.info "Loading module #{module_dir} [OK]"
447
+ counter += 1
448
+ @@modules[name] = {
449
+ :type => :ruby,
450
+ :home => module_dir,
451
+ :hash => get_module_hash(name)
452
+ }
453
+ rescue Exception => e
454
+ Sfp::Agent.logger.warn "Loading module #{dir}/#{name} [Failed]\n#{e}"
455
+ end
456
+ elsif File.exist?("#{module_dir}/main")
457
+ Sfp::Agent.logger.info "Loading module #{module_dir} [OK]"
458
+ @@modules[name] = {
459
+ :type => :shell,
460
+ :home => module_dir,
461
+ :hash => get_module_hash(name)
462
+ }
436
463
  counter += 1
437
- @@modules << name
438
- rescue Exception => e
439
- Sfp::Agent.logger.warn "Loading module #{dir}/#{name} [Failed]\n#{e}"
464
+ else
465
+ logger.warn "Module #{module_dir} is invalid."
440
466
  end
441
- }
467
+ end
442
468
  end
443
469
  Sfp::Agent.logger.info "Successfully loading #{counter} modules."
444
470
  end
@@ -467,27 +493,11 @@ module Sfp
467
493
  end
468
494
 
469
495
  def self.get_modules
470
- return [] if not (defined? @@modules and @@modules.is_a? Array)
471
- data = {}
472
- @@modules.each { |m| data[m] = get_module_hash(m) }
473
- data
474
- end
475
-
476
- # Push a list of modules to an agent using a script in $SFPAGENT_HOME/bin/install_module.
477
- #
478
- # parameters:
479
- # :address => address of target agent
480
- # :port => port of target agent
481
- # :modules => an array of modules' name that will be pushed
482
- #
483
- def self.push_modules(p={})
484
- fail "Incomplete parameters." if !p[:modules] or !p[:address] or !p[:port]
485
-
486
- install_module = File.expand_path('../../../bin/install_module', __FILE__)
487
- modules = p[:modules].join(' ')
488
- cmd = "cd #{@@config[:modules_dir]}; #{install_module} #{p[:address]} #{p[:port]} #{modules}"
489
- result = `#{cmd}`
490
- (result =~ /status: ok/)
496
+ #return [] if not (defined? @@modules and @@modules.is_a?(Hash))
497
+ #data = {}
498
+ #@@modules.each_key { |m| data[m] = get_module_hash(m) }
499
+ #data
500
+ (defined?(@@modules) ? @@modules : {})
491
501
  end
492
502
 
493
503
  def self.uninstall_all_modules(p={})
@@ -662,14 +672,14 @@ module Sfp
662
672
  @logger = logger
663
673
  end
664
674
 
665
- # Process HTTP Get request
675
+ # Process HTTP GET request
666
676
  #
667
677
  # uri:
668
- # /pid => save daemon's PID to a file (only requested from localhost)
669
- # /state => return the current state
670
- # /model => return the current model
671
- # /sfp => return the SFP description of a module
672
- # /modules => return a list of available modules
678
+ # /pid => save daemon's PID to a file (only requested from localhost)
679
+ # /state => return the current state
680
+ # /model => return the current model
681
+ # /sfp => return the SFP description of a module
682
+ # /modules => return a list of available modules
673
683
  # /agents => return a list of agents database
674
684
  # /log => return last 100 lines of log file
675
685
  #
@@ -708,7 +718,9 @@ module Sfp
708
718
  status, content_type, body = get_sfp({:module => path[10, path.length-10]})
709
719
 
710
720
  elsif path == '/modules'
711
- status, content_type, body = [200, 'application/json', JSON.generate(Sfp::Agent.get_modules)]
721
+ mods = {}
722
+ Sfp::Agent.get_modules.each { |name,data| mods[name] = data[:hash] }
723
+ status, content_type, body = [200, 'application/json', JSON.generate(mods)]
712
724
 
713
725
  elsif path == '/agents'
714
726
  status, content_type, body = [200, 'application/JSON', JSON.generate(Sfp::Agent.get_agents)]
@@ -724,7 +736,7 @@ module Sfp
724
736
  response.body = body
725
737
  end
726
738
 
727
- # Handle HTTP Post request
739
+ # Handle HTTP POST request
728
740
  #
729
741
  # uri:
730
742
  # /execute => receive an action's schema and execute it
@@ -746,16 +758,16 @@ module Sfp
746
758
  response.body = body
747
759
  end
748
760
 
749
- # Handle HTTP Put request
761
+ # Handle HTTP PUT request
750
762
  #
751
763
  # uri:
752
- # /model => receive a new model and then save it
764
+ # /model => receive a new model and then save it
753
765
  # /model/cache => receive a "cache" model and then save it
754
- # /modules => save the module if parameter "module" is provided
755
- # /agents => save the agents' list if parameter "agents" is provided
766
+ # /modules => save the module if parameter "module" is provided
767
+ # /agents => save the agents' list if parameter "agents" is provided
756
768
  # /bsig => receive BSig model and receive it in cached directory
757
769
  # /bsig/satisfier => receive goal request from other agents and then start
758
- # a satisfier thread to try to achieve it
770
+ # a satisfier thread in order to achieve it
759
771
  #
760
772
  def do_PUT(request, response)
761
773
  status = 400
@@ -800,15 +812,15 @@ module Sfp
800
812
  response.body = body
801
813
  end
802
814
 
803
- # Handle HTTP Delete request
815
+ # Handle HTTP DELETE request
804
816
  #
805
817
  # uri:
806
- # /model => delete existing model
818
+ # /model => delete existing model
807
819
  # /model/cache => delete all cache models
808
820
  # /model/cache/name => delete cache model of agent "name"
809
- # /modules => delete all modules from module database
810
- # /modules/name => delete module "name" from module database
811
- # /agents => delete all agents from agent database
821
+ # /modules => delete all modules from module database
822
+ # /modules/name => delete module "name" from module database
823
+ # /agents => delete all agents from agent database
812
824
  # /agents/name => delete "name" from agent database
813
825
  # /bsig => delete existing BSig model
814
826
  #
@@ -7,8 +7,8 @@ class Sfp::BSig
7
7
  MaxTries = 5
8
8
 
9
9
  SatisfierPath = '/bsig/satisfier'
10
- CacheDir = (Process.euid == 0 ? '/var/sfpagent' : File.expand_path(Dir.home + '/.sfpagent'))
11
- SatisfierLockFile = "#{CacheDir}/bsig.satisfier.lock.#{Time.now.to_i}"
10
+ Home = ((Process.euid == 0 and File.directory?('/var')) ? '/var/sfpagent' : File.expand_path(Dir.home + '/.sfpagent'))
11
+ SatisfierLockFile = "#{Home}/bsig.satisfier.lock.#{Time.now.to_i}"
12
12
 
13
13
  attr_reader :enabled, :status, :mode
14
14
 
@@ -33,7 +33,7 @@ class Sfp::BSig
33
33
  Thread.new {
34
34
  register_satisfier_thread(:reset)
35
35
 
36
- system("rm -f #{CacheDir}/operator.*.lock")
36
+ system("rm -f #{Home}/operator.*.lock")
37
37
 
38
38
  Sfp::Agent.logger.info "[main] BSig engine is running."
39
39
 
@@ -307,7 +307,7 @@ class Sfp::BSig
307
307
 
308
308
  def lock_operator(operator)
309
309
  @lock.synchronize {
310
- operator_lock_file = "#{CacheDir}/operator.#{operator['id']}.#{operator['name']}.lock"
310
+ operator_lock_file = "#{Home}/operator.#{operator['id']}.#{operator['name']}.lock"
311
311
  return false if File.exist?(operator_lock_file)
312
312
  File.open(operator_lock_file, 'w') { |f| f.write('1') }
313
313
  return true
@@ -316,7 +316,7 @@ class Sfp::BSig
316
316
 
317
317
  def unlock_operator(operator)
318
318
  @lock.synchronize {
319
- operator_lock_file = "#{CacheDir}/operator.#{operator['id']}.#{operator['name']}.lock"
319
+ operator_lock_file = "#{Home}/operator.#{operator['id']}.#{operator['name']}.lock"
320
320
  File.delete(operator_lock_file) if File.exist?(operator_lock_file)
321
321
  }
322
322
  end
@@ -1,10 +1,71 @@
1
+ require 'yaml'
2
+ require 'shellwords'
3
+
4
+ module Sfp::Module
5
+ end
6
+
7
+ ###############
8
+ #
9
+ # Module Sfp::Resource must be included by every module. It provides
10
+ # standard methods which are used by Runtime engine in mapping between
11
+ # SFP object and schema implementation.
12
+ #
13
+ # accessible attributes
14
+ # - parent : holds instance of parent's object
15
+ #
16
+ # - synchronized : an list of SFP procedures that must be executed in
17
+ # serial
18
+ #
19
+ # - path : an absolute path of this instance
20
+ #
21
+ # read-only attributes
22
+ # - state : holds the current state of this module instance
23
+ #
24
+ # - model : holds the model of desired state of this module
25
+ # instance
26
+ #
27
+ # methods:
28
+ # - init : invoked by Runtime engine after instantiating this
29
+ # module instance for initialization
30
+ #
31
+ # - update_state : invoked by Runtime engine to request this module
32
+ # instance to update the current state which should
33
+ # be kept in attribute @state
34
+ #
35
+ # - to_model : can be invoked by this module instance to set the
36
+ # current state equals the desired state (model), or
37
+ # in short: @state == @model
38
+ #
39
+ # - resolve_state : can be invoked by this module to resolve given
40
+ # reference of current state either local or other
41
+ # module instances
42
+ #
43
+ # - resolve : an alias to method resolve_state
44
+ #
45
+ # - resolve_model : can be invoked by this module to resolve given
46
+ # reference of desired state (model) either local or
47
+ # other module instances
48
+ #
49
+ # - log : return logger object
50
+ #
51
+ # - copy : copy a file, whose path is the first parameter, to
52
+ # a destination path given in the second parameter
1
53
  #
2
- # predefined methods: update_state, apply, reset, resolve, resolve_model, resolve_state
54
+ # - render : render given template file, whose path is the first
55
+ # parameter, and the template's variable is a merged
56
+ # between a Hash in the second parameter with model;
57
+ # the result is returned as a string
3
58
  #
59
+ # - render_file : render given template file, whose path is the first
60
+ # parameter, and the template's variable is a merged
61
+ # between a Hash on the second parameter with model;
62
+ # the result is written back to the file
63
+ #
64
+ ###############
4
65
  module Sfp::Resource
5
66
  @@resource = Object.new.extend(Sfp::Resource)
6
67
 
7
- attr_accessor :parent, :synchronized
68
+ attr_accessor :parent, :synchronized, :path
8
69
  attr_reader :state, :model
9
70
 
10
71
  def init(model={})
@@ -99,5 +160,53 @@ module Sfp::Resource
99
160
  end
100
161
  end
101
162
 
102
- module Sfp::Module
163
+ class Sfp::Module::Shell
164
+ include Sfp::Resource
165
+
166
+ attr_reader :home, :main
167
+
168
+ def initialize(metadata)
169
+ ### set module's home directory
170
+ @home = metadata[:home]
171
+
172
+ ### set main shell command
173
+ @main = @home + '/main'
174
+ end
175
+
176
+ def update_state
177
+ @state = invoke({
178
+ :command => :state,
179
+ :model => @model,
180
+ :path => @path
181
+ })
182
+ end
183
+
184
+ def execute(name, parameters={})
185
+ result = invoke({
186
+ :command => :execute,
187
+ :procedure => name.split('.').last,
188
+ :parameters => parameters,
189
+ :model => @model,
190
+ :path => @path
191
+ })
192
+ if result['status'] != 'ok'
193
+ log.error "Error in executing #{name} - description: #{result['description']}"
194
+ false
195
+ else
196
+ true
197
+ end
198
+ end
199
+
200
+ private
201
+
202
+ def invoke(parameters)
203
+ log.info Shellwords.shellescape(JSON.generate(parameters))
204
+ begin
205
+ output = `#{@main} #{Shellwords.shellescape(JSON.generate(parameters))}`
206
+ JSON.parse(output)
207
+ rescue Exception => exp
208
+ log.info "Invalid module output: #{output}"
209
+ raise exp
210
+ end
211
+ end
103
212
  end
@@ -27,14 +27,27 @@ class Sfp::Runtime
27
27
 
28
28
  module_path, method_name = action['name'].pop_ref
29
29
  mod = @root.at?(module_path)[:_self]
30
- raise Exception, "Module #{module_path} cannot be found!" if mod.nil?
31
- raise Exception, "Cannot execute #{action['name']}!" if not mod.respond_to?(method_name)
32
30
 
33
- params = normalise_parameters(action['parameters'])
34
- if mod.synchronized.rindex(method_name)
35
- @mutex_procedure.synchronize { mod.send method_name.to_sym, params }
31
+ if mod.nil?
32
+ raise Exception, "Module #{module_path} cannot be found!"
33
+
34
+ elsif mod.is_a?(Sfp::Module::Shell)
35
+ params = normalise_parameters(action['parameters'])
36
+ mod.execute method_name, params
37
+
38
+ elsif not mod.respond_to?(method_name)
39
+ raise Exception, "Cannot execute #{action['name']}!"
40
+
36
41
  else
37
- mod.send method_name.to_sym, params
42
+ params = normalise_parameters(action['parameters'])
43
+ if mod.synchronized.rindex(method_name)
44
+ @mutex_procedure.synchronize {
45
+ mod.send method_name.to_sym, params
46
+ }
47
+ else
48
+ mod.send method_name.to_sym, params
49
+ end
50
+
38
51
  end
39
52
 
40
53
  # TODO - check post-execution state for verification
@@ -98,7 +111,7 @@ class Sfp::Runtime
98
111
  def update_model(model, root, path)
99
112
  object = {}
100
113
  if model['_context'] == 'object' and model['_isa'].to_s.isref #and model['_isa'].to_s != '$.Object'
101
- object[:_self] = instantiate_sfp_object(model, root)
114
+ object[:_self] = instantiate_sfp_object(model, path)
102
115
  end
103
116
 
104
117
  model.each do |key,child|
@@ -110,28 +123,47 @@ class Sfp::Runtime
110
123
  object
111
124
  end
112
125
 
113
- def instantiate_sfp_object(model, root)
114
- # get SFP schema name
115
- schema_name = model['_isa'].sub(/^\$\./, '')
126
+ def shell_module?(schema)
127
+ Sfp::Agent.get_modules.each do |name,data|
128
+ return true if schema == name and data[:type] == :shell
129
+ end
130
+ false
131
+ end
132
+
133
+ def instantiate_sfp_object(model, path)
134
+ ### get SFP schema's name
135
+ schema = model['_isa'].sub(/^\$\./, '')
136
+ object = nil
116
137
 
117
- # throw an exception if schema's implementation is not exist!
118
- raise Exception, "Implementation of schema #{schema_name} is not available!" if
119
- not Sfp::Module.const_defined?(schema_name)
138
+ if schema[0] =~ /[A-Z]/ and Sfp::Module.const_defined?(schema)
139
+ ### create an instance of the schema
140
+ object = Sfp::Module::const_get(schema).new
120
141
 
121
- # create an instance of the schema
122
- object = Sfp::Module::const_get(schema_name).new
142
+ elsif shell_module?(schema)
143
+ ### get module's metadata
144
+ metadata = Sfp::Agent.get_modules[schema]
145
+
146
+ ### create module wrapper instance
147
+ object = Sfp::Module::Shell.new(metadata)
148
+
149
+ else
150
+ # throw an exception if schema's implementation is not exist!
151
+ raise Exception, "Implementation of schema #{schema} is not available!"
152
+
153
+ end
123
154
 
124
155
  # initialize the instance
125
- object_model = model.select { |k,v| k[0,1] != '_' and
126
- not (v.is_a?(Hash) and v['_context'] == 'procedure') }
127
156
  object.init(model)
128
-
157
+
129
158
  # update list of synchronized procedures
130
159
  model.each { |k,v|
131
160
  next if k[0,1] == '_' or not (v.is_a?(Hash) and v['_context'] == 'procedure')
132
161
  object.synchronized << k if v['_synchronized']
133
162
  }
134
163
 
164
+ # set object's path
165
+ object.path = path
166
+
135
167
  object
136
168
  end
137
169
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sfpagent
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.10
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-11-07 00:00:00.000000000 Z
12
+ date: 2013-11-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sfp
16
- requirement: &21609180 !ruby/object:Gem::Requirement
16
+ requirement: &6198020 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 0.3.17
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *21609180
24
+ version_requirements: *6198020
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: rake
27
- requirement: &21608740 !ruby/object:Gem::Requirement
27
+ requirement: &6197580 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,7 +32,7 @@ dependencies:
32
32
  version: '0'
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *21608740
35
+ version_requirements: *6197580
36
36
  description: A Ruby implementation of SFP agent.
37
37
  email: herry13@gmail.com
38
38
  executables: