sfpagent 0.1.0 → 0.1.1
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/README.md +56 -8
- data/bin/sfpagent +1 -1
- data/lib/sfpagent/agent.rb +86 -12
- data/lib/sfpagent/module.rb +5 -0
- data/lib/sfpagent/net_helper.rb +56 -0
- data/lib/sfpagent/runtime.rb +57 -149
- data/lib/sfpagent.rb +4 -2
- data/sfpagent.gemspec +1 -1
- metadata +5 -9
data/README.md
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
SFP Agent for Ruby
|
2
2
|
==================
|
3
3
|
- Author: Herry (herry13@gmail.com)
|
4
|
-
- Version: 0.
|
5
|
-
- License: [BSD License](https://github.com/herry13/
|
4
|
+
- Version: 0.1.1
|
5
|
+
- License: [BSD License](https://github.com/herry13/sfpagent/blob/master/LICENSE)
|
6
6
|
|
7
|
-
A
|
7
|
+
A Ruby script and API of an SFP agent. The agent could be accessed through HTTP RESTful API.
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
$ gem install sfpagent
|
9
|
+
With this agent, you could manage a software component such as get the state, install, uninstall, update
|
10
|
+
its configuration, etc. Each configuration should be specified in [SFP language](https://github.com/herry13/sfp).
|
11
|
+
Every software component could have a set of methods which could be called through HTTP request.
|
14
12
|
|
15
13
|
|
16
14
|
Requirements
|
@@ -20,3 +18,53 @@ Requirements
|
|
20
18
|
- sfp (>= 0.3.0)
|
21
19
|
- antlr3
|
22
20
|
- json
|
21
|
+
|
22
|
+
|
23
|
+
To install
|
24
|
+
----------
|
25
|
+
|
26
|
+
$ gem install sfpagent
|
27
|
+
|
28
|
+
|
29
|
+
As daemon
|
30
|
+
---------
|
31
|
+
- start the agent daemon
|
32
|
+
|
33
|
+
$ sfpagent -s
|
34
|
+
|
35
|
+
In default, the agent will listen at port **1314**.
|
36
|
+
|
37
|
+
- stop the agent daemon
|
38
|
+
|
39
|
+
$ sfpagent -t
|
40
|
+
|
41
|
+
|
42
|
+
Cached Directory
|
43
|
+
----------------
|
44
|
+
Cached directory keeps all agent's local data such as:
|
45
|
+
- log file
|
46
|
+
- PID file
|
47
|
+
- model file
|
48
|
+
- installed modules
|
49
|
+
|
50
|
+
In default, the agent will use (and created if not exist):
|
51
|
+
- directory **~/.sfpagent**, when the daemon is running with non-root user,
|
52
|
+
- directory **/var/sfpagent**, when the daemon is running with root user.
|
53
|
+
|
54
|
+
|
55
|
+
HTTP RESTful API
|
56
|
+
----------------
|
57
|
+
- GET
|
58
|
+
- /state : return the state of the agent
|
59
|
+
- /model : return the model of the agent
|
60
|
+
- /modules : return the list of modules
|
61
|
+
- /log : return the last 100 lines of the log file
|
62
|
+
|
63
|
+
- POST
|
64
|
+
- /execute : execute an action as specified in "action" parameter
|
65
|
+
|
66
|
+
- PUT
|
67
|
+
- /model : set/replace the model with given model as specified in "model" parameter
|
68
|
+
- /module : set/replace the module if "module" parameter is specified, or delete the module if the parameter is not exist
|
69
|
+
|
70
|
+
|
data/bin/sfpagent
CHANGED
@@ -4,7 +4,7 @@ libdir = File.expand_path(File.dirname(__FILE__))
|
|
4
4
|
require "#{libdir}/../lib/sfpagent"
|
5
5
|
|
6
6
|
opts = Trollop::options do
|
7
|
-
version "sfpagent 0.
|
7
|
+
version "sfpagent 0.1.1 (c) 2013 Herry"
|
8
8
|
banner <<-EOS
|
9
9
|
SFP Agent that provides a Ruby framework for managing system configurations. The configurations are modelled in SFP language.
|
10
10
|
|
data/lib/sfpagent/agent.rb
CHANGED
@@ -9,6 +9,8 @@ require 'logger'
|
|
9
9
|
|
10
10
|
module Sfp
|
11
11
|
module Agent
|
12
|
+
NetHelper = Object.new.extend(Nuri::Net::Helper)
|
13
|
+
|
12
14
|
if Process.euid == 0
|
13
15
|
CachedDir = '/var/sfpagent'
|
14
16
|
else
|
@@ -185,8 +187,9 @@ module Sfp
|
|
185
187
|
# Return the current state of the model.
|
186
188
|
#
|
187
189
|
def self.get_state(as_sfp=true)
|
188
|
-
return nil if !defined?
|
190
|
+
return nil if !defined?(@@runtime) or @@runtime.nil?
|
189
191
|
begin
|
192
|
+
@@runtime.get_state if @@runtime.modules.nil?
|
190
193
|
return @@runtime.get_state(as_sfp)
|
191
194
|
rescue Exception => e
|
192
195
|
@@logger.error "Get state [Failed] #{e}\n#{e.backtrace.join("\n")}"
|
@@ -194,6 +197,39 @@ module Sfp
|
|
194
197
|
false
|
195
198
|
end
|
196
199
|
|
200
|
+
def self.resolve(path, as_sfp=true)
|
201
|
+
return Sfp::Undefined.new if !defined?(@@runtime) or @@runtime.nil? or @@runtime.modules.nil?
|
202
|
+
begin
|
203
|
+
path = path.simplify
|
204
|
+
_, node, _ = path.split('.', 3)
|
205
|
+
if @@runtime.modules.has_key?(node)
|
206
|
+
# local resolve
|
207
|
+
parent, attribute = path.pop_ref
|
208
|
+
mod = @@runtime.modules.at?(parent)
|
209
|
+
if mod.is_a?(Hash)
|
210
|
+
mod[:_self].update_state
|
211
|
+
state = mod[:_self].state
|
212
|
+
return state[attribute] if state.has_key?(attribute)
|
213
|
+
end
|
214
|
+
else
|
215
|
+
agents = get_agents
|
216
|
+
if agents[node].is_a?(Hash)
|
217
|
+
agent = agents[node]
|
218
|
+
path = path[1, path.length-1].gsub /\./, '/'
|
219
|
+
code, data = NetHelper.get_data(agent['sfpAddress'], agent['sfpPort'], "/state#{path}")
|
220
|
+
if code.to_i == 200
|
221
|
+
state = JSON[data]['state']
|
222
|
+
return Sfp::Unknown.new if state == '<sfp::unknown>'
|
223
|
+
return state if !state.is_a?(String) or state[0,15] != '<sfp::undefined'
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
rescue Exception => e
|
228
|
+
@@logger.error "Resolve #{path} [Failed] #{e}\n#{e.backtrace.join("\n")}"
|
229
|
+
end
|
230
|
+
Sfp::Undefined.new
|
231
|
+
end
|
232
|
+
|
197
233
|
# Execute an action
|
198
234
|
#
|
199
235
|
# @param action contains the action's schema.
|
@@ -342,13 +378,13 @@ module Sfp
|
|
342
378
|
raise Exception, "Invalid agents list." if not agents.is_a?(Hash)
|
343
379
|
buffer = {}
|
344
380
|
agents.each { |name,data|
|
345
|
-
raise Exception "Invalid agents list." if not data.is_a?(Hash) or
|
346
|
-
not data.has_key?('
|
347
|
-
not data.has_key?('
|
381
|
+
raise Exception, "Invalid agents list." if not data.is_a?(Hash) or
|
382
|
+
not data.has_key?('sfpAddress') or data['sfpAddress'].to_s.strip == '' or
|
383
|
+
not data.has_key?('sfpPort')
|
348
384
|
buffer[name] = {}
|
349
|
-
buffer[name]['
|
350
|
-
buffer[name]['
|
351
|
-
buffer[name]['
|
385
|
+
buffer[name]['sfpAddress'] = data['sfpAddress'].to_s
|
386
|
+
buffer[name]['sfpPort'] = data['sfpPort'].to_s.strip.to_i
|
387
|
+
buffer[name]['sfpPort'] = DefaultPort if buffer[name]['sfpPort'] == 0
|
352
388
|
}
|
353
389
|
f.write(JSON.generate(buffer))
|
354
390
|
f.flush
|
@@ -408,6 +444,9 @@ module Sfp
|
|
408
444
|
elsif path == '/modules'
|
409
445
|
status, content_type, body = [200, 'application/json', JSON.generate(Sfp::Agent.get_modules)]
|
410
446
|
|
447
|
+
elsif path == '/agents'
|
448
|
+
status, content_type, body = [200, 'application/JSON', JSON.generate(Sfp::Agent.get_agents)]
|
449
|
+
|
411
450
|
elsif path == '/log'
|
412
451
|
status, content_type, body = [200, 'text/plain', Sfp::Agent.get_log(100)]
|
413
452
|
|
@@ -423,6 +462,8 @@ module Sfp
|
|
423
462
|
#
|
424
463
|
# uri:
|
425
464
|
# /execute => receive an action's schema and execute it
|
465
|
+
# /migrate => SFP object migration
|
466
|
+
# /duplicate => SFP object duplication
|
426
467
|
#
|
427
468
|
def do_POST(request, response)
|
428
469
|
status = 400
|
@@ -433,6 +474,14 @@ module Sfp
|
|
433
474
|
path = (request.path[-1,1] == '/' ? ryyequest.path.chop : request.path)
|
434
475
|
if path == '/execute'
|
435
476
|
status, content_type, body = self.execute({:query => request.query})
|
477
|
+
|
478
|
+
elsif path =~ /\/migrate\/.+/
|
479
|
+
status, content_type, body = self.migrate({:src => path[8, path.length-8],
|
480
|
+
:dest => request.query['destination']})
|
481
|
+
|
482
|
+
elsif path =~ /\/duplicate\/.+/
|
483
|
+
# TODO
|
484
|
+
|
436
485
|
end
|
437
486
|
end
|
438
487
|
|
@@ -458,13 +507,9 @@ module Sfp
|
|
458
507
|
if path == '/model'
|
459
508
|
status, content_type, body = self.set_model({:query => request.query})
|
460
509
|
|
461
|
-
elsif path =~ /\/module\/.+/
|
462
|
-
status, content_type, body = self.manage_modules({:name => path[8, path.length-8],
|
463
|
-
:query => request.query})
|
464
|
-
|
465
510
|
elsif path =~ /\/modules\/.+/
|
466
511
|
status, content_type, body = self.manage_modules({:name => path[9, path.length-9],
|
467
|
-
|
512
|
+
:query => request.query})
|
468
513
|
|
469
514
|
elsif path == '/modules'
|
470
515
|
status, content_type, body = self.manage_modules({:delete => true})
|
@@ -480,6 +525,35 @@ module Sfp
|
|
480
525
|
response.body = body
|
481
526
|
end
|
482
527
|
|
528
|
+
def migrate(p={})
|
529
|
+
# migrate: source path, destination path
|
530
|
+
#@logger.info "migrate #{p[:src]} => #{p[:dest]}"
|
531
|
+
return [400, 'plain/text', 'Destination path should begin with "/"'] if p[:dest].to_s[0,1] != '/'
|
532
|
+
begin
|
533
|
+
# reformat the source and destination paths to SFP reference
|
534
|
+
p[:src] = '$' + p[:src].gsub(/\//, '.')
|
535
|
+
p[:dest] = '$' + p[:dest].gsub(/\//, '.')
|
536
|
+
|
537
|
+
# find the target in agents' database
|
538
|
+
agents = Sfp::Agent.get_agents
|
539
|
+
data = agents.at?(p[:dest])
|
540
|
+
return [404, 'plain/text', 'Unrecognized destination!'] if !data.is_a?(Hash)
|
541
|
+
|
542
|
+
# send the sub-model to destination
|
543
|
+
model = Sfp::Agent.get_model
|
544
|
+
return [404, '', ''] if model.nil?
|
545
|
+
submodel = model.at?(p[:src])
|
546
|
+
|
547
|
+
# TODO
|
548
|
+
# 1. send the configuration to destination
|
549
|
+
|
550
|
+
return [200, 'plain/text', "#{p[:src]} #{p[:dest]}:#{data.inspect}"]
|
551
|
+
rescue Exception => e
|
552
|
+
@logger.error "Migration failed #{e}\n#{e.backtrace.join("\n")}"
|
553
|
+
end
|
554
|
+
return [500, 'plain/text', e.to_s]
|
555
|
+
end
|
556
|
+
|
483
557
|
def manage_agents(p={})
|
484
558
|
begin
|
485
559
|
if p[:query].has_key?('agents')
|
data/lib/sfpagent/module.rb
CHANGED
@@ -2,6 +2,7 @@ require 'etc'
|
|
2
2
|
require 'fileutils'
|
3
3
|
|
4
4
|
module Sfp::Resource
|
5
|
+
attr_accessor :parent
|
5
6
|
attr_reader :state, :model
|
6
7
|
|
7
8
|
def init(model, default)
|
@@ -23,6 +24,10 @@ module Sfp::Resource
|
|
23
24
|
|
24
25
|
alias_method :reset, :to_model
|
25
26
|
|
27
|
+
def resolve(path)
|
28
|
+
Sfp::Agent.resolve(path.simplify)
|
29
|
+
end
|
30
|
+
|
26
31
|
protected
|
27
32
|
def exec_seq(*commands)
|
28
33
|
commands = [commands.to_s] if not commands.is_a?(Array)
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
module Nuri::Net
|
5
|
+
end
|
6
|
+
|
7
|
+
module Nuri::Net::Helper
|
8
|
+
def http_request(uri, request, open_timeout=5, read_timeout=1800)
|
9
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
10
|
+
http.open_timeout = open_timeout
|
11
|
+
http.read_timeout = read_timeout
|
12
|
+
http.start
|
13
|
+
http.request(request) { |res| return [res.code, res.body] }
|
14
|
+
end
|
15
|
+
|
16
|
+
def post_data(address, port, path, data, open_timeout=5, read_timeout=1800)
|
17
|
+
address = address.to_s.strip
|
18
|
+
port = port.to_s.strip
|
19
|
+
path = path.to_s.strip
|
20
|
+
raise Exception, "Invalid parameters [address:#{address},port:#{port},path:#{path}]" if
|
21
|
+
address.length <= 0 or port.length <= 0 or path.length <= 0
|
22
|
+
|
23
|
+
path.sub!(/^\/+/, '')
|
24
|
+
url = URI.parse("http://#{address}:#{port}/#{path}")
|
25
|
+
req = Net::HTTP::Post.new(url.path)
|
26
|
+
req.set_form_data(data)
|
27
|
+
http_request(url, req, open_timeout, read_timeout)
|
28
|
+
end
|
29
|
+
|
30
|
+
def put_data(address, port, path, data, open_timeout=5, read_timeout=1800)
|
31
|
+
address = address.to_s.strip
|
32
|
+
port = port.to_s.strip
|
33
|
+
path = path.to_s.strip
|
34
|
+
raise Exception, "Invalid parameters [address:#{address},port:#{port},path:#{path}]" if
|
35
|
+
address.length <= 0 or port.length <= 0 or path.length <= 0
|
36
|
+
|
37
|
+
path.sub!(/^\/+/, '')
|
38
|
+
url = URI.parse("http://#{address}:#{port}/#{path}")
|
39
|
+
req = Net::HTTP::Put.new(url.path)
|
40
|
+
req.set_form_data(data)
|
41
|
+
http_request(url, req, open_timeout, read_timeout)
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_data(address, port, path, open_timeout=5, read_timeout=1800)
|
45
|
+
address = address.to_s.strip
|
46
|
+
port = port.to_s.strip
|
47
|
+
path = path.to_s.strip
|
48
|
+
raise Exception, "Invalid parameters [address:#{address},port:#{port},path:#{path}]" if
|
49
|
+
address.length <= 0 or port.length <= 0 or path.length <= 0
|
50
|
+
|
51
|
+
path.sub!(/^\/+/, '')
|
52
|
+
url = URI.parse("http://#{address}:#{port}/#{path}")
|
53
|
+
req = Net::HTTP::Get.new(url.path)
|
54
|
+
http_request(url, req, open_timeout, read_timeout)
|
55
|
+
end
|
56
|
+
end
|
data/lib/sfpagent/runtime.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
class Sfp::Runtime
|
2
|
+
attr_reader :modules
|
3
|
+
|
2
4
|
def initialize(parser)
|
3
5
|
@parser = parser
|
4
6
|
@root = @parser.root
|
7
|
+
@modules = nil
|
5
8
|
end
|
6
9
|
|
7
10
|
def execute_action(action)
|
@@ -11,7 +14,7 @@ class Sfp::Runtime
|
|
11
14
|
p
|
12
15
|
end
|
13
16
|
|
14
|
-
self.get_state if not defined? @modules
|
17
|
+
self.get_state if not defined?(@modules) or @modules.nil?
|
15
18
|
|
16
19
|
module_path, method_name = action['name'].pop_ref
|
17
20
|
mod = @modules.at?(module_path)[:_self]
|
@@ -23,20 +26,24 @@ class Sfp::Runtime
|
|
23
26
|
end
|
24
27
|
|
25
28
|
def get_state(as_sfp=false)
|
26
|
-
def cleanup(
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
29
|
+
def cleanup(model)
|
30
|
+
model.select { |k,v| k[0,1] != '_' and !(v.is_a?(Hash) and v['_context'] != 'object') }
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_hidden_attributes(model, state)
|
34
|
+
model.each { |k,v|
|
35
|
+
state[k] = v if (k[0,1] == '_' and k != '_parent') or
|
36
|
+
(v.is_a?(Hash) and v['_context'] == 'procedure')
|
37
|
+
}
|
31
38
|
end
|
32
39
|
|
33
40
|
# Load the implementation of an object, and return its current state
|
34
|
-
# @param
|
41
|
+
# @param model a Hash
|
35
42
|
# @return a Hash which is the state of the object
|
36
43
|
#
|
37
|
-
def
|
44
|
+
def instantiate_module(model, root, as_sfp=false)
|
38
45
|
# extract class name
|
39
|
-
class_name =
|
46
|
+
class_name = model['_isa'].sub(/^\$\./, '')
|
40
47
|
|
41
48
|
# throw an exception if schema's implementation is not exist!
|
42
49
|
raise Exception, "Implementation of schema #{class_name} is not available!" if
|
@@ -44,45 +51,55 @@ class Sfp::Runtime
|
|
44
51
|
|
45
52
|
# create an instance of the schema
|
46
53
|
mod = Sfp::Module::const_get(class_name).new
|
47
|
-
default = cleanup(root.at?(
|
48
|
-
|
49
|
-
mod.init(
|
50
|
-
|
51
|
-
# update and get state
|
52
|
-
mod.update_state
|
53
|
-
state = mod.state
|
54
|
-
|
55
|
-
# insert all hidden attributes, except "_parent"
|
56
|
-
value.each do |k,v|
|
57
|
-
state[k] = v if (k[0,1] == '_' and k != '_parent') or
|
58
|
-
(v.is_a?(Hash) and v['_context'] == 'procedure')
|
59
|
-
end if as_sfp
|
60
|
-
[mod, state]
|
54
|
+
default = cleanup(root.at?(model['_isa']))
|
55
|
+
ruby_model = cleanup(model)
|
56
|
+
mod.init(ruby_model, default)
|
57
|
+
mod
|
61
58
|
end
|
62
59
|
|
63
60
|
# Return the state of an object
|
64
61
|
#
|
65
|
-
def get_object_state(
|
62
|
+
def get_object_state(model, root, as_sfp=false, path='$')
|
66
63
|
modules = {}
|
67
64
|
state = {}
|
68
|
-
if
|
69
|
-
if
|
70
|
-
# if this
|
65
|
+
if model['_context'] == 'object' and model['_isa'].to_s.isref
|
66
|
+
if model['_isa'] != '$.Object'
|
67
|
+
# if this model is an instance of a subclass of Object, then
|
71
68
|
# get the current state of this object
|
72
|
-
modules[:_self]
|
69
|
+
#modules[:_self] = nil
|
70
|
+
mod = (!defined?(@modules) or @modules.nil? ? nil : @modules.at?(path))
|
71
|
+
if mod.is_a?(Hash)
|
72
|
+
modules[:_self] = mod[:_self]
|
73
|
+
else
|
74
|
+
# the module has not been instantiated yet!
|
75
|
+
modules[:_self] = instantiate_module(model, root, as_sfp)
|
76
|
+
end
|
77
|
+
# update and get the state
|
78
|
+
modules[:_self].update_state
|
79
|
+
state = modules[:_self].state
|
80
|
+
if !mod.nil? and mod.has_key?(:_vars)
|
81
|
+
state.keep_if { |k,v| mod[:_vars].index(k) }
|
82
|
+
modules[:_vars] = mod[:_vars]
|
83
|
+
else
|
84
|
+
modules[:_vars] = state.keys
|
85
|
+
end
|
86
|
+
# set hidden attributes
|
87
|
+
add_hidden_attributes(model, state) if as_sfp
|
73
88
|
end
|
74
89
|
end
|
75
90
|
|
76
91
|
# get the state for each attributes which are not covered by this
|
77
92
|
# object's module
|
78
|
-
(
|
93
|
+
(model.keys - state.keys).each do |key|
|
79
94
|
next if key[0,1] == '_'
|
80
|
-
if
|
81
|
-
modules[key], state[key] = get_object_state(
|
95
|
+
if model[key].is_a?(Hash)
|
96
|
+
modules[key], state[key] = get_object_state(model[key], root, as_sfp, path.push(key)) if
|
97
|
+
model[key]['_context'] == 'object'
|
98
|
+
modules[key]['_parent'] = modules if modules[key].is_a?(Hash)
|
82
99
|
else
|
83
100
|
state[key] = Sfp::Undefined.new
|
84
101
|
end
|
85
|
-
|
102
|
+
end
|
86
103
|
|
87
104
|
[modules, state]
|
88
105
|
end
|
@@ -91,6 +108,8 @@ class Sfp::Runtime
|
|
91
108
|
root.accept(Sfp::Visitor::ParentEliminator.new)
|
92
109
|
@modules, state = get_object_state(root, root, as_sfp)
|
93
110
|
|
111
|
+
@modules.accept(ParentGenerator)
|
112
|
+
|
94
113
|
state
|
95
114
|
end
|
96
115
|
|
@@ -112,6 +131,12 @@ class Sfp::Runtime
|
|
112
131
|
end
|
113
132
|
end
|
114
133
|
|
134
|
+
ParentGenerator = Object.new
|
135
|
+
def ParentGenerator.visit(name, value, parent)
|
136
|
+
value['_parent'] = parent if value.is_a?(Hash)
|
137
|
+
true
|
138
|
+
end
|
139
|
+
|
115
140
|
def execute_sequential_plan(plan)
|
116
141
|
puts 'Execute a sequential plan...'
|
117
142
|
|
@@ -127,120 +152,3 @@ class Sfp::Runtime
|
|
127
152
|
true
|
128
153
|
end
|
129
154
|
end
|
130
|
-
|
131
|
-
=begin
|
132
|
-
def execute(plan)
|
133
|
-
plan = JSON.parse(plan)
|
134
|
-
if plan['type'] == 'sequential'
|
135
|
-
execute_sequential(plan)
|
136
|
-
else
|
137
|
-
execute_parallel(plan)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
|
142
|
-
def execute_sequential(plan)
|
143
|
-
puts 'Execute a sequential plan...'
|
144
|
-
|
145
|
-
plan['workflow'].each_index { |index|
|
146
|
-
action = plan['workflow'][index]
|
147
|
-
print "#{index+1}) #{action['name']} "
|
148
|
-
|
149
|
-
module_path, method_name = action['name'].pop_ref
|
150
|
-
mod = @modules.at?(module_path)[:_self]
|
151
|
-
raise Exception, "Cannot execute #{action['name']}!" if not mod.respond_to?(method_name)
|
152
|
-
if not mod.send method_name.to_sym, normalise_parameters(action['parameters'])
|
153
|
-
puts '[Failed]'
|
154
|
-
return false
|
155
|
-
end
|
156
|
-
|
157
|
-
puts '[OK]'
|
158
|
-
}
|
159
|
-
true
|
160
|
-
end
|
161
|
-
|
162
|
-
def execute_parallel(plan)
|
163
|
-
# TODO
|
164
|
-
puts 'Execute a parallel plan...'
|
165
|
-
false
|
166
|
-
end
|
167
|
-
=end
|
168
|
-
|
169
|
-
=begin
|
170
|
-
def plan
|
171
|
-
# generate initial state
|
172
|
-
task = { 'initial' => Sfp::Helper.to_state('initial', self.get_state(true)) }
|
173
|
-
|
174
|
-
# add schemas
|
175
|
-
@root.each { |k,v|
|
176
|
-
next if !v.is_a?(Hash) or v['_context'] != 'class'
|
177
|
-
task[k] = v
|
178
|
-
}
|
179
|
-
|
180
|
-
# add goal constraint
|
181
|
-
model = @root.select { |k,v| v.is_a?(Hash) and v['_context'] == 'object' }
|
182
|
-
goalgen = Sfp::Helper::GoalGenerator.new
|
183
|
-
model.accept(goalgen)
|
184
|
-
task['goal'] = goalgen.results
|
185
|
-
|
186
|
-
# remove old parent links
|
187
|
-
task.accept(Sfp::Visitor::ParentEliminator.new)
|
188
|
-
|
189
|
-
# reconstruct Sfp parent links
|
190
|
-
task.accept(Sfp::Visitor::SfpGenerator.new(task))
|
191
|
-
|
192
|
-
# solve and return the plan solution
|
193
|
-
planner = Sfp::Planner.new
|
194
|
-
planner.solve({:sfp => task, :pretty_json => true})
|
195
|
-
end
|
196
|
-
=end
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
=begin
|
201
|
-
module Helper
|
202
|
-
def self.create_object(name)
|
203
|
-
{ '_self' => name, '_context' => 'object', '_isa' => '$.Object', '_classes' => ['$.Object'] }
|
204
|
-
end
|
205
|
-
|
206
|
-
def self.create_state(name)
|
207
|
-
{ '_self' => name, '_context' => 'state' }
|
208
|
-
end
|
209
|
-
|
210
|
-
def self.to_state(name, value)
|
211
|
-
raise Exception, 'Given value should be a Hash!' if not value.is_a?(Hash)
|
212
|
-
value['_self'] = name
|
213
|
-
value['_context'] = 'state'
|
214
|
-
value
|
215
|
-
end
|
216
|
-
|
217
|
-
module Constraint
|
218
|
-
def self.equals(value)
|
219
|
-
{ '_context' => 'constraint', '_type' => 'equals', '_value' => value }
|
220
|
-
end
|
221
|
-
|
222
|
-
def self.and(name)
|
223
|
-
{ '_context' => 'constraint', '_type' => 'and', '_self' => name }
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
class GoalGenerator
|
228
|
-
attr_reader :results
|
229
|
-
|
230
|
-
def initialize
|
231
|
-
@results = Sfp::Helper::Constraint.and('goal')
|
232
|
-
end
|
233
|
-
|
234
|
-
def visit(name, value, parent)
|
235
|
-
return false if name[0,1] == '_'
|
236
|
-
if value.is_a?(Hash)
|
237
|
-
return true if value['_context'] == 'object'
|
238
|
-
return false
|
239
|
-
end
|
240
|
-
|
241
|
-
@results[ parent.ref.push(name) ] = Sfp::Helper::Constraint.equals(value)
|
242
|
-
false
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
=end
|
data/lib/sfpagent.rb
CHANGED
@@ -3,12 +3,14 @@ require 'rubygems'
|
|
3
3
|
require 'json'
|
4
4
|
require 'sfp'
|
5
5
|
|
6
|
+
module Nuri
|
7
|
+
end
|
8
|
+
|
6
9
|
# internal dependencies
|
7
10
|
libdir = File.expand_path(File.dirname(__FILE__))
|
8
11
|
|
12
|
+
require libdir + '/sfpagent/net_helper.rb'
|
9
13
|
require libdir + '/sfpagent/executor.rb'
|
10
|
-
|
11
14
|
require libdir + '/sfpagent/runtime.rb'
|
12
15
|
require libdir + '/sfpagent/module.rb'
|
13
|
-
|
14
16
|
require libdir + '/sfpagent/agent.rb'
|
data/sfpagent.gemspec
CHANGED
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.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2013-07-03 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: sfp
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirement: &17002580 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,12 +21,7 @@ dependencies:
|
|
21
21
|
version: 0.3.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
25
|
-
none: false
|
26
|
-
requirements:
|
27
|
-
- - ~>
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
version: 0.3.0
|
24
|
+
version_requirements: *17002580
|
30
25
|
description: A Ruby implementation of SFP agent.
|
31
26
|
email: herry13@gmail.com
|
32
27
|
executables:
|
@@ -43,6 +38,7 @@ files:
|
|
43
38
|
- lib/sfpagent/agent.rb
|
44
39
|
- lib/sfpagent/executor.rb
|
45
40
|
- lib/sfpagent/module.rb
|
41
|
+
- lib/sfpagent/net_helper.rb
|
46
42
|
- lib/sfpagent/runtime.rb
|
47
43
|
- sfpagent.gemspec
|
48
44
|
homepage: https://github.com/herry13/sfpagent
|
@@ -66,7 +62,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
66
62
|
version: '0'
|
67
63
|
requirements: []
|
68
64
|
rubyforge_project: sfpagent
|
69
|
-
rubygems_version: 1.8.
|
65
|
+
rubygems_version: 1.8.11
|
70
66
|
signing_key:
|
71
67
|
specification_version: 3
|
72
68
|
summary: SFP Agent
|