omf_ec 6.0.0.pre.3 → 6.0.0.pre.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/Rakefile +1 -0
  2. data/bin/omf_ec +264 -0
  3. data/example/engine_oedl.rb +52 -0
  4. data/example/engine_test.rb +90 -0
  5. data/example/test_exp/test00.rb +12 -0
  6. data/example/test_exp/test01.rb +22 -0
  7. data/example/test_exp/test02.rb +30 -0
  8. data/{exp_repo/test/exp → example/test_exp}/test03.rb +2 -42
  9. data/{exp_repo/test/exp → example/test_exp}/test04.rb +2 -2
  10. data/{exp_repo/test/exp → example/test_exp}/test05.rb +4 -4
  11. data/{exp_repo/test/exp → example/test_exp}/test06.rb +6 -6
  12. data/example/test_exp/test07.rb +65 -0
  13. data/lib/omf_ec/app_definition.rb +57 -0
  14. data/lib/omf_ec/backward/app_definition.rb +35 -0
  15. data/lib/omf_ec/backward/core_ext/array.rb +19 -0
  16. data/lib/omf_ec/backward/default_events.rb +71 -0
  17. data/lib/omf_ec/backward/dsl.rb +83 -0
  18. data/lib/omf_ec/backward/exp/testbed.rb +47 -0
  19. data/lib/omf_ec/backward/group.rb +72 -0
  20. data/lib/omf_ec/context/app_context.rb +54 -0
  21. data/lib/omf_ec/context/def_app_context.rb +6 -0
  22. data/lib/omf_ec/context/group_context.rb +88 -0
  23. data/lib/omf_ec/context/net_context.rb +46 -0
  24. data/lib/omf_ec/context.rb +10 -0
  25. data/lib/omf_ec/dsl.rb +159 -0
  26. data/lib/omf_ec/experiment.rb +71 -0
  27. data/lib/omf_ec/group.rb +158 -0
  28. data/lib/omf_ec/version.rb +1 -1
  29. data/lib/omf_ec.rb +34 -1
  30. data/omf_ec.gemspec +2 -3
  31. data/test/omf_ec/context_spec.rb +19 -0
  32. data/test/omf_ec/group_spec.rb +14 -0
  33. data/test/test_helper.rb +19 -0
  34. metadata +44 -89
  35. data/bin/omf +0 -147
  36. data/bin/omf_pre +0 -76
  37. data/bin/omf_test +0 -161
  38. data/example/net_devices.rb +0 -75
  39. data/exp_repo/system/exp/eventlib.rb +0 -96
  40. data/exp_repo/system/exp/imageNode.rb +0 -283
  41. data/exp_repo/system/exp/reset.rb +0 -21
  42. data/exp_repo/system/exp/saveNode.rb +0 -99
  43. data/exp_repo/system/exp/stat.rb +0 -49
  44. data/exp_repo/system/exp/stdlib.rb +0 -122
  45. data/exp_repo/system/exp/tell.rb +0 -53
  46. data/exp_repo/system/exp/testlib.rb +0 -12
  47. data/exp_repo/system/exp/winlib.rb +0 -154
  48. data/exp_repo/system/topo/active.rb +0 -9
  49. data/exp_repo/system/topo/all.rb +0 -10
  50. data/exp_repo/system/topo/circle.rb +0 -23
  51. data/exp_repo/test/app/aodvd.rb +0 -73
  52. data/exp_repo/test/app/appDef1.rb +0 -102
  53. data/exp_repo/test/app/athstats.rb +0 -76
  54. data/exp_repo/test/app/echo.rb +0 -36
  55. data/exp_repo/test/app/gennyReceiverAppDef.rb +0 -100
  56. data/exp_repo/test/app/gennySenderAppDef.rb +0 -106
  57. data/exp_repo/test/app/itgdec.rb +0 -79
  58. data/exp_repo/test/app/itgr.rb +0 -77
  59. data/exp_repo/test/app/itgs.rb +0 -105
  60. data/exp_repo/test/app/nop.rb +0 -36
  61. data/exp_repo/test/app/otg2.rb +0 -68
  62. data/exp_repo/test/app/otg2_mp.rb +0 -56
  63. data/exp_repo/test/app/otr2.rb +0 -56
  64. data/exp_repo/test/app/otr2_mp.rb +0 -51
  65. data/exp_repo/test/app/trace_oml2.rb +0 -62
  66. data/exp_repo/test/app/wlanconfig_oml2.rb +0 -42
  67. data/exp_repo/test/exp/conf-room-demo.rb +0 -118
  68. data/exp_repo/test/exp/planetlab.rb +0 -82
  69. data/exp_repo/test/exp/test01.rb +0 -42
  70. data/exp_repo/test/exp/test02.rb +0 -60
  71. data/exp_repo/test/exp/tutorial/hello-world-wired.rb +0 -79
  72. data/exp_repo/test/exp/tutorial/hello-world-wireless.rb +0 -87
  73. data/exp_repo/test/exp/tutorial/using-filters.rb +0 -69
  74. data/exp_repo/test/exp/tutorial/using-groups.rb +0 -64
  75. data/exp_repo/test/exp/tutorial/using-properties.rb +0 -93
  76. data/exp_repo/test/exp/tutorial/using-prototypes.rb +0 -111
  77. data/exp_repo/test/proto/aodvrouter.rb +0 -55
  78. data/exp_repo/test/proto/driverqueryapp.rb +0 -59
  79. data/exp_repo/test/proto/forwarder.rb +0 -73
  80. data/exp_repo/test/proto/itgcbrsender.rb +0 -70
  81. data/exp_repo/test/proto/itgdecoder.rb +0 -64
  82. data/exp_repo/test/proto/itgreceiver.rb +0 -55
  83. data/exp_repo/test/proto/itgvoipsender.rb +0 -64
  84. data/exp_repo/test/proto/listener2.rb +0 -62
  85. data/exp_repo/test/proto/nop.rb +0 -47
  86. data/exp_repo/test/proto/probelink.rb +0 -48
  87. data/exp_repo/test/proto/raw_receiver.rb +0 -64
  88. data/exp_repo/test/proto/receiver2_mp.rb +0 -48
  89. data/exp_repo/test/proto/sender2_mp.rb +0 -54
  90. data/exp_repo/test/proto/udp_receiver.rb +0 -55
  91. data/exp_repo/test/proto/udp_sender.rb +0 -61
