sfpagent 0.1.12 → 0.1.13

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
@@ -23,7 +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
+ $ apt-get install ruby1.9.1 ruby1.9.1-dev libz-dev libaugeas-ruby1.9.1
27
27
  $ gem install sfpagent
28
28
 
29
29
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.12
1
+ 0.1.13
data/bin/sfpagent CHANGED
@@ -14,14 +14,14 @@ Usage:
14
14
  where [options] are:
15
15
  EOS
16
16
 
17
- opt :start, "Start the agent. If --daemon option is set true, then the agent will start as a daemon."
18
- opt :stop, "Stop the daemon agent."
19
- opt :restart, "Restart the daemon agent."
20
- opt :status, "Print the status of the daemon agent."
17
+ opt :start, "Start the agent. If --daemon option is set true, then the agent will start as a daemon.", :short => '-s'
18
+ opt :stop, "Stop the daemon agent.", :short => '-t'
19
+ opt :restart, "Restart the daemon agent.", :short => '-r'
20
+ opt :status, "Print the status of the daemon agent.", :short => '-a'
21
21
  opt :port, "Port number of the daemon agent should listen to.", :short => '-p', :default => Sfp::Agent::DefaultPort
22
- opt :state, "Given a model, print the state of all modules. (Note: [model-file] should be specified.)"
23
- opt :execute, "Given a model, execute a plan in given file. (Note: [model-file] should be specified.)"
24
- opt :pretty, "Print the result in a pretty JSON format.", :short => '-r'
22
+ #opt :state, "Given a model, print the state of all modules. (Note: [model-file] should be specified.)"
23
+ #opt :execute, "Given a model, execute a plan in given file. (Note: [model-file] should be specified.)"
24
+ #opt :pretty, "Print the result in a pretty JSON format.", :short => '-r'
25
25
  #opt :daemon, "Start the agent as a daemon.", :default => true
26
26
  opt :ssl, "Set the agent to use HTTPS instead of HTTP.", :default => false
27
27
  opt :certfile, "Certificate file for HTTPS.", :default => ''
@@ -40,6 +40,9 @@ module Sfp
40
40
 
41
41
  @@runtime_lock = Mutex.new
42
42
 
43
+ @@agents_database = nil
44
+ @@agents_database_modified_time = nil
45
+
43
46
  def self.logger
44
47
  @@logger
45
48
  end
@@ -47,13 +50,16 @@ module Sfp
47
50
  # Start the agent.
48
51
  #
49
52
  # options:
50
- # :daemon => true if running as a daemon, false if as a normal application
51
- # :port
52
- # :ssl
53
- # :certfile
54
- # :keyfile
53
+ # :daemon => true if running as a daemon, false if as a console application
54
+ # :port => port of web server will listen to
55
+ # :ssl => set true to enable HTTPS
56
+ # :certfile => certificate file path for HTTPS
57
+ # :keyfile => key file path for HTTPS
55
58
  #
56
59
  def self.start(p={})
60
+ Sfp::Agent.logger.info "Starting SFP Agent daemons..."
61
+ puts "Starting SFP Agent daemons..."
62
+
57
63
  Process.daemon
58
64
 
59
65
  begin
@@ -66,10 +72,10 @@ module Sfp
66
72
  load_modules(p)
67
73
 
68
74
  # reload model
69
- build_model({:complete => true})
75
+ update_model({:rebuild => true})
70
76
 
71
77
  # create web server
72
- server_type = (p[:daemon] ? WEBrick::Daemon : WEBrick::SimpleServer)
78
+ server_type = WEBrick::SimpleServer
73
79
  port = (p[:port] ? p[:port] : DefaultPort)
