omf_ec 6.0.0.pre.4 → 6.0.0.pre.5

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.
@@ -22,51 +22,19 @@ module OmfEc
22
22
  end
23
23
  end
24
24
 
25
- def defApplication(uri,name,&block)
25
+ def defApplication(uri, name=nil ,&block)
26
26
  # URI parameter was used by previous OMF5 EC, for now we
27
27
  # do nothing with it in OMF6
28
+ name = uri if name.nil?
28
29
  def_application(name,&block)
29
30
  end
30
31
 
31
32
  def defGroup(name, *members, &block)
32
33
  group = OmfEc::Group.new(name)
33
- OmfEc.exp.groups << group
34
-
35
- members.each do |m|
36
- m_group = OmfEc.exp.groups.find { |v| v.name == m }
37
- if m_group
38
- group.members += m_group.members
39
- else
40
- group.members << m
41
- end
42
- end
34
+ OmfEc.experiment.add_group(group)
35
+ group.add_resource(*members)
43
36
 
44
37
  block.call(group) if block
45
-
46
- OmfEc.comm.subscribe(group.id, create_if_non_existent: true) do |m|
47
- unless m.error?
48
- members.each do |m|
49
- group.add_resource(m)
50
- end
51
-
52
- rg = OmfEc.comm.get_topic(group.id)
53
-
54
- rg.on_message lambda {|m| m.operation == :inform && m.read_content('inform_type') == 'FAILED' && m.context_id.nil? } do |i|
55
- warn "RC reports failure: '#{i.read_content("reason")}'"
56
- end
57
-
58
- rg.on_message lambda {|m| m.operation == :inform && m.read_content('inform_type') == 'STATUS' && m.context_id.nil? } do |i|
59
- r = OmfEc.exp.state.find { |v| v[:uid] == i.read_property(:uid) }
60
- unless r.nil?
61
- i.each_property do |p|
62
- key = p.attr('key').to_sym
63
- r[key] = i.read_property(key)
64
- end
65
- end
66
- Experiment.instance.process_events
67
- end
68
- end
69
- end
70
38
  end
71
39
 
72
40
  # Wait for some time before issuing more commands
@@ -1,4 +1,4 @@
1
- comm = OmfEc.comm
1
+ comm = OmfCommon.comm
2
2
 
3
3
  testbed_topic = comm.get_topic('testbed')
4
4
 
@@ -6,11 +6,11 @@ msgs = {
6
6
  create: comm.create_message([type: 'application']),
7
7
  req_platform: comm.request_message([:platform]),
8
8
  conf_path: comm.configure_message([binary_path: @cmd]),
9
- run_application: comm.configure_message([state: :run])
9
+ run_application: comm.configure_message([state: :running])
10
10
  }
11
11
 
12
- msgs[:create].on_inform_created do |message|
13
- app_topic = comm.get_topic(message.resource_id)
12
+ msgs[:create].on_inform_creation_ok do |message|
13
+ app_topic = comm.get_topic(message.res_id)
14
14
  app_topic.subscribe do
15
15
  msgs[:req_platform].publish app_topic.id
16
16
  sleep 1
@@ -21,16 +21,16 @@ msgs[:create].on_inform_created do |message|
21
21
 
22
22
  app_topic.on_message do |m|
23
23
  if m.operation == :inform
24
- case m.read_content("inform_type")
24
+ case m.read_content("itype")
25
25
  when 'STATUS'
26
26
  if m.read_property("status_type") == 'APP_EVENT'
27
27
  after (2) { comm.disconnect } if m.read_property("event") =~ /DONE.(OK|ERROR)/
28
28
  puts m.read_property("msg")
29
29
  end
30
30
  when 'ERROR'
31
- logger.error m.read_content('reason') if m.read_content("inform_type") == 'ERROR'
31
+ logger.error m.read_content('reason') if m.read_content("itype") == 'ERROR'
32
32
  when 'WARN'
33
- logger.warn m.read_content('reason') if m.read_content("inform_type") == 'WARN'
33
+ logger.warn m.read_content('reason') if m.read_content("itype") == 'WARN'
34
34
  end