data/lib/omf_ec/dsl.rb ADDED
@@ -0,0 +1,159 @@
1
+ require 'active_support/core_ext'
2
+ require 'eventmachine'
3
+
4
+ module OmfEc
5
+ # DSL methods to be used for OEDL scripts
6
+ module DSL
7
+ # Use EM timer to execute after certain time
8
+ #
9
+ # @example do something after 2 seconds
10
+ #
11
+ # after 2.seconds { 'do something' }
12
+ def after(time, &block)
13
+ OmfEc.comm.add_timer(time, block)
14
+ end
15
+
16
+ # Use EM periodic timer to execute after certain time
17
+ #
18
+ # @example do something every 2 seconds
19
+ #
20
+ # every 2.seconds { 'do something' }
21
+ def every(time, &block)
22
+ OmfEc.comm.add_periodic_timer(time, block)
23
+ end
24
+
25
+ def def_application(name,&block)
26
+ app_def = OmfEc::AppDefinition.new(name)
27
+ OmfEc.exp.app_definitions[name] = app_def
28
+ block.call(app_def) if block
29
+ end
30
+
31
+ # Define a group, create a pubsub topic for the group
32
+ #
33
+ # @param [String] name name of the group
34
+ #
35
+ # @example add resource 'a' to group 'bob'
36
+ # def_group('bob') do |g|
37
+ # g.add_resource('a')
38
+ # end
39
+ #
40
+ # @see OmfEc::Backward::DSL#defGroup
41
+ 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
67
+ end
68
+
69
+ # Get a group instance
70
+ #
71
+ # @param [String] name name of the group
72
+ def group(name, &block)
73
+ group = OmfEc.exp.groups.find {|v| v.name == name}
74
+ block.call(group) if block
75
+ group
76
+ end
77
+
78
+ # Iterator for all defined groups
79
+ def all_groups(&block)
80
+ OmfEc.exp.groups.each do |g|
81
+ block.call(g) if block
82
+ end
83
+ end
84
+
85
+ alias_method :all_nodes!, :all_groups
86
+
87
+ # Exit the experiment
88
+ #
89
+ # @see OmfEc::Experiment.done
90
+ def done!
91
+ OmfEc::Experiment.done
92
+ end
93
+
94
+ alias_method :done, :done!
95
+
96
+ # Define an experiment property which can be used to bind
97
+ # to application and other properties. Changing an experiment
98
+ # property should also change the bound properties, or trigger
99
+ # commands to change them.
100
+ #
101
+ # @param name of property
102
+ # @param default_value for this property
103
+ # @param description short text description of this property
104
+ #
105
+ def def_property(name, default_value, description = nil)
106
+ OmfEc.exp.property[name] ||= default_value
107
+ end
108
+
109
+ # Return the context for setting experiment wide properties
110
+ def property
111
+ OmfEc.exp.property
112
+ end
113
+
114
+ alias_method :prop, :property
115
+
116
+ # Check if all elements in array equal the value provided
117
+ #
118
+ def all_equal(array, value = nil, &block)
119
+ if array.empty?
120
+ false
121
+ else
122
+ if value
123
+ array.all? { |v| v.to_s == value.to_s }
124
+ else
125
+ array.all?(&block)
126
+ end
127
+ end
128
+ end
129
+
130
+ # Check if any elements in array equals the value provided
131
+ #
132
+ def one_equal(array, value)
133
+ array.any? ? false : array.all? { |v| v.to_s == value.to_s }
134
+ end
135
+
136
+ # Define an event
137
+ 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
143
+ end
144
+
145
+ # Define an event callback
146
+ def on_event(name, consume_event = true, &callback)
147
+ event = OmfEc.exp.events.find { |v| v[:name] == name }
148
+ if event.nil?
149
+ raise RuntimeError, "Event '#{name}' not defined"
150
+ else
151
+ event[:callbacks] ||= []
152
+ event[:callbacks] << callback
153
+ event[:consume_event] = consume_event
154
+ end
155
+ end
156
+
157
+ include OmfEc::Backward::DSL
158
+ end
159
+ end
@@ -0,0 +1,71 @@
1
+ require 'hashie'
2
+ require 'singleton'
3
+
4
+ module OmfEc
5
+ # Experiment class to hold relevant state information
6
+ #
7
+ class Experiment
8
+ include Singleton
9
+
10
+ attr_accessor :property,:state, :comm, :groups, :events, :name, :app_definitions, :sub_groups, :oml_uri
11
+
12
+ def initialize
13
+ @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 ||= []
21
+ end
22
+
23
+ # Unique experiment id
24
+ def id
25
+ @name.nil? ? @id : "#{@name}-#{@id}"
26
+ end
27
+
28
+ # Parsing user defined events, checking conditions against internal state, and execute callbacks if triggered
29
+ 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)
33
+ info "Event triggered: '#{event[:name]}'"
34
+ self.events.delete(event) if event[:consume_event]
35
+
36
+ # Last in first serve callbacks
37
+ event[:callbacks].reverse.each do |callback|
38
+ callback.call
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ # Purely for backward compatibility
46
+ class << self
47
+ # Disconnect communicator, try to delete any XMPP affiliations
48
+ def done
49
+ info "Exit in up to 20 seconds..."
50
+
51
+ OmfEc.comm.add_timer(10) do
52
+ info "Release applications and network interfaces"
53
+
54
+ allGroups do |g|
55
+ g.resources[type: 'application'].release
56
+ g.resources[type: 'net'].release unless g.net_ifs.find_all { |v| v.conf[:type] == 'net' }.empty?
57
+ g.resources[type: 'wlan'].release unless g.net_ifs.find_all { |v| v.conf[:type] == 'wlan' }.empty?
58
+ end
59
+
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
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,158 @@
1
+ require 'securerandom'
2
+
3
+ module OmfEc
4
+ # Group instance used in experiment script
5
+ #
6
+ # @!attribute name [String] name of the resource
7
+ # @!attribute id [String] pubsub topic id of the resource
8
+ # @!attribute net_ifs [Array] network interfaces defined to be added to group
9
+ # @!attribute members [Array] holding members to be added to group
10
+ # @!attribute apps [Array] holding applications to be added to group
11
+ class Group
12
+ attr_accessor :name, :id, :net_ifs, :members, :app_contexts
13
+
14
+ # @param [String] name name of the group
15
+ # @param [Hash] opts
16
+ # @option opts [Boolean] :unique Should the group be unique or not, default is true
17
+ def initialize(name, opts = {})
18
+ @opts = {unique: true}.merge!(opts)
19
+ self.name = name
20
+ self.id = @opts[:unique] ? SecureRandom.uuid : self.name
21
+ # Add empty holders for members, network interfaces, and apps
22
+ self.net_ifs = []
23
+ self.members = []
24
+ self.app_contexts = []
25
+ end
26
+
27
+ # Add existing resources to the group
28
+ #
29
+ # Resources to be added could be a list of resources, groups, or the mixture of both.
30
+ def add_resource(*names)
31
+ names.each do |name|
32
+ # resource to add is a group
33
+ if OmfEc.exp.groups.any? { |v| v.name == name }
34
+ self.add_resource(*group(name).members.uniq)
35
+ else
36
+ OmfEc.comm.subscribe(name) do |m|
37
+ unless m.error?
38
+ # resource with uid: name is available
39
+ unless OmfEc.exp.state.any? { |v| v[:uid] == name }
40
+ OmfEc.exp.state << { uid: name }
41
+ end
42
+
43
+ r = OmfEc.comm.get_topic(name)
44
+
45
+ r.on_message lambda {|m| m.operation == :inform && m.read_content('inform_type') == 'STATUS' && m.context_id.nil? } do |i|
46
+ r = OmfEc.exp.state.find { |v| v[:uid] == i.read_property(:uid) }
47
+ unless r.nil?
48
+ i.each_property do |p|
49
+ key = p.attr('key').to_sym
50
+ r[key] = i.read_property(key)
51
+ end
52
+ end
53
+ Experiment.instance.process_events
54
+ end
55
+
56
+ # Receive failed inform message
57
+ r.on_message lambda {|m| m.operation == :inform && m.read_content('inform_type') == 'FAILED' && m.context_id.nil? } do |i|
58
+ warn "RC reports failure: '#{i.read_content("reason")}'"
59
+ end
60
+
61
+ c = OmfEc.comm.configure_message(self.id) do |m|
62
+ m.property(:membership, self.id)
63
+ end
64
+
65
+ c.publish name
66
+
67
+ c.on_inform_status do |i|
68
+ r = OmfEc.exp.state.find { |v| v[:uid] == name }
69
+ r[:membership] = i.read_property(:membership)
70
+ Experiment.instance.process_events
71
+ end
72
+
73
+ c.on_inform_failed do |i|
74
+ warn "RC reports failure: '#{i.read_content("reason")}'"
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+
82
+ # Create a set of new resources and add them to the group
83
+ #
84
+ # @param [String] name
85
+ # @param [Hash] opts to be used to create new resources
86
+ def create_resource(name, opts, &block)
87
+
88
+ # Make a deep copy of opts in case it contains structures of structures
89
+ begin
90
+ opts = Marshal.load ( Marshal.dump(opts.merge(hrn: name)))
91
+ rescue Exception => e
92
+ raise "#{e.message} - Could not deep copy opts: '#{opts.inspect}'"
93
+ end
94
+
95
+ # Naming convention of child resource group
96
+ resource_group_name = "#{self.id}_#{opts[:type]}"
97
+
98
+
99
+ unless OmfEc.exp.sub_groups.include?(resource_group_name)
100
+ OmfEc.exp.sub_groups << resource_group_name
101
+
102
+ rg = OmfEc.comm.get_topic(resource_group_name)
103
+ # Receive status inform message
104
+ rg.on_message lambda {|m| m.operation == :inform && m.read_content('inform_type') == 'STATUS' && m.context_id.nil? } do |i|
105
+ r = OmfEc.exp.state.find { |v| v[:uid] == i.read_property(:uid) }
106
+ unless r.nil?
107
+ if i.read_property("status_type") == 'APP_EVENT'
108
+ info "APP_EVENT #{i.read_property('event')} "+
109
+ "from app #{i.read_property("app")} - msg: #{i.read_property("msg")}"
110
+ end
111
+ i.each_property do |p|
112
+ r[p.attr('key').to_sym] = p.content.ducktype
113
+ end
114
+ end
115
+ Experiment.instance.process_events
116
+ end
117
+
118
+ # Receive failed inform message
119
+ rg.on_message lambda {|m| m.operation == :inform && m.read_content('inform_type') == 'FAILED' && m.context_id.nil? } do |i|
120
+ warn "RC reports failure: '#{i.read_content("reason")}'"
121
+ end
122
+ end
123
+
124
+ # We create another group topic for new resouce
125
+ OmfEc.comm.subscribe(resource_group_name, create_if_non_existent: true) do |m|
126
+ unless m.error?
127
+
128
+ c = OmfEc.comm.create_message(self.id) do |m|
129
+ m.property(:membership, resource_group_name)
130
+ opts.each_pair do |k, v|
131
+ m.property(k, v)
132
+ end
133
+ end
134
+
135
+ c.publish self.id
136
+
137
+ c.on_inform_created do |i|
138
+ info "#{opts[:type]} #{i.resource_id} created"
139
+ OmfEc.exp.state << { uid: i.resource_id, type: opts[:type], hrn: name, membership: [resource_group_name]}
140
+ block.call if block
141
+ Experiment.instance.process_events
142
+ end
143
+
144
+ c.on_inform_failed do |i|
145
+ warn "RC reports failure: '#{i.read_content("reason")}'"
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ # @return [OmfEc::Context::GroupContext]
152
+ def resources
153
+ OmfEc::Context::GroupContext.new(group: self.id)
154
+ end
155
+
156
+ include OmfEc::Backward::Group
157
+ end
158
+ end
@@ -1,3 +1,3 @@
1
1
  module OmfEc