74
80
  config = { :Host => '0.0.0.0',
75
81
  :Port => port,
@@ -89,35 +95,16 @@ module Sfp
89
95
  # trap signal
90
96
  ['INT', 'KILL', 'HUP'].each { |signal|
91
97
  trap(signal) {
92
- Sfp::Agent.logger.info "Shutting down web server"
93
- bsig_engine.disable
98
+ Sfp::Agent.logger.info "Shutting down web server and BSig engine..."
99
+ bsig_engine.stop
94
100
  server.shutdown
95
101
  }
96
102
  }
97
103
 
98
- # send request to local web server to save its PID
99
- fork {
100
- sleep 0.5
101
- 1.upto(5) do |i|
102
- begin
103
- NetHelper.get_data('127.0.0.1', config[:Port], '/pid')
104
- break if File.exist?(PIDFile)
105
- rescue
106
- sleep (i*i)
107
- end
108
- end
109
- puts "SFP Agent is running with PID #{File.read(PIDFile)}" if File.exist?(PIDFile)
110
- }
111
-
112
- # start BSig's main thread in a separate process
113
- fork {
114
- bsig_engine.enable({:mode => :main})
115
- }
104
+ File.open(PIDFile, 'w', 0644) { |f| f.write($$.to_s) }
116
105
 
117
- # enable BSig's satisfier
118
- bsig_engine.enable({:mode => :satisfier})
106
+ bsig_engine.start
119
107
 
120
- # start web server
121
108
  server.start
122
109
 
123
110
  rescue Exception => e
@@ -129,54 +116,36 @@ module Sfp
129
116
  # Stop the agent's daemon.
130
117
  #
131
118
  def self.stop
132
- # stopping web server (main thread)
133
- pid = (File.exist?(PIDFile) ? File.read(PIDFile).to_i : nil)
134
- if not pid.nil? and `ps h #{pid}`.strip =~ /.*sfpagent.*/
135
- Process.kill('HUP', pid)
136
- puts "Stopping SFP Agent with PID #{pid}"
137
- File.delete(PIDFile) if File.exist?(PIDFile)
138
- else
139
- puts "SFP Agent is not running."
140
- end
119
+ begin
120
+ pid = File.read(PIDFile).to_i
121
+ puts "Stopping SFP Agent with PID #{pid}..."
122
+ Process.kill 'HUP', pid
141
123
 
142
- # stopping BSig engine
143
- pid_bsig = (File.exist?(BSigPIDFile) ? File.read(BSigPIDFile).to_i : nil)
144
- if not pid_bsig.nil? and `ps h #{pid_bsig}`.strip =~ /.*sfpagent.*/
145
- Process.kill('HUP', pid_bsig)
146
- puts "Stopping BSig engine with PID #{pid_bsig}"
147
- File.delete(BSigPIDFile) if File.exist?(BSigPIDFile)
148
- else
149
- puts "BSig engine is not running."
124
+ sleep (Sfp::BSig::SleepTime + 0.25)
125
+
126
+ # forcely kill the process if it is still running
127
+ system("kill -9 #{pid} 1>/dev/null 2>/dev/null")
128
+
129
+ Sfp::Agent.logger.info "SFP Agent daemon has stopped."
130
+ puts "SFP Agent daemon has stopped."
131
+ rescue
132
+ puts "SFP Agent is not running."
150
133
  end
151
134
 
152
- Sfp::Agent.logger.info "SFP Agent daemon has been stopped."
135
+ ensure
136
+ File.delete(PIDFile) if File.exist?(PIDFile)
153
137
  end
154
138
 
155
139
  # Print the status of the agent.
156
140
  #
157
141
  def self.status
158
- if not File.exist?(PIDFile)
159
- puts "SFP Agent is not running."
160
- else
142
+ begin
161
143
  pid = File.read(PIDFile).to_i
162
- if `ps hf #{pid}`.strip =~ /.*sfpagent.*/
163
- puts "SFP Agent is running with PID #{pid}"
164
- else
165
- File.delete(PIDFile)
166
- puts "SFP Agent is not running."
167
- end
168
- end
169
-
170
- if not File.exist?(BSigPIDFile)
171
- puts "BSig engine is not running."
172
- else
173
- pid = File.read(BSigPIDFile).to_i
174
- if `ps hf #{pid}`.strip =~ /.*sfpagent.*/
175
- puts "BSig engine is running with PID #{pid}"
176
- else
177
- File.delete(BSigPIDFile)
178
- puts "BSig engine is not running."
179
- end
144
+ Process.kill 0, pid
145
+ puts "SFP Agent is running with PID #{pid}"
146
+ rescue
147
+ puts "SFP Agent is not running."
148
+ File.delete(PIDFile) if File.exist?(PIDFile)
180
149
  end
181
150
  end
182
151
 
@@ -198,10 +167,8 @@ module Sfp
198
167
  f.flush
199
168
  f.truncate(f.pos)
200
169
  }
