omf_common 6.0.0.pre.7 → 6.0.0.pre.8
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/lib/omf_common.rb +1 -0
- data/lib/omf_common/comm.rb +2 -0
- data/lib/omf_common/dsl/xmpp.rb +14 -2
- data/lib/omf_common/dsl/xmpp_mp.rb +36 -0
- data/lib/omf_common/exec_app.rb +163 -163
- data/lib/omf_common/measure.rb +8 -0
- data/lib/omf_common/message.rb +62 -8
- data/lib/omf_common/topic.rb +1 -1
- data/lib/omf_common/version.rb +1 -1
- data/omf_common.gemspec +1 -0
- data/test/omf_common/message_spec.rb +20 -8
- metadata +20 -3
data/lib/omf_common.rb
CHANGED
data/lib/omf_common/comm.rb
CHANGED
data/lib/omf_common/dsl/xmpp.rb
CHANGED
@@ -23,11 +23,13 @@ module OmfCommon
|
|
23
23
|
jid = "#{username}@#{server}"
|
24
24
|
client.setup(jid, password)
|
25
25
|
client.run
|
26
|
+
MPConnection.inject(Time.now.to_f, jid, 'connect') if OmfCommon::Measure.enabled?
|
26
27
|
end
|
27
28
|
|
28
29
|
# Shut down XMPP connection
|
29
30
|
def disconnect
|
30
31
|
shutdown
|
32
|
+
OmfCommon::DSL::Xmpp::MPConnection.inject(Time.now.to_f, jid, 'disconnect') if OmfCommon::Measure.enabled?
|
31
33
|
end
|
32
34
|
|
33
35
|
# Create a new pubsub topic with additional configuration
|
@@ -49,6 +51,7 @@ module OmfCommon
|
|
49
51
|
# @param [String] topic Pubsub topic name
|
50
52
|
def subscribe(topic, &block)
|
51
53
|
pubsub.subscribe(topic, nil, default_host, &callback_logging(__method__, topic, &block))
|
54
|
+
MPSubscription.inject(Time.now.to_f, jid, 'join', topic) if OmfCommon::Measure.enabled?
|
52
55
|
end
|
53
56
|
|
54
57
|
# Un-subscribe all existing subscriptions from all pubsub topics.
|
@@ -56,6 +59,7 @@ module OmfCommon
|
|
56
59
|
pubsub.subscriptions(default_host) do |m|
|
57
60
|
m[:subscribed] && m[:subscribed].each do |s|
|
58
61
|
pubsub.unsubscribe(s[:node], nil, s[:subid], default_host, &callback_logging(__method__, s[:node], s[:subid]))
|
62
|
+
MPSubscription.inject(Time.now.to_f, jid, 'leave', s[:node]) if OmfCommon::Measure.enabled?
|
59
63
|
end
|
60
64
|
end
|
61
65
|
end
|
@@ -71,6 +75,7 @@ module OmfCommon
|
|
71
75
|
def publish(topic, message, &block)
|
72
76
|
raise StandardError, "Invalid message" unless message.valid?
|
73
77
|
pubsub.publish(topic, message, default_host, &callback_logging(__method__, topic, message.operation, &block))
|
78
|
+
MPPublished.inject(Time.now.to_f, jid, topic, message.to_s.gsub("\n",'')) if OmfCommon::Measure.enabled?
|
74
79
|
end
|
75
80
|
|
76
81
|
# Generate OMF related message
|
@@ -91,6 +96,8 @@ module OmfCommon
|
|
91
96
|
end
|
92
97
|
end
|
93
98
|
end
|
99
|
+
else
|
100
|
+
Message.send(m_name)
|
94
101
|
end
|
95
102
|
|
96
103
|
OmfCommon::TopicMessage.new(message, self)
|
@@ -124,8 +131,13 @@ module OmfCommon
|
|
124
131
|
|
125
132
|
# Event callback for pubsub topic event(item published)
|
126
133
|
#
|
127
|
-
def topic_event(
|
128
|
-
|
134
|
+
def topic_event(&block)
|
135
|
+
guard_block = proc do |event|
|
136
|
+
passed = (event.items?) && (!event.delayed?) && event.items.first.payload
|
137
|
+
MPReceived.inject(Time.now.to_f, jid, event.node, event.items.first.payload.to_s.gsub("\n",'')) if OmfCommon::Measure.enabled? && passed
|
138
|
+
passed
|
139
|
+
end
|
140
|
+
pubsub_event(guard_block, &callback_logging(__method__, &block))
|
129
141
|
end
|
130
142
|
|
131
143
|
# Return a topic object represents pubsub topic
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module OmfCommon
|
2
|
+
module DSL
|
3
|
+
module Xmpp
|
4
|
+
class MPConnection < OML4R::MPBase
|
5
|
+
name :xmpp_connections
|
6
|
+
param :time, :type => :double
|
7
|
+
param :jid, :type => :string
|
8
|
+
param :operation, :type => :string
|
9
|
+
end
|
10
|
+
|
11
|
+
class MPPublished < OML4R::MPBase
|
12
|
+
name :xmpp_published
|
13
|
+
param :time, :type => :double
|
14
|
+
param :jid, :type => :string
|
15
|
+
param :topic, :type => :string
|
16
|
+
param :xml_stanza, :type => :string
|
17
|
+
end
|
18
|
+
|
19
|
+
class MPReceived < OML4R::MPBase
|
20
|
+
name :xmpp_received
|
21
|
+
param :time, :type => :double
|
22
|
+
param :jid, :type => :string
|
23
|
+
param :topic, :type => :string
|
24
|
+
param :xml_stanza, :type => :string
|
25
|
+
end
|
26
|
+
|
27
|
+
class MPSubscription < OML4R::MPBase
|
28
|
+
name :xmpp_subscriptions
|
29
|
+
param :time, :type => :double
|
30
|
+
param :jid, :type => :string
|
31
|
+
param :operation, :type => :string
|
32
|
+
param :topic, :type => :string
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/omf_common/exec_app.rb
CHANGED
@@ -1,163 +1,163 @@
|
|
1
|
-
#
|
2
|
-
# Copyright (c) 2006-2012 National ICT Australia (NICTA), Australia
|
3
|
-
#
|
4
|
-
# Copyright (c) 2004-2009 WINLAB, Rutgers University, USA
|
5
|
-
#
|
6
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
-
# of this software and associated documentation files (the "Software"), to deal
|
8
|
-
# in the Software without restriction, including without limitation the rights
|
9
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
-
# copies of the Software, and to permit persons to whom the Software is
|
11
|
-
# furnished to do so, subject to the following conditions:
|
12
|
-
#
|
13
|
-
# The above copyright notice and this permission notice shall be included in
|
14
|
-
# all copies or substantial portions of the Software.
|
15
|
-
#
|
16
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
-
# THE SOFTWARE.
|
23
|
-
#
|
24
|
-
#
|
25
|
-
# Library of client side helpers
|
26
|
-
#
|
27
|
-
require 'fcntl'
|
28
|
-
|
29
|
-
#
|
30
|
-
# Run an application on the client.
|
31
|
-
#
|
32
|
-
# Borrows from Open3
|
33
|
-
#
|
34
|
-
class ExecApp
|
35
|
-
|
36
|
-
# Holds the pids for all active apps
|
37
|
-
@@all_apps = Hash.new
|
38
|
-
|
39
|
-
# True if this active app is being killed by a proper
|
40
|
-
# call to ExecApp.signal_all() or signal()
|
41
|
-
# (i.e. when the caller of ExecApp decided to stop the application,
|
42
|
-
# as far as we are concerned, this is a 'clean' exit)
|
43
|
-
@clean_exit = false
|
44
|
-
|
45
|
-
# Return an application instance based on its ID
|
46
|
-
#
|
47
|
-
# @param [String] id of the application to return
|
48
|
-
def ExecApp.[](id)
|
49
|
-
app = @@all_apps[id]
|
50
|
-
logger.info "Unknown application '#{id}/#{id.class}'" if app.nil?
|
51
|
-
return app
|
52
|
-
end
|
53
|
-
|
54
|
-
def ExecApp.signal_all(signal = 'KILL')
|
55
|
-
@@all_apps.each_value { |app| app.signal(signal) }
|
56
|
-
end
|
57
|
-
|
58
|
-
def stdin(line)
|
59
|
-
logger.debug "Writing '#{line}' to app '#{@id}'"
|
60
|
-
@stdin.write("#{line}\n")
|
61
|
-
@stdin.flush
|
62
|
-
end
|
63
|
-
|
64
|
-
def signal(signal = 'KILL')
|
65
|
-
@clean_exit = true
|
66
|
-
Process.kill(signal, @pid)
|
67
|
-
end
|
68
|
-
|
69
|
-
#
|
70
|
-
# Run an application 'cmd' in a separate thread and monitor
|
71
|
-
# its stdout. Also send status reports to the 'observer' by
|
72
|
-
# calling its "on_app_event(eventType, appId, message")"
|
73
|
-
#
|
74
|
-
# @param id ID of application (used for reporting)
|
75
|
-
# @param observer Observer of application's progress
|
76
|
-
# @param cmd Command path and args
|
77
|
-
# @param map_std_err_to_out If true report stderr as stdin [false]
|
78
|
-
#
|
79
|
-
def initialize(id, observer, cmd, map_std_err_to_out = false)
|
80
|
-
|
81
|
-
@id = id
|
82
|
-
@observer = observer
|
83
|
-
@@all_apps[id] = self
|
84
|
-
|
85
|
-
pw = IO::pipe # pipe[0] for read, pipe[1] for write
|
86
|
-
pr = IO::pipe
|
87
|
-
pe = IO::pipe
|
88
|
-
|
89
|
-
logger.debug "Starting application '#{id}' - cmd: '#{cmd}'"
|
90
|
-
@observer.on_app_event(:STARTED, id, cmd)
|
91
|
-
@pid = fork {
|
92
|
-
# child will remap pipes to std and exec cmd
|
93
|
-
pw[1].close
|
94
|
-
STDIN.reopen(pw[0])
|
95
|
-
pw[0].close
|
96
|
-
|
97
|
-
pr[0].close
|
98
|
-
STDOUT.reopen(pr[1])
|
99
|
-
pr[1].close
|
100
|
-
|
101
|
-
pe[0].close
|
102
|
-
STDERR.reopen(pe[1])
|
103
|
-
pe[1].close
|
104
|
-
|
105
|
-
begin
|
106
|
-
exec(cmd)
|
107
|
-
rescue => ex
|
108
|
-
cmd = cmd.join(' ') if cmd.kind_of?(Array)
|
109
|
-
STDERR.puts "exec failed for '#{cmd}' (#{$!}): #{ex}"
|
110
|
-
end
|
111
|
-
# Should never get here
|
112
|
-
exit!
|
113
|
-
}
|
114
|
-
|
115
|
-
pw[0].close
|
116
|
-
pr[1].close
|
117
|
-
pe[1].close
|
118
|
-
monitor_pipe(:stdout, pr[0])
|
119
|
-
monitor_pipe(map_std_err_to_out ? :stdout : :stderr, pe[0])
|
120
|
-
# Create thread which waits for application to exit
|
121
|
-
Thread.new(id, @pid) do |id, pid|
|
122
|
-
ret = Process.waitpid(pid)
|
123
|
-
status = $?
|
124
|
-
@@all_apps.delete(@id)
|
125
|
-
# app finished
|
126
|
-
if (status == 0) || @clean_exit
|
127
|
-
s = "OK"
|
128
|
-
logger.debug "Application '#{id}' finished"
|
129
|
-
else
|
130
|
-
s = "ERROR"
|
131
|
-
logger.debug "Application '#{id}' failed (code=#{status})"
|
132
|
-
end
|
133
|
-
@observer.on_app_event("DONE.#{s}", @id, "status: #{status}")
|
134
|
-
end
|
135
|
-
@stdin = pw[1]
|
136
|
-
end
|
137
|
-
|
138
|
-
private
|
139
|
-
|
140
|
-
#
|
141
|
-
# Create a thread to monitor the process and its output
|
142
|
-
# and report that back to the server
|
143
|
-
#
|
144
|
-
# @param name Name of app stream to monitor (should be :stdout, :stderr)
|
145
|
-
# @param pipe Pipe to read from
|
146
|
-
#
|
147
|
-
def monitor_pipe(name, pipe)
|
148
|
-
Thread.new() do
|
149
|
-
begin
|
150
|
-
while true do
|
151
|
-
s = pipe.readline.chomp
|
152
|
-
@observer.on_app_event(name.to_s.upcase, @id, s)
|
153
|
-
end
|
154
|
-
rescue EOFError
|
155
|
-
# do nothing
|
156
|
-
rescue Exception => err
|
157
|
-
logger.error "monitorApp(#{@id}): #{err}"
|
158
|
-
ensure
|
159
|
-
pipe.close
|
160
|
-
end
|
161
|
-
end
|
162
|
-
end
|
163
|
-
end
|
1
|
+
#
|
2
|
+
# Copyright (c) 2006-2012 National ICT Australia (NICTA), Australia
|
3
|
+
#
|
4
|
+
# Copyright (c) 2004-2009 WINLAB, Rutgers University, USA
|
5
|
+
#
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
7
|
+
# of this software and associated documentation files (the "Software"), to deal
|
8
|
+
# in the Software without restriction, including without limitation the rights
|
9
|
+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
10
|
+
# copies of the Software, and to permit persons to whom the Software is
|
11
|
+
# furnished to do so, subject to the following conditions:
|
12
|
+
#
|
13
|
+
# The above copyright notice and this permission notice shall be included in
|
14
|
+
# all copies or substantial portions of the Software.
|
15
|
+
#
|
16
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
17
|
+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
18
|
+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
19
|
+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
20
|
+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
21
|
+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
22
|
+
# THE SOFTWARE.
|
23
|
+
#
|
24
|
+
#
|
25
|
+
# Library of client side helpers
|
26
|
+
#
|
27
|
+
require 'fcntl'
|
28
|
+
|
29
|
+
#
|
30
|
+
# Run an application on the client.
|
31
|
+
#
|
32
|
+
# Borrows from Open3
|
33
|
+
#
|
34
|
+
class ExecApp
|
35
|
+
|
36
|
+
# Holds the pids for all active apps
|
37
|
+
@@all_apps = Hash.new
|
38
|
+
|
39
|
+
# True if this active app is being killed by a proper
|
40
|
+
# call to ExecApp.signal_all() or signal()
|
41
|
+
# (i.e. when the caller of ExecApp decided to stop the application,
|
42
|
+
# as far as we are concerned, this is a 'clean' exit)
|
43
|
+
@clean_exit = false
|
44
|
+
|
45
|
+
# Return an application instance based on its ID
|
46
|
+
#
|
47
|
+
# @param [String] id of the application to return
|
48
|
+
def ExecApp.[](id)
|
49
|
+
app = @@all_apps[id]
|
50
|
+
logger.info "Unknown application '#{id}/#{id.class}'" if app.nil?
|
51
|
+
return app
|
52
|
+
end
|
53
|
+
|
54
|
+
def ExecApp.signal_all(signal = 'KILL')
|
55
|
+
@@all_apps.each_value { |app| app.signal(signal) }
|
56
|
+
end
|
57
|
+
|
58
|
+
def stdin(line)
|
59
|
+
logger.debug "Writing '#{line}' to app '#{@id}'"
|
60
|
+
@stdin.write("#{line}\n")
|
61
|
+
@stdin.flush
|
62
|
+
end
|
63
|
+
|
64
|
+
def signal(signal = 'KILL')
|
65
|
+
@clean_exit = true
|
66
|
+
Process.kill(signal, @pid)
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Run an application 'cmd' in a separate thread and monitor
|
71
|
+
# its stdout. Also send status reports to the 'observer' by
|
72
|
+
# calling its "on_app_event(eventType, appId, message")"
|
73
|
+
#
|
74
|
+
# @param id ID of application (used for reporting)
|
75
|
+
# @param observer Observer of application's progress
|
76
|
+
# @param cmd Command path and args
|
77
|
+
# @param map_std_err_to_out If true report stderr as stdin [false]
|
78
|
+
#
|
79
|
+
def initialize(id, observer, cmd, map_std_err_to_out = false)
|
80
|
+
|
81
|
+
@id = id
|
82
|
+
@observer = observer
|
83
|
+
@@all_apps[id] = self
|
84
|
+
|
85
|
+
pw = IO::pipe # pipe[0] for read, pipe[1] for write
|
86
|
+
pr = IO::pipe
|
87
|
+
pe = IO::pipe
|
88
|
+
|
89
|
+
logger.debug "Starting application '#{id}' - cmd: '#{cmd}'"
|
90
|
+
@observer.on_app_event(:STARTED, id, cmd)
|
91
|
+
@pid = fork {
|
92
|
+
# child will remap pipes to std and exec cmd
|
93
|
+
pw[1].close
|
94
|
+
STDIN.reopen(pw[0])
|
95
|
+
pw[0].close
|
96
|
+
|
97
|
+
pr[0].close
|
98
|
+
STDOUT.reopen(pr[1])
|
99
|
+
pr[1].close
|
100
|
+
|
101
|
+
pe[0].close
|
102
|
+
STDERR.reopen(pe[1])
|
103
|
+
pe[1].close
|
104
|
+
|
105
|
+
begin
|
106
|
+
exec(cmd)
|
107
|
+
rescue => ex
|
108
|
+
cmd = cmd.join(' ') if cmd.kind_of?(Array)
|
109
|
+
STDERR.puts "exec failed for '#{cmd}' (#{$!}): #{ex}"
|
110
|
+
end
|
111
|
+
# Should never get here
|
112
|
+
exit!
|
113
|
+
}
|
114
|
+
|
115
|
+
pw[0].close
|
116
|
+
pr[1].close
|
117
|
+
pe[1].close
|
118
|
+
monitor_pipe(:stdout, pr[0])
|
119
|
+
monitor_pipe(map_std_err_to_out ? :stdout : :stderr, pe[0])
|
120
|
+
# Create thread which waits for application to exit
|
121
|
+
Thread.new(id, @pid) do |id, pid|
|
122
|
+
ret = Process.waitpid(pid)
|
123
|
+
status = $?
|
124
|
+
@@all_apps.delete(@id)
|
125
|
+
# app finished
|
126
|
+
if (status == 0) || @clean_exit
|
127
|
+
s = "OK"
|
128
|
+
logger.debug "Application '#{id}' finished"
|
129
|
+
else
|
130
|
+
s = "ERROR"
|
131
|
+
logger.debug "Application '#{id}' failed (code=#{status})"
|
132
|
+
end
|
133
|
+
@observer.on_app_event("DONE.#{s}", @id, "status: #{status}")
|
134
|
+
end
|
135
|
+
@stdin = pw[1]
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
#
|
141
|
+
# Create a thread to monitor the process and its output
|
142
|
+
# and report that back to the server
|
143
|
+
#
|
144
|
+
# @param name Name of app stream to monitor (should be :stdout, :stderr)
|
145
|
+
# @param pipe Pipe to read from
|
146
|
+
#
|
147
|
+
def monitor_pipe(name, pipe)
|
148
|
+
Thread.new() do
|
149
|
+
begin
|
150
|
+
while true do
|
151
|
+
s = pipe.readline.chomp
|
152
|
+
@observer.on_app_event(name.to_s.upcase, @id, s)
|
153
|
+
end
|
154
|
+
rescue EOFError
|
155
|
+
# do nothing
|
156
|
+
rescue Exception => err
|
157
|
+
logger.error "monitorApp(#{@id}): #{err}"
|
158
|
+
ensure
|
159
|
+
pipe.close
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
data/lib/omf_common/message.rb
CHANGED
@@ -4,6 +4,16 @@ require 'securerandom'
|
|
4
4
|
require 'openssl'
|
5
5
|
|
6
6
|
module OmfCommon
|
7
|
+
|
8
|
+
class MPMessage < OML4R::MPBase
|
9
|
+
name :message
|
10
|
+
param :time, :type => :double
|
11
|
+
param :operation, :type => :string
|
12
|
+
param :msg_id, :type => :string
|
13
|
+
param :context_id, :type => :string
|
14
|
+
param :content, :type => :string
|
15
|
+
end
|
16
|
+
|
7
17
|
# Refer to resource life cycle, instance methods are basically construct & parse XML fragment
|
8
18
|
#
|
9
19
|
# @example To create a valid omf message, e.g. a 'configure' message:
|
@@ -17,6 +27,11 @@ module OmfCommon
|
|
17
27
|
OMF_NAMESPACE = "http://schema.mytestbed.net/#{OmfCommon::PROTOCOL_VERSION}/protocol"
|
18
28
|
SCHEMA_FILE = "#{File.dirname(__FILE__)}/protocol/#{OmfCommon::PROTOCOL_VERSION}.rng"
|
19
29
|
OPERATION = %w(create configure request release inform)
|
30
|
+
# When OML instrumentation is enabled, we do not want to send a the same
|
31
|
+
# measurement twice, once when a message is created for publishing to T,
|
32
|
+
# and once when this message comes back (as we are also a subscriber of T)
|
33
|
+
# Thus we keep track of message IDs here (again only when OML is enabled)
|
34
|
+
@@msg_id_list = []
|
20
35
|
|
21
36
|
class << self
|
22
37
|
OPERATION.each do |operation|
|
@@ -35,8 +50,13 @@ module OmfCommon
|
|
35
50
|
end
|
36
51
|
|
37
52
|
def parse(xml)
|
53
|
+
raise ArgumentError, 'Can not parse an empty XML into OMF message' if xml.nil? || xml.empty?
|
38
54
|
xml_root = Nokogiri::XML(xml).root
|
39
|
-
new(xml_root.element_name, nil, xml_root.namespace.href).inherit(xml_root)
|
55
|
+
result = new(xml_root.element_name, nil, xml_root.namespace.href).inherit(xml_root)
|
56
|
+
if OmfCommon::Measure.enabled? && !@@msg_id_list.include?(result.msg_id)
|
57
|
+
MPMessage.inject(Time.now.to_f, result.operation.to_s, result.msg_id, result.context_id, result.to_s.gsub("\n",''))
|
58
|
+
end
|
59
|
+
result
|
40
60
|
end
|
41
61
|
end
|
42
62
|
|
@@ -47,7 +67,7 @@ module OmfCommon
|
|
47
67
|
key_node.write_attr('key', key)
|
48
68
|
|
49
69
|
unless value.nil?
|
50
|
-
key_node.write_attr('type', value.class
|
70
|
+
key_node.write_attr('type', ruby_type_2_prop_type(value.class))
|
51
71
|
c_node = value_node_set(value)
|
52
72
|
|
53
73
|
if c_node.class == Array
|
@@ -66,7 +86,7 @@ module OmfCommon
|
|
66
86
|
[].tap do |array|
|
67
87
|
value.each_pair do |k, v|
|
68
88
|
n = Message.new(k)
|
69
|
-
n.write_attr('type', v.class
|
89
|
+
n.write_attr('type', ruby_type_2_prop_type(v.class))
|
70
90
|
|
71
91
|
c_node = value_node_set(v, k)
|
72
92
|
if c_node.class == Array
|
@@ -80,7 +100,7 @@ module OmfCommon
|
|
80
100
|
when Array
|
81
101
|
value.map do |v|
|
82
102
|
n = Message.new('item')
|
83
|
-
n.write_attr('type', v.class
|
103
|
+
n.write_attr('type', ruby_type_2_prop_type(v.class))
|
84
104
|
|
85
105
|
c_node = value_node_set(v, 'item')
|
86
106
|
if c_node.class == Array
|
@@ -104,9 +124,20 @@ module OmfCommon
|
|
104
124
|
#
|
105
125
|
def sign
|
106
126
|
write_attr('msg_id', OpenSSL::Digest::SHA1.new(canonicalize)) if read_attr('id').nil? || read_attr('id').empty?
|
127
|
+
if OmfCommon::Measure.enabled?
|
128
|
+
MPMessage.inject(Time.now.to_f, operation.to_s, msg_id, context_id, self.to_s.gsub("\n",''))
|
129
|
+
@@msg_id_list << msg_id
|
130
|
+
end
|
107
131
|
self
|
108
132
|
end
|
109
133
|
|
134
|
+
# param :time, :type => :int32
|
135
|
+
# param :operation, :type => :string
|
136
|
+
# param :msg_id, :type => :string
|
137
|
+
# param :context_id, :type => :string
|
138
|
+
# param :content, :type => :string
|
139
|
+
|
140
|
+
|
110
141
|
# Validate against relaxng schema
|
111
142
|
#
|
112
143
|
def valid?
|
@@ -151,7 +182,11 @@ module OmfCommon
|
|
151
182
|
#
|
152
183
|
def read_content(element_name)
|
153
184
|
element_content = read_element("//#{element_name}").first.content rescue nil
|
154
|
-
element_content.
|
185
|
+
unless element_content.nil?
|
186
|
+
element_content.empty? ? nil : element_content
|
187
|
+
else
|
188
|
+
nil
|
189
|
+
end
|
155
190
|
end
|
156
191
|
|
157
192
|
# Context ID will be requested quite often
|
@@ -164,6 +199,14 @@ module OmfCommon
|
|
164
199
|
read_property(:resource_id) || read_content(:resource_id)
|
165
200
|
end
|
166
201
|
|
202
|
+
def publish_to
|
203
|
+
read_property(:publish_to) || read_content(:publish_to)
|
204
|
+
end
|
205
|
+
|
206
|
+
def msg_id
|
207
|
+
read_attr('msg_id')
|
208
|
+
end
|
209
|
+
|
167
210
|
# Get a property by key
|
168
211
|
#
|
169
212
|
# @param [String] key name of the property element
|
@@ -178,17 +221,17 @@ module OmfCommon
|
|
178
221
|
def reconstruct_data(node)
|
179
222
|
case node.attr('type')
|
180
223
|
when 'array'
|
181
|
-
|
182
|
-
mash[:items] = node.element_children.map do |child|
|
224
|
+
node.element_children.map do |child|
|
183
225
|
reconstruct_data(child)
|
184
226
|
end
|
185
|
-
mash
|
186
227
|
when /hash/
|
187
228
|
mash ||= Hashie::Mash.new
|
188
229
|
node.element_children.each do |child|
|
189
230
|
mash[child.attr('key') || child.element_name] ||= reconstruct_data(child)
|
190
231
|
end
|
191
232
|
mash
|
233
|
+
when /boolean/
|
234
|
+
node.content == "true"
|
192
235
|
else
|
193
236
|
node.content.empty? ? nil : node.content.ducktype
|
194
237
|
end
|
@@ -205,5 +248,16 @@ module OmfCommon
|
|
205
248
|
def print_app_event
|
206
249
|
"APP_EVENT (#{read_property(:app)}, ##{read_property(:seq)}, #{read_property(:event)}): #{read_property(:msg)}"
|
207
250
|
end
|
251
|
+
|
252
|
+
private
|
253
|
+
|
254
|
+
def ruby_type_2_prop_type(ruby_class_type)
|
255
|
+
v_type = ruby_class_type.to_s.downcase
|
256
|
+
if %w(trueclass falseclass).include?(v_type)
|
257
|
+
'boolean'
|
258
|
+
else
|
259
|
+
v_type
|
260
|
+
end
|
261
|
+
end
|
208
262
|
end
|
209
263
|
end
|
data/lib/omf_common/topic.rb
CHANGED
data/lib/omf_common/version.rb
CHANGED
data/omf_common.gemspec
CHANGED
@@ -68,22 +68,25 @@ describe OmfCommon::Message do
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
describe "
|
72
|
-
it "must
|
71
|
+
describe "when asked to parse a XML element into Message object" do
|
72
|
+
it "must create the message object correctly " do
|
73
73
|
xml = Message.create do |m|
|
74
74
|
m.property('type', 'vm')
|
75
75
|
m.property('os', 'debian')
|
76
76
|
m.property('memory', { value: 1024, unit: 'mb', precision: 0 })
|
77
77
|
m.property('devices', [{ name: 'w0', driver: 'mod_bob'}, { name: 'w1', driver: ['mod1', 'mod2']} ])
|
78
|
+
m.property('true', true)
|
79
|
+
m.property('false', false)
|
80
|
+
m.property('boolean_array', [false, true])
|
78
81
|
end.canonicalize
|
79
82
|
|
80
83
|
message = Message.parse(xml)
|
81
84
|
|
82
85
|
message.must_be_kind_of Message
|
83
86
|
message.operation.must_equal :create
|
84
|
-
message.read_element("//property").size.must_equal
|
87
|
+
message.read_element("//property").size.must_equal 7
|
85
88
|
message.read_content("unit").must_equal 'mb'
|
86
|
-
message.read_element("/create/property").size.must_equal
|
89
|
+
message.read_element("/create/property").size.must_equal 7
|
87
90
|
message.read_property("type").must_equal 'vm'
|
88
91
|
message.read_property(:type).must_equal 'vm'
|
89
92
|
|
@@ -94,13 +97,22 @@ describe OmfCommon::Message do
|
|
94
97
|
memory.precision.must_equal 0
|
95
98
|
|
96
99
|
devices = message.read_property(:devices)
|
97
|
-
devices.
|
98
|
-
devices.
|
99
|
-
devices.
|
100
|
+
devices.must_be_kind_of Array
|
101
|
+
devices.size.must_equal 2
|
102
|
+
devices.find { |v| v.name == 'w1'}.driver.size.must_equal 2
|
100
103
|
# Each property iterator
|
101
104
|
message.each_property do |v|
|
102
|
-
%w(type os memory devices).must_include v.attr('key')
|
105
|
+
%w(type os memory devices true false boolean_array).must_include v.attr('key')
|
103
106
|
end
|
107
|
+
|
108
|
+
message.read_property(:true).must_equal true
|
109
|
+
message.read_property(:false).must_equal false
|
110
|
+
message.read_property('boolean_array').must_equal [false, true]
|
111
|
+
end
|
112
|
+
|
113
|
+
it "must fail if parse an empty xml" do
|
114
|
+
lambda { Message.parse("") }.must_raise ArgumentError
|
115
|
+
lambda { Message.parse(nil) }.must_raise ArgumentError
|
104
116
|
end
|
105
117
|
end
|
106
118
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omf_common
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.0.0.pre.
|
4
|
+
version: 6.0.0.pre.8
|
5
5
|
prerelease: 6
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-10-
|
12
|
+
date: 2012-10-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
@@ -123,6 +123,22 @@ dependencies:
|
|
123
123
|
- - ~>
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: 1.2.0
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: oml4r
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 2.8.0
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 2.8.0
|
126
142
|
description: Common library of OMF, a generic framework for controlling and managing
|
127
143
|
networking testbeds.
|
128
144
|
email:
|
@@ -140,7 +156,9 @@ files:
|
|
140
156
|
- lib/omf_common/core_ext/object.rb
|
141
157
|
- lib/omf_common/core_ext/string.rb
|
142
158
|
- lib/omf_common/dsl/xmpp.rb
|
159
|
+
- lib/omf_common/dsl/xmpp_mp.rb
|
143
160
|
- lib/omf_common/exec_app.rb
|
161
|
+
- lib/omf_common/measure.rb
|
144
162
|
- lib/omf_common/message.rb
|
145
163
|
- lib/omf_common/protocol/6.0.rnc
|
146
164
|
- lib/omf_common/protocol/6.0.rng
|
@@ -182,4 +200,3 @@ signing_key:
|
|
182
200
|
specification_version: 3
|
183
201
|
summary: Common library of OMF
|
184
202
|
test_files: []
|
185
|
-
has_rdoc:
|