omf_common 6.0.0.pre.10 → 6.0.0.pre.11
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/monitor_topic.rb +80 -0
- data/bin/send_create.rb +94 -0
- data/bin/send_request.rb +58 -0
- data/example/engine_alt.rb +136 -0
- data/example/vm_alt.rb +65 -0
- data/lib/omf_common.rb +224 -3
- data/lib/omf_common/comm.rb +113 -46
- data/lib/omf_common/comm/amqp/amqp_communicator.rb +76 -0
- data/lib/omf_common/comm/amqp/amqp_topic.rb +91 -0
- data/lib/omf_common/comm/local/local_communicator.rb +64 -0
- data/lib/omf_common/comm/local/local_topic.rb +42 -0
- data/lib/omf_common/comm/topic.rb +190 -0
- data/lib/omf_common/{dsl/xmpp.rb → comm/xmpp/communicator.rb} +93 -53
- data/lib/omf_common/comm/xmpp/topic.rb +147 -0
- data/lib/omf_common/{dsl → comm/xmpp}/xmpp_mp.rb +2 -0
- data/lib/omf_common/eventloop.rb +94 -0
- data/lib/omf_common/eventloop/em.rb +57 -0
- data/lib/omf_common/eventloop/local_evl.rb +78 -0
- data/lib/omf_common/message.rb +112 -229
- data/lib/omf_common/message/json/json_message.rb +129 -0
- data/lib/omf_common/message/xml/message.rb +410 -0
- data/lib/omf_common/message/xml/relaxng_schema.rb +17 -0
- data/lib/omf_common/message/xml/topic_message.rb +20 -0
- data/lib/omf_common/protocol/6.0.rnc +11 -21
- data/lib/omf_common/protocol/6.0.rng +52 -119
- data/lib/omf_common/version.rb +1 -1
- data/omf_common.gemspec +4 -2
- data/test/fixture/pubsub.rb +19 -19
- data/test/omf_common/{dsl/xmpp_spec.rb → comm/xmpp/communicator_spec.rb} +47 -111
- data/test/omf_common/comm/xmpp/topic_spec.rb +113 -0
- data/test/omf_common/comm_spec.rb +1 -0
- data/test/omf_common/message/xml/message_spec.rb +136 -0
- data/test/omf_common/message_spec.rb +37 -131
- data/test/test_helper.rb +4 -1
- metadata +38 -28
- data/lib/omf_common/core_ext/object.rb +0 -21
- data/lib/omf_common/relaxng_schema.rb +0 -17
- data/lib/omf_common/topic.rb +0 -34
- data/lib/omf_common/topic_message.rb +0 -20
- data/test/omf_common/topic_message_spec.rb +0 -114
- data/test/omf_common/topic_spec.rb +0 -75
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
DESCR = %{
|
4
|
+
Monitor a set of resources (topics) and print all observed messages.
|
5
|
+
|
6
|
+
If the 'follow-children' flag is set, automatically add all resources
|
7
|
+
created by the monitored resources to the monitor set. Please note
|
8
|
+
that there will be a delay until the new monitors are in place which
|
9
|
+
can result in missed messages.
|
10
|
+
}
|
11
|
+
|
12
|
+
require 'omf_common'
|
13
|
+
|
14
|
+
OP_MODE = :development
|
15
|
+
|
16
|
+
opts = {
|
17
|
+
communication: {
|
18
|
+
url: 'amqp://srv.mytestbed.net'
|
19
|
+
},
|
20
|
+
eventloop: { type: :em},
|
21
|
+
logging: {
|
22
|
+
level: 'info'
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
observed_topic = nil
|
27
|
+
$follow_children = true
|
28
|
+
|
29
|
+
op = OptionParser.new
|
30
|
+
op.banner = "Usage: #{op.program_name} [options] topic1 topic2 ...\n#{DESCR}\n"
|
31
|
+
op.on '-c', '--comms-url URL', "URL to communication layer [#{opts[:communication][:url]}]" do |url|
|
32
|
+
opts[:communication][:url] = url
|
33
|
+
end
|
34
|
+
op.on '-f', "--[no-]follow-children", "Follow all newly created resources [#{$follow_children}]" do |flag|
|
35
|
+
$follow_children = flag
|
36
|
+
end
|
37
|
+
op.on '-d', '--debug', "Set logging to DEBUG level" do
|
38
|
+
opts[:logging][:level] = 'debug'
|
39
|
+
end
|
40
|
+
op.on_tail('-h', "--help", "Show this message") { $stderr.puts op; exit }
|
41
|
+
observed_topics = op.parse(ARGV)
|
42
|
+
|
43
|
+
unless observed_topics
|
44
|
+
$stderr.puts 'Missing declaration of topics to follow'
|
45
|
+
$stderr.puts op
|
46
|
+
exit(-1)
|
47
|
+
end
|
48
|
+
|
49
|
+
$observed_topics = {}
|
50
|
+
|
51
|
+
def observe(tname, comm)
|
52
|
+
return if $observed_topics.key? tname
|
53
|
+
|
54
|
+
info "Observing '#{tname}'"
|
55
|
+
$observed_topics[tname] = true
|
56
|
+
comm.subscribe(tname) do |topic|
|
57
|
+
topic.on_message do |msg|
|
58
|
+
ts = Time.now.strftime('%H:%M:%S')
|
59
|
+
puts "#{ts} #{msg.type}(#{msg.itype}) #{msg.inspect}"
|
60
|
+
puts " #{topic.id}"
|
61
|
+
msg.each_property do |name, value|
|
62
|
+
puts " #{name}: #{value}"
|
63
|
+
end
|
64
|
+
puts "------"
|
65
|
+
|
66
|
+
if $follow_children && msg.itype == 'creation_ok'
|
67
|
+
#puts ">>>>>> #{msg}"
|
68
|
+
observe(msg[:res_id], comm)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
OmfCommon.init(OP_MODE, opts) do |el|
|
75
|
+
OmfCommon.comm.on_connected do |comm|
|
76
|
+
observed_topics.each do |topic|
|
77
|
+
observe(topic, comm)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/bin/send_create.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
#
|
2
|
+
DESCR = %{
|
3
|
+
Send a create to a specific resource (topic) and print out any replies.
|
4
|
+
|
5
|
+
Any additional command line arguments are interpreted as paramters to
|
6
|
+
the create.
|
7
|
+
}
|
8
|
+
|
9
|
+
require 'omf_common'
|
10
|
+
|
11
|
+
OP_MODE = :development
|
12
|
+
|
13
|
+
opts = {
|
14
|
+
communication: {
|
15
|
+
# url: 'amqp://srv.mytestbed.net'
|
16
|
+
},
|
17
|
+
eventloop: { type: :em},
|
18
|
+
logging: {
|
19
|
+
level: 'info'
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
resource_url = nil
|
24
|
+
resource_type = nil
|
25
|
+
|
26
|
+
op = OptionParser.new
|
27
|
+
op.banner = "Usage: #{op.program_name} [options] type pname1: val1 pname2: val2 ...\n#{DESCR}\n"
|
28
|
+
op.on '-r', '--resource-url URL', "URL of resource" do |url|
|
29
|
+
resource_url = url
|
30
|
+
end
|
31
|
+
op.on '-t', '--type TYPE', "Type of resource to create" do |type|
|
32
|
+
resource_type = type
|
33
|
+
end
|
34
|
+
op.on '-d', '--debug', "Set logging to DEBUG level" do
|
35
|
+
opts[:logging][:level] = 'debug'
|
36
|
+
end
|
37
|
+
op.on_tail('-h', "--help", "Show this message") { $stderr.puts op; exit }
|
38
|
+
rest = op.parse(ARGV) || []
|
39
|
+
|
40
|
+
unless resource_url || resource_type
|
41
|
+
$stderr.puts 'Missing --resource-url --type or'
|
42
|
+
$stderr.puts op
|
43
|
+
exit(-1)
|
44
|
+
end
|
45
|
+
|
46
|
+
r = resource_url.split('/')
|
47
|
+
resource = r.pop
|
48
|
+
opts[:communication][:url] = r.join('/')
|
49
|
+
|
50
|
+
copts = {}
|
51
|
+
key = nil
|
52
|
+
def err_exit
|
53
|
+
$stderr.puts("Options need to be of the 'key: value' type")
|
54
|
+
exit(-1)
|
55
|
+
end
|
56
|
+
rest.each do |s|
|
57
|
+
sa = s.split(':')
|
58
|
+
if sa.length == 2
|
59
|
+
err_exit if key
|
60
|
+
copts[sa[0]] = sa[1]
|
61
|
+
else
|
62
|
+
if s.end_with?(':')
|
63
|
+
err_exit if key
|
64
|
+
key = s[0]
|
65
|
+
else
|
66
|
+
err_exit unless key
|
67
|
+
copts[key] = s[0]
|
68
|
+
key = nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
err_exit if key
|
73
|
+
|
74
|
+
OmfCommon.init(OP_MODE, opts) do |el|
|
75
|
+
OmfCommon.comm.on_connected do |comm|
|
76
|
+
comm.subscribe(resource) do |topic|
|
77
|
+
# topic.on_inform do |msg|
|
78
|
+
# puts "#{resource} <#{msg.type}(#{msg.itype})> #{msg.inspect}"
|
79
|
+
# msg.each_property do |name, value|
|
80
|
+
# puts " #{name}: #{value}"
|
81
|
+
# end
|
82
|
+
# puts "------"
|
83
|
+
# end
|
84
|
+
|
85
|
+
topic.create(resource_type, copts) do |msg|
|
86
|
+
puts "#{resource} <#{msg.type}(#{msg.itype})> #{msg.inspect}"
|
87
|
+
msg.each_property do |name, value|
|
88
|
+
puts " #{name}: #{value}"
|
89
|
+
end
|
90
|
+
puts "------"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
data/bin/send_request.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#
|
2
|
+
DESCR = %{
|
3
|
+
Send a request to a specific resource (topic) and print out any replies.
|
4
|
+
|
5
|
+
Any additional command line arguments are interpreted as limiting the request
|
6
|
+
to those, otherwise all properties are requested.
|
7
|
+
}
|
8
|
+
|
9
|
+
require 'omf_common'
|
10
|
+
|
11
|
+
OP_MODE = :development
|
12
|
+
|
13
|
+
opts = {
|
14
|
+
communication: {
|
15
|
+
# url: 'amqp://srv.mytestbed.net'
|
16
|
+
},
|
17
|
+
eventloop: { type: :em},
|
18
|
+
logging: {
|
19
|
+
level: 'info'
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
resource_url = nil
|
24
|
+
|
25
|
+
op = OptionParser.new
|
26
|
+
op.banner = "Usage: #{op.program_name} [options] prop1 prop2 ...\n#{DESCR}\n"
|
27
|
+
op.on '-r', '--resource-url URL', "URL of resource" do |url|
|
28
|
+
resource_url = url
|
29
|
+
end
|
30
|
+
op.on '-d', '--debug', "Set logging to DEBUG level" do
|
31
|
+
opts[:logging][:level] = 'debug'
|
32
|
+
end
|
33
|
+
op.on_tail('-h', "--help", "Show this message") { $stderr.puts op; exit }
|
34
|
+
req_properties = op.parse(ARGV) || []
|
35
|
+
|
36
|
+
unless resource_url
|
37
|
+
$stderr.puts 'Missing --resource-url'
|
38
|
+
$stderr.puts op
|
39
|
+
exit(-1)
|
40
|
+
end
|
41
|
+
|
42
|
+
r = resource_url.split('/')
|
43
|
+
resource = r.pop
|
44
|
+
opts[:communication][:url] = r.join('/')
|
45
|
+
|
46
|
+
OmfCommon.init(OP_MODE, opts) do |el|
|
47
|
+
OmfCommon.comm.on_connected do |comm|
|
48
|
+
comm.subscribe(resource) do |topic|
|
49
|
+
topic.request(req_properties) do |msg|
|
50
|
+
puts "#{resource} <#{msg.type}(#{msg.itype})> #{msg.inspect}"
|
51
|
+
msg.each_property do |name, value|
|
52
|
+
puts " #{name}: #{value}"
|
53
|
+
end
|
54
|
+
puts "------"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# OMF_VERSIONS = 6.0
|
2
|
+
require 'omf_common'
|
3
|
+
|
4
|
+
opts = {
|
5
|
+
communication: {
|
6
|
+
url: 'amqp://localhost',
|
7
|
+
}
|
8
|
+
}
|
9
|
+
|
10
|
+
# $stdout.sync = true
|
11
|
+
# Logging.appenders.stdout(
|
12
|
+
# 'my_format',
|
13
|
+
# :layout => Logging.layouts.pattern(:date_pattern => '%H:%M:%S',
|
14
|
+
# :pattern => '%d %5l %c{2}: %m\n',
|
15
|
+
# :color_scheme => 'none'))
|
16
|
+
# Logging.logger.root.appenders = 'my_format'
|
17
|
+
# Logging.logger.root.level = :debug if opts[:debug]
|
18
|
+
|
19
|
+
# Environment setup
|
20
|
+
#OmfCommon.init(:developement, opts)
|
21
|
+
OmfCommon.init(:local)
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
def create_engine(garage)
|
26
|
+
garage.create(:engine, name: 'mp4') do |msg|
|
27
|
+
if msg.success?
|
28
|
+
engine = msg.resource
|
29
|
+
on_engine_created(engine, garage)
|
30
|
+
else
|
31
|
+
logger.error "Resource creation failed - #{msg[:reason]}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# This is an alternative version of creating a new engine.
|
38
|
+
# We create teh message first without sending it, then attach various
|
39
|
+
# response handlers and finally publish it.
|
40
|
+
#
|
41
|
+
# TODO: This is most likely NOT working yet
|
42
|
+
#
|
43
|
+
def create_engine2
|
44
|
+
msg = garage.create_message('mp4')
|
45
|
+
msg.on_created do |engine, emsg|
|
46
|
+
on_engine_created(engine, garage)
|
47
|
+
end
|
48
|
+
msg.on_created_failed do |fmsg|
|
49
|
+
logger.error "Resource creation failed - #{msg[:reason]}"
|
50
|
+
end
|
51
|
+
msg.publish
|
52
|
+
end
|
53
|
+
|
54
|
+
# This method is called whenever a new engine has been created by the garage.
|
55
|
+
#
|
56
|
+
# @param [Topic] engine Topic representing the created engine
|
57
|
+
#
|
58
|
+
def on_engine_created(engine, garage)
|
59
|
+
# Monitor all status information from teh engine
|
60
|
+
engine.on_inform_status do |msg|
|
61
|
+
msg.each_property do |name, value|
|
62
|
+
logger.info "#{name} => #{value}"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
engine.on_inform_failed do |msg|
|
67
|
+
logger.error msg.read_content("reason")
|
68
|
+
end
|
69
|
+
|
70
|
+
# Send a request for specific properties
|
71
|
+
puts ">>> SENDING REQUEST"
|
72
|
+
engine.request([:max_rpm, {:provider => {country: 'japan'}}, :max_power]) do |msg|
|
73
|
+
#engine.request([:max_rpm, :max_power])
|
74
|
+
#engine.request() do |msg|
|
75
|
+
puts ">>> REPLY #{msg.inspect}"
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
|
80
|
+
|
81
|
+
return
|
82
|
+
|
83
|
+
# Now we will apply 50% throttle to the engine
|
84
|
+
engine.configure(throttle: 50)
|
85
|
+
|
86
|
+
# Some time later, we want to reduce the throttle to 0, to avoid blowing up the engine
|
87
|
+
engine.after(5) do
|
88
|
+
engine.configure(throttle: 0)
|
89
|
+
|
90
|
+
# While we are at it, also test error handling
|
91
|
+
engine.request([:error]) do |msg|
|
92
|
+
if msg.success?
|
93
|
+
logger.error "Expected unsuccessful reply"
|
94
|
+
else
|
95
|
+
logger.info "Received expected fail message - #{msg[:reason]}"
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# 10 seconds later, we will 'release' this engine, i.e. shut it down
|
101
|
+
#engine.after(10) { release_engine(engine, garage) }
|
102
|
+
end
|
103
|
+
|
104
|
+
def release_engine(engine, garage)
|
105
|
+
logger.info "Time to release engine #{engine}"
|
106
|
+
garage.release engine do |rmsg|
|
107
|
+
puts "===> ENGINE RELEASED: #{rmsg}"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
OmfCommon.eventloop.run do |el|
|
112
|
+
OmfCommon.comm.on_connected do |comm|
|
113
|
+
|
114
|
+
# Create garage proxy
|
115
|
+
load File.join(File.dirname(__FILE__), '..', '..', 'omf_rc', 'example', 'garage_controller.rb')
|
116
|
+
garage_inst = OmfRc::ResourceFactory.create(:garage, hrn: :garage_1)
|
117
|
+
|
118
|
+
# Get handle on existing entity
|
119
|
+
comm.subscribe('garage_1') do |garage|
|
120
|
+
|
121
|
+
garage.on_inform_failed do |msg|
|
122
|
+
logger.error msg
|
123
|
+
end
|
124
|
+
# wait until garage topic is ready to receive
|
125
|
+
garage.on_subscribed do
|
126
|
+
create_engine(garage)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
el.after(20) { el.stop }
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
puts "DONE"
|
136
|
+
|
data/example/vm_alt.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
|
2
|
+
# Communication setup
|
3
|
+
Comm.init(:xmpp)
|
4
|
+
|
5
|
+
def create_vm(vm_name, host)
|
6
|
+
opts = {
|
7
|
+
name: 'my_VM_123',
|
8
|
+
ubuntu_opts: { bridge: 'br0' },
|
9
|
+
vmbuilder_opts: {
|
10
|
+
ip: '10.0.0.240',
|
11
|
+
net: '10.0.0.0',
|
12
|
+
bcast: '10.255.255.255',
|
13
|
+
mask: '255.0.0.0',
|
14
|
+
gw: '10.0.0.200',
|
15
|
+
dns: '10.0.0.200'
|
16
|
+
}
|
17
|
+
}
|
18
|
+
host.create(:vm, opts) do |msg|
|
19
|
+
if msg.success?
|
20
|
+
vm = msg.resource
|
21
|
+
on_vm_created(vm, host)
|
22
|
+
else
|
23
|
+
logger.error "Resource creation failed - #{msg[:reason]}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def on_vm_created(vm, host)
|
29
|
+
logger.info "Created #{vm}"
|
30
|
+
vm.on_inform_status do |msg|
|
31
|
+
msg.each_property do |name, value|
|
32
|
+
logger.info "#{name} => #{value}"
|
33
|
+
end
|
34
|
+
if vm.state == :running
|
35
|
+
puts "HURRAY, vm '#{vm}' is up and running"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
vm.after(10) do
|
40
|
+
vm.configure(state: :run)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
OmfCommon.eventloop.run do |el|
|
45
|
+
OmfCommon.comm.on_connected do |comm|
|
46
|
+
# Get handle on existing entity
|
47
|
+
comm.subscribe('host_1') do |host|
|
48
|
+
|
49
|
+
host.on_inform_failed do |msg|
|
50
|
+
logger.error msg
|
51
|
+
end
|
52
|
+
# wait until host topic is ready to receive
|
53
|
+
host.on_subscribed do
|
54
|
+
create_vm(host)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
el.after(20) { el.stop }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
puts "DONE"
|
64
|
+
|
65
|
+
|
data/lib/omf_common.rb
CHANGED
@@ -1,17 +1,238 @@
|
|
1
1
|
require 'active_support/core_ext'
|
2
|
+
|
2
3
|
require 'omf_common/default_logging'
|
3
4
|
require 'omf_common/version'
|
4
5
|
require 'omf_common/measure'
|
5
6
|
require 'omf_common/message'
|
6
7
|
require 'omf_common/comm'
|
7
8
|
require 'omf_common/command'
|
8
|
-
require 'omf_common/topic'
|
9
|
-
require 'omf_common/topic_message'
|
10
9
|
require 'omf_common/key'
|
11
10
|
require 'omf_common/core_ext/string'
|
12
|
-
require 'omf_common/
|
11
|
+
require 'omf_common/eventloop'
|
13
12
|
|
14
13
|
include OmfCommon::DefaultLogging
|
15
14
|
|
16
15
|
module OmfCommon
|
16
|
+
DEFAULTS = {
|
17
|
+
development: {
|
18
|
+
eventloop: {
|
19
|
+
type: 'em'
|
20
|
+
},
|
21
|
+
logging: {
|
22
|
+
level: 'debug',
|
23
|
+
|
24
|
+
appenders: {
|
25
|
+
stdout: {
|
26
|
+
date_pattern: '%H:%M:%S',
|
27
|
+
pattern: '%d %5l %c{2}: %m\n',
|
28
|
+
color_scheme: 'default'
|
29
|
+
}
|
30
|
+
}
|
31
|
+
}
|
32
|
+
},
|
33
|
+
production: {
|
34
|
+
eventloop: {
|
35
|
+
type: :em
|
36
|
+
},
|
37
|
+
logging: {
|
38
|
+
level: 'info',
|
39
|
+
|
40
|
+
appenders: {
|
41
|
+
file: {
|
42
|
+
log_dir: '/var/log',
|
43
|
+
#log_file: 'foo.log',
|
44
|
+
date_pattern: '%F %T %z',
|
45
|
+
pattern: '[%d] %-5l %c: %m\n'
|
46
|
+
}
|
47
|
+
}
|
48
|
+
|
49
|
+
}
|
50
|
+
},
|
51
|
+
local: {
|
52
|
+
communication: {
|
53
|
+
type: :local,
|
54
|
+
},
|
55
|
+
eventloop: { type: :local},
|
56
|
+
logging: {
|
57
|
+
level: 'debug',
|
58
|
+
|
59
|
+
appenders: {
|
60
|
+
stdout: {
|
61
|
+
date_pattern: '%H:%M:%S',
|
62
|
+
pattern: '%d %5l %c{2}: %m\n',
|
63
|
+
color_scheme: 'none'
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
},
|
68
|
+
test_dev: {
|
69
|
+
daemonize: {
|
70
|
+
dir_mode: :script,
|
71
|
+
dir: '/tmp',
|
72
|
+
backtrace: true,
|
73
|
+
log_dir: '/tmp',
|
74
|
+
log_output: true
|
75
|
+
},
|
76
|
+
eventloop: {
|
77
|
+
type: :local
|
78
|
+
},
|
79
|
+
logging: {
|
80
|
+
level: 'debug',
|
81
|
+
appenders: {
|
82
|
+
file: {
|
83
|
+
log_dir: '/tmp',
|
84
|
+
#log_file: 'foo.log',
|
85
|
+
date_pattern: '%F %T %z',
|
86
|
+
pattern: '[%d] %-5l %c: %m\n'
|
87
|
+
}
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
#
|
94
|
+
# Initialize the OMF runtime.
|
95
|
+
# Options are:
|
96
|
+
# :communication
|
97
|
+
# :type
|
98
|
+
# ... specific opts
|
99
|
+
# :eventloop
|
100
|
+
# :type {:em|:local...}
|
101
|
+
#
|
102
|
+
# @param [Hash] opts
|
103
|
+
#
|
104
|
+
def self.init(op_mode, opts = {}, &block)
|
105
|
+
if op_mode && defs = DEFAULTS[op_mode.to_sym]
|
106
|
+
opts = _rec_merge(defs, opts)
|
107
|
+
end
|
108
|
+
if dopts = opts.delete(:daemonize)
|
109
|
+
dopts[:app_name] ||= "#{File.basename($0, File.extname($0))}_daemon"
|
110
|
+
require 'daemons'
|
111
|
+
Daemons.run_proc(dopts[:app_name], dopts) do
|
112
|
+
init(nil, opts, &block)
|
113
|
+
end
|
114
|
+
return
|
115
|
+
end
|
116
|
+
|
117
|
+
if lopts = opts[:logging]
|
118
|
+
_init_logging(lopts) unless lopts.empty?
|
119
|
+
end
|
120
|
+
unless copts = opts[:communication]
|
121
|
+
raise "Missing :communication description"
|
122
|
+
end
|
123
|
+
eopts = opts[:eventloop]
|
124
|
+
|
125
|
+
# Initialise event loop
|
126
|
+
Eventloop.init(eopts)
|
127
|
+
# start eventloop immediately if we received a run block
|
128
|
+
eventloop.run do
|
129
|
+
Comm.init(copts)
|
130
|
+
block.call(eventloop) if block
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Return the communication driver instance
|
135
|
+
#
|
136
|
+
def self.comm()
|
137
|
+
Comm.instance
|
138
|
+
end
|
139
|
+
|
140
|
+
# Return the communication driver instance
|
141
|
+
#
|
142
|
+
def self.eventloop()
|
143
|
+
Eventloop.instance
|
144
|
+
end
|
145
|
+
|
146
|
+
# Load a YAML file and return it as hash.
|
147
|
+
#
|
148
|
+
# options:
|
149
|
+
# :symbolize_keys FLAG: Symbolize keys if set
|
150
|
+
# :path:
|
151
|
+
# :same - Look in the same directory as '$0'
|
152
|
+
# :remove_root ROOT_NAME: Remove the root node. Throw exception if not ROOT_NAME
|
153
|
+
# :wait_for_readable SECS: Wait until the yaml file becomes readable. Check every SECS
|
154
|
+
#
|
155
|
+
def self.load_yaml(file_name, opts = {})
|
156
|
+
if path_opt = opts[:path]
|
157
|
+
case path_opt
|
158
|
+
when :same
|
159
|
+
file_name = File.join(File.dirname($0), file_name)
|
160
|
+
else
|
161
|
+
raise "Unknown value '#{path_opt}' for 'path' option"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
if readable_check = opts[:wait_for_readable]
|
165
|
+
while not File.readable?(file_name)
|
166
|
+
puts "WAIT #{file_name}"
|
167
|
+
sleep readable_check # wait until file shows up
|
168
|
+
end
|
169
|
+
end
|
170
|
+
yh = YAML.load_file(file_name)
|
171
|
+
if opts[:symbolize_keys]
|
172
|
+
yh = _rec_sym_keys(yh)
|
173
|
+
end
|
174
|
+
if root = opts[:remove_root]
|
175
|
+
if yh.length != 1 && yh.key?(root)
|
176
|
+
raise "Expected root '#{root}', but found '#{yh.keys.inspect}"
|
177
|
+
end
|
178
|
+
yh = yh.delete(root)
|
179
|
+
end
|
180
|
+
yh
|
181
|
+
end
|
182
|
+
|
183
|
+
# DO NOT CALL DIRECTLY
|
184
|
+
#
|
185
|
+
def self._init_logging(opts = {})
|
186
|
+
logger = Logging.logger.root
|
187
|
+
if appenders = opts[:appenders]
|
188
|
+
logger.clear_appenders
|
189
|
+
appenders.each do |type, topts|
|
190
|
+
case type.to_sym
|
191
|
+
when :stdout
|
192
|
+
$stdout.sync = true
|
193
|
+
logger.add_appenders(
|
194
|
+
Logging.appenders.stdout('custom',
|
195
|
+
:layout => Logging.layouts.pattern(topts)
|
196
|
+
))
|
197
|
+
|
198
|
+
when :file
|
199
|
+
dir_name = topts.delete(:log_dir) || DEF_LOG_DIR
|
200
|
+
file_name = topts.delete(:log_file) || "#{File.basename($0, File.extname($0))}.log"
|
201
|
+
path = File.join(dir_name, file_name)
|
202
|
+
logger.add_appenders(
|
203
|
+
Logging.appenders.file(path,
|
204
|
+
:layout => Logging.layouts.pattern(topts)
|
205
|
+
))
|
206
|
+
else
|
207
|
+
raise "Unknown logging appender type '#{type}'"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
if level = opts[:level]
|
212
|
+
logger.level = level.to_sym
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def self._rec_merge(this_hash, other_hash)
|
217
|
+
r = {}
|
218
|
+
this_hash.merge(other_hash) do |key, oldval, newval|
|
219
|
+
r[key] = oldval.is_a?(Hash) ? _rec_merge(oldval, newval) : newval
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# Recusively Symbolize keys of hash
|
224
|
+
#
|
225
|
+
def self._rec_sym_keys(hash)
|
226
|
+
h = {}
|
227
|
+
hash.each do |k, v|
|
228
|
+
if v.is_a? Hash
|
229
|
+
v = _rec_sym_keys(v)
|
230
|
+
elsif v.is_a? Array
|
231
|
+
v = v.map {|e| e.is_a?(Hash) ? _rec_sym_keys(e) : e }
|
232
|
+
end
|
233
|
+
h[k.to_sym] = v
|
234
|
+
end
|
235
|
+
h
|
236
|
+
end
|
237
|
+
|
17
238
|
end
|