201
- build_model
170
+ update_model
202
171
  Sfp::Agent.logger.info "Setting the model [OK]"
203
- else
204
- #Sfp::Agent.logger.info "The model is not changed."
205
172
  end
206
173
  return true
207
174
  rescue Exception => e
@@ -212,7 +179,7 @@ module Sfp
212
179
 
213
180
  # Reload the model from cached file.
214
181
  #
215
- def self.build_model(p={})
182
+ def self.update_model(p={})
216
183
  if not File.exist?(ModelFile)
217
184
  Sfp::Agent.logger.info "There is no model in cache."
218
185
  else
@@ -220,7 +187,7 @@ module Sfp
220
187
  @@runtime_lock.synchronize {
221
188
  data = File.read(ModelFile)
222
189
  @@current_model_hash = Digest::MD5.hexdigest(data)
223
- if !defined?(@@runtime) or @@runtime.nil? or p[:complete]
190
+ if !defined?(@@runtime) or @@runtime.nil? or p[:rebuild]
224
191
  @@runtime = Sfp::Runtime.new(JSON[data])
225
192
  else
226
193
  @@runtime.set_model(JSON[data])
@@ -363,7 +330,7 @@ module Sfp
363
330
  module_file = "#{dir}/#{name}/#{name}.rb"
364
331
  next if not File.exist?(module_file)
365
332
  begin
366
- load module_file #require module_file
333
+ load module_file # use 'load' than 'require'
367
334
  Sfp::Agent.logger.info "Loading module #{dir}/#{name} [OK]"
368
335
  counter += 1
369
336
  @@modules << name
@@ -458,7 +425,7 @@ module Sfp
458
425
  load_modules(@@config)
459
426
 
460
427
  # rebuild the model
461
- build_model({:complete => true})
428
+ update_model({:rebuild => true})
462
429
 
463
430
  Sfp::Agent.logger.info "Installing module #{name} [OK]"
464
431
 
@@ -493,15 +460,13 @@ module Sfp
493
460
  true
494
461
  end
495
462
 
496
- @@agents_data = nil
497
- @@agents_data_modified_time = nil
498
463
  def self.get_agents
499
464
  return {} if not File.exist?(AgentsDataFile)
500
- return @@agents_data if File.mtime(AgentsDataFile) == @@agents_data_modified_time
501
- @@agents_data = JSON[File.read(AgentsDataFile)]
465
+ return @@agents_database if File.mtime(AgentsDataFile) == @@agents_database_modified_time
466
+ @@agents_database = JSON[File.read(AgentsDataFile)]
502
467
  end
503
468
 
504
- # A class that handles each request.
469
+ # A class that handles HTTP request.
505
470
  #
506
471
  class Handler < WEBrick::HTTPServlet::AbstractServlet
507
472
  def initialize(server, logger)
@@ -511,11 +476,13 @@ module Sfp
511
476
  # Process HTTP Get request
512
477
  #
513
478
  # uri:
514
- # /pid => save daemon's PID to a file
515
- # /state => return the current state
516
- # /model => return the current model
479
+ # /pid => save daemon's PID to a file (only requested from localhost)
480
+ # /state => return the current state
481
+ # /model => return the current model
517
482
  # /schemata => return the schemata of a module
518
- # /modules => return a list of available modules
483
+ # /modules => return a list of available modules
484
+ # /agents => return a list of agents database
485
+ # /log => return last 100 lines of log file
519
486
  #
520
487
  def do_GET(request, response)
521
488
  status = 400
@@ -587,12 +554,17 @@ module Sfp
587
554
  response.body = body
588
555
  end
589
556
 
557
+ # Handle HTTP Put request
558
+ #
590
559
  # uri:
591
- # /model => receive a new model and save to cached file
592
- # /modules => save the module if parameter "module" is provided
593
- # delete the module if parameter "module" is not provided
594
- # /agents => save the agents' list if parameter "agents" is provided
595
- # delete all agents if parameter "agents" is not provided
560
+ # /model => receive a new model and save to cached file
561
+ # /modules => save the module if parameter "module" is provided
562
+ # delete the module if parameter "module" is not provided
563
+ # /agents => save the agents' list if parameter "agents" is provided
564
+ # delete all agents if parameter "agents" is not provided
565
+ # /bsig => receive BSig model and receive it in cached directory
566
+ # /bsig/satisfier => receive goal request from other agents and then start
567
+ # a satisfier thread to try to achieve it
596
568
  def do_PUT(request, response)
597
569
  status = 400
598
570
  content_type, body = ''
data/lib/sfpagent/bsig.rb CHANGED
@@ -3,69 +3,55 @@ require 'thread'
3
3
  class Sfp::BSig
4
4
  include Nuri::Net::Helper
5
5
 
6
- BSigSleepTime = 5
6
+ SleepTime = 5
7
7
  MaxTries = 5
8
8
 
9
9
  SatisfierPath = '/bsig/satisfier'
10
10
  CachedDir = (Process.euid == 0 ? '/var/sfpagent' : File.expand_path('~/.sfpagent'))
11
11
  SatisfierLockFile = "#{CachedDir}/bsig.satisfier.lock.#{Time.now.nsec}"
12
12
 
13
- attr_reader :enabled, :mode
13
+ attr_reader :enabled, :status, :mode
14
14
 
15
15
  def initialize(p={})
16
16
  @lock = Mutex.new
17
17
  @enabled = false
18
+ @status = :stopped
18
19
  end
19
20
 
20
- def disable
21
+ def stop
21
22
  @enabled = false
22
23
  end
23
24
 
24
- def enable(p={})
25
+ def start
26
+ @enabled = true
25
27
  @lock.synchronize {
26
- return if @enabled
27
- @enabled = true
28
+ return if @status == :running
29
+ @status = :running
28
30
  }
29
31
 
30
- @mode = p[:mode]
31
- if p[:mode] == :main
32
- enable_main_thread
33
- elsif p[:mode] == :satisfier
34
- enable_satisfier_thread
35
- end
36
- end
37
-
38
- def enable_satisfier_thread
39
- Sfp::Agent.logger.info "[#{@mode}] BSig engine is enabled."
40
- end
32
+ Thread.new {
33
+ register_satisfier_thread(:reset)
34
+
35
+ system("rm -f #{CachedDir}/operator.*.lock")
36
+
37
+ Sfp::Agent.logger.info "[main] BSig engine is running."
38
+
39
+ puts "BSig Engine is running with PID #{$$}"
40
+ File.open(Sfp::Agent::BSigPIDFile, 'w') { |f| f.write($$.to_s) }
41
+
42
+ self.execute_model
43
+
44
+ File.delete(SatisfierLockFile) if File.exist?(SatisfierLockFile)
45
+ Sfp::Agent.logger.info "[main] BSig engine has stopped."
41
46
 
42
- def enable_main_thread
43
- ['INT', 'KILL', 'HUP'].each { |signal|
44
- trap(signal) {
45
- Sfp::Agent.logger.info "[#{@mode}] Shutting down BSig engine"
46
- disable
47
- }
47
+ @status = :stopped
48
48
  }
49
-
50
- register_satisfier_thread(:reset)
51
-
52
- system("rm -f #{CachedDir}/operator.*.lock")
53
-
54
- Sfp::Agent.logger.info "[#{@mode}] BSig engine is running."
55
-
56
- puts "BSig Engine is running with PID #{$$}"
57
- File.open(Sfp::Agent::BSigPIDFile, 'w') { |f| f.write($$.to_s) }
58
-
59
- self.execute_model
60
-
61
- File.delete(SatisfierLockFile) if File.exist?(SatisfierLockFile)
62
- Sfp::Agent.logger.info "[#{@mode}] BSig engine has stopped."
63
49
  end
64
50
 
65
51
  def execute_model
66
- Sfp::Agent.logger.info "[#{@mode}] Executing BSig model"
52
+ Sfp::Agent.logger.info "[main] Executing BSig model"
67
53
 
68
- previous_status = nil
54
+ previous_exec_status = exec_status = nil
69
55
  while @enabled
70
56
  begin
71
57
 
@@ -73,25 +59,25 @@ class Sfp::BSig
73
59
 
74
60
  bsig = Sfp::Agent.get_bsig
75
61
  if bsig.nil?
76
- status = :no_bsig
77
- sleep BSigSleepTime
62
+ exec_status = :no_bsig
63
+ sleep SleepTime
78
64
  else
79
- status = achieve_local_goal(bsig['id'], bsig['goal'], bsig['operators'], 1)
80
- if status == :failure
81
- Sfp::Agent.logger.error "[#{@mode}] Executing BSig model [Failed]"
82
- sleep BSigSleepTime
83
- elsif status == :no_flaw
84
- sleep BSigSleepTime
65
+ exec_status = achieve_local_goal(bsig['id'], bsig['goal'], bsig['operators'], 1, :main)
66
+ if exec_status == :failure
67
+ Sfp::Agent.logger.error "[main] Executing BSig model [Failed]"
68
+ sleep SleepTime
69
+ elsif exec_status == :no_flaw
70
+ sleep SleepTime
85
71
  end
86
72
  end
87
73
 
88
- if previous_status != status
89
- Sfp::Agent.logger.info "[#{@mode}] BSig engine - status: " + status.to_s
90
- previous_status = status
74
+ if previous_exec_status != exec_status
75
+ Sfp::Agent.logger.info "[main] BSig engine - status: " + exec_status.to_s
76
+ previous_exec_status = exec_status
91
77
  end
92
78
  rescue Exception => e
93
- Sfp::Agent.logger.error "[#{@mode}] Error on executing BSig model\n#{e}\n#{e.backtrace.join("\n")}"
94
- sleep BSigSleepTime
79
+ Sfp::Agent.logger.error "[main] Error on executing BSig model\n#{e}\n#{e.backtrace.join("\n")}"
80
+ sleep SleepTime
95
81
  end
96
82
  end
97
83
  end
@@ -106,11 +92,12 @@ class Sfp::BSig
106
92
  end
107
93
 
108
94
  # returns
109
- # :no_flaw : there is no goal-flaw
110
- # :failure : there is a failure on achieving the goal
111
- # :ongoing : the selected operator is being executed
112
- # :repaired : some goal-flaws have been repaired, but the goal may have other flaws
113
- def achieve_local_goal(id, goal, operators, pi)
95
+ # :no_flaw => there is no goal-flaw
96
+ # :failure => there is a failure on achieving the goal
97
+ # :ongoing => the selected operator is being executed
98
+ # :repaired => some goal-flaws have been repaired, but the goal may have other flaws
99
+ #
100
+ def achieve_local_goal(id, goal, operators, pi, mode)
114
101
  operator = nil
115
102
 
116
103
  current = get_current_state
@@ -120,25 +107,25 @@ class Sfp::BSig
120
107
  operator = select_operator(flaws, operators, pi)
121
108
  return :failure if operator.nil?
122
109
 
123
- #Sfp::Agent.logger.info "[#{@mode}] Flaws: #{JSON.generate(flaws)}"
110
+ #Sfp::Agent.logger.info "[#{mode}] Flaws: #{JSON.generate(flaws)}" # debugging
124
111
 
125
112
  return :ongoing if not lock_operator(operator)
126
113
 
127
- Sfp::Agent.logger.info "[#{@mode}] Selected operator: #{operator['name']}"
114
+ Sfp::Agent.logger.info "[#{mode}] Selected operator: #{operator['name']}"
128
115
 
129
116
  next_pi = operator['pi'] + 1
130
117
  pre_local, pre_remote = split_preconditions(operator)
131
118
 
132
- #Sfp::Agent.logger.info "[#{@mode}] local-flaws: #{JSON.generate(pre_local)}, remote-flaws: #{JSON.generate(pre_remote)}"
119
+ #Sfp::Agent.logger.info "[#{mode}] local-flaws: #{JSON.generate(pre_local)}, remote-flaws: #{JSON.generate(pre_remote)}" # debugging
133
120
 
134
121
  status = nil
135
122
  tries = MaxTries
136
123
  begin
137
- status = achieve_local_goal(id, pre_local, operators, next_pi)
124
+ status = achieve_local_goal(id, pre_local, operators, next_pi, mode)
138
125
  if status == :no_flaw or status == :failure or not @enabled
139
126
  break
140
127
  elsif status == :ongoing
141
- sleep BSigSleepTime
128
+ sleep SleepTime
142
129
  tries += 1
143
130
  elsif status == :repaired
144
131
  tries = MaxTries
@@ -147,8 +134,8 @@ class Sfp::BSig
147
134
  end until tries <= 0
148
135
 
149
136
  if status != :no_flaw or
150
- not achieve_remote_goal(id, pre_remote, next_pi) or
151
- not invoke(operator)
137
+ not achieve_remote_goal(id, pre_remote, next_pi, mode) or
138
+ not invoke(operator, mode)
152
139
 
153
140
  unlock_operator(operator) if not operator.nil?
154
141
  return :failure
@@ -158,13 +145,13 @@ class Sfp::BSig
158
145
  :repaired
159
146
  end
160
147
 
161
- def achieve_remote_goal(id, goal, pi)
148
+ def achieve_remote_goal(id, goal, pi, mode)
162
149
  if goal.length > 0
163
150
  agents = Sfp::Agent.get_agents
164
151
  split_goal_by_agent(goal).each do |agent_name,agent_goal|
165
152
  return false if not agents.has_key?(agent_name) or agents[agent_name]['sfpAddress'].to_s == ''
166
153
 
167
- return false if not send_goal_to_agent(agents[agent_name], id, agent_goal, pi, agent_name)
154
+ return false if not send_goal_to_agent(agents[agent_name], id, agent_goal, pi, agent_name, mode)
168
155
  end
169
156
  end
170
157
  true
@@ -182,11 +169,11 @@ class Sfp::BSig
182
169
  status = nil
183
170
  tries = MaxTries
184
171
  begin
185
- status = achieve_local_goal(bsig['id'], goal, bsig['operators'], pi)
172
+ status = achieve_local_goal(bsig['id'], goal, bsig['operators'], pi, :satisfier)
186
173
  if status == :no_flaw or status == :failure or not @enabled
187
174
  break
188
175
  elsif status == :ongoing
189
- sleep BSigSleepTime
176
+ sleep SleepTime
190
177
  tries += 1
191
178
  elsif status == :repaired
192
179
  tries = MaxTries
@@ -251,15 +238,16 @@ class Sfp::BSig
251
238
  agent_goal
252
239
  end
253
240
 
254
- def send_goal_to_agent(agent, id, g, pi, agent_name='')
241
+ def send_goal_to_agent(agent, id, g, pi, agent_name='', mode)
255
242
  data = {'id' => id,
256
243
  'goal' => JSON.generate(g),
257
244
  'pi' => pi}
258
- Sfp::Agent.logger.info "[#{@mode}] Request goal to: #{agent_name} [WAIT]"
245
+
246
+ Sfp::Agent.logger.info "[#{mode}] Request goal to: #{agent_name} [WAIT]"
259
247
 
260
248
  code, _ = put_data(agent['sfpAddress'], agent['sfpPort'], SatisfierPath, data)
261
249
 
262
- Sfp::Agent.logger.info "[#{@mode}] Request goal to: #{agent_name} - status: " + code.to_s
250
+ Sfp::Agent.logger.info "[#{mode}] Request goal to: #{agent_name} - status: #{code}"
263
251
 
264
252
  (code == '200')
265
253
  end
@@ -322,8 +310,8 @@ Sfp::Agent.logger.info "[#{@mode}] Request goal to: #{agent_name} - status: " +
322
310
  [local, remote]
323
311
  end
324
312
 
325
- def invoke(operator)
326
- Sfp::Agent.logger.info "[#{@mode}] Invoking #{operator['name']}"
313
+ def invoke(operator, mode)
314
+ Sfp::Agent.logger.info "[#{mode}] Invoking #{operator['name']}"
327
315
  Sfp::Agent.execute_action(operator)
328
316
  end
329
317
  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.12
4
+ version: 0.1.13
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -13,7 +13,7 @@ date: 2013-08-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sfp
16
- requirement: &10824140 !ruby/object:Gem::Requirement
16
+ requirement: &6605340 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,7 +21,7 @@ dependencies:
21
21
  version: 0.3.12
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *10824140
24
+ version_requirements: *6605340
25
25
  description: A Ruby implementation of SFP agent.
26
26
  email: herry13@gmail.com
27
27
  executables: