cirrocumulus 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
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
+