35
35
  end
36
36
  end
@@ -5,6 +5,10 @@ module OmfEc
5
5
  module Group
6
6
  # The following are ODEL 5 methods
7
7
 
8
+ def resource_group(type)
9
+ "#{self.id}_#{type.to_s}"
10
+ end
11
+
8
12
  # Create an application for the group and start it
9
13
  #
10
14
  def exec(name)
@@ -14,25 +18,35 @@ module OmfEc
14
18
 
15
19
  e_name = "#{self.name}_application_#{name}_created_#{e_uid}"
16
20
 
21
+ resource_group_name = "#{self.id}_application"
22
+
17
23
  def_event e_name do |state|
18
- state.find_all { |v| v[:hrn] == name }.size >= self.members.uniq.size
24
+ state.find_all { |v| v[:hrn] == name && v[:membership] && v[:membership].include?(resource_group_name)}.size >= self.members.uniq.size
19
25
  end
20
26
 
21
27
  on_event e_name do
22
- resources[type: 'application', name: name].state = :run
28
+ resources[type: 'application', name: name].state = :running
23
29
  end
24
30
  end
25
31
 
26
32
  def startApplications
27
- resources[type: 'application'].state = :run
33
+ if self.app_contexts.empty?
34
+ warn "No applications defined in group #{self.name}. Nothing to start"
35
+ else
36
+ resources[type: 'application'].state = :running
37
+ end
28
38
  end
29
39
 
30
40
  def stopApplications
31
- resources[type: 'application'].state = :stop
41
+ if self.app_contexts.empty?
42
+ warn "No applications defined in group #{self.name}. Nothing to stop"
43
+ else
44
+ resources[type: 'application'].state = :stopped
45
+ end
32
46
  end
33
47
 
34
48
  def addApplication(name, &block)
35
- app_cxt = OmfEc::Context::AppContext.new(name)
49
+ app_cxt = OmfEc::Context::AppContext.new(name,self)
36
50
  block.call(app_cxt) if block
37
51
  self.app_contexts << app_cxt
38
52
  end
@@ -49,16 +63,16 @@ module OmfEc
49
63
 
50
64
  def method_missing(name, *args, &block)
51
65
  if name =~ /w(\d+)/
52
- net = self.net_ifs.find { |v| v.conf[:hrn] == "wlan#{$1}" }
66
+ net = self.net_ifs.find { |v| v.conf[:if_name] == "wlan#{$1}" }
53
67
  if net.nil?
54
- net = OmfEc::Context::NetContext.new(:type => 'wlan', :hrn => "wlan#{$1}", :index => $1)
68
+ net = OmfEc::Context::NetContext.new(:type => 'wlan', :if_name => "wlan#{$1}", :index => $1)
55
69
  self.net_ifs << net
56
70
  end
57
71
  net
58
72
  elsif name =~ /e(\d+)/
59
- net = self.net_ifs.find { |v| v.conf[:hrn] == "eth#{$1}" }
73
+ net = self.net_ifs.find { |v| v.conf[:if_name] == "eth#{$1}" }
60
74
  if net.nil?
61
- net = OmfEc::Context::NetContext.new(:type => 'net', :hrn => "eth#{$1}", :index => $1)
75
+ net = OmfEc::Context::NetContext.new(:type => 'net', :if_name => "eth#{$1}", :index => $1)
62
76
  self.net_ifs << net
63
77
  end
64
78
  net
@@ -8,44 +8,75 @@ module OmfEc::Context
8
8
  # values for each. Thus we need to distinguish these different context
9
9
  @@context_count = Hash.new
10
10
 
11
- def initialize(name)
12
- if OmfEc.exp.app_definitions.key?(name)
13
- self.app_def = OmfEc.exp.app_definitions[name]
11
+ def initialize(name, group)
12
+ if OmfEc.experiment.app_definitions.key?(name)
13
+ self.app_def = OmfEc.experiment.app_definitions[name]
14
14
  self.param_values = Hash.new
15
15
  self.oml_collections = Array.new
16
16
  @@context_count[name] = 0 unless @@context_count.key?(name)
17
17
  id = @@context_count[name]
18
18
  @@context_count[name] += 1
19
19
  self.name = "#{name}_cxt_#{id}"
20
+ @group = group
20
21
  self
21
22
  else
22
23
  raise RuntimeError, "Cannot create context for unknwon application '#{name}'"
23
24
  end
24
25
  end
25
26
 
26
- def setProperty(key, value)
27
- @param_values[key] = value
27
+ def setProperty(key, property_value)
28
+ app_def_param = app_def.properties.parameters
29
+ raise OEDLUnknownProperty.new(key, "Unknown parameter '#{key}' for application "+
30
+ "definition '#{app_def.name}'") if app_def_param.nil? || !app_def_param.key?(key)
31
+ if property_value.kind_of?(ExperimentProperty)
32
+ @param_values[key] = property_value.value
33
+ # if this app parameter has its dynamic attribute set to true, then
34
+ # we register a callback block to the ExperimentProperty, which will
35
+ # be called each time the property changes its value
36
+ if app_def_param[key][:dynamic]
37
+ info "Binding dynamic parameter '#{key}' to the property '#{property_value.name}'"
38
+ property_value.on_change do |new_value|
39
+ info "Updating dynamic app parameter '#{key}' with value: '#{new_value}'"
40
+ OmfEc.subscribe_and_monitor(@group.resource_group(:application)) do |topic|
41
+ p = properties
42
+ p[:parameters][key.to_sym][:value] = property_value.value
43
+ topic.configure(p, { guard: { hrn: @name} } )
44
+ end
45
+ end
46
+ end
47
+ else
48
+ @param_values[key] = property_value
49
+ end
28
50
  self
29
51
  end
30
52
 
31
53
  # For now this follows v5.4 syntax...
32
54
  # We have not yet finalised an OML syntax inside OEDL for v6
33
55
  def measure(mp,filters)
34
- collection = {:url => OmfEc.exp.oml_uri, :streams => [] }
56
+ collection = {:url => OmfEc.experiment.oml_uri, :streams => [] }
35
57
  stream = { :mp => mp , :filters => [] }.merge(filters)
36
58
  collection[:streams] << stream
37
59
  @oml_collections << collection
38
60
  end
39
61
 
40
62
  def properties
41
- # deep copy the properties from the our app definition
63
+ # deep copy the properties from the app definition
42
64
  original = Marshal.load(Marshal.dump(app_def.properties))
65
+ # now build the properties for this context
66
+ # - use the properties from app definition as the base
67
+ # - if this context's param_values has a property which also exists in
68
+ # the app def and if that property has an assigned value, then
69
+ # use that value for the properties of this context
43
70
  p = original.merge({:type => 'application'})
44
- @param_values.each { |k,v| p[:parameters][k][:value] = v if p[:parameters].key?(k) }
71
+ @param_values.each do |k,v|
72
+ if p[:parameters].key?(k)
73
+ p[:parameters][k][:value] = v.kind_of?(ExperimentProperty) ? v.value : v
74
+ end
75
+ end
45
76
  if @oml_collections.size > 0
46
77
  p[:use_oml] = true
47
78
  p[:oml][:id] = @name
48
- p[:oml][:experiment] = OmfEc.exp.id
79
+ p[:oml][:experiment] = OmfEc.experiment.id
49
80
  p[:oml][:collection] = @oml_collections
50
81
  end
51
82
  p
@@ -28,60 +28,31 @@ module OmfEc::Context
28
28
  end
29
29
 
30
30
  def send_message(name, value = nil, &block)
31
- send_to = self.group
32
- send_to = send_to + "_#{self.guard[:type]}" if self.guard[:type]
33
-
34
- # if release, we need to request resource ids first
35
- op_name = self.operation == :release ? "request_message" : "#{self.operation}_message"
36
-
37
- o_m = OmfEc.comm.__send__(op_name, send_to) do |m|
38
- m.element(:guard) do |g|
39
- self.guard.each_pair do |k, v|
40
- g.property(k, v)
41
- end
42
- end
43
-
44
- unless self.operation == :release
45
- m.property(name, value)
46
- end
47
-
48
- unless self.operation == :configure
49
- m.property(:uid)
50
- m.property(:hrn)
51
- end
31
+ if self.guard[:type]
32
+ topic = self.group.resource_topic(self.guard[:type])
33
+ else
34
+ topic = self.group.topic
52
35
  end
53
36
 
54
- o_m.publish send_to
55
-
56
- o_m.on_inform_status do |i|
57
- if self.operation == :release
58
- uid = i.read_property(:uid)
59
- info "Going to release #{uid}"
60
- release_m = OmfEc.comm.release_message(self.group) { |m| m.element('resource_id', uid) }
61
-
62
- release_m.publish self.group
63
-
64
- release_m.on_inform_released do |m|
65
- info "#{m.resource_id} released"
66
- r = OmfEc.exp.state.find { |v| v[:uid] == m.resource_id }
67
- r[:released] = true unless r.nil?
68
- block.call if block
69
- Experiment.instance.process_events
37
+ case self.operation
38
+ when :configure
39
+ topic.configure({ name => value }, { guard: self.guard })
40
+ when :request
41
+ topic.request([:uid, :hrn, name], { guard: self.guard })
42
+ when :release
43
+ topics_to_release = OmfEc.experiment.state.find_all do |res_state|
44
+ all_equal(self.guard.keys) do |k|
45
+ res_state[k] == self.guard[k]
70
46
  end
71
47
  end
72
48
 
73
- r = OmfEc.exp.state.find { |v| v[:uid] == i.read_property(:uid) }
74
- unless r.nil?
75
- i.each_property do |p|
76
- p_key = p.attr('key').to_sym
77
- r[p_key] = i.read_property(p_key)
49
+ topics_to_release.each do |res_state|
50
+ OmfEc.subscribe_and_monitor(res_state.uid) do |child_topic|
51
+ OmfEc.subscribe_and_monitor(self.group.id) do |group_topic|
52
+ group_topic.release(child_topic) if child_topic
53
+ end
78
54
  end
79
55
  end
80
- Experiment.instance.process_events
81
- end
82
-
83
- o_m.on_inform_failed do |i|
84
- warn "RC reports failure: '#{i.read_content("reason")}'"
85
56
  end
86
57
  end
87
58
  end
@@ -27,7 +27,7 @@ module OmfEc::Context
27
27
  else
28
28
  net_prop
29
29
  end
30
- self.conf.merge!(net_prop => args[0])
30
+ self.conf.merge!(net_prop => args[0].to_s)
31
31
  else
32
32
  super
33
33
  end
@@ -35,10 +35,10 @@ module OmfEc::Context
35
35
 
36
36
  def map_channel_freq
37
37
  if self.conf[:channel] && self.conf[:frequency].nil?
38
- self.conf[:frequency] = FREQUENCY[self.conf[:channel].to_i]
38
+ self.conf[:frequency] = FREQUENCY[self.conf[:channel].to_s.to_i]
39
39
  end
40
40
  if self.conf[:channel].nil? && self.conf[:frequency]
41
- self.conf[:channel] = FREQUENCY.keys.find { |k| FREQUENCY[k] == self.conf[:frequency].to_i }
41
+ self.conf[:channel] = FREQUENCY.keys.find { |k| FREQUENCY[k] == self.conf[:frequency].to_sto_i }
42
42
  end
43
43
  self
44
44
  end
data/lib/omf_ec/dsl.rb CHANGED
@@ -4,13 +4,49 @@ require 'eventmachine'
4
4
  module OmfEc
5
5
  # DSL methods to be used for OEDL scripts
6
6
  module DSL
