cirrocumulus 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,67 @@
1
+ module Cirrocumulus
2
+ # Message. Used by agents to communicate
3
+ class Message
4
+ attr_accessor :sender, :act, :content
5
+ attr_accessor :receiver, :reply_with, :in_reply_to, :conversation_id
6
+ attr_accessor :ontology
7
+
8
+ def initialize(sender, act, content)
9
+ @sender = sender
10
+ @act = act
11
+ @content = content
12
+ end
13
+
14
+ def failed?
15
+ act == 'failure' || act == 'refuse'
16
+ end
17
+
18
+ def context
19
+ Context.new(@sender, @reply_with)
20
+ end
21
+
22
+ def self.parse_params(content, subroutine = false)
23
+ return parse_params(content.size == 1 ? content[0] : content, true) if !subroutine
24
+
25
+ return [] if content.nil?
26
+ return content if !content.is_a?(Array)
27
+ return [] if content.size == 0
28
+ return {content[0] => []} if content.size == 1
29
+ return {content[0] => parse_params(content[1], true)} if content.size == 2
30
+
31
+ res = {content[0] => []}
32
+
33
+ if content.all? {|item| !item.is_a?(Array)}
34
+ content.each_with_index do |item,i|
35
+ if i == 0
36
+ res[content[0]] = []
37
+ else
38
+ res[content[0]] << item
39
+ end
40
+ end
41
+ else
42
+ content.each_with_index do |item,i|
43
+ if i == 0
44
+ res[content[0]] = {}
45
+ else
46
+ res[content[0]].merge!(parse_params(item, true))
47
+ end
48
+ end
49
+ end
50
+
51
+ res
52
+ end
53
+ end
54
+
55
+ # Message context. Includes sender, reply-with and conversation-id
56
+ class Context
57
+ attr_reader :sender
58
+ attr_reader :reply_with
59
+ attr_reader :conversation_id
60
+
61
+ def initialize(sender, reply_with, conversation_id = nil)
62
+ @sender = sender
63
+ @reply_with = reply_with
64
+ @conversation_id = conversation_id
65
+ end
66
+ end
67
+ end
@@ -17,11 +17,13 @@ module Ontology
17
17
  end
18
18
 
19
19
  def tick()
20
+ time = Time.now.to_i
21
+
20
22
  @sagas.each do |saga|
21
23
  next if saga.is_finished?
24
+
22
25
  begin
23
- saga.timeout -= 1 if saga.timeout > 0
24
- saga.handle(nil) if saga.timeout == 0
26
+ saga.handle(nil) if saga.timed_out?(time)
25
27
  rescue Exception => e
26
28
  Log4r::Logger['agent'].warn "Got exception while ticking saga: %s\n%s" % [e.to_s, e.backtrace.to_s]
27
29
  end
@@ -35,7 +37,7 @@ module Ontology
35
37
  @sagas.each do |saga|
36
38
  next if saga.is_finished?
37
39
 
38
- if saga.id == message.in_reply_to
40
+ if [message.in_reply_to, message.conversation_id].include?(saga.id)
39
41
  was_processed = true
40
42
  saga.handle(message)
41
43
  end
@@ -1,6 +1,8 @@
1
1
  require 'thread'
2
2
 
3
3
  module RuleEngine
4
+ # Rule representation.
5
+ # After processing a ruleset, all rules are wrapped with this object.
4
6
  class RuleDescription
5
7
  attr_reader :name
6
8
  attr_reader :conditions
@@ -13,10 +15,12 @@ module RuleEngine
13
15
  @options = options
14
16
  @code = code
15
17
  end
16
-
17
18
  end
18
19
 
20
+ # Core class for Cirrocumulus Rule Engine.
21
+ # All the magic about asserting/retracting facts and pattern-matching is performed here.
19
22
  class Base
23
+ # DSL-method for defining rules.
20
24
  def self.rule(name, facts, options = {}, &block)
21
25
  current_ruleset << RuleDescription.new(name, facts, options, block)
22
26
  end
@@ -47,22 +51,32 @@ module RuleEngine
47
51
  log "Empty ruleset" if self.class.current_ruleset.empty?
48
52
  end
49
53
 
54
+ # Asserts new fact. If 'silent' is set to true, does not perform any associated rules
55
+ #
56
+ # * *Returns* :
57
+ # - nothing
50
58
  def assert(fact, silent = false)
51
59
  @mutex.synchronize do
52
60
  assert_nonblocking(fact, silent)
53
61
  end
54
62
  end
55
63
 
64
+ # Retracts an existing fact. If 'silent' is set to true, does not perform any associated rules
65
+ #
66
+ # * *Returns* :
67
+ # - nothing
56
68
  def retract(fact, silent = false)
57
69
  @mutex.synchronize do
