omf_web 0.9.6 → 0.9.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +168 -13
- data/bin/omf-web-basic +3 -3
- data/doc/index.md +205 -0
- data/example/NOT_WORKING/brooklyn/brooklyn_server.rb +2 -2
- data/example/NOT_WORKING/frisbee/data_sources/parse_log.rb +1 -1
- data/example/NOT_WORKING/frisbee/viz_server.rb +1 -1
- data/example/NOT_WORKING/gec12/gec12_demo_server.rb +1 -1
- data/example/NOT_WORKING/gec12/visualization.rb +2 -2
- data/example/NOT_WORKING/network/network_server.rb +2 -2
- data/example/NOT_WORKING/wimax/test.rb +2 -2
- data/example/NOT_WORKING/wimax/viz_server.rb +2 -2
- data/example/bridge/auth_basic.rb +75 -0
- data/example/bridge/config.ru +101 -0
- data/example/bridge/configure/configure_widget.rb +32 -0
- data/example/bridge/data_sources/sensor-sqlite.rb +28 -6
- data/example/bridge/data_sources/test31.sq3 +0 -0
- data/example/bridge/htdocs/{js/graph → graph/js}/bridge.js +2 -2
- data/example/bridge/htdocs/{js/graph → graph/js}/event_line_chart.js +7 -6
- data/example/bridge/htdocs/{js/graph → graph/js}/event_table.js +13 -5
- data/example/bridge/htdocs/template/login.html +23 -0
- data/example/bridge/viz_server.rb +3 -5
- data/example/bridge/widgets/configure.yaml +12 -0
- data/example/bridge/widgets/login.yaml +16 -0
- data/example/bridge/{overview.yaml → widgets/overview.yaml} +7 -4
- data/example/demo/data_sources/animals.rb +1 -1
- data/example/demo/data_sources/downloads.rb +1 -1
- data/example/demo/data_sources/generator.rb +1 -1
- data/example/demo/data_sources/histogram.rb +1 -1
- data/example/demo/data_sources/mobile_network.rb +4 -3
- data/example/demo/data_sources/movies.rb +1 -1
- data/example/demo/data_sources/network.rb +4 -3
- data/example/demo/data_sources/returns.rb +1 -1
- data/example/demo/data_sources/static_network.rb +4 -3
- data/example/demo/data_sources/walk.rb +1 -1
- data/example/demo/demo_viz_server.rb +1 -1
- data/example/demo/widgets/linked_graphs_tab.yaml +1 -1
- data/example/openflow-gec15/README.md +21 -0
- data/example/openflow-gec15/code_tab.yaml +36 -0
- data/example/openflow-gec15/dashboard_tab.yaml +72 -0
- data/example/openflow-gec15/doc/screenshot.png +0 -0
- data/example/openflow-gec15/exp_source.rb +104 -0
- data/example/openflow-gec15/of_viz_server.rb +63 -0
- data/example/openflow-gec15/openflow-demo.sq3 +0 -0
- data/example/openflow-gec15/raw_tab.yaml +37 -0
- data/example/openflow-gec15/repository/of-exp.rb +12 -0
- data/example/openflow-gec15/repository/sample.md +52 -0
- data/example/openflow-gec15/repository/trema-ctl6.rb +148 -0
- data/example/simple/README.md +2 -0
- data/example/simple/data_sources/gimi31.sq3 +0 -0
- data/example/simple/data_sources/ping_source.rb +56 -0
- data/example/simple/simple_viz_server.rb +39 -0
- data/example/simple/widgets/charts_tab.yaml +38 -0
- data/lib/omf-web/config.ru +31 -3
- data/lib/omf-web/data_source_proxy.rb +29 -26
- data/lib/omf-web/rack/session_authenticator.rb +93 -0
- data/lib/omf-web/rack/tab_mapper.rb +10 -5
- data/lib/omf-web/rack/websocket_handler.rb +17 -6
- data/lib/omf-web/theme/abstract_page.rb +1 -1
- data/lib/omf-web/theme/bright/flow_renderer.rb +2 -2
- data/lib/omf-web/theme/bright/layout_renderer.rb +15 -0
- data/lib/omf-web/theme/bright/mustache_renderer.rb +29 -0
- data/lib/omf-web/theme/bright/one_column_renderer.rb +2 -2
- data/lib/omf-web/theme/bright/page.rb +33 -8
- data/lib/omf-web/theme/bright/tabbed_renderer.rb +2 -3
- data/lib/omf-web/theme/bright/two_columns_renderer.rb +3 -4
- data/lib/omf-web/version.rb +1 -1
- data/lib/omf-web/widget/code_widget.rb +0 -7
- data/lib/omf-web/widget/layout/two_columns_layout.rb +3 -2
- data/lib/omf-web/widget/mustache_widget.rb +44 -0
- data/lib/omf-web/widget.rb +14 -1
- data/lib/omf_common/lobject.rb +6 -3
- data/omf_web.gemspec +3 -1
- data/share/htdocs/graph/js/abstract_nv_chart.js +14 -4
- data/share/htdocs/graph/js/abstract_widget.js +5 -4
- data/share/htdocs/graph/js/line_chart3.js +2 -0
- data/share/htdocs/graph/js/map2.js +3 -3
- data/share/htdocs/graph/js/network2.js +51 -19
- data/share/htdocs/graph/js/scatter_plot.js +6 -2
- data/share/htdocs/graph/js/table2.js +5 -2
- data/share/htdocs/js/data_source2.js +40 -8
- data/share/htdocs/js/mustache.js +29 -0
- data/share/htdocs/theme/abstract/abstract.js +10 -3
- data/share/htdocs/vendor/mustache-0.7.0/CHANGES +21 -0
- data/share/htdocs/vendor/mustache-0.7.0/LICENSE +10 -0
- data/share/htdocs/vendor/mustache-0.7.0/README.md +374 -0
- data/share/htdocs/vendor/mustache-0.7.0/jquery.mustache.js +635 -0
- data/share/htdocs/vendor/mustache-0.7.0/mustache.js +612 -0
- data/share/htdocs/vendor/nv_d3/js/nv.d3.js +9 -1
- data/share/htdocs/vendor/raphael-2.1.0/raphael.js +5815 -0
- metadata +74 -9
- data/DESIGN_NOTES.txt +0 -56
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'omf_web'
|
2
|
+
require 'omf_common/lobject'
|
3
|
+
require 'omf_oml/network'
|
4
|
+
require 'omf_oml/table'
|
5
|
+
require 'omf_oml/sql_source'
|
6
|
+
|
7
|
+
require 'em-postgresql-sequel'
|
8
|
+
|
9
|
+
|
10
|
+
include OMF::OML
|
11
|
+
|
12
|
+
class ExpDB < OMF::Common::LObject
|
13
|
+
|
14
|
+
|
15
|
+
def initialize(db_opts)
|
16
|
+
@db_opts = db_opts
|
17
|
+
init_network
|
18
|
+
end
|
19
|
+
|
20
|
+
def init_network
|
21
|
+
@nw = nw = OmlNetwork.new('network')
|
22
|
+
nw.node_schema [[:x, :float], [:y, :float]]
|
23
|
+
nw.create_node :n0, :x => 0.5, :y => 0.8
|
24
|
+
nw.create_node :n1, :x => 0.2, :y => 0.5
|
25
|
+
nw.create_node :n2, :x => 0.8, :y => 0.5
|
26
|
+
nw.create_node :n3, :x => 0.8, :y => 0.2
|
27
|
+
|
28
|
+
nw.link_schema [[:ts, :float], [:bytes, :int], [:rate, :float], [:load, :float]]
|
29
|
+
@links = {}
|
30
|
+
@links[:l20] = nw.create_link(:l20, :n2, :n0, :ts => 0, :bytes => 0, :rate => 0, :load => 0)
|
31
|
+
@links[:l10] = nw.create_link(:l10, :n1, :n0, :ts => 0, :bytes => 0, :rate => 0, :load => 0)
|
32
|
+
@links[:l21] = nw.create_link(:l21, :n2, :n1, :ts => 0, :bytes => 0, :rate => 0, :load => 0)
|
33
|
+
@links[:l32] = nw.create_link(:l32, :n3, :n2, :ts => 0, :bytes => 0, :rate => 0, :load => 0)
|
34
|
+
|
35
|
+
|
36
|
+
OMF::Web.register_datasource nw.to_table(:nodes, :index => :id)
|
37
|
+
OMF::Web.register_datasource nw.to_table(:links, :index => :id)
|
38
|
+
@link_history = nw.to_table(:links, :max_size => 100)
|
39
|
+
OMF::Web.register_datasource @link_history, :name => 'link_history'
|
40
|
+
end
|
41
|
+
|
42
|
+
def setup_nmetric(stream)
|
43
|
+
schema = stream.schema
|
44
|
+
t = OMF::OML::OmlTable.new(:nmetric, schema, :max_size => 1000)
|
45
|
+
ts_i = schema.index_for_col(:oml_ts_server)
|
46
|
+
name_i = schema.index_for_col(:name)
|
47
|
+
tx_i = schema.index_for_col(:tx_bytes)
|
48
|
+
rx_i = schema.index_for_col(:rx_bytes)
|
49
|
+
|
50
|
+
def process(l, ts, bytes, max_rate)
|
51
|
+
if (delta_t = ts - l[:ts]) > 0
|
52
|
+
old_v = l[:bytes]
|
53
|
+
delta_v = bytes >= old_v ? bytes - old_v : bytes
|
54
|
+
l[:ts] = ts
|
55
|
+
l[:bytes] = bytes
|
56
|
+
l[:rate] = rate = 1.0 * delta_v / delta_t
|
57
|
+
#l[:rate] = rate = 230000
|
58
|
+
l[:load] = 1.0 * rate / max_rate
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
stream.on_new_tuple() do |v|
|
63
|
+
r = v.to_a(true)
|
64
|
+
#puts "RRR >> #{r.inspect}"
|
65
|
+
t.add_row(r)
|
66
|
+
ts = r[ts_i]; name = r[name_i].to_sym; tx = r[tx_i]; rx = r[rx_i]
|
67
|
+
#puts "VVV(#{ts}) >> #{v.row.inspect}"
|
68
|
+
@nw.transaction do
|
69
|
+
case name
|
70
|
+
when :eth0
|
71
|
+
process @links[:l20], ts, tx, 120e3 #1e6
|
72
|
+
when :wlan0
|
73
|
+
process @links[:l21], ts, tx, 4e6
|
74
|
+
process @links[:l10], ts, tx, 4e6
|
75
|
+
when :wlan1
|
76
|
+
process @links[:l32], ts, rx, 4e6
|
77
|
+
end
|
78
|
+
end
|
79
|
+
sleep 0.5 if ts > 7300
|
80
|
+
end
|
81
|
+
|
82
|
+
# nw.transaction do
|
83
|
+
# links.each_with_index do |l, i|
|
84
|
+
# l[:ts] = ts
|
85
|
+
# l[:load] = rand() * frac + i * frac
|
86
|
+
# end
|
87
|
+
# end
|
88
|
+
|
89
|
+
OMF::Web.register_datasource t
|
90
|
+
end
|
91
|
+
|
92
|
+
def run
|
93
|
+
ep = OMF::OML::OmlSqlSource.new(@db_opts, :check_interval => 3.0)
|
94
|
+
ep.on_new_stream() do |stream|
|
95
|
+
info "Stream: #{stream.stream_name}"
|
96
|
+
if stream.stream_name == 'nmetrics_net_if'
|
97
|
+
setup_nmetric(stream)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
ep.run
|
101
|
+
self
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
|
2
|
+
require 'omf_common/lobject'
|
3
|
+
OMF::Common::Loggable.init_log 'of-demo'
|
4
|
+
|
5
|
+
|
6
|
+
require 'omf_oml/table'
|
7
|
+
|
8
|
+
$testing_database = 'sqlite://example/openflow-gec15/openflow-demo.sq3'
|
9
|
+
$oml_database = 'postgres://norbit.npc.nicta.com.au/openflow-demo?user=oml2&password=omlisgoodforyou'
|
10
|
+
|
11
|
+
def load_environment
|
12
|
+
require 'omf-web/content/file_repository'
|
13
|
+
OMF::Web::FileContentRepository.register_file_repo(:code, File.join(File.dirname(__FILE__), 'repository'), true)
|
14
|
+
|
15
|
+
|
16
|
+
Dir.glob("#{File.dirname(__FILE__)}/*_source.rb").each do |fn|
|
17
|
+
load fn
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'yaml'
|
21
|
+
Dir.glob("#{File.dirname(__FILE__)}/*_tab.yaml").each do |fn|
|
22
|
+
h = YAML.load_file(fn)
|
23
|
+
if w = h['widget']
|
24
|
+
OMF::Web.register_widget w
|
25
|
+
else
|
26
|
+
MObject.error "Don't know what to do with '#{fn}'"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# Start database adapter
|
31
|
+
EM.next_tick do
|
32
|
+
EM::run do
|
33
|
+
wv = ExpDB.new($oml_database)
|
34
|
+
wv.run
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
# Configure the web server
|
41
|
+
#
|
42
|
+
opts = {
|
43
|
+
:app_name => 'ov_demo',
|
44
|
+
:page_title => 'Dynamic Routing',
|
45
|
+
:handlers => {
|
46
|
+
# delay connecting to databases to AFTER we may run as daemon
|
47
|
+
:pre_rackup => lambda { load_environment },
|
48
|
+
:pre_parse => lambda do |p|
|
49
|
+
p.separator ""
|
50
|
+
p.separator "DEMO options:"
|
51
|
+
p.on("--local-testing", "If set, use local database for testing [#{$testing_database}]") do
|
52
|
+
$oml_database = $testing_database
|
53
|
+
end
|
54
|
+
p.on("--oml-database DATABASE", "Database containing measurement data [#{$oml_database}]") do |f|
|
55
|
+
$oml_database = f
|
56
|
+
end
|
57
|
+
p.separator ""
|
58
|
+
end
|
59
|
+
|
60
|
+
}
|
61
|
+
}
|
62
|
+
require 'omf_web'
|
63
|
+
OMF::Web.start(opts)
|
Binary file
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
# Simple tab showing a line chart with supporting table
|
5
|
+
#
|
6
|
+
|
7
|
+
widget:
|
8
|
+
id: raw
|
9
|
+
name: Raw
|
10
|
+
top_level: true
|
11
|
+
priority: 200
|
12
|
+
type: layout/tabbed
|
13
|
+
widgets:
|
14
|
+
|
15
|
+
# - name: Ping Line
|
16
|
+
# type: data/line_chart3
|
17
|
+
# data_source:
|
18
|
+
# name: ping
|
19
|
+
# mapping:
|
20
|
+
# x_axis:
|
21
|
+
# property: oml_ts_client
|
22
|
+
# y_axis:
|
23
|
+
# property: rtt
|
24
|
+
# max: 2.0
|
25
|
+
# group_by: link
|
26
|
+
|
27
|
+
- name: Link
|
28
|
+
type: data/table2
|
29
|
+
data_source:
|
30
|
+
name: link_history
|
31
|
+
|
32
|
+
- name: NMetric
|
33
|
+
type: data/table2
|
34
|
+
data_source:
|
35
|
+
name: nmetric
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,12 @@
|
|
1
|
+
defProperty('wired', 'omf.nicta.node2', "Wired node (endpoint)") # baseline.ndz
|
2
|
+
defGroup('ap', property.ap) do |node|
|
3
|
|
1
4
|
# wlan0 is not part of OVS
|
2
5
|
# the IP address is the GRE tunnel endpoint
|
3
6
|
node.net.w0.mode = "adhoc"
|
4
7
|
node.net.w0.type = 'g'
|
5
8
|
node.net.w0.channel = "6"
|
6
9
|
node.net.w0.essid = "adhoc"
|
7
10
|
node.net.w0.ip = "172.16.2.1"
|
11
|
+
# wlan1 is part of OVS
|
8
12
|
node.net.w1.mode = "master"
|
9
13
|
node.net.w1.type = 'g'
|
10
14
|
node.net.w1.channel = "10"
|
11
15
|
node.net.w1.essid = "ap"
|
12
16
|
|
13
17
|
onNodeUp do |n|
|
14
18
|
n.exec("ifconfig br-int up; ovs-vsctl set controller br-int connection-mode=out-of-band; ifconfig eth0 0")
|
15
19
|
n.exec("ovs-vsctl add-port br-int gre1 -- set interface gre1 type=gre options:remote_ip=172.16.2.2")
|
16
20
|
n.exec("ovs-vsctl add-port br-int eth0")
|
17
21
|
n.exec("ovs-vsctl add-port br-int wlan1")
|
18
22
|
n.exec("while true; do timeout 10 nmetrics-oml2 -s 2 -i eth0 --oml-server tcp:10.0.0.200:5000 --oml-exp-id 1 --oml-id 1 --oml-text; done")
|
19
23
|
#n.exec("/root/monitor_ovs_ports.rb --oml-id ap --oml-server tcp:norbit.npc.nicta.com.au:5000")
|
20
24
|
end
|
21
25
|
|
26
|
+
defGroup('adhoc', property.adhoc) do |node|
|
22
27
|
|
23
28
|
# wlan0 is not part of OVS
|
24
29
|
# the IP address is the GRE tunnel endpoint
|
25
30
|
node.net.w0.mode = "adhoc"
|
26
31
|
node.net.w0.type = 'g'
|
27
32
|
node.net.w0.channel = "6"
|
28
33
|
node.net.w0.essid = "adhoc"
|
29
34
|
node.net.w0.ip = "172.16.2.2"
|
30
35
|
|
31
36
|
onNodeUp do |n|
|
32
37
|
n.exec("ifconfig br-int up; ovs-vsctl set controller br-int connection-mode=out-of-band; ifconfig eth0 0")
|
33
38
|
n.exec("ovs-vsctl add-port br-int gre1 -- set interface gre1 type=gre options:remote_ip=172.16.2.1")
|
34
39
|
n.exec("ovs-vsctl add-port br-int eth0")
|
35
40
|
#n.exec("/root/monitor_ovs_ports.rb --oml-id adhoc --oml-server tcp:norbit.npc.nicta.com.au:5000")
|
36
41
|
end
|
42
|
+
defGroup('wireless', property.wireless) do |node|
|
37
43
|
# no OVS on this node
|
38
44
|
node.net.w0.mode = "managed"
|
39
45
|
node.net.w0.type = 'g'
|
40
46
|
node.net.w0.channel = "10"
|
41
47
|
node.net.w0.essid = "ap"
|
42
48
|
node.net.w0.ip = "172.16.1.4"
|
43
49
|
node.addApplication("test:app:otg2", :id => 'flow1') do |app|
|
44
50
|
app.setProperty('cbr:rate', 800000)
|
45
51
|
app.setProperty('udp:local_host', '172.16.1.4')
|
46
52
|
app.setProperty('udp:dst_host', '172.16.1.1')
|
47
53
|
app.setProperty('udp:dst_port', 3000)
|
48
54
|
app.measure('udp_out', :samples => 1)
|
49
55
|
end
|
50
56
|
|
51
57
|
node.addApplication("test:app:otg2", :id => 'flow2') do |app|
|
52
58
|
app.setProperty('cbr:rate', 800000)
|
53
59
|
app.setProperty('udp:local_host', '172.16.1.4')
|
54
60
|
app.setProperty('udp:dst_host', '172.16.1.1')
|
55
61
|
app.setProperty('udp:dst_port', 3000)
|
56
62
|
app.measure('udp_out', :samples => 1)
|
57
63
|
end
|
64
|
+
defGroup('wired', property.wired) do |node|
|
58
65
|
node.addApplication("test:app:otr2") do |app|
|
59
66
|
app.setProperty('udp:local_host', '172.16.1.1')
|
60
67
|
app.setProperty('udp:local_port', 3000)
|
61
68
|
app.measure('udp_in', :samples => 1)
|
62
69
|
end
|
70
|
+
# no OVS on this node
|
63
71
|
node.net.e0.ip = "172.16.1.1"
|
72
|
+
onEvent(:ALL_UP) do |event|
|
64
73
|
allGroups.exec("sysctl -w net.ipv6.conf.all.disable_ipv6=1")
|
74
|
+
group("wired").startApplications
|
65
75
|
info "Start your OpenFlow controller now!"
|
76
|
+
while true
|
66
77
|
info "Starting flow 1"
|
67
78
|
group("wireless").startApplication('flow1')
|
68
79
|
sleep 10
|
69
80
|
info "Starting flow 2"
|
70
81
|
group("wireless").startApplication('flow2')
|
71
82
|
sleep 10
|
72
83
|
info "Stopping flow 1. Flow 2 should now re-route over flow 1's path"
|
73
84
|
group("wireless").stopApplication('flow1')
|
74
85
|
sleep 20
|
75
86
|
info "Starting flow 1. Should use secondary path now."
|
76
87
|
group("wireless").startApplication('flow1')
|
77
88
|
sleep 20
|
78
89
|
info "Stopping flow 2"
|
79
90
|
group("wireless").stopApplication('flow2')
|
80
91
|
info "Stopping flow 1"
|
81
92
|
group("wireless").stopApplication('flow1')
|
82
93
|
sleep 10
|
83
94
|
info "Restarting experiment cycle"
|
84
95
|
end
|
96
|
+
|
97
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
title: Lorem ipsum dolor sit
|
2
|
+
|
3
|
+
# Lorem ipsum dolor sit
|
4
|
+
|
5
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin
|
6
|
+
sollicitudin nibh eu ligula lobortis ornare. Sed nibh nibh,
|
7
|
+
ullamcorper at vehicula ac, molestie ac nunc. Duis sodales, nisi vel
|
8
|
+
pellentesque imperdiet, nisi massa accumsan lorem, gravida scelerisque
|
9
|
+
velit est vitae eros. Suspendisse eu lacinia elit.
|
10
|
+
|
11
|
+
\[
|
12
|
+
\sum_{n=1}^\infty \frac{1}{n}
|
13
|
+
\text{ is divergent, but }
|
14
|
+
\lim_{n \to \infty} \sum_{i=1}^n \frac{1}{i} - \ln n \text{exists.}
|
15
|
+
\]
|
16
|
+
|
17
|
+
Suspendisse laoreet, lacus quis dignissim volutpat, dolor augue convallis lectus,
|
18
|
+
ac consectetur yyyy sem iaculis diam. Donec iaculis mattis iaculis.
|
19
|
+
Curabitur ut nisl in sapien semper ullamcorper in id turpis. Vivamus
|
20
|
+
sed sapien justo, ac scelerisque nibh. Sed eget quam velit. Lorem
|
21
|
+
ipsum dolor sit amet, consectetur adipiscing elit.
|
22
|
+
|
23
|
+
{{{
|
24
|
+
widget:
|
25
|
+
title: Fusce vehicula sapien
|
26
|
+
type: data/pie_chart2
|
27
|
+
data_sources: animals
|
28
|
+
mapping:
|
29
|
+
value: count
|
30
|
+
fill_color: category10()
|
31
|
+
label: name
|
32
|
+
width: 0.6
|
33
|
+
margin:
|
34
|
+
left: 0
|
35
|
+
right: 0
|
36
|
+
top: 0
|
37
|
+
bottom: 0
|
38
|
+
}}}
|
39
|
+
|
40
|
+
Aliquam tortor elit, condimentum et tincidunt vitae, consequat id
|
41
|
+
lacus. Fusce vehicula sapien sed leo varius at dictum purus
|
42
|
+
consectetur. Vestibulum sit amet nisl nisl. Suspendisse bibendum
|
43
|
+
iaculis rhoncus. Vivamus elementum lacinia metus, vitae fringilla diam
|
44
|
+
commodo et.
|
45
|
+
|
46
|
+
### Cras ut volutpat magna
|
47
|
+
|
48
|
+
Integer pharetra pellentesque
|
49
|
+
interdum. Nunc diam quam, volutpat a iaculis pellentesque, aliquet a
|
50
|
+
mauris. Praesent quam purus, mattis ullamcorper sagittis a, feugiat
|
51
|
+
non lorem.
|
52
|
+
|
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'omf-oml/endpoint'
|
3
|
+
require 'omf-oml/table'
|
4
|
+
require 'omf_common/lobject'
|
5
|
+
|
6
|
+
OMLPORT=5000
|
7
|
+
# threshold for transmitted bytes/s on AP's eth0 interface
|
8
|
+
# when exceeded, route new flows through secondary path
|
9
|
+
PRIMARY_THRESHOLD=100000
|
10
|
+
|
11
|
+
class OFDemo < Controller
|
12
|
+
|
13
|
+
add_timer_event :check_flows, 3, :periodic
|
14
|
+
|
15
|
+
def start
|
16
|
+
@switches = {"ap" => 0x32d0cfcb0, "adhoc" => 0x32d081a16, "of1" => 0x2320ca156c}
|
17
|
+
@ports = Hash.new
|
18
|
+
@detour=false
|
19
|
+
@lastflow=0
|
20
|
+
|
21
|
+
OMF::Common::Loggable.init_log File.basename($0).split('.')[0]
|
22
|
+
ep = OMF::OML::OmlEndpoint.new(OMLPORT, '0.0.0.0')
|
23
|
+
ep.on_new_stream() do |name, stream|
|
24
|
+
#puts "New stream: #{name}::#{stream}"
|
25
|
+
txcount=0
|
26
|
+
first=true
|
27
|
+
stream.on_new_tuple() do |t|
|
28
|
+
tx=t.to_a[11].to_i
|
29
|
+
if first
|
30
|
+
first=false
|
31
|
+
next
|
32
|
+
end
|
33
|
+
#puts "New tuple: #{t.to_a.inspect}"
|
34
|
+
txc=tx-txcount
|
35
|
+
txcount=tx
|
36
|
+
@detour = txc > PRIMARY_THRESHOLD
|
37
|
+
puts "AP eth0 reports #{txc} bytes/s, saturated: #{@detour}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
ep.run(true)
|
41
|
+
end
|
42
|
+
|
43
|
+
def switch_ready dpid
|
44
|
+
puts "Switch #{@switches.index(dpid)} (#{dpid.to_hex}) has signed in"
|
45
|
+
send_message dpid, FeaturesRequest.new
|
46
|
+
end
|
47
|
+
|
48
|
+
def features_reply dpid, message
|
49
|
+
@ports[dpid] = Hash.new
|
50
|
+
# read port name and number from the features_reply
|
51
|
+
message.ports.each do | p |
|
52
|
+
#puts "#{@switches.index(d)} : #{p.name} = #{p.number}"
|
53
|
+
@ports[dpid][p.name] = p.number
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def packet_in dpid, message
|
58
|
+
# drop it if we don't now the switch or its ports (yet)
|
59
|
+
return if @switches.index(dpid).nil? or @ports[dpid].nil?
|
60
|
+
|
61
|
+
arp_error="Unidentified ARP traffic. You may have started the controller too early, please restart it."
|
62
|
+
|
63
|
+
# handle ARP traffic manually to avoid packet storm in our circular topology
|
64
|
+
if message.arp?
|
65
|
+
if @switches.index(dpid)=="ap"
|
66
|
+
if message.in_port==@ports[dpid]['wlan1']
|
67
|
+
packet_out dpid, message, @ports[dpid]['eth0']
|
68
|
+
elsif message.in_port==@ports[dpid]['eth0']
|
69
|
+
packet_out dpid, message, @ports[dpid]['wlan1']
|
70
|
+
else
|
71
|
+
puts arp_error
|
72
|
+
end
|
73
|
+
elsif @switches.index(dpid)=="of1"
|
74
|
+
if message.in_port==2
|
75
|
+
packet_out dpid, message, 3
|
76
|
+
elsif message.in_port==3
|
77
|
+
packet_out dpid, message, 2
|
78
|
+
else
|
79
|
+
puts arp_error
|
80
|
+
end
|
81
|
+
end
|
82
|
+
return
|
83
|
+
end
|
84
|
+
|
85
|
+
# from now on we are only interested on IPv4 packets arriving on AP over wlan1
|
86
|
+
return if !message.ipv4? or @switches.index(dpid)!="ap" or message.in_port!=@ports[dpid]['wlan1']
|
87
|
+
|
88
|
+
# slow down adding of flows
|
89
|
+
# t=Time.now.to_i
|
90
|
+
# if t-@lastflow > 2
|
91
|
+
# @lastflow=t
|
92
|
+
# else
|
93
|
+
# return
|
94
|
+
# end
|
95
|
+
|
96
|
+
# add the flow on AP after adding all the others to avoid loss of inital packets
|
97
|
+
if @detour
|
98
|
+
puts "Adding flow over secondary path"
|
99
|
+
# broken due to trema bug
|
100
|
+
#flow_mod @switches["adhoc"], message, @ports[dpid]['eth0']
|
101
|
+
#flow_mod @switches["of1"], message, 2
|
102
|
+
flow_mod dpid, message, @ports[dpid]['gre1']
|
103
|
+
else
|
104
|
+
puts "Adding flow over primary path"
|
105
|
+
# broken due to trema bug
|
106
|
+
#flow_mod @switches["of1"], message, 2
|
107
|
+
flow_mod dpid, message, @ports[dpid]['eth0']
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
# periodically check if the throughput on primary path is below threshold
|
113
|
+
# if yes, remove flows that currently use secondary path
|
114
|
+
def check_flows
|
115
|
+
return if @ports[@switches["ap"]].nil?
|
116
|
+
if !@detour
|
117
|
+
puts "Deleting flows on switch #{@switches["ap"].to_hex} with out_port #{@ports[@switches["ap"]]['gre1']}"
|
118
|
+
send_flow_mod_delete(
|
119
|
+
@switches["ap"].to_i,
|
120
|
+
:actions => ActionOutput.new( :port => @ports[@switches["ap"]]['gre1'] )
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
##############################################################################
|
126
|
+
private
|
127
|
+
##############################################################################
|
128
|
+
|
129
|
+
def flow_mod datapath_id, message, port_no
|
130
|
+
#p Match.from( message, [ :dl_type, :nw_proto ] )
|
131
|
+
send_flow_mod_add(
|
132
|
+
datapath_id,
|
133
|
+
:match => Match.from( message ),
|
134
|
+
:actions => ActionOutput.new( :port => port_no ),
|
135
|
+
:idle_timeout => 2
|
136
|
+
)
|
137
|
+
end
|
138
|
+
|
139
|
+
def packet_out datapath_id, message, port_no
|
140
|
+
send_packet_out(
|
141
|
+
datapath_id,
|
142
|
+
:packet_in => message,
|
143
|
+
:actions => ActionOutput.new( :port => port_no )
|
144
|
+
)
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
Binary file
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'omf_web'
|
2
|
+
require 'omf_common/lobject'
|
3
|
+
require 'omf_oml/table'
|
4
|
+
require 'omf_oml/sql_source'
|
5
|
+
|
6
|
+
|
7
|
+
class PingDB < OMF::Common::LObject
|
8
|
+
|
9
|
+
LINKS = {'Source1::192.168.4.11' => 'link 4',
|
10
|
+
'Source1::192.168.5.11' => 'link 5',
|
11
|
+
'Source2::192.168.1.13' => 'link 1',
|
12
|
+
'Source2::192.168.2.10' => 'link 2',
|
13
|
+
'Source2::192.168.4.10' => 'link 4',
|
14
|
+
'Source3::192.168.2.12' => 'link 2',
|
15
|
+
'Source3::192.168.3.12' => 'link 3',
|
16
|
+
'Source3::192.168.5.12' => 'link 5',
|
17
|
+
'Source3::192.168.6.12' => 'link 6',
|
18
|
+
'Source4::192.168.1.13' => 'link 1',
|
19
|
+
'Source4::192.168.3.12' => 'link 3',
|
20
|
+
'Source5::192.168.6.12' => 'link 6'
|
21
|
+
}
|
22
|
+
|
23
|
+
def initialize(db_name)
|
24
|
+
@db_name = db_name
|
25
|
+
end
|
26
|
+
|
27
|
+
def setup_table(stream)
|
28
|
+
schema = stream.schema.clone
|
29
|
+
schema.insert_column_at(0, :link)
|
30
|
+
puts stream.schema.names.inspect
|
31
|
+
|
32
|
+
t = OMF::OML::OmlTable.new(:ping, schema)
|
33
|
+
stream.on_new_tuple() do |v|
|
34
|
+
r = v.to_a(true)
|
35
|
+
link_name = "#{v[:oml_sender]}::#{v[:dest_addr]}"
|
36
|
+
#r.insert 0, LINKS[link_name] || "XXX - #{link_name}"
|
37
|
+
r.insert 0, link_name
|
38
|
+
t.add_row(r)
|
39
|
+
end
|
40
|
+
OMF::Web.register_datasource t
|
41
|
+
end
|
42
|
+
|
43
|
+
def run
|
44
|
+
ep = OMF::OML::OmlSqlSource.new(@db_name, :check_interval => 3.0)
|
45
|
+
ep.on_new_stream() do |stream|
|
46
|
+
info "Stream: #{stream.stream_name}"
|
47
|
+
if stream.stream_name == 'pingmonitor_myping'
|
48
|
+
setup_table(stream)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
ep.run
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
wv = PingDB.new('sqlite://example/simple/data_sources/gimi31.sq3').run()
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
require 'omf_common/lobject'
|
3
|
+
OMF::Common::Loggable.init_log 'simple'
|
4
|
+
|
5
|
+
|
6
|
+
require 'omf_oml/table'
|
7
|
+
|
8
|
+
def load_environment
|
9
|
+
require 'omf-web/content/file_repository'
|
10
|
+
|
11
|
+
|
12
|
+
Dir.glob("#{File.dirname(__FILE__)}/data_sources/*.rb").each do |fn|
|
13
|
+
load fn
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'yaml'
|
17
|
+
Dir.glob("#{File.dirname(__FILE__)}/widgets/*.yaml").each do |fn|
|
18
|
+
h = YAML.load_file(fn)
|
19
|
+
if w = h['widget']
|
20
|
+
OMF::Web.register_widget w
|
21
|
+
else
|
22
|
+
MObject.error "Don't know what to do with '#{fn}'"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
# Configure the web server
|
29
|
+
#
|
30
|
+
opts = {
|
31
|
+
:app_name => 'simple',
|
32
|
+
:page_title => 'Simple Demo',
|
33
|
+
:handlers => {
|
34
|
+
# delay connecting to databases to AFTER we may run as daemon
|
35
|
+
:pre_rackup => lambda { load_environment },
|
36
|
+
}
|
37
|
+
}
|
38
|
+
require 'omf_web'
|
39
|
+
OMF::Web.start(opts)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
# Simple tab showing a line chart with supporting table
|
5
|
+
#
|
6
|
+
|
7
|
+
widget:
|
8
|
+
id: main
|
9
|
+
name: Main
|
10
|
+
top_level: true
|
11
|
+
priority: 900
|
12
|
+
type: layout/tabbed
|
13
|
+
widgets:
|
14
|
+
|
15
|
+
- name: Ping Line
|
16
|
+
type: data/line_chart3
|
17
|
+
data_source:
|
18
|
+
name: ping
|
19
|
+
mapping:
|
20
|
+
x_axis:
|
21
|
+
property: oml_ts_client
|
22
|
+
y_axis:
|
23
|
+
property: rtt
|
24
|
+
max: 2.0
|
25
|
+
group_by: link
|
26
|
+
axis:
|
27
|
+
x:
|
28
|
+
legend: Time (sec)
|
29
|
+
y:
|
30
|
+
legend: RTT (ms)
|
31
|
+
|
32
|
+
|
33
|
+
- name: Table
|
34
|
+
type: data/table2
|
35
|
+
data_source:
|
36
|
+
name: ping
|
37
|
+
|
38
|
+
|
data/lib/omf-web/config.ru
CHANGED
@@ -7,6 +7,12 @@ use ::Rack::ShowExceptions
|
|
7
7
|
OMF::Web::Runner.instance.life_cycle(:pre_rackup)
|
8
8
|
options = OMF::Web::Runner.instance.options
|
9
9
|
|
10
|
+
require 'omf-web/rack/session_authenticator'
|
11
|
+
use OMF::Web::Rack::SessionAuthenticator, #:expire_after => 10,
|
12
|
+
#:login_url => '/tab/login',
|
13
|
+
:no_session => ['^/resource/', '^/login', '^/logout']
|
14
|
+
|
15
|
+
|
10
16
|
map "/resource" do
|
11
17
|
require 'omf-web/rack/multi_file'
|
12
18
|
run OMF::Web::Rack::MultiFile.new(options[:static_dirs])
|
@@ -36,11 +42,33 @@ map "/tab" do
|
|
36
42
|
run OMF::Web::Rack::TabMapper.new(options)
|
37
43
|
end
|
38
44
|
|
39
|
-
map "/widget" do
|
40
|
-
require 'omf-web/rack/widget_mapper'
|
41
|
-
run OMF::Web::Rack::WidgetMapper.new(options)
|
45
|
+
# map "/widget" do
|
46
|
+
# require 'omf-web/rack/widget_mapper'
|
47
|
+
# run OMF::Web::Rack::WidgetMapper.new(options)
|
48
|
+
# end
|
49
|
+
|
50
|
+
map '/login' do
|
51
|
+
handler = Proc.new do |env|
|
52
|
+
# req = ::Rack::Request.new(env)
|
53
|
+
# #puts ">>> post?: #{req.post?} - #{req.params.inspect}"
|
54
|
+
# if req.post?
|
55
|
+
# email = req.params["email"]
|
56
|
+
# pw = req.params["password"]
|
57
|
+
# remember = req.params["remember"] == "on"
|
58
|
+
# Authenticator.signon(email, pw, remember)
|
59
|
+
# end
|
60
|
+
[301, {'Location' => '/tab', "Content-Type" => ""}, ['Next window!']]
|
61
|
+
end
|
62
|
+
run handler
|
42
63
|
end
|
43
64
|
|
65
|
+
map '/logout' do
|
66
|
+
handler = Proc.new do |env|
|
67
|
+
OMF::Web::Rack::SessionAuthenticator.logout
|
68
|
+
[301, {'Location' => '/tab', "Content-Type" => ""}, ['Next window!']]
|
69
|
+
end
|
70
|
+
run handler
|
71
|
+
end
|
44
72
|
|
45
73
|
map "/" do
|
46
74
|
handler = Proc.new do |env|
|