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.
- data/.travis.yml +1 -1
- data/VERSION +1 -1
- data/bin/sfpagent +17 -1
- data/lib/sfpagent/agent.rb +91 -79
- data/lib/sfpagent/bsig.rb +5 -5
- data/lib/sfpagent/module.rb +112 -3
- data/lib/sfpagent/runtime.rb +50 -18
- metadata +6 -6
data/.travis.yml
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/bin/sfpagent
CHANGED
@@ -9,7 +9,7 @@ end
|
|
9
9
|
opts = Trollop::options do
|
10
10
|
version "sfpagent #{version?} (c) 2013 Herry"
|
11
11
|
banner <<-EOS
|
12
|
-
|
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
|
|
data/lib/sfpagent/agent.rb
CHANGED
@@ -13,21 +13,21 @@ module Sfp
|
|
13
13
|
module Agent
|
14
14
|
NetHelper = Object.new.extend(Sfp::Helper::Net)
|
15
15
|
|
16
|
-
|
17
|
-
Dir.mkdir(
|
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 = "#{
|
22
|
-
LogFile = "#{
|
23
|
-
ModelFile = "#{
|
24
|
-
AgentsDataFile = "#{
|
21
|
+
PIDFile = "#{Home}/sfpagent.pid"
|
22
|
+
LogFile = "#{Home}/sfpagent.log"
|
23
|
+
ModelFile = "#{Home}/sfpagent.model"
|
24
|
+
AgentsDataFile = "#{Home}/sfpagent.agents"
|
25
25
|
|
26
|
-
CacheModelFile = "#{
|
26
|
+
CacheModelFile = "#{Home}/cache.model"
|
27
27
|
|
28
|
-
BSigFile = "#{
|
29
|
-
BSigPIDFile = "#{
|
30
|
-
BSigThreadsLockFile = "#{
|
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 : "#{
|
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
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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
|
-
|
423
|
+
###############
|
424
|
+
#
|
425
|
+
# Load all modules in given agent's module directory.
|
418
426
|
#
|
419
427
|
# options:
|
420
|
-
# :dir => directory that
|
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.
|
436
|
+
if dir != '' and File.directory?(dir)
|
428
437
|
Sfp::Agent.logger.info "Modules directory: #{dir}"
|
429
|
-
Dir.entries(dir).each
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
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
|
-
|
438
|
-
|
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?
|
471
|
-
data = {}
|
472
|
-
|
473
|
-
data
|
474
|
-
|
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
|
675
|
+
# Process HTTP GET request
|
666
676
|
#
|
667
677
|
# uri:
|
668
|
-
#
|
669
|
-
#
|
670
|
-
#
|
671
|
-
#
|
672
|
-
#
|
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
|
-
|
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
|
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
|
761
|
+
# Handle HTTP PUT request
|
750
762
|
#
|
751
763
|
# uri:
|
752
|
-
#
|
764
|
+
# /model => receive a new model and then save it
|
753
765
|
# /model/cache => receive a "cache" model and then save it
|
754
|
-
#
|
755
|
-
#
|
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
|
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
|
815
|
+
# Handle HTTP DELETE request
|
804
816
|
#
|
805
817
|
# uri:
|
806
|
-
#
|
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
|
-
#
|
810
|
-
#
|
811
|
-
#
|
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
|
#
|
data/lib/sfpagent/bsig.rb
CHANGED
@@ -7,8 +7,8 @@ class Sfp::BSig
|
|
7
7
|
MaxTries = 5
|
8
8
|
|
9
9
|
SatisfierPath = '/bsig/satisfier'
|
10
|
-
|
11
|
-
SatisfierLockFile = "#{
|
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 #{
|
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 = "#{
|
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 = "#{
|
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
|
data/lib/sfpagent/module.rb
CHANGED
@@ -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
|
-
#
|
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
|
-
|
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
|
data/lib/sfpagent/runtime.rb
CHANGED
@@ -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
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
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,
|
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
|
114
|
-
|
115
|
-
|
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
|
-
|
118
|
-
|
119
|
-
|
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
|
-
|
122
|
-
|
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.
|
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-
|
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: &
|
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: *
|
24
|
+
version_requirements: *6198020
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rake
|
27
|
-
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: *
|
35
|
+
version_requirements: *6197580
|
36
36
|
description: A Ruby implementation of SFP agent.
|
37
37
|
email: herry13@gmail.com
|
38
38
|
executables:
|