7
+
8
+ # Define OEDL-specific exceptions. These are the Exceptions that might be
9
+ # raised when the OMF EC is processing an OEDL experiment scripts
10
+ #
11
+ # The base exception is OEDLException
12
+ class OEDLException < Exception; end
13
+
14
+ class OEDLArgumentException < OEDLException
15
+ attr_reader :cmd, :arg
16
+ def initialize(cmd, arg, msg = nil)
17
+ @cmd = cmd
18
+ @arg = arg
19
+ msg ||= "Illegal value for argument '#{arg}' in command '#{cmd}'"
20
+ super(msg)
21
+ end
22
+ end
23
+
24
+ class OEDLCommandException < OEDLException
25
+ attr_reader :cmd
26
+ def initialize(cmd, msg = nil)
27
+ @cmd = cmd
28
+ msg ||= "Illegal command '#{cmd}' unsupported by OEDL"
29
+ super(msg)
30
+ end
31
+ end
32
+
33
+ class OEDLUnknownProperty < OEDLException
34
+ attr_reader :cmd
35
+ def initialize(name, msg = nil)
36
+ @name = name
37
+ msg ||= "Unknown property '#{name}', not previously defined in your OEDL experiment"
38
+ super(msg)
39
+ end
40
+ end
41
+
42
+
7
43
  # Use EM timer to execute after certain time
8
44
  #
9
45
  # @example do something after 2 seconds
10
46
  #
11
47
  # after 2.seconds { 'do something' }
12
48
  def after(time, &block)
13
- OmfEc.comm.add_timer(time, block)
49
+ OmfCommon.eventloop.after(time, &block)
14
50
  end
15
51
 
16
52
  # Use EM periodic timer to execute after certain time
@@ -19,12 +55,12 @@ module OmfEc
19
55
  #
20
56
  # every 2.seconds { 'do something' }
21
57
  def every(time, &block)
22
- OmfEc.comm.add_periodic_timer(time, block)
58
+ OmfCommon.eventloop.every(time, &block)
23
59
  end
24
60
 
25
61
  def def_application(name,&block)
26
62
  app_def = OmfEc::AppDefinition.new(name)
27
- OmfEc.exp.app_definitions[name] = app_def
63
+ OmfEc.experiment.app_definitions[name] = app_def
28
64
  block.call(app_def) if block
29
65
  end
30
66
 
@@ -39,47 +75,29 @@ module OmfEc
39
75
  #
40
76
  # @see OmfEc::Backward::DSL#defGroup
41
77
  def def_group(name, &block)
42
- group = OmfEc::Group.new(name)
43
- OmfEc.exp.groups << group
44
-
45
- OmfEc.comm.subscribe(group.id, create_if_non_existent: true) do |m|
46
- unless m.error?
47
- block.call group if block
48
-
49
- rg = OmfEc.comm.get_topic(group.id)
50
-
51
- rg.on_message lambda {|m| m.operation == :inform && m.read_content('inform_type') == 'FAILED' && m.context_id.nil? } do |i|
52
- warn "RC reports failure: '#{i.read_content("reason")}'"
53
- end
54
-
55
- rg.on_message lambda {|m| m.operation == :inform && m.read_content('inform_type') == 'STATUS' && m.context_id.nil? } do |i|
56
- r = OmfEc.exp.state.find { |v| v[:uid] == i.read_property(:uid) }
57
- unless r.nil?
58
- i.each_property do |p|
59
- key = p.attr('key').to_sym
60
- r[key] = i.read_property(key)
61
- end
62
- end
63
- Experiment.instance.process_events
64
- end
65
- end
66
- end
78
+ group = OmfEc::Group.new(name, &block)
79
+ OmfEc.experiment.add_group(group)
80
+ group
67
81
  end
68
82
 
69
83
  # Get a group instance
70
84
  #
71
85
  # @param [String] name name of the group
72
86
  def group(name, &block)
73
- group = OmfEc.exp.groups.find {|v| v.name == name}
87
+ group = OmfEc.experiment.group(name)
88
+ raise RuntimeError, "Group #{name} not found" if group.nil?
89
+
74
90
  block.call(group) if block
75
91
  group
76
92
  end
77
93
 
78
94
  # Iterator for all defined groups
79
95
  def all_groups(&block)
