omf_common 6.0.0.pre.10 → 6.0.0.pre.11
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/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
|