omf_common 6.0.0.pre.7 → 6.0.0.pre.8
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|