80
- OmfEc.exp.groups.each do |g|
81
- block.call(g) if block
82
- end
96
+ OmfEc.experiment.each_group(&block)
97
+ end
98
+
99
+ def all_groups?(&block)
100
+ OmfEc.experiment.all_groups?(&block)
83
101
  end
84
102
 
85
103
  alias_method :all_nodes!, :all_groups
@@ -103,12 +121,12 @@ module OmfEc
103
121
  # @param description short text description of this property
104
122
  #
105
123
  def def_property(name, default_value, description = nil)
106
- OmfEc.exp.property[name] ||= default_value
124
+ OmfEc.experiment.add_property(name, default_value, description)
107
125
  end
108
126
 
109
127
  # Return the context for setting experiment wide properties
110
128
  def property
111
- OmfEc.exp.property
129
+ return OmfEc.experiment.property
112
130
  end
113
131
 
114
132
  alias_method :prop, :property
@@ -135,16 +153,13 @@ module OmfEc
135
153
 
136
154
  # Define an event
137
155
  def def_event(name, &trigger)
138
- if OmfEc.exp.events.find { |v| v[:name] == name }
139
- raise RuntimeError, "Event '#{name}' has been defined"
140
- else
141
- OmfEc.exp.events << { name: name, trigger: trigger }
142
- end
156
+ raise ArgumentError, 'Need a trigger callback' if trigger.nil?
157
+ OmfEc.experiment.add_event(name, trigger)
143
158
  end
144
159
 
145
160
  # Define an event callback
146
161
  def on_event(name, consume_event = true, &callback)
147
- event = OmfEc.exp.events.find { |v| v[:name] == name }
162
+ event = OmfEc.experiment.event(name)
148
163
  if event.nil?
149
164
  raise RuntimeError, "Event '#{name}' not defined"
150
165
  else
@@ -1,5 +1,6 @@
1
1
  require 'hashie'
2
2
  require 'singleton'
3
+ require 'monitor'
3
4
 
4
5
  module OmfEc
5
6
  # Experiment class to hold relevant state information
@@ -7,17 +8,112 @@ module OmfEc
7
8
  class Experiment
8
9
  include Singleton
9
10
 
10
- attr_accessor :property,:state, :comm, :groups, :events, :name, :app_definitions, :sub_groups, :oml_uri
11
+ include MonitorMixin
12
+
13
+ attr_accessor :name, :oml_uri, :app_definitions, :property, :cmdline_properties
14
+ attr_reader :groups, :sub_groups, :state
11
15
 
12
16
  def initialize
13
17
  @id = Time.now.utc.iso8601
