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

Sign up to get free protection for your applications and to get access to all the features.
@@ -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