2
- VERSION = "6.0.0.pre.3"
2
+ VERSION = "6.0.0.pre.4"
3
3
  end
data/lib/omf_ec.rb CHANGED
@@ -1,5 +1,38 @@
1
+ require "omf_common"
2
+ require 'omf_ec/backward/dsl'
3
+ require 'omf_ec/backward/group'
4
+ require 'omf_ec/backward/app_definition'
5
+ require 'omf_ec/backward/default_events'
6
+ require 'omf_ec/backward/core_ext/array'
1
7
  require "omf_ec/version"
8
+ require "omf_ec/experiment"
9
+ require "omf_ec/group"
10
+ require "omf_ec/app_definition"
11
+ require "omf_ec/context"
12
+ require "omf_ec/dsl"
2
13
 
3
14
  module OmfEc
4
- # Your code goes here...
15
+ class << self
16
+ # Experiment instance
17
+ #
18
+ # @return [OmfEc::Experiment]
19
+ def experiment
20
+ Experiment.instance
21
+ end
22
+
23
+ alias_method :exp, :experiment
24
+
25
+ # Experiment's communicator instance
26
+ # @return [OmfCommon::Comm]
27
+ def communicator
28
+ Experiment.instance.comm
29
+ end
30
+
31
+ # Full path of lib directory
32
+ def lib_root
33
+ File.expand_path("../..", "#{__FILE__}/lib")
34
+ end
35
+
36
+ alias_method :comm, :communicator
37
+ end
5
38
  end
