blob: a424249213df9e485c05eb0d5e5138b5b8d42a55 [file] [log] [blame]
Boyoung Jeong1cca5e82018-08-01 21:00:08 +09001/*
2 * Copyright 2016-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 ONOS GUI -- Openstack Telemetry View Module
19 */
20(function () {
21 'use strict';
22
23 // injected references
boyoung2a8549d22018-11-23 20:42:37 +090024 var $log, $scope, $location, ks, fs, cbs, ns, tov, ots, wss, tts, api, gs, ps, ds;
Boyoung Jeong1cca5e82018-08-01 21:00:08 +090025
boyoung2a8549d22018-11-23 20:42:37 +090026 // constants
27 var pCls = 'topo-p',
28 idTelemetry = 'topo-p-telemetry',
29 idTelemetryDiag = 'telemetry-dialog',
30 telemetryPanelOpts = {
31 edge: 'left',
32 width: 330, // telemetry panel width
33 }
34
35 // panels
36 var telemetry;
37
38 // selected info (by mouse click event)
39 var selectedItem
40
41 // constants
42 var ostIsActReq = 'openstackFlowStatsIsActivatedRequest',
43 ostIsActResp = 'openstackFlowStatsIsActivatedResponse',
44 ostCreateReq = 'openstackFlowStatsCreateRequest',
45 ostCreateResp = 'openstackFlowStatsCreateResponse';
46
47 var topoLion = function (x) {
48 return '#ttrafov#' + x + '#';
49 };
50
51 var overlay = {
52 overlayId: 'ostelemetry-overlay',
53 glyphId: 'm_details',
54 tooltip: 'Openstack Telemetry Overlay',
55
56 activate: function () {
57 $log.debug("Openstack telemetry topology overlay is ACTIVATED");
58 },
59 deactivate: function () {
60 destroyTelemetryPanel();
61 $log.debug("Openstack telemetry topology overlay is DEACTIVATED");
62 },
63
64 // detail panel button definitions
65 buttons: {
66 createHostTelemetryBtn: {
67 gid: 'm_details',
68 tt: 'Create Host-to-Host Telemetry',
69 cb: displayTelemetry
70 },
71 showRelatedTraffic: {
72 gid: 'm_relatedIntents',
73 tt: function () { return topoLion('tr_btn_show_related_traffic'); },
74 cb: function (data) { tts.showRelatedIntents(); },
75 },
76 },
77
78 hooks: {
79 multi: function (selectOrder) {
80 var selectedHost = new Object();
81 $log.debug("Selected object: ", selectOrder);
82 for (var index in selectOrder) {
83 if (index == 0) {
84 selectedHost.src = selectOrder[index];
85 $log.debug("Source host: ", selectedHost.src);
86 } else if (index == 1) {
87 selectedHost.dst = selectOrder[index];
88 $log.debug("Destination host: ", selectedHost.dst);
89 }
90 }
91
92 selectedItem = selectedHost;
93
94 tov.addDetailButton('showRelatedTraffic');
95 if(selectOrder.length == 2) {
96 tov.addDetailButton('createHostTelemetryBtn');
97 }
98 }
99 }
100 };
101
102 // Panel API
103 function createTopoPanel(id, opts) {
104 var p = ps.createPanel(id, opts),
105 pid = id,
106 header, body, footer;
107 p.classed(pCls, true);
108
109 function panel() {
110 return p;
111 }
112
113 function hAppend(x) {
114 return header.append(x);
115 }
116
117 function bAppend(x) {
118 return body.append(x);
119 }
120
121 function fAppend(x) {
122 return footer.append(x);
123 }
124
125 function setup() {
126 p.empty();
127
128 p.append('div').classed('header', true);
129 p.append('div').classed('body', true);
130 p.append('div').classed('footer', true);
131
132 header = p.el().select('.header');
133 body = p.el().select('.body');
134 footer = p.el().select('.footer');
135 }
136
137 function destroy() {
138 ps.destroyPanel(pid);
139 }
140
141 return {
142 panel: panel,
143 setup: setup,
144 destroy: destroy,
145 appendHeader: hAppend,
146 appendBody: bAppend,
147 appendFooter: fAppend,
148 };
149 }
150
151 function hideTelemetryPanel() {
152 telemetry.panel().hide();
153 }
154
155 function destroyTelemetryPanel() {
156 if(telemetry != null) {
157 telemetry.destroy();
158 }
159 telemetry = null;
160 }
161
162 function addInput(tbody, type, id, label, value) {
163 var tr = tbody.append('tr'),
164 lab;
165 if (typeof label === 'string') {
166 lab = label.replace(/_/g, ' ');
167 } else {
168 lab = label;
169 }
170
171 tr.append('td').attr('class', 'label').text(lab + ' :');
172
173 if (type == 'radio') {
174 var td = tr.append('td');
175 for(var index in value) {
176 if(index == 0) {
177 td.append('input').classed( type + '-input', true)
178 .attr('type', type)
179 .attr('value', value[index])
180 .attr('name', label)
181 .attr('id', id)
182 .attr('checked', 'true');
183 } else {
184 td.append('input').classed( type + '-input', true)
185 .attr('type', type)
186 .attr('name', label)
187 .attr('id', id)
188 .attr('value', value[index]);
189 }
190 td.append('span').text(value[index]);
191 }
192 } else {
193 tr.append('td').append('input').classed(type + '-input', true).attr('type', type)
194 .attr('id', id).attr('value', value);
195 }
196 }
197
198 function addButton(tr, callback, value) {
199 tr.append('td').append('input').classed('button-input', true).attr('type', 'button')
200 .attr('value', value).on('click', callback);
201 }
202
203 function makeButton(callback, text, keyName) {
204 var cb = fs.isF(callback),
205 key = fs.isS(keyName);
206
207 function invoke() {
208 cb && cb();
209 }
210
211 return createDiv('telemetry-button')
212 .text(text)
213 .on('click', invoke);
214 }
215
216 function createDiv(cls) {
217 var div = d3.select(document.createElement('div'));
218 if (cls) {
219 div.classed(cls, true);
220 }
221 return div;
222 }
223
224 function displayTelemetry() {
225 $log.debug("sendEvent openstackFlowStatsIsActivatedRequest: ", selectedItem);
226 wss.sendEvent(ostIsActReq, selectedItem);
227 }
228
229 function respIsActCb(selected) {
230 $log.debug("openstackFlowStatsIsActivatedResponse: ", selected);
231 if(telemetry == null) {
232 telemetry = createTopoPanel(idTelemetry, telemetryPanelOpts);
233 }
234 telemetry.setup();
235
236 var svg = telemetry.appendHeader('div')
237 .classed('icon', true)
238 .append('svg'),
239 title = telemetry.appendHeader('h2'),
240 table = telemetry.appendBody('table'),
241 tbody = table.append('tbody'),
242 glyphId = 'm_details';
243
244 gs.addGlyph(svg, glyphId, 30, 0, [1, 1]);
245
246 title.text('Create Openstack Telemetry');
247
248 addInput(tbody, 'text', 'srcIp', 'Source IP', selected.srcName);
249 addInput(tbody, 'text', 'dstIp', 'Destination IP', selected.dstName);
250 addInput(tbody, 'radio', 'ipProto', 'Protocol', selected.ipProtoList);
251 addInput(tbody, 'number', 'srcPort', 'Source Port', "");
252 addInput(tbody, 'number', 'dstPort', 'Destination Port', "");
253
254 telemetry.appendFooter('hr');
255 var footTr = telemetry.appendFooter('table').append('tbody').append('tr');
256
257 addButton(footTr, createTelemetry, 'Create');
258 addButton(footTr, hideTelemetryPanel, 'Cancel');
259
260 telemetry.panel().show();
261 }
262
263 function createTelemetry() {
264 var telemetryInfo = {};
265
266 telemetryInfo.srcIp = document.getElementById('srcIp').value;
267 telemetryInfo.dstIp = document.getElementById('dstIp').value;
268 telemetryInfo.ipProto = document.querySelector('input[name="Protocol"]:checked').value;
269 telemetryInfo.srcPort = document.getElementById('srcPort').value;
270 telemetryInfo.dstPort = document.getElementById('dstPort').value;
271
272 if(telemetryInfo.srcPort == ""){
273 telemetryInfo.srcPort = 0;
274 }
275 if(telemetryInfo.dstPort == ""){
276 telemetryInfo.dstPort = 0;
277 }
278
279 $log.debug("Creation request: ", telemetryInfo);
280 wss.sendEvent(ostCreateReq, telemetryInfo);
281 hideTelemetryPanel();
282 }
283
284 function respCreateCb(result) {
285 $log.debug("Creation response: ", result);
286
287 function dOK() {
288 if(result.result == "Failed"){
289 displayTelemetry(selectedItem);
290 } else {
291 destroyTelemetryPanel();
292 }
293 }
294
295 function createContent(value) {
296 var content = ds.createDiv();
297 content.append('p').text(value);
298 return content;
299 }
300
301 ds.openDialog(idTelemetryDiag, telemetryPanelOpts)
302 .setTitle("Create Telemetry " + result.result)
303 .addContent(createContent(result.value))
304 .addOk(dOK);
305 }
306
307 /*
308 Variable for Chart View
309 */
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900310 var hasFlow;
311
312 var gFlowId;
313 var gPeriod;
314
315 var labels = new Array(1);
316 var data = new Array(2);
317 for (var i = 0; i < 2; i++) {
318 data[i] = new Array(1);
319 }
320
321 var max;
322
323 function ceil(num) {
324 if (isNaN(num)) {
325 return 0;
326 }
327 var pre = num.toString().length - 1
328 var pow = Math.pow(10, pre);
329 return (Math.ceil(num / pow)) * pow;
330 }
331
332 function maxInArray(array) {
333 var merged = [].concat.apply([], array);
334 return Math.max.apply(null, merged);
335 }
336
boyoung2a8549d22018-11-23 20:42:37 +0900337 /*
338 Chart View : Controller
339 */
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900340 angular.module('ovOpenstacktelemetry', ["chart.js"])
341 .controller('OvOpenstacktelemetryCtrl',
342 ['$log', '$scope', '$location', 'FnService', 'ChartBuilderService', 'NavService',
343
344 function (_$log_, _$scope_, _$location_, _fs_, _cbs_, _ns_) {
345 var params;
346 $log = _$log_;
347 $scope = _$scope_;
348 $location = _$location_;
349 fs = _fs_;
350 cbs = _cbs_;
351 ns = _ns_;
352
353 params = $location.search();
354
355 if (params.hasOwnProperty('flowOpt')) {
356 $scope.flowOpt = params['flowOpt'];
357 hasFlow = true;
358 } else if (params.hasOwnProperty('periodOpt')) {
359 $scope.periodOpt = params['periodOpt'];
360 hasFlow = true;
361 } else {
362 hasFlow = false;
363 }
364
365 cbs.buildChart({
366 scope: $scope,
367 tag: 'openstacktelemetry',
368 query: params
369 });
370
371 $scope.$watch('chartData', function () {
372 if (!fs.isEmptyObject($scope.chartData)) {
373 $scope.showLoader = false;
374 var length = $scope.chartData.length;
375 labels = new Array(length);
376 for (var i = 0; i < 2; i++) {
377 data[i] = new Array(length);
378 }
379
380 $scope.chartData.forEach(function (cm, idx) {
381 data[0][idx] = (cm.curr_acc_packet - cm.prev_acc_packet);
382 data[1][idx] = (cm.curr_acc_byte - cm.prev_acc_byte);
383
384 labels[idx] = cm.label;
385 });
386 }
387
388 max = maxInArray(data)
389 $scope.labels = labels;
390 $scope.data = data;
391 $scope.options = {
392 scaleOverride : true,
393 scaleSteps : 10,
394 scaleStepWidth : ceil(max) / 10,
395 scaleStartValue : 0,
396 scaleFontSize : 16
397 };
398 $scope.onClick = function (points, evt) {
399 var label = labels[points[0]._index];
400 if (label) {
401 ns.navTo('openstacktelemetry', { flowOpt: label });
402 $log.log(label);
403 }
404 };
405
406 if (!fs.isEmptyObject($scope.annots)) {
407 $scope.flowIds = JSON.parse($scope.annots.flowIds);
408 $scope.periodOptions = JSON.parse($scope.annots.periodOptions);
409 }
410
411 $scope.onChange = function (flowId) {
412 gFlowId = flowId;
413 ns.navTo('openstacktelemetry', { periodOpt: gPeriod , flowOpt: flowId });
414 };
415
416 $scope.onPeriodChange = function (period) {
417 gPeriod = period;
418 ns.navTo('openstacktelemetry', { periodOpt: period , flowOpt: gFlowId });
419 };
420 });
421
422 $scope.series = ['Current Packet', 'Current Byte'];
423
424 $scope.labels = labels;
425 $scope.data = data;
426
427 $scope.chartColors = [
428 '#286090',
429 '#F7464A',
430 '#46BFBD',
431 '#FDB45C',
432 '#97BBCD',
433 '#4D5360',
434 '#8c4f9f'
435 ];
436 Chart.defaults.global.colours = $scope.chartColors;
437
438 $scope.showLoader = true;
439
440 $log.log('OvOpenstacktelemetryCtrl has been created');
boyoung2a8549d22018-11-23 20:42:37 +0900441 }])
442 // Network Topology View : Factory
443 .factory('OpenstacktelemetryService',
444 ['$log', 'FnService', 'WebSocketService', 'GlyphService', 'PanelService', 'DialogService',
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900445
boyoung2a8549d22018-11-23 20:42:37 +0900446 function (_$log_, _fs_, _wss_, _gs_, _ps_, _ds_) {
447 $log = _$log_;
448 fs = _fs_;
449 wss = _wss_;
450 gs = _gs_;
451 ps = _ps_;
452 ds = _ds_;
453
454 var handlers = {},
455 telemetryOverlay = 'ostelemetry-overlay',
456 defaultOverlay = 'traffic';
457
458 handlers[ostIsActResp] = respIsActCb;
459 handlers[ostCreateResp] = respCreateCb;
460
461 wss.bindHandlers(handlers);
462
463 return {
464 displayTelemetry: displayTelemetry
465 };
466 }])
467 .run(['$log', 'TopoOverlayService', 'OpenstacktelemetryService', 'TopoTrafficService',
468
469 function (_$log_, _tov_, _ots_, _tts_) {
470 $log = _$log_;
471 tov = _tov_;
472 ots = _ots_;
473 tts = _tts_;
474 tov.register(overlay);
475 }]
476 );
Boyoung Jeong1cca5e82018-08-01 21:00:08 +0900477}());