cirrocumulus 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc ADDED
@@ -0,0 +1,24 @@
1
+ = Cirrocumulus
2
+
3
+ Cirrocumulus is an agent-based (cloud) infrastructure management system. Each agent, running on a host, is responsible for its own problem and cooperates with the rest via XMPP as a transport and FIPA-ACL messages as a protocol.
4
+
5
+ == Technical
6
+ === Message structure
7
+
8
+ Each message is serialized in XML.
9
+ It contains routing information, action type and content. Content always is an s-expression.
10
+
11
+ Message structure looks like:
12
+ <fipa-message
13
+ receiver="optional receiving agent identifier"
14
+ ontology="domain, e.g. cirrocumulus-vps, cirrocumulus-xen"
15
+ act="request|query-ref|query-if|inform|failure">
16
+ <content>
17
+ (s-expression)
18
+ </content>
19
+ </fipa-message>
20
+
21
+ === Action types
22
+ * request - asks receiver to perform some action, described in content
23
+ * query-ref - query receiver for some information
24
+ * query-if - asks receiver, if given proposition in content is true or false
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ #
2
+ # To change this template, choose Tools | Templates
3
+ # and open the template in the editor.
4
+
5
+
6
+ require 'rubygems'
7
+ require 'rake'
8
+ require 'rake/clean'
9
+ require 'rake/gempackagetask'
10
+ require 'rake/rdoctask'
11
+ require 'rake/testtask'
12
+
13
+ spec = Gem::Specification.new do |s|
14
+ s.name = 'cirrocumulus'
15
+ s.homepage = 'https://github.com/deil/cirrocumulus'
16
+ s.version = '0.1.1'
17
+ s.has_rdoc = false
18
+ s.extra_rdoc_files = ['README.rdoc']
19
+ s.summary = 'Agent-based infrastructure management system'
20
+ s.description = 'Engine for agent-based infrastructure management system'
21
+ s.author = 'Anton Kosyakin'
22
+ s.email = 'deil@mneko.net'
23
+ # s.executables = ['your_executable_here']
24
+ s.files = %w(README.rdoc Rakefile) + Dir.glob("{bin,lib,spec}/**/*")
25
+ s.require_path = "lib"
26
+ s.bindir = "bin"
27
+ s.license = ['GPL-2']
28
+ s.add_dependency("activesupport", "~> 2.3.11")
29
+ s.add_dependency("log4r", "~> 1.1.9")
30
+ s.add_dependency("systemu")
31
+ s.add_dependency("xmpp4r", "~> 0.5")
32
+ s.add_dependency("xmpp4r-simple", "~> 0.8.8")
33
+ end
34
+
35
+ Rake::GemPackageTask.new(spec) do |p|
36
+ p.gem_spec = spec
37
+ p.need_tar = true
38
+ p.need_zip = true
39
+ end
40
+
41
+ Rake::RDocTask.new do |rdoc|
42
+ files =['README.rdoc', 'lib/**/*.rb']
43
+ rdoc.rdoc_files.add(files)
44
+ rdoc.main = "README" # page to start on
45
+ rdoc.title = "cirrocumulus Docs"
46
+ rdoc.rdoc_dir = 'doc/rdoc' # rdoc output folder
47
+ rdoc.options << '--line-numbers'
48
+ end
49
+
50
+ #Rake::TestTask.new do |t|
51
+ # t.test_files = FileList['test/**/*.rb']
52
+ #end
File without changes
@@ -0,0 +1,182 @@
1
+ class Agent
2
+ class AgentInfo
3
+ attr_accessor :identifier
4
+ attr_accessor :default_ontology
5
+ attr_accessor :last_seen_at
6
+
7
+ def initialize
8
+ @identifier = @default_ontology = @last_seen_at = nil
9
+ end
10
+ end
11
+
12
+ class NetworkMap
13
+
14
+ INVALIDATE_PERIOD = 600*2
15
+
16
+ attr_reader :agents
17
+ attr_accessor :version
18
+ attr_reader :valid
19
+
20
+ def initialize(agent)
21
+ Log4r::Logger['agent'].debug "initializing empty network map"
22
+ @agent = agent
23
+ @agents = []
24
+ @version = 0
25
+ @valid = 0
26
+ end
27
+
28
+ def tick(cm)
29
+ @valid -= 1
30
+ if @valid <= 0
31
+ Log4r::Logger['agent'].debug "invalidating network map"
32
+ msg = Cirrocumulus::Message.new(nil, 'request', [:update, [:map, @version.to_s]])
33
+ msg.ontology = 'cirrocumulus-map'
34
+ cm.send(msg)
35
+ @valid = INVALIDATE_PERIOD
36
+ end
37
+ end
38
+
39
+ def handle_message(message, cm)
40
+ if message.ontology == 'cirrocumulus-map'
41
+ return if !message.receiver.blank? && (message.receiver != @agent.identifier)
42
+ #p message
43
+
44
+ if message.act == 'inform'
45
+ if message.content.first == :"="
46
+ ontology = message.content[2].first
47
+ agent = @agents.find {|a| a.identifier == message.sender}
48
+ if agent
49
+ agent.default_ontology = ontology
50
+ agent.last_seen_at = Time.now.to_i
51
+ @version = Time.now.to_i
52
+ Log4r::Logger['agent'].info "got neighbour details: #{agent.inspect}"
53
+ end
54
+ else
55
+ agent_info = message.content
56
+ agent = AgentInfo.new
57
+ agent_info.each do |param|
58
+ if param.first == :identifier
59
+ agent.identifier = param.second
60
+ elsif param.first == :default_ontology
61
+ agent.default_ontology = param.second
62
+ elsif param.first == :last_seen_at
63
+ agent.last_seen_at = param.second.to_i
64
+ end
65
+ end
66
+
67
+ my_agent = @agents.find {|a| a.identifier == agent.identifier}
68
+ if my_agent.nil?
69
+ my_agent = agent
70
+ @agents << agent
71
+ else
72
+ my_agent.last_seen_at = [my_agent.last_seen_at, agent.last_seen_at].max
73
+ my_agent.default_ontology = agent.default_ontology || my_agent.default_ontology
74
+ end
75
+
76
+ Log4r::Logger['agent'].info "neighbour updated: #{my_agent.inspect}"
77
+ @version = Time.now.to_i
78
+ end
79
+ elsif message.act == 'request'
80
+ map_request = message.content
81
+ foreign_map = map_request.second
82
+ foreign_map_version = foreign_map.second.to_i
83
+ if @version >= foreign_map_version
84
+ @agents.each do |agent|
85
+ next if agent.default_ontology.blank?
86
+ msg = Cirrocumulus::Message.new(nil, 'inform', [
87
+ [:identifier, agent.identifier],
88
+ [:default_ontology, agent.default_ontology],
89
+ [:last_seen_at, agent.last_seen_at.to_s]
90
+ ])
91
+ msg.receiver = message.sender
92
+ msg.ontology = 'cirrocumulus-map'
93
+ cm.send(msg)
94
+ end
95
+ end
96
+
97
+ process_agent(message, cm)
98
+ elsif message.act == 'query-ref'
99
+ #p message.content
100
+ if message.content.first == :default_ontology
101
+ msg = Cirrocumulus::Message.new(nil, 'inform', [:'=', [:default_ontology], [@agent.default_ontology]])
102
+ msg.receiver = message.sender
103
+ msg.ontology = 'cirrocumulus-map'
104
+ cm.send(msg)
105
+ end
106
+ end
107
+ else
108
+ process_agent(message, cm)
109
+ end
110
+ end
111
+
112
+ private
113
+
114
+ def process_agent(message, cm)
115
+ agent_id = message.sender
116
+ return if agent_id == @agent.identifier
117
+
118
+ agent = @agents.find {|a| a.identifier == agent_id}
119
+ if agent
120
+ agent.last_seen_at = Time.now.to_i
121
+ @version = Time.now.to_i
122
+ else
123
+ agent = AgentInfo.new
124
+ agent.identifier = agent_id
125
+ agent.last_seen_at = Time.now.to_i
126
+ Log4r::Logger['agent'].info "discovered neighbour: #{agent.identifier}"
127
+ @agents << agent
128
+ @version = Time.now.to_i
129
+
130
+ msg = Cirrocumulus::Message.new(nil, 'query-ref', [:default_ontology])
131
+ msg.receiver = agent.identifier
132
+ msg.ontology = 'cirrocumulus-map'
133
+ cm.send(msg)
134
+ end
135
+ end
136
+ end
137
+
138
+ attr_reader :default_ontology
139
+ attr_reader :identifier
140
+ attr_reader :network_map
141
+
142
+ def initialize(cm)
143
+ @cm = cm
144
+ @identifier = cm.jid
145
+ @sagas = []
146
+ @saga_idx = 0
147
+ @network_map = NetworkMap.new(self)
148
+ end
149
+
150
+ def tick()
151
+ @network_map.tick(@cm)
152
+
153
+ @sagas.each do |saga|
154
+ next if saga.is_finished?
155
+ saga.timeout -= 1 if saga.timeout > 0
156
+ saga.handle(nil) if saga.timeout == 0
157
+ end
158
+ end
159
+
160
+ def restore_state()
161
+ end
162
+
163
+ def handles_ontology?(ontology)
164
+ return @default_ontology == ontology || ontology == 'cirrocumulus-map'
165
+ end
166
+
167
+ def handle_message(message, kb)
168
+ @network_map.handle_message(message, @cm)
169
+
170
+ if message.ontology != 'cirrocumulus-map'
171
+ handle(message, kb)
172
+ end
173
+ end
174
+
175
+ def self.get_node(sender)
176
+ sender.split('-').first
177
+ end
178
+
179
+ def self.get_subsystem(sender)
180
+ sender.split('-').second
181
+ end
182
+ end
@@ -0,0 +1,179 @@
1
+ require 'xmpp4r'
2
+ require 'xmpp4r-simple'
3
+ require 'sexpistol'
4
+ require 'systemu'
5
+ require 'activesupport'
6
+
7
+ class Cirrocumulus
8
+ class Message
9
+ attr_accessor :sender, :act, :content
10
+ attr_accessor :receiver, :reply_with, :in_reply_to
11
+ attr_accessor :ontology
12
+
13
+ def initialize(sender, act, content)
14
+ @sender = sender
15
+ @act = act
16
+ @content = content
17
+ end
18
+
19
+ def failed?
20
+ act == 'failure' || act == 'refuse'
21
+ end
22
+
23
+ def context
24
+ Context.new(@sender, @reply_with)
25
+ end
26
+ end
27
+
28
+ class Context
29
+ attr_reader :sender
30
+ attr_reader :reply_with
31
+
32
+ def initialize(sender, reply_with)
33
+ @sender = sender
34
+ @reply_with = reply_with
35
+ end
36
+ end
37
+
38
+ def self.platform
39
+ if PLATFORM =~ /freebsd/
40
+ return 'freebsd'
41
+ elsif PLATFORM =~ /linux/
42
+ return 'linux'
43
+ end
44
+
45
+ return 'unknown'
46
+ end
47
+
48
+ attr_reader :jid
49
+
50
+ def initialize(suffix, generate_jid = true)
51
+ Log4r::Logger['cirrocumulus'].info 'platform: ' + Cirrocumulus::platform
52
+ _, hostname = systemu 'hostname'
53
+ hostname.strip!
54
+ @jid = generate_jid ? "#{hostname}-#{suffix}" : suffix
55
+ Log4r::Logger['cirrocumulus'].info "logging as " + @jid
56
+ connect()
57
+ end
58
+
59
+ def send(message)
60
+ msg = "<fipa-message ontology=\"#{message.ontology}\""
61
+ msg += " receiver=\"#{message.receiver}\"" if message.receiver
62
+ msg += " act=\"#{message.act}\""
63
+ msg += " reply-with=\"#{message.reply_with}\"" if message.reply_with
64
+ msg += " in-reply-to=\"#{message.in_reply_to}\"" if message.in_reply_to
65
+ message_content = message.content if message.content.is_a? String
66
+ message_content = Sexpistol.new.to_sexp(message.content) if message.content.is_a? Array
67
+ msg += "><content>#{message_content}</content></fipa-message>"
68
+ @im.send!("<message type=\"groupchat\" to=\"#{JABBER_CONFERENCE}\" id=\"aaefa\"><body>#{msg.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;')}</body></message>")
69
+ end
70
+
71
+ def inform(receiver, answer, ontology = nil)
72
+ msg = "<fipa-message ontology=\"#{ontology || @ontology}\" receiver=\"#{receiver}\" act=\"inform\"><content>#{answer}</content></fipa-message>"
73
+ @im.send!("<message type=\"groupchat\" to=\"#{JABBER_CONFERENCE}\" id=\"aaefa\"><body>#{msg.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;')}</body></message>")
74
+ end
75
+
76
+ def refuse(receiver, action, reason, ontology = nil)
77
+ msg = "<fipa-message ontology=\"#{ontology || @ontology}\" receiver=\"#{receiver}\" act=\"refuse\"><content>(#{action} #{reason})</content></fipa-message>"
78
+ @im.send!("<message type=\"groupchat\" to=\"#{JABBER_CONFERENCE}\" id=\"aaefa\"><body>#{msg.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;')}</body></message>")
79
+ end
80
+
81
+ def failure(receiver, action, ontology = nil)
82
+ msg = "<fipa-message ontology=\"#{ontology || @ontology}\" receiver=\"#{receiver}\" act=\"failure\"><content>#{action}</content></fipa-message>"
83
+ @im.send!("<message type=\"groupchat\" to=\"#{JABBER_CONFERENCE}\" id=\"aaefa\"><body>#{msg.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;')}</body></message>")
84
+ end
85
+
86
+ def request(receiver, action, ontology = nil)
87
+ msg = "<fipa-message ontology=\"#{ontology || @ontology}\" receiver=\"#{receiver}\" act=\"request\"><content>#{action}</content></fipa-message>"
88
+ @im.send!("<message type=\"groupchat\" to=\"#{JABBER_CONFERENCE}\" id=\"aaefa\"><body>#{msg.gsub('&', '&amp;').gsub('<', '&lt;').gsub('>', '&gt;')}</body></message>")
89
+ end
90
+
91
+ def run(agent, kb, sniff = false)
92
+ Log4r::Logger['cirrocumulus'].info("entering main loop")
93
+ agent.restore_state()
94
+
95
+ s = Sexpistol.new
96
+
97
+ loop do
98
+ kb.collect_knowledge()
99
+
100
+ begin
101
+ connect() if @im.nil? || !@im.connected?
102
+ rescue Exception => e
103
+ puts e.to_s
104
+ end
105
+
106
+ next if @im.nil? || !@im.connected?
107
+
108
+ @im.received_messages do |message|
109
+ next if !message.x('jabber:x:delay').nil?
110
+
111
+ begin
112
+ xml = Hash.from_xml(message.body)['fipa_message']
113
+
114
+ ontology = xml['ontology']
115
+ sender = message.from.resource
116
+ receiver = xml['receiver']
117
+ supported_ontology = agent.handles_ontology?(ontology)
118
+ if (supported_ontology && (receiver == @jid || receiver.blank?)) || receiver == @jid || sniff
119
+ act = xml['act']
120
+ content_raw = xml['content']
121
+ content = s.parse_string(content_raw)
122
+ msg = Cirrocumulus::Message.new(sender, act, content)
123
+ msg.receiver = receiver
124
+ msg.reply_with = xml['reply_with']
125
+ msg.in_reply_to = xml['in_reply_to']
126
+ msg.ontology = ontology
127
+ flatten_message_content(msg)
128
+ agent.handle_message(msg, kb)
129
+ end
130
+ rescue Exception => e
131
+ puts e.to_s
132
+ puts e.backtrace
133
+ end
134
+ end
135
+
136
+ agent.tick()
137
+ sleep 0.5
138
+ end
139
+
140
+ @im.disconnect
141
+ end
142
+
143
+ private
144
+
145
+ def connect()
146
+ begin
147
+ @im.disconnect if @im && @im.connected?
148
+ full_jid = @jid + "@" + JABBER_SERVER
149
+ @im = Jabber::Simple.new(full_jid, JABBER_DEFAULT_PASSWORD)
150
+ rescue Jabber::ClientAuthenticationFailure => ex
151
+ Log4r::Logger['cirrocumulus'].warn ex.to_s
152
+ Log4r::Logger['cirrocumulus'].info "registering new account with default password"
153
+
154
+ client = Jabber::Client.new(full_jid)
155
+ client.connect()
156
+ client.register(JABBER_DEFAULT_PASSWORD) #, {'username' => full_jid, 'password' => JABBER_DEFAULT_PASSWORD})
157
+ client.close()
158
+ @im = Jabber::Simple.new(full_jid, JABBER_DEFAULT_PASSWORD)
159
+ rescue Exception => ex
160
+ puts ex
161
+ #puts ex.backtrace.to_s
162
+ end
163
+
164
+ if !@im.nil? && @im.connected?
165
+ Log4r::Logger['cirrocumulus'].info 'joining ' + JABBER_CONFERENCE
166
+ @im.send!("<presence to='#{JABBER_CONFERENCE}/#{@jid}' />")
167
+ end
168
+ end
169
+
170
+ def flatten_message_content(message)
171
+ if !message.content.is_a?(Array)
172
+ message.content = [message.content]
173
+ else
174
+ while message.content.is_a?(Array) && message.content.size == 1 && message.content.first.is_a?(Array)
175
+ message.content = message.content.first
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,44 @@
1
+ class Kb
2
+ def initialize
3
+ @knowledge = []
4
+ end
5
+
6
+ def add_fact(key, value)
7
+ s = Sexpistol.new
8
+ key_str = s.to_sexp(key)
9
+ #puts "add: #{key_str}"
10
+ @knowledge << {:key => key_str, :value => value}
11
+ end
12
+
13
+ def query_fact(key)
14
+ s = Sexpistol.new
15
+ key_str = s.to_sexp(key)
16
+
17
+ #puts "query: #{key}"
18
+ @knowledge.each do |h|
19
+ if h[:key] == key_str
20
+ #puts "found: #{h[:value]}"
21
+ return h[:value]
22
+ end
23
+ end
24
+
25
+ nil
26
+ end
27
+
28
+ def remove_fact(key)
29
+ #puts "remove fact: #{key}"
30
+ @knowledge.delete(key)
31
+ end
32
+
33
+ def keys
34
+ res = []
35
+ @knowledge.each do |h|
36
+ res << h[:key]
37
+ end
38
+
39
+ res
40
+ end
41
+
42
+ def collect_knowledge()
43
+ end
44
+ end
@@ -0,0 +1,4 @@
1
+ require 'log4r'
2
+ require 'log4r/configurator'
3
+
4
+ Log4r::Configurator.load_xml_file(File.join(AGENT_ROOT, 'config/log4r.xml'))
@@ -0,0 +1,197 @@
1
+ module Agent
2
+ class AgentInfo
3
+ attr_accessor :identifier
4
+ attr_accessor :default_ontology
5
+ attr_accessor :last_seen_at
6
+
7
+ def initialize
8
+ @identifier = @default_ontology = @last_seen_at = nil
9
+ end
10
+ end
11
+
12
+ class NetworkMap
13
+
14
+ INVALIDATE_PERIOD = 600*2
15
+
16
+ attr_reader :agents
17
+ attr_accessor :version
18
+ attr_reader :valid
19
+
20
+ def initialize(agent)
21
+ Log4r::Logger['agent'].debug "initializing empty network map"
22
+ @agent = agent
23
+ @agents = []
24
+ @version = 0
25
+ @valid = 0
26
+ end
27
+
28
+ def tick(cm)
29
+ @valid -= 1
30
+ if @valid <= 0
31
+ Log4r::Logger['agent'].debug "invalidating network map"
32
+ msg = Cirrocumulus::Message.new(nil, 'request', [:update, [:map, @version.to_s]])
33
+ msg.ontology = 'cirrocumulus-map'
34
+ cm.send(msg)
35
+ @valid = INVALIDATE_PERIOD
36
+ end
37
+ end
38
+
39
+ def handle_message(message, cm)
40
+ if message.ontology == 'cirrocumulus-map'
41
+ return if !message.receiver.blank? && (message.receiver != @agent.identifier)
42
+ #p message
43
+
44
+ if message.act == 'inform'
45
+ if message.content.first == :"="
46
+ ontology = message.content[2].first
47
+ agent = @agents.find {|a| a.identifier == message.sender}
48
+ if agent
49
+ agent.default_ontology = ontology
50
+ agent.last_seen_at = Time.now.to_i
51
+ @version = Time.now.to_i
52
+ Log4r::Logger['agent'].info "got neighbour details: #{agent.inspect}"
53
+ end
54
+ else
55
+ agent_info = message.content
56
+ agent = AgentInfo.new
57
+ agent_info.each do |param|
58
+ if param.first == :identifier
59
+ agent.identifier = param.second
60
+ elsif param.first == :default_ontology
61
+ agent.default_ontology = param.second
62
+ elsif param.first == :last_seen_at
63
+ agent.last_seen_at = param.second.to_i
64
+ end
65
+ end
66
+
67
+ my_agent = @agents.find {|a| a.identifier == agent.identifier}
68
+ if my_agent.nil?
69
+ my_agent = agent
70
+ @agents << agent
71
+ else
72
+ my_agent.last_seen_at = [my_agent.last_seen_at, agent.last_seen_at].max
73
+ my_agent.default_ontology = agent.default_ontology || my_agent.default_ontology
74
+ end
75
+
76
+ Log4r::Logger['agent'].info "neighbour updated: #{my_agent.inspect}"
77
+ @version = Time.now.to_i
78
+ end
79
+ elsif message.act == 'request'
80
+ map_request = message.content
81
+ foreign_map = map_request.second
82
+ foreign_map_version = foreign_map.second.to_i
83
+ if @version >= foreign_map_version
84
+ @agents.each do |agent|
85
+ next if agent.default_ontology.blank?
86
+ msg = Cirrocumulus::Message.new(nil, 'inform', [
87
+ [:identifier, agent.identifier],
88
+ [:default_ontology, agent.default_ontology],
89
+ [:last_seen_at, agent.last_seen_at.to_s]
90
+ ])
91
+ msg.receiver = message.sender
92
+ msg.ontology = 'cirrocumulus-map'
93
+ cm.send(msg)
94
+ end
95
+ end
96
+
97
+ process_agent(message, cm)
98
+ elsif message.act == 'query-ref'
99
+ #p message.content
100
+ if message.content.first == :default_ontology
101
+ msg = Cirrocumulus::Message.new(nil, 'inform', [:'=', [:default_ontology], [@agent.default_ontology]])
102
+ msg.receiver = message.sender
103
+ msg.ontology = 'cirrocumulus-map'
104
+ cm.send(msg)
105
+ end
106
+ end
107
+ else
108
+ process_agent(message, cm)
109
+ end
110
+ end
111
+
112
+ private
113
+
114
+ def process_agent(message, cm)
115
+ agent_id = message.sender
116
+ return if agent_id == @agent.identifier
117
+
118
+ agent = @agents.find {|a| a.identifier == agent_id}
119
+ if agent
120
+ agent.last_seen_at = Time.now.to_i
121
+ @version = Time.now.to_i
122
+ else
123
+ agent = AgentInfo.new
124
+ agent.identifier = agent_id
125
+ agent.last_seen_at = Time.now.to_i
126
+ Log4r::Logger['agent'].info "discovered neighbour: #{agent.identifier}"
127
+ @agents << agent
128
+ @version = Time.now.to_i
129
+
130
+ msg = Cirrocumulus::Message.new(nil, 'query-ref', [:default_ontology])
131
+ msg.receiver = agent.identifier
132
+ msg.ontology = 'cirrocumulus-map'
133
+ cm.send(msg)
134
+ end
135
+ end
136
+ end
137
+
138
+ class Base
139
+ attr_reader :identifier
140
+ attr_reader :network_map
141
+
142
+ def initialize(cm)
143
+ Log4r::Logger['agent'].info('Initializing new agent')
144
+
145
+ @cm = cm
146
+ @identifier = cm.jid
147
+ @ontologies = []
148
+ @network_map = NetworkMap.new(self)
149
+ end
150
+
151
+ def load_ontologies(ontologies_list)
152
+ ontologies_list.each do |ontology_name|
153
+ ontology = eval("#{ontology_name}.new(self)")
154
+ self.ontologies << ontology
155
+ end
156
+ end
157
+
158
+ def handles_ontology?(ontology_name)
159
+ self.ontologies.any? {|ontology| ontology.name == ontology_name}
160
+ end
161
+
162
+ def restore_state()
163
+ self.ontologies.each do |ontology|
164
+ begin
165
+ ontology.restore_state()
166
+ rescue Exception => e
167
+ Log4r::Logger['agent'].warn "failed to restore state for ontology %s" % ontology.name
168
+ Log4r::Logger['agent'].warn e.backtrace.to_s
169
+ end
170
+ end
171
+ end
172
+
173
+ def send_message(message)
174
+ @cm.send(message)
175
+ end
176
+
177
+ def tick()
178
+ @network_map.tick(@cm)
179
+
180
+ self.ontologies.each {|ontology| ontology.tick() }
181
+ end
182
+
183
+ def handle_message(message, kb)
184
+ @network_map.handle_message(message, @cm)
185
+ self.ontologies.each {|ontology| ontology.handle_message(message, kb) if message.ontology == ontology.name}
186
+ rescue Exception => e
187
+ Log4r::Logger['agent'].warn "failed to handle incoming message: %s" % e.to_s
188
+ puts e.backtrace.to_s
189
+ end
190
+
191
+ protected
192
+
193
+ attr_reader :cm
194
+ attr_reader :ontologies
195
+
196
+ end
197
+ end
@@ -0,0 +1,28 @@
1
+ module Ontology
2
+ class Base
3
+ attr_reader :name
4
+ attr_reader :agent
5
+
6
+ def initialize(name, agent)
7
+ @name = name
8
+ @agent = agent
9
+ end
10
+
11
+ def restore_state()
12
+ puts "call to dummy Ontology::Base.restore_state()"
13
+ end
14
+
15
+ def tick()
16
+ end
17
+
18
+ def handle_message(message, kb)
19
+ puts "call to dummy Ontology::Base.handle_message()"
20
+ end
21
+
22
+ protected
23
+
24
+ def logger
25
+ Log4r::Logger['agent']
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,53 @@
1
+ class Saga
2
+ attr_reader :id
3
+ attr_reader :context
4
+ attr_reader :finished
5
+ attr_accessor :timeout
6
+
7
+ DEFAULT_TIMEOUT = 15
8
+ LONG_TIMEOUT = 60
9
+
10
+ STATE_ERROR = -1
11
+ STATE_START = 0
12
+ STATE_FINISHED = 255
13
+
14
+ def initialize(id, cm, agent)
15
+ @agent = agent
16
+ @cm = cm
17
+ @id = id
18
+ @finished = false
19
+ @timeout = -1
20
+ @state = STATE_START
21
+ end
22
+
23
+ def is_finished?
24
+ @finished || @state == STATE_ERROR
25
+ end
26
+
27
+ protected
28
+
29
+ def clear_timeout()
30
+ @timeout = -1
31
+ end
32
+
33
+ def set_timeout(secs)
34
+ Log4r::Logger['agent'].debug "[#{id}] waiting for #{secs} second(s)" if secs > 1
35
+ @timeout = secs*2
36
+ end
37
+
38
+ def change_state(new_state)
39
+ Log4r::Logger['agent'].debug "[#{id}] switching state from #{@state} to #{new_state}"
40
+ @state = new_state
41
+ end
42
+
43
+ def finish()
44
+ clear_timeout()
45
+ change_state(STATE_FINISHED)
46
+ @finished = true
47
+ Log4r::Logger['agent'].info "[#{id}] finished"
48
+ end
49
+
50
+ def error()
51
+ change_state(STATE_ERROR)
52
+ end
53
+ end
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cirrocumulus
3
+ version: !ruby/object:Gem::Version
4
+ hash: 25
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 1
10
+ version: 0.1.1
11
+ platform: ruby
12
+ authors:
13
+ - Anton Kosyakin
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-09-13 00:00:00 +04:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: activesupport
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 21
30
+ segments:
31
+ - 2
32
+ - 3
33
+ - 11
34
+ version: 2.3.11
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: log4r
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 1
46
+ segments:
47
+ - 1
48
+ - 1
49
+ - 9
50
+ version: 1.1.9
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: systemu
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 3
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ type: :runtime
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: xmpp4r
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ hash: 1
76
+ segments:
77
+ - 0
78
+ - 5
79
+ version: "0.5"
80
+ type: :runtime
81
+ version_requirements: *id004
82
+ - !ruby/object:Gem::Dependency
83
+ name: xmpp4r-simple
84
+ prerelease: false
85
+ requirement: &id005 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ~>
89
+ - !ruby/object:Gem::Version
90
+ hash: 47
91
+ segments:
92
+ - 0
93
+ - 8
94
+ - 8
95
+ version: 0.8.8
96
+ type: :runtime
97
+ version_requirements: *id005
98
+ description: Engine for agent-based infrastructure management system
99
+ email: deil@mneko.net
100
+ executables: []
101
+
102
+ extensions: []
103
+
104
+ extra_rdoc_files:
105
+ - README.rdoc
106
+ files:
107
+ - README.rdoc
108
+ - Rakefile
109
+ - lib/cirrocumulus.rb
110
+ - lib/cirrocumulus/agent.rb
111
+ - lib/cirrocumulus/kb.rb
112
+ - lib/cirrocumulus/saga.rb
113
+ - lib/cirrocumulus/logger.rb
114
+ - lib/cirrocumulus/ontology.rb
115
+ - lib/cirrocumulus/engine.rb
116
+ - lib/cirrocumulus/master_agent.rb
117
+ has_rdoc: true
118
+ homepage: https://github.com/deil/cirrocumulus
119
+ licenses:
120
+ - - GPL-2
121
+ post_install_message:
122
+ rdoc_options: []
123
+
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ hash: 3
132
+ segments:
133
+ - 0
134
+ version: "0"
135
+ required_rubygems_version: !ruby/object:Gem::Requirement
136
+ none: false
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ hash: 3
141
+ segments:
142
+ - 0
143
+ version: "0"
144
+ requirements: []
145
+
146
+ rubyforge_project:
147
+ rubygems_version: 1.3.7
148
+ signing_key:
149
+ specification_version: 3
150
+ summary: Agent-based infrastructure management system
151
+ test_files: []
152
+