data/omf_ec.gemspec CHANGED
@@ -15,12 +15,11 @@ Gem::Specification.new do |s|
15
15
 
16
16
  s.files = `git ls-files`.split("\n")
17
17
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
- #s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
- s.executables = ["omf_pre"]
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
19
  s.require_paths = ["lib"]
21
20
 
22
21
  # specify any dependencies here; for example:
23
22
  s.add_development_dependency "minitest", "~> 3.2"
24
23
  s.add_runtime_dependency "omf_common", "~> 6.0.0.pre"
25
- s.add_runtime_dependency "gli", "~> 2.0.0.pre"
24
+ s.add_runtime_dependency "gli", "~> 2.4.1"
26
25
  end
@@ -0,0 +1,19 @@
1
+ require 'test_helper'
2
+ require 'omf_ec/context'
3
+
4
+ describe OmfEc::Context do
5
+ before do
6
+ @context = OmfEc::Context::GroupContext.new(group: 'universe')
7
+ end
8
+
9
+ describe "when initialised with options" do
10
+ it "must be able to respond to random group operation method" do
11
+ skip
12
+ end
13
+
14
+ it "must be able to construct guards" do
15
+ g = @context[name: 'bob'][type: 'engine', group: 'universe'].guard
16
+ g.must_equal({ name: 'bob', type: 'engine', group: 'universe' })
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ require 'test_helper'
2
+ require 'omf_ec/group'
3
+
4
+ describe OmfEc::Group do
5
+ describe "when initialised" do
6
+ it "must be generate unique id if :unique option is on" do
7
+ OmfEc::Group.new('bob').id.wont_equal 'bob'
8
+ end
9
+
10
+ it "must use name as id if :unique option is off" do
11
+ OmfEc::Group.new('bob', unique: false).id.must_equal 'bob'
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ require 'simplecov'
2
+ SimpleCov.start { add_filter "/test" }
3
+
4
+ gem 'minitest'
5
+ require 'minitest/autorun'
6
+ require 'minitest/pride'
7
+
8
+ require 'omf_ec'
9
+
10
+ # Default fixture directory
11
+ FIXTURE_DIR = "#{File.dirname(__FILE__)}/fixture"
12
+
13
+ # Shut up all the loggers
14
+ Logging.logger.root.clear_appenders
15
+
16
+ # Reading fixture file
17
+ def fixture(name)
18
+ File.read("#{FIXTURE_DIR}/#{name.to_s}")
19
+ end