58
70
  retract_nonblocking(fact, silent)
59
71
  end
60
72
  end
61
73
 
74
+ # Replaces fact value
75
+ #
76
+ # * *Returns* :
77
+ # - nothing
62
78
  def replace(pattern, values)
63
79
  @mutex.synchronize do
64
- log "replace #{pattern.inspect} for #{values.inspect}"
65
-
66
80
  data = match(pattern)
67
81
  data.each do |match_data|
68
82
  old_fact = pattern.clone
@@ -74,8 +88,18 @@ module RuleEngine
74
88
  end
75
89
  end
76
90
 
77
- retract_nonblocking(old_fact, true)
78
- assert_nonblocking(new_fact)
91
+ facts_are_same = true
92
+ old_fact.each_with_index do |item, idx|
93
+ new_item = new_fact[idx]
94
+ facts_are_same = false if new_item != item
95
+ end
96
+
97
+ unless facts_are_same
98
+ log "replace #{pattern.inspect} for #{values.inspect}"
99
+
100
+ retract_nonblocking(old_fact, true)
101
+ assert_nonblocking(new_fact)
102
+ end
79
103
  end
80
104
  end
81
105
  end
@@ -94,6 +118,7 @@ module RuleEngine
94
118
  res
95
119
  end
96
120
 
121
+ # Starts this rule engine instance.
97
122
  def start()
98
123
  @worker_thread = Thread.new do
99
124
  while true do
@@ -103,6 +128,7 @@ module RuleEngine
103
128
  end
104
129
  end
105
130
 
131
+ # Executes all associated with current KB rules. Normally, this shouldn't be called by the programmer.
106
132
  def execute()
107
133
  process()
108
134
  end
@@ -2,7 +2,6 @@ class Saga
2
2
  attr_reader :id
3
3
  attr_reader :context
4
4
  attr_reader :finished
5
- attr_accessor :timeout
6
5
 
7
6
  DEFAULT_TIMEOUT = 15
8
7
  LONG_TIMEOUT = 60
@@ -15,7 +14,7 @@ class Saga
15
14
  @id = id
16
15
  @ontology = ontology
17
16
  @finished = false
18
- @timeout = -1
17
+ @timeout_at = -1
19
18
  @state = STATE_START
20
19
  end
21
20
 
@@ -23,15 +22,19 @@ class Saga
23
22
  @finished || @state == STATE_ERROR
24
23
  end
25
24
 
25
+ def timed_out?(time)
26
+ @timeout_at > 0 && @timeout_at <= time
27
+ end
28
+
26
29
  protected
27
30
 
28
31
  def clear_timeout()
29
- @timeout = -1
32
+ @timeout_at = -1
30
33
  end
31
34
 
32
35
  def set_timeout(secs)
33
36
  Log4r::Logger['agent'].debug "[#{id}] waiting for #{secs} second(s)" if secs > 1
34
- @timeout = secs*2
37
+ @timeout_at = Time.now.to_i + secs
35
38
  end
36
39
 
37
40
  def change_state(new_state)
