sfpagent 0.1.4 → 0.1.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  SFP Agent for Ruby
2
2
  ==================
3
3
  - Author: Herry (herry13@gmail.com)
4
- - Version: 0.1.4
4
+ - [Version](https://github.com/herry13/sfpagent/blob/master/VERSION)
5
5
  - License: [BSD License](https://github.com/herry13/sfpagent/blob/master/LICENSE)
6
6
 
7
7
  A Ruby script and API of an SFP agent. The agent could be accessed through HTTP RESTful API.
@@ -23,6 +23,7 @@ Requirements
23
23
  To install
24
24
  ----------
25
25
 
26
+ $ apt-get install git make gcc ruby1.9.1 ruby1.9.1-dev libz-dev libaugeas-ruby1.9.1 libxml2-dev libxslt-dev
26
27
  $ gem install sfpagent
27
28
 
28
29
 
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.5
data/bin/sfpagent CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- libdir = File.expand_path(File.dirname(__FILE__))
4
- require "#{libdir}/../lib/sfpagent"
3
+ dir = File.expand_path(File.dirname(__FILE__))
4
+ require "#{dir}/../lib/sfpagent"
5
5
 
6
6
  opts = Trollop::options do
7
- version "sfpagent 0.1.4 (c) 2013 Herry"
7
+ version "sfpagent " + File.read("#{dir}/../VERSION").sub(/\n/, '') + " (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
 
@@ -0,0 +1,22 @@
1
+ module Sfp::BSig
2
+ end
3
+
4
+ module Sfp::BSig::Main
5
+ def execute_model
6
+ # TODO -- implement
7
+ end
8
+
9
+ def achieve_local_goals(version, goals, operators, pi)
10
+ # TODO -- implement
11
+ end
12
+
13
+ def achieve_remote_goals(version, goals, pi)
14
+ # TODO -- implement
15
+ end
16
+ end
17
+
18
+ module Sfp::BSig::Satisfier
19
+ def receive_goals(agent, version, goals, pi)
20
+ # TODO -- implement
21
+ end
22
+ end
@@ -2,7 +2,7 @@
2
2
  # predefined methods: update_state, apply, reset, resolve
3
3
  #
4
4
  module Sfp::Resource
5
- attr_accessor :parent
5
+ attr_accessor :parent, :synchronized
6
6
  attr_reader :state, :model
7
7
 
8
8
  def init(model, default)
@@ -10,7 +10,7 @@ module Sfp::Resource
10
10
  model.each { |k,v| @model[k] = v }
11
11
  @state = {}
12
12
  @default = {}
13
- #default.each { |k,v| @state[k] = @default[k] = v }
13
+ @synchronized = []
14
14
  end
15
15
 
16
16
  def update_state
@@ -1,7 +1,10 @@
1
+ require 'thread'
2
+
1
3
  class Sfp::Runtime
2
4
  attr_reader :modules
3
5
 
4
6
  def initialize(parser)
7
+ @mutex_procedure = Mutex.new
5
8
  @parser = parser
6
9
  @root = @parser.root
7
10
  @modules = nil
@@ -22,7 +25,13 @@ class Sfp::Runtime
22
25
  raise Exception, "Cannot execute #{action['name']}!" if not mod.respond_to?(method_name)
23
26
 
24
27
  params = normalise_parameters(action['parameters'])
25
- mod.send method_name.to_sym, params
28
+ if mod.synchronized.rindex(method_name)
29
+ @mutex_procedure.synchronize { mod.send method_name.to_sym, params }
30
+ else
31
+ mod.send method_name.to_sym, params
32
+ end
33
+
34
+ # TODO - check post-execution state for verification
26
35
  end
27
36
 
28
37
  def get_state(as_sfp=false)
@@ -54,6 +63,14 @@ class Sfp::Runtime
54
63
  default = cleanup(root.at?(model['_isa']))
55
64
  ruby_model = cleanup(model)
56
65
  mod.init(ruby_model, default)
66
+
67
+ # update synchronized list of procedures
68
+ model.each { |k,v|
69
+ next if k[0,1] == '_' or not (v.is_a?(Hash) and v['_context'] == 'procedure')
70
+ mod.synchronized << k if v['_synchronized']
71
+ }
72
+
73
+ # return the object instant
57
74
  mod
58
75
  end
59
76
 
@@ -113,42 +130,11 @@ class Sfp::Runtime
113
130
  state
114
131
  end
115
132
 
116
- def execute_plan(plan)
117
- plan = JSON[plan]
118
- if plan['type'] == 'sequential'
119
- execute_sequential_plan(plan)
120
- else
121
- raise Exception, "Not implemented yet!"
122
- end
123
- end
124
-
125
133
  protected
126
- class SfpState
127
- def visit(name, value, parent)
128
- parent.delete(name) if name[0,1] == '_' or
129
- (value.is_a?(Hash) and value['_context'] != 'object')
130
- true
131
- end
132
- end
133
-
134
134
  ParentGenerator = Object.new
135
135
  def ParentGenerator.visit(name, value, parent)
136
136
  value['_parent'] = parent if value.is_a?(Hash)
137
137
  true
138
138
  end
139
139
 
140
- def execute_sequential_plan(plan)
141
- puts 'Execute a sequential plan...'
142
-
143
- plan['workflow'].each_index { |index|
144
- action = plan['workflow'][index]
145
- print "#{index+1}) #{action['name']} "
146
- if not execute_action(action)
147
- puts '[Failed]'
148
- return false
149
- end
150
- puts '[OK]'
151
- }
152
- true
153
- end
154
140
  end
data/lib/sfpagent.rb CHANGED
@@ -6,11 +6,13 @@ require 'sfp'
6
6
  module Nuri
7
7
  end
8
8
 
9
+ module Sfp
10
+ end
11
+
9
12
  # internal dependencies
10
13
  libdir = File.expand_path(File.dirname(__FILE__))
11
14
 
12
15
  require libdir + '/sfpagent/net_helper.rb'
13
- require libdir + '/sfpagent/executor.rb'
14
16
  require libdir + '/sfpagent/runtime.rb'
15
17
  require libdir + '/sfpagent/module.rb'
16
18
  require libdir + '/sfpagent/agent.rb'
data/sfpagent.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'sfpagent'
3
- s.version = '0.1.4'
3
+ s.version = File.read(File.join(File.dirname(__FILE__), 'VERSION')).sub(/\n/, '')
4
4
  s.date = '2013-08-13'
5
5
  s.summary = 'SFP Agent'
6
6
  s.description = 'A Ruby implementation of SFP agent.'
@@ -16,5 +16,5 @@ Gem::Specification.new do |s|
16
16
  s.homepage = 'https://github.com/herry13/sfpagent'
17
17
  s.rubyforge_project = 'sfpagent'
18
18
 
19
- s.add_dependency 'sfp', '~> 0.3.6'
19
+ s.add_dependency 'sfp', '~> 0.3.9'
20
20
  end
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
4
+ version: 0.1.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,15 +13,15 @@ date: 2013-08-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sfp
16
- requirement: &13245980 !ruby/object:Gem::Requirement
16
+ requirement: &20504460 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
20
20
  - !ruby/object:Gem::Version
21
- version: 0.3.6
21
+ version: 0.3.9
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *13245980
24
+ version_requirements: *20504460
25
25
  description: A Ruby implementation of SFP agent.
26
26
  email: herry13@gmail.com
27
27
  executables:
@@ -32,11 +32,12 @@ files:
32
32
  - .gitignore
33
33
  - LICENSE
34
34
  - README.md
35
+ - VERSION
35
36
  - bin/cert.rb
36
37
  - bin/sfpagent
37
38
  - lib/sfpagent.rb
38
39
  - lib/sfpagent/agent.rb
39
- - lib/sfpagent/executor.rb
40
+ - lib/sfpagent/bsig.rb
40
41
  - lib/sfpagent/module.rb
41
42
  - lib/sfpagent/net_helper.rb
42
43
  - lib/sfpagent/runtime.rb
@@ -1,207 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'json'
4
- require 'thread'
5
-
6
- module Sfp
7
- module Executor
8
- class ExecutionException < Exception; end
9
- class ParallelExecutionException < Exception; end
10
- class SequentialExecutionException < Exception; end
11
-
12
- # @param :plan the plan to be executed
13
- # @param :owner an object that implement the action
14
- # @param :retry number of retries (default: 2) when execution is failed
15
- #
16
- def execute_plan(params={})
17
- if params[:plan].nil? or not params[:plan].is_a?(Hash)
18
- raise ExecutionException, 'Plan is not available.'
19
- elsif params[:plan]['type'].to_s == 'parallel' or
20
- params[:plan][:type].to_s == 'parallel'
21
- return self.execute_parallel_plan(params)
22
- elsif params[:plan]['type'].to_s == 'sequential' or
23
- params[:plan][:type].to_s == 'sequential'
24
- return self.execute_sequential_plan(params)
25
- else
26
- raise ExecutionException, 'Unknown type of plan!'
27
- end
28
- false
29
- end
30
-
31
- # @param :plan the plan to be executed
32
- # @param :owner an object that implement the action
33
- # @param :retry number of retries (default: 2) when execution is failed
34
- #
35
- def execute_parallel_plan(params={})
36
- def assign_action_with_id(id)
37
- thread_id = next_thread_id
38
- action = @actions[id]
39
- action[:executor] = thread_id
40
- self.thread_execute_action(thread_id, action)
41
- end
42
-
43
- def next_thread_id
44
- id = 0
45
- @mutex.synchronize { @thread_id = id = @thread_id + 1 }
46
- id
47
- end
48
-
49
- def action_to_string(action)
50
- "#{action['id']}:#{action['name']}#{JSON.generate(action['parameters'])}"
51
- end
52
-
53
- def thread_execute_action(tid, action)
54
- t = Thread.new {
55
- @mutex.synchronize { @threads << tid }
56
-
57
- while not @failed and not action[:executed]
58
- # execute the action
59
- op_str = action_to_string(action)
60
- #Nuri::Util.puts "[ExecutorThread: #{tid}] #{op_str}"
61
- success = false
62
- num = @retry
63
- begin
64
- success = @owner.execute_action { action }
65
- num -= 1
66
- end while not success and num > 0
67
-
68
- # check if execution failed
69
- if success
70
- next_actions = []
71
- @mutex.synchronize {
72
- # set executed
73
- action[:executed] = true
74
- # select next action to be executed from all predecessor actions
75
- # if each action has not been assigned to any thread yet
76
- if action['successors'].length > 0
77
- action['successors'].each { |id|
78
- if @actions[id][:executor].nil?
79
- predecessors_ok = true
80
- @actions[id]['predecessors'].each { |pid|
81
- predecessors_ok = (predecessors_ok and @actions[pid][:executed])
82
- }
83
- next_actions << id if predecessors_ok
84
- end
85
- }
86
- end
87
- next_actions.each { |id| @actions[id][:executor] = tid }
88
- }
89
- if next_actions.length > 0
90
- # execute next actions
91
- action = @actions[next_actions[0]]
92
- if next_actions.length > 1
93
- for i in 1..(next_actions.length-1)
94
- assign_action_with_id(next_actions[i])
95
- end
96
- end
97
- end
98
-
99
- else
100
- Nuri::Util.error "Failed executing #{op_str}!"
101
- @mutex.synchronize {
102
- @failed = true # set global flag
103
- @actions_failed << action
104
- }
105
- end
106
- end
107
-
108
- @mutex.synchronize { @threads.delete(tid) }
109
- }
110
- end
111
-
112
- if params[:plan].nil? or not params[:plan].is_a?(Hash)
113
- raise ParallelExecutionException, 'Plan is not available.'
114
- elsif params[:plan]['type'].to_s == 'parallel' or
115
- params[:plan][:type].to_s == 'parallel'
116
- else
117
- raise ParallelExecutionException, 'Not a parallel plan.'
118
- end
119
-
120
- @owner = params[:owner]
121
- @retry = (params[:retry].nil? ? 2 : params[:retry].to_i)
122
-
123
- @actions = params[:plan]['workflow']
124
- @actions.sort! { |x,y| x['id'] <=> y['id'] }
125
- @actions.each { |op| op[:executed] = false; op[:executor] = nil; }
126
-
127
- @threads = []
128
- @actions_failed = []
129
- @mutex = Mutex.new
130
- @failed = false
131
- @thread_id = 0
132
-
133
- params[:plan]['init'].each { |op_id| assign_action_with_id(op_id) }
134
-
135
- begin
136
- sleep 1
137
- end while @threads.length > 0
138
-
139
- Nuri::Util.log "Using #{@thread_id} threads in execution."
140
-
141
- return (not @failed)
142
- end
143
-
144
- # @param :plan the plan to be executed
145
- # @param :owner an object that implement the action
146
- # @param :retry number of retries (default: 2) when execution is failed
147
- #
148
- def execute_sequential_plan(params={})
149
- if params[:plan].nil? or not params[:plan].is_a?(Hash)
150
- raise ParallelExecutionException, 'Plan is not available.'
151
- elsif params[:plan]['type'].to_s == 'sequential' or
152
- params[:plan][:type].to_s == 'sequential'
153
- else
154
- raise ParallelExecutionException, 'Not a parallel plan.'
155
- end
156
-
157
- @owner = params[:owner]
158
- @retry = (params[:retry].nil? ? 2 : params[:retry].to_i)
159
- params[:plan]['workflow'].each { |action|
160
- success = false
161
- num = @retry
162
- begin
163
- success, data = @owner.execute_action { action }
164
- puts data.to_s if params[:print_output]
165
- num -= 1
166
- end while not success and num > 0
167
- return false if not success
168
- }
169
- true
170
- end
171
- end
172
-
173
- class RubyExecutor
174
- def execute_plan(params={})
175
- exec = Object.new
176
- exec.extend(Sfp::Executor)
177
- params[:owner] = self
178
- exec.execute_plan(params)
179
- end
180
-
181
- def execute_action
182
- # TODO
183
- action = yield
184
- puts "Exec: #{action.inspect}"
185
- [true, nil]
186
- end
187
- end
188
-
189
- class BashExecutor < RubyExecutor
190
- def execute_action
191
- # TODO
192
- action = yield
193
- module_dir = (ENV.has_key?("SFP_HOME") ? ENV['SFP_HOME'] : ".")
194
- script_path = "#{action['name'].sub!(/^\$\./, '')}"
195
- script_path = "#{module_dir}/#{script_path.gsub!(/\./, '/')}"
196
- cmd = "/bin/bash #{script_path}"
197
- action['parameters'].each { |p| cmd += " '#{p}'" }
198
- begin
199
- data = `#{cmd}`
200
- rescue Exception => exp
201
- $stderr.puts "#{exp}\n#{exp.backtrace}"
202
- [false, nil]
203
- end
204
- [true, data]
205
- end
206
- end
207
- end