14
- self.property ||= Hashie::Mash.new
15
- self.comm ||= OmfCommon::Comm.new(:xmpp)
16
- self.state ||= []
17
- self.groups ||= []
18
- self.events ||= []
19
- self.app_definitions ||= Hash.new
20
- self.sub_groups ||= []
18
+ @state ||= [] #TODO: we need to keep history of all the events and not ovewrite them
19
+ @groups ||= []
20
+ @events ||= []
21
+ @app_definitions ||= Hash.new
22
+ @sub_groups ||= []
23
+ @cmdline_properties ||= Hash.new
24
+ super
25
+ end
26
+
27
+ def property
28
+ return ExperimentProperty
29
+ end
30
+
31
+ def add_property(name, value = nil, description = nil)
32
+ override_value = @cmdline_properties[name.to_s.to_sym]
33
+ value = override_value unless override_value.nil?
34
+ ExperimentProperty.create(name, value, description)
35
+ end
36
+
37
+ def resource_state(id)
38
+ @state.find { |v| v[:uid].to_s == id.to_s }
39
+ end
40
+
41
+ alias_method :resource, :resource_state
42
+
43
+ def resource_by_hrn(hrn)
44
+ @state.find { |v| v[:hrn].to_s == hrn.to_s }
45
+ end
46
+
47
+ def add_or_update_resource_state(name, opts = {})
48
+ self.synchronize do
49
+ res = resource_state(name)
50
+ if res
51
+ opts.each do |key, value|
52
+ if value.class == Array
53
+ # Merge array values
54
+ res[key] ||= []
55
+ res[key] += value
56
+ res[key].uniq!
57
+ elsif value.kind_of? Hash
58
+ # Merge hash values
59
+ res[key] ||= {}
60
+ res[key].merge(value)
61
+ else
62
+ # Overwrite otherwise
63
+ res[key] = value
64
+ end
65
+ end
66
+ else
67
+ info "Newly discovered resource >> #{opts[:uid]}"
68
+ @state << Hashie::Mash.new({ uid: name }.merge(opts))
69
+ end
70
+ end
71
+ end
72
+
73
+ alias_method :add_resource, :add_or_update_resource_state
74
+
75
+ def sub_group(name)
76
+ @sub_groups.find { |v| v == name }
77
+ end
78
+
79
+ def add_sub_group(name)
80
+ self.synchronize do
81
+ @sub_groups << name unless @sub_groups.include?(name)
82
+ end
83
+ end
84
+
85
+ def group(name)
86
+ groups.find { |v| v.name == name }
87
+ end
88
+
89
+ def add_group(group)
90
+ self.synchronize do
91
+ raise ArgumentError, "Expect Group object, got #{group.inspect}" unless group.kind_of? OmfEc::Group
92
+ @groups << group unless group(group.name)
93
+ end
94
+ end
95
+
96
+ def each_group(&block)
97
+ if block
98
+ groups.each { |g| block.call(g) }
99
+ else
100
+ groups
101
+ end
102
+ end
103
+
104
+ def all_groups?(&block)
105
+ !groups.empty? && groups.all? { |g| block ? block.call(g) : g }
106
+ end
107
+
108
+ def event(name)
109
+ @events.find { |v| v[:name] == name }
110
+ end
111
+
112
+ def add_event(name, trigger)
113
+ self.synchronize do
114
+ raise RuntimeError, "Event '#{name}' has been defined" if event(name)
115
+ @events << { name: name, trigger: trigger }
116
+ end
21
117
  end
22
118
 
23
119
  # Unique experiment id
@@ -27,11 +123,11 @@ module OmfEc
27
123
 
28
124
  # Parsing user defined events, checking conditions against internal state, and execute callbacks if triggered
29
125
  def process_events
30
- EM.next_tick do
31
- self.events.find_all { |v| v[:callbacks] && !v[:callbacks].empty? }.each do |event|
32
- if event[:trigger].call(self.state)
126
+ self.synchronize do
127
+ @events.find_all { |v| v[:callbacks] && !v[:callbacks].empty? }.each do |event|
128
+ if event[:trigger].call(@state)
33
129
  info "Event triggered: '#{event[:name]}'"
34
- self.events.delete(event) if event[:consume_event]
130
+ @events.delete(event) if event[:consume_event]
35
131
 
36
132
  # Last in first serve callbacks
37
133
  event[:callbacks].reverse.each do |callback|
@@ -46,9 +142,9 @@ module OmfEc
46
142
  class << self
47
143
  # Disconnect communicator, try to delete any XMPP affiliations
48
144
  def done
49
- info "Exit in up to 20 seconds..."
145
+ info "Exit in up to 15 seconds..."
50
146
 
51
- OmfEc.comm.add_timer(10) do
147
+ OmfCommon.eventloop.after(10) do
52
148
  info "Release applications and network interfaces"
53
149
 
54
150
  allGroups do |g|
@@ -57,12 +153,8 @@ module OmfEc
57
153
  g.resources[type: 'wlan'].release unless g.net_ifs.find_all { |v| v.conf[:type] == 'wlan' }.empty?
58
154
  end
59
155
 
60
- OmfEc.comm.add_timer(5) do
61
- OmfEc.comm.disconnect(delete_affiliations: true)
62
-
63
- OmfEc.comm.add_timer(5) do
64
- OmfEc.comm.disconnect
65
- end
156
+ OmfCommon.eventloop.after(5) do
157
+ OmfCommon.comm.disconnect
66
158
  end
67
159
  end
68
160
  end