@@ -0,0 +1,68 @@
1
+ require 'bundler/setup'
2
+ require_relative 'cirrocumulus'
3
+ require_relative 'cirrocumulus/engine'
4
+
5
+ puts Cirrocumulus::PLATFORM
6
+ exit 0
7
+ #require_relative 'cirrocumulus/rule_engine.rb'
8
+
9
+ class Test < RuleEngine::Base
10
+ rule 'convert', [[:temperature, :X, 'F']] do |engine, params|
11
+ puts "qqq"
12
+ x = params[:X].to_i
13
+ engine.retract([:temperature, x, 'F'])
14
+ y = 5*(x - 32)/9
15
+ engine.assert([:temperature, y, 'C'])
16
+ end
17
+
18
+ rule 'guest_powered_off', [[:guest, :X, :powered_off]], :for => 10.seconds do |engine, params|
19
+ puts "guest_powered_off"
20
+ end
21
+
22
+ rule 'monitor_md', [[:virtual_disk, :X, :active], [:mdraid, :X, :failed]] do |engine, params|
23
+ # md devices is failed, but virtual disk should be up
24
+ p params
25
+ puts "virtual disk #{params[:X]} should be up, but corresponding md devices is failed!"
26
+ end
27
+ end
28
+
29
+ #RuleEngine::Server.run()
30
+
31
+ e = Test.new
32
+ e.assert [:guest, "233bed174ab0802fd908f981d64d185b", :powered_off]
33
+ e.assert [:guest, "233bed174ab0802fd908f981d64d185b", :running]
34
+ e.assert [:guest, "233bed174ab0802fd908f981d64d185b", :state, :powered_on]
35
+ e.replace [:guest, "233bed174ab0802fd908f981d64d185b", :state, :STATE], :powered_off
36
+
37
+ p e.match [:guest, "233bed174ab0802fd908f981d64d185b", :running]
38
+ #while true do
39
+ e.tick()
40
+ # sleep 1
41
+ #end
42
+
43
+ gets
44
+ e.dump_kb()
45
+ exit(0)
46
+
47
+ e.assert [:virtual_disk, 163, :active]
48
+ #e.assert [:virtual_disk, 139, :active]
49
+ #e.assert [:virtual_disk, 145, :active]
50
+ #e.assert [:virtual_disk, 146, :active]
51
+ #e.assert [:virtual_disk, 149, :active]
52
+ e.assert [:virtual_disk, 153, :active]
53
+ #e.assert [:virtual_disk, 154, :active]
54
+ #e.assert [:virtual_disk, 156, :active]
55
+ e.assert [:virtual_disk, 158, :active]
56
+ #e.assert [:virtual_disk, 137, :active]
57
+ #e.assert [:virtual_disk, 135, :active]
58
+ #e.assert [:virtual_disk, 159, :active]
59
+ #e.assert [:virtual_disk, 103, :active]
60
+ #e.assert [:virtual_disk, 102, :active]
61
+ #e.assert [:virtual_disk, 20, :active]
62
+ #e.assert [:virtual_disk, 2, :active]
63
+ #e.assert [:virtual_disk, 777, :active]
64
+ #e.assert [:virtual_disk, 90, :active]
65
+ e.assert [:mdraid, 153, :failed], true
66
+ e.assert [:mdraid, 158, :failed], true
67
+ e.execute()
68
+ gets
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ require 'sexpistol'
3
+
4
+ def map_sub(arr)
5
+ return [] if arr.nil?
6
+ return arr if !arr.is_a?(Array)
7
+ return [] if arr.size == 0
8
+ return {arr[0] => []} if arr.size == 1
9
+ return {arr[0] => map_sub(arr[1])} if arr.size == 2
10
+
11
+ res = {arr[0] => []}
12
+
13
+ arr.each_with_index do |item,i|
14
+ next if i == 0
15
+ res[arr[0]] << map_sub(item)
16
+ end
17
+
18
+ res
19
+ end
20
+
21
+ def map(arr)
22
+ return map_sub(arr[0]) if arr.size == 1
23
+ return map_sub(arr)
24
+ end
25
+
26
+ s = Sexpistol.new
27
+ e = s.parse_string "(create (vds (ram 256) (eth \"1\" \"2\")))"
28
+
29
+ p e
30
+ p map(e)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cirrocumulus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.6.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: 2011-12-01 00:00:00.000000000 Z
12
+ date: 2012-04-10 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
16
- requirement: &77891350 !ruby/object:Gem::Requirement
16
+ requirement: &72357370 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ~>
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: 2.3.11
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *77891350
24
+ version_requirements: *72357370
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: log4r
27
- requirement: &77890270 !ruby/object:Gem::Requirement
27
+ requirement: &72356070 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ~>
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: 1.1.9
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *77890270
35
+ version_requirements: *72356070
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: systemu
38
- requirement: &77888870 !ruby/object:Gem::Requirement
38
+ requirement: &71921240 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ! '>='
@@ -43,10 +43,10 @@ dependencies:
43
43
  version: '0'
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *77888870
46
+ version_requirements: *71921240
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: xmpp4r
49
- requirement: &77888390 !ruby/object:Gem::Requirement
49
+ requirement: &71920240 !ruby/object:Gem::Requirement
50
50
  none: false
51
51
  requirements:
52
52
  - - ~>
@@ -54,10 +54,10 @@ dependencies:
54
54
  version: '0.5'
55
55
  type: :runtime
56
56
  prerelease: false
57
- version_requirements: *77888390
57
+ version_requirements: *71920240
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: xmpp4r-simple
60
- requirement: &77887740 !ruby/object:Gem::Requirement
60
+ requirement: &71919220 !ruby/object:Gem::Requirement
61
61
  none: false
62
62
  requirements:
63
63
  - - ! '>='
@@ -65,10 +65,10 @@ dependencies:
65
65
  version: '0'
66
66
  type: :runtime
67
67
  prerelease: false
68
- version_requirements: *77887740
68
+ version_requirements: *71919220
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: eventmachine
71
- requirement: &77886600 !ruby/object:Gem::Requirement
71
+ requirement: &71916250 !ruby/object:Gem::Requirement
72
72
  none: false
73
73
  requirements:
74
74
  - - ! '>='
@@ -76,10 +76,10 @@ dependencies:
76
76
  version: '0'
77
77
  type: :runtime
78
78
  prerelease: false
79
- version_requirements: *77886600
79
+ version_requirements: *71916250
80
80
  - !ruby/object:Gem::Dependency
81
81
  name: deil_sexpistol
82
- requirement: &77885090 !ruby/object:Gem::Requirement
82
+ requirement: &71914020 !ruby/object:Gem::Requirement
83
83
  none: false
84
84
  requirements:
85
85
  - - ! '>='
@@ -87,40 +87,51 @@ dependencies:
87
87
  version: '0'
88
88
  type: :runtime
89
89
  prerelease: false
90
- version_requirements: *77885090
90
+ version_requirements: *71914020
91
91
  - !ruby/object:Gem::Dependency
92
- name: bundler
93
- requirement: &78301580 !ruby/object:Gem::Requirement
92
+ name: guid
93
+ requirement: &71931850 !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ type: :runtime
100
+ prerelease: false
101
+ version_requirements: *71931850
102
+ - !ruby/object:Gem::Dependency
103
+ name: rdoc
104
+ requirement: &71930640 !ruby/object:Gem::Requirement
94
105
  none: false
95
106
  requirements:
96
107
  - - ~>
97
108
  - !ruby/object:Gem::Version
98
- version: 1.0.0
109
+ version: '3.12'
99
110
  type: :development
100
111
  prerelease: false
101
- version_requirements: *78301580
112
+ version_requirements: *71930640
102
113
  - !ruby/object:Gem::Dependency
103
- name: jeweler
104
- requirement: &78300700 !ruby/object:Gem::Requirement
114
+ name: bundler
115
+ requirement: &71928880 !ruby/object:Gem::Requirement
105
116
  none: false
106
117
  requirements:
107
118
  - - ~>
108
119
  - !ruby/object:Gem::Version
109
- version: 1.6.4
120
+ version: 1.0.0
110
121
  type: :development
111
122
  prerelease: false
112
- version_requirements: *78300700
123
+ version_requirements: *71928880
113
124
  - !ruby/object:Gem::Dependency
114
- name: rcov
115
- requirement: &78299830 !ruby/object:Gem::Requirement
125
+ name: jeweler
126
+ requirement: &71927190 !ruby/object:Gem::Requirement
116
127
  none: false
117
128
  requirements:
118
- - - ! '>='
129
+ - - ~>
119
130
  - !ruby/object:Gem::Version
120
- version: '0'
131
+ version: 1.8.3
121
132
  type: :development
122
133
  prerelease: false
123
- version_requirements: *78299830
134
+ version_requirements: *71927190
124
135
  description: Engine for building your own agents, providing you base functionality
125
136
  for loading ontologies, communicating with other agents and parsing FIPA-ACL messages
126
137
  email: deil@mneko.net
@@ -131,24 +142,37 @@ extra_rdoc_files:
131
142
  - README.rdoc
132
143
  files:
133
144
  - .document
145
+ - .idea/.name
146
+ - .idea/.rakeTasks
147
+ - .idea/cirrocumulus.iml
148
+ - .idea/encodings.xml
149
+ - .idea/misc.xml
150
+ - .idea/modules.xml
151
+ - .idea/scopes/scope_settings.xml
152
+ - .idea/vcs.xml
153
+ - .idea/workspace.xml
134
154
  - Gemfile
155
+ - Gemfile.lock
135
156
  - LICENSE.txt
136
157
  - README.rdoc
137
158
  - Rakefile
138
159
  - VERSION
139
160
  - cirrocumulus.gemspec
161
+ - lib/.gitignore
140
162
  - lib/cirrocumulus.rb
141
163
  - lib/cirrocumulus/agent.rb
142
164
  - lib/cirrocumulus/agent_wrapper.rb
143
- - lib/cirrocumulus/engine.rb
144
- - lib/cirrocumulus/kb.rb
165
+ - lib/cirrocumulus/jabber_bus.rb
145
166
  - lib/cirrocumulus/logger.rb
167
+ - lib/cirrocumulus/message.rb
146
168
  - lib/cirrocumulus/ontology.rb
147
169
  - lib/cirrocumulus/rule_engine.rb
148
170
  - lib/cirrocumulus/rule_server.rb
149
171
  - lib/cirrocumulus/rules/engine.rb
150
172
  - lib/cirrocumulus/rules/run_queue.rb
151
173
  - lib/cirrocumulus/saga.rb
174
+ - lib/test.rb
175
+ - lib/test2.rb
152
176
  - test/helper.rb
153
177
  - test/test_cirrocumulus.rb
154
178
  homepage: http://github.com/deil/cirrocumulus
@@ -163,10 +187,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
163
187
  requirements:
164
188
  - - ! '>='
165
189
  - !ruby/object:Gem::Version
166
- version: '0'
167
- segments:
168
- - 0
169
- hash: 821784403
190
+ version: 1.9.2
170
191
  required_rubygems_version: !ruby/object:Gem::Requirement
171
192
  none: false
172
193
  requirements: