2 * Copyright (c) 2016 highstreet technologies GmbH and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 define(['app/mwtnConnect/mwtnConnect.module',
10 'app/mwtnConnect/mwtnConnect.services',
11 'app/mwtnCommons/mwtnCommons.module'],
12 function(mwtnConnectApp) {
14 mwtnConnectApp.register.controller('mwtnConnectCtrl', ['$scope', '$rootScope', '$timeout', '$window', '$q', 'uiGridConstants', '$uibModal', '$mwtnConnect', '$mwtnLog', 'NetConfServer',
15 function($scope, $rootScope, $timeout, $window, $q, uiGridConstants, $uibModal, $mwtnConnect, $mwtnLog, NetConfServer) {
17 var COMPONENT = 'mwtnConnectCtrl';
18 $mwtnLog.info({component: COMPONENT, message: 'mwtnConnectCtrl started!'});
20 $rootScope.section_logo = 'src/app/mwtnConnect/images/sdncConnect.png'; // Add your topbar logo location here such as 'assets/images/logo_topology.gif'
22 $scope.highlightFilteredHeader = $mwtnConnect.highlightFilteredHeader;
24 $scope.oneAtATime = true;
25 $scope.status = {requiredNes: true};
27 $scope.spinner.TEST = true;
29 var requiredNesConnectionStatusCellTemplate = [
30 '<div class="ui-grid-cell-contents" ng-class="{ \'green\': grid.getCellValue(row, col) === \'connected\'}">',
31 ' <i ng-class="{\'fa fa-link\': grid.getCellValue(row, col) === \'connected\', \'fa fa-chain-broken\': grid.getCellValue(row, col) !== \'connected\'}" aria-hidden="true"></i>',
32 ' <span>{{grid.getCellValue(row, col)}}</span>',
35 var nameCellTemplate = [
36 '<div class="ui-grid-cell-contents">',
37 ' <a href="{{row.entity.webUri}}" target="_blank" title="Access NE web application" ng-show="row.entity.webUri">',
38 ' <i class="fa fa-external-link" aria-hidden="true"></i>',
39 ' <span>{{grid.getCellValue(row, col)}}</span>',
41 ' <span ng-show="!row.entity.webUri">{{grid.getCellValue(row, col)}}</span>',
44 // '<button class="btn btn-primary" ng-click="grid.appScope.edit(row.entity)"><i class="fa fa-pencil"></i></button>',
45 // '<button class="btn btn-default" ng-click="grid.appScope.delete(row.entity)"><i class="fa fa-times mwtnError"></i></button>',
46 var requiredNesActionCellTemplate = [
47 '<span> </span>',
48 '<div class="btn-group">',
49 ' <button class="btn btn-primary" ng-click="grid.appScope.connect(row.entity)" title="Mount"><i class="fa fa-link" aria-hidden="true"></i></button>',
50 ' <button class="btn btn-warning" ng-click="grid.appScope.disconnect(row.entity)" title="Unmount"><i class="fa fa-chain-broken" aria-hidden="true"></i></button>',
51 ' <button class="btn btn-success" ng-click="grid.appScope.showDetails(row.entity)" title="Information"><i class="fa fa-info-circle" aria-hidden="true"></i></button>',
52 '<div class="btn-group">',
53 '<span> </span>',
55 ' <a class="btn btn-primary" ng-href="#/pnfFault/{{row.entity.name}}" title="Fault Management" target="fm">F</a>',
56 ' <a class="btn btn-primary" ng-href="#/pnfBrowser/{{row.entity.name}}" title="Configuration Management" target="cm">C</a>',
57 ' <a class="btn btn-default" title="Accounting Management" target="am">A</a>',
58 ' <a class="btn btn-primary" ng-href="#/pnfPerformanceHistory/{{row.entity.name}}" title="Performance Management" target="pm">P</a>',
59 ' <a class="btn btn-default" title="Security Management" target="sm">S</a>',
61 '<span> </span>',
62 '<div class="btn-group">',
63 ' <a class="btn btn-primary" ng-href="#/pnfInventory/{{row.entity.name}}" title="Inventory Management" target="im">I</a>',
65 '<span> </span>'].join('');
68 $scope.requiredNesGridOptions = JSON.parse(JSON.stringify($mwtnConnect.gridOptions));
69 $scope.requiredNesGridOptions.rowHeight = 44;
70 $scope.requiredNesGridOptions.columnDefs = [
71 { field: 'connectionStatus', type: 'string', displayName: 'Connection status', headerCellClass: $scope.highlightFilteredHeader, width : 160, cellTemplate: requiredNesConnectionStatusCellTemplate },
72 // { field: 'id', type: 'number', displayName: 'Id', headerCellClass: $scope.highlightFilteredHeader, width : 50, cellClass: 'number', pinnedLeft : true , sort: {
73 // direction: uiGridConstants.ASC,
77 { field: 'name', type: 'string', displayName: 'Name', headerCellClass: $scope.highlightFilteredHeader, width : 230, cellTemplate: nameCellTemplate, pinnedLeft : true , sort: {
78 direction: uiGridConstants.ASC,
82 { field: 'ipaddress', type: 'number', displayName: 'IP address', headerCellClass: $scope.highlightFilteredHeader, width : 140, cellClass: 'number' },
83 { field: 'port', type: 'number', displayName: 'Port', headerCellClass: $scope.highlightFilteredHeader, width : 80, cellClass: 'number' },
84 { field: 'client', type: 'number', displayName: 'Client', headerCellClass: $scope.highlightFilteredHeader, width : 140 },
85 { field: 'username', type: 'string', displayName: 'User name', headerCellClass: $scope.highlightFilteredHeader, width : 100, visible: false },
86 { field: 'password', type: 'string', displayName: 'Password', headerCellClass: $scope.highlightFilteredHeader, width : 100, visible: false },
87 { field: 'radioSignalIds', type: 'string', displayName: 'Radio signal ids', headerCellClass: $scope.highlightFilteredHeader, width : 150, visible: false},
90 enableSorting : false,
91 enableFiltering: false,
92 cellTemplate: requiredNesActionCellTemplate,
98 var unknownNesActionCellTemplate = [
99 '<a class="vCenter" ng-class="{attention: grid.appScope.hover, hidden: onfAirInterfaceRevision}" >',
100 '<button class="btn btn-default" ng-show="row.entity[\'node-id\'] !== \'controller-config\'" ng-click="grid.appScope.unmount(row.entity)">Unmount</button>',
101 '<button class="btn btn-primary" ng-show="row.entity[\'node-id\'] !== \'controller-config\' && row.entity.onfCoreModelRevision" ng-click="grid.appScope.addToRequiredNetworkElements(row.entity)">',
102 '<i class="pull-left fa fa-spinner fa-pulse" ng-show="row.entity.spinner"></i>',
103 '<span class="white">{{ "MWTN_MAKE_KNOWN" | translate }}<span>',
105 '<button class="btn btn-default" ng-click="grid.appScope.showDetails(row.entity, false)"><i class="fa fa-info-circle" aria-hidden="true"></i></button>',
106 '</a>' ].join('<span> </span>');
107 $scope.unknownNesGridOptions = JSON.parse(JSON.stringify($mwtnConnect.gridOptions));
108 $scope.unknownNesGridOptions.rowHeight = 44;
109 $scope.unknownNesGridOptions.columnDefs = [
110 { field: 'node-id', type: 'string', displayName: 'Name', headerCellClass: $scope.highlightFilteredHeader, width : 200, sort: {
111 direction: uiGridConstants.ASC,
114 { field: 'netconf-node-topology:host', type: 'number', displayName: 'IP address', headerCellClass: $scope.highlightFilteredHeader, width : 150, cellClass: 'number' },
115 { field: 'netconf-node-topology:port', type: 'number', displayName: 'NetConf port', headerCellClass: $scope.highlightFilteredHeader, width : 120, cellClass: 'number' },
116 { field: 'onfCoreModelRevision', type: 'string', displayName: 'CoreModel revision', headerCellClass: $scope.highlightFilteredHeader, width : 160, cellClass: 'number' },
117 { field: 'onfAirInterfaceRevision', type: 'string', displayName: 'AirInterface revision', headerCellClass: $scope.highlightFilteredHeader, width : 160, cellClass: 'number' },
118 { field: 'netconf-node-topology:connection-status', type: 'string', displayName: 'Connection status', headerCellClass: $scope.highlightFilteredHeader, width : 160 },
121 enableSorting : false,
122 enableFiltering: false,
123 cellTemplate: unknownNesActionCellTemplate,
130 * Request all defined (required) network elements from database and
131 * update the corresponding table in the ui.
133 var getRequiredNetworkElements = function() {
134 $mwtnConnect.getRequiredNetworkElements().then(function(networkElements) {
135 $scope.requiredNesGridOptions.data = networkElements;
136 getActualNetworkElements();
138 $scope.requiredNesGridOptions.data = [];
141 getRequiredNetworkElements();
144 * A function, which returns a boolean, which indicates, whether a network
145 * element is required or not.
146 * @param {string} neId - A mount point identifier.
147 * @return {boolean} True, if network element is required in the network, otherwise false.
149 var isRequired = function(neId) {
150 if ($scope.requiredNesGridOptions.data) {
152 $scope.requiredNesGridOptions.data.map(function(rne) {
153 if (rne.name === neId) result = true;
161 var setConnectionStatus = function(neId, connectionStatus) {
162 if ($scope.requiredNesGridOptions.data) {
163 $scope.requiredNesGridOptions.data.map(function(rne) {
164 if (rne.name === neId) rne.connectionStatus = connectionStatus;
169 var setValues = function(ane) {
170 if ($scope.requiredNesGridOptions.data) {
172 var getExtension = function(extensions, name) {
173 if (extensions === undefined) {
176 var result = extensions.filter(function(ex){
177 return ex['value-name'] === name;
181 if (result.length > 0) {
189 $scope.requiredNesGridOptions.data.map(function(rne) {
190 // TODO use filter! and avoid push?
191 if (rne.name === ane['node-id']) {
192 rne.connectionStatus = ane['netconf-node-topology:connection-status'];
193 rne.ipaddress = ane['netconf-node-topology:host'];
194 rne.port = ane['netconf-node-topology:port'];
195 rne.client = ane.client;
197 rne.onfCapabilities = ane.onfCapabilities;
199 var extensions = ['webUri', 'cliAddress', 'appCommand'];
200 extensions.map(function(extension){
201 rne[extension] = undefined;
203 if (ane.onfCoreModelRevision) {
204 $mwtnConnect.getActualNetworkElement(ane['node-id'], ane.onfCoreModelRevision).then(function(success){
205 success = $mwtnConnect.yangifyObject(success);
206 extensions.map(function(extension){
207 rne[extension] = getExtension(success['network-element'].extension, extension);
218 var getActualNetworkElements = function() {
220 if ($scope.requiredNesGridOptions.data) {
221 $scope.requiredNesGridOptions.data.map(function(ne) {
222 // ne.connectionStatus = 'disconnected';
225 $mwtnConnect.getMountPoints().then(function(mountpoints) {
226 $scope.unknownNesGridOptions.data = [];
227 mountpoints.map(function(mountpoint) {
228 if (isRequired(mountpoint['node-id'])) {
229 // setConnectionStatus(ne['node-id'], ne['netconf-node-topology:connection-status']);
230 setValues(mountpoint);
232 // console.log('mountpoint', JSON.stringify(mountpoint));
233 $scope.unknownNesGridOptions.data.push(mountpoint);
237 $mwtnLog.info({component: COMPONENT, message: JSON.stringify(error)});
241 $scope.netconfServer = {};
244 * A function which inquires data from a netconf server and stores it in a database.
245 * @param {{'node-id': string, ipAddress: string, port: number, username: string, password: string}} netconfServer - A netConf server object with all connectivity parameters.
247 $scope.addToRequiredNetworkElements = function(netconfServer) {
249 $scope.netconfServer = netconfServer;
250 var neId = netconfServer['node-id'];
252 var index = $scope.unknownNesGridOptions.data.map(function(item) {
253 return item['node-id'];
254 }).indexOf(netconfServer['node-id']);
257 $mwtnConnect.getSingleDocument('mwtn', 'required-networkelement', neId).then(function(doc){
258 // Network element alrady exists in database
260 $scope.unknownNesGridOptions.data[index].spinner = true;
262 // $onapAai.createPnf(neId, doc).then(function(success){
264 // }, function(error) {
268 $mwtnConnect.createSingleDocument('mwtn', 'required-networkelement', neId, doc).then(function(success){
269 $timeout(function() {
270 $scope.status.requiredNes = true;
271 $scope.unknownNesGridOptions.data[index].spinner = false;
274 $timeout(function() {
275 $scope.status.requiredNes = true;
276 $scope.unknownNesGridOptions.data[index].spinner = false;
278 console.log(JSON.stringify(error));
281 // Network element does not exist in database, data inqured from real network element
282 var modalInstance = $uibModal.open({
284 ariaLabelledBy: 'modal-title',
285 ariaDescribedBy: 'modal-body',
286 templateUrl: 'src/app/mwtnConnect/templates/addToRequired.tpl.html',
287 controller: 'AddToRequiredMessageCtrl',
290 netconfServer: function () {
291 return $scope.netconfServer;
296 modalInstance.result.then(function (netconfServer) {
297 $scope.unknownNesGridOptions.data[index].spinner = true;
298 $mwtnConnect.addRequiredNetworkElement(netconfServer).then(function(success){
299 $mwtnLog.info({component: COMPONENT, message: 'Adding to database: ' + netconfServer['node-id']});
301 // $onapAai.createPnf(netconfServer['node-id'], success.config.data).then(function(success){
303 // }, function(error) {
307 $timeout(function() {
308 $scope.status.requiredNes = true;
309 $scope.unknownNesGridOptions.data[index].spinner = false;
312 $scope.unknownNesGridOptions.data[index].spinner = false;
313 $mwtnLog.error({component: COMPONENT, message: JSON.stringify(error)});
316 $mwtnLog.info({component: COMPONENT, message: 'Creation of new planned NetworkElement dismissed!'});
322 $scope.newMountingPoint = {
323 name: 'new-netconf-server',
324 ipaddress: '127.0.0.1',
330 $scope.mount = function() {
331 $scope.mountError = undefined;
332 $scope.mountSuccess = undefined;
333 $scope.processing = true;
334 $mwtnConnect.mount($scope.newMountingPoint).then(function(success){
335 $scope.processing = false;
336 $scope.mountSuccess = ['NETCONF server', $scope.newMountingPoint.name, 'successfully mounted.'].join(' ');
338 $scope.processing = false;
339 $scope.mountError = ['NETCONF server', $scope.newMountingPoint.name, 'could not be mounted.'].join(' ');
343 $scope.connect = function(ne) {
344 ne.connectionStatus = 'connecting...';
345 $mwtnConnect.mount(ne).then(function(success){
346 // ne.connectionStatus = 'connected';
348 // ne.connectionStatus = 'connected';
352 $scope.disconnect = function(ne) {
353 ne.connectionStatus = 'connecting...';
354 $mwtnConnect.unmount(ne.name).then(function(success){
355 ne.connectionStatus = 'disconnected';
357 ne.connectionStatus = 'unknown';
361 $scope.showDetails = function(ne, required) {
362 $scope.currentNetworkElement = ne;
363 $scope.currentNetworkElement.required = required;
364 if (required !== false) {
365 $scope.currentNetworkElement.required = true;
367 var modalInstance = $uibModal.open({
369 ariaLabelledBy: 'modal-title',
370 ariaDescribedBy: 'modal-body',
371 templateUrl: 'src/app/mwtnConnect/templates/mountPointDetails.tpl.html',
372 controller: 'MountPointDetailsCtrl',
375 currentNetworkElement: function () {
376 return $scope.currentNetworkElement;
381 modalInstance.result.then(function(success) {
382 if (success.hide || success.delete) {
383 var nodeId = success.hide || success.delete;
384 $scope.requiredNesGridOptions.data.map(function(item, index, array){
385 if (item.name === nodeId) {
386 array.splice(index, 1);
390 $mwtnLog.info({component: COMPONENT, message: 'Mointpoint details closed'});
391 }, function (error) {
392 $mwtnLog.info({component: COMPONENT, message: 'Mointpoint details dismissed!'});
396 var removeFromNodeList = function(nodeId) {
397 var index = $scope.unknownNesGridOptions.data.length;
399 if ($scope.unknownNesGridOptions.data[index]['node-id'] === nodeId) {
400 $scope.unknownNesGridOptions.data.splice(index, 1);
405 $scope.unmount = function(netConfServer) {
406 netConfServer['netconf-node-topology:connection-status'] = 'disconnecting...';
407 $mwtnConnect.unmount(netConfServer['node-id']).then(function(response) {
408 $mwtnLog.info({component: COMPONENT, message: 'Mounting point deleted: ' + netConfServer['node-id'] });
409 removeFromNodeList(netConfServer['node-id']);
411 $mwtnLog.info({component: COMPONENT, message: 'Unmounting of '+netConfServer['node-id']+' failed!'});
412 removeFromNodeList(netConfServer['node-id']);
416 $scope.edit = function(row) {
417 console.info(JSON.stringify(row));
419 $scope.delete = function(row) {
420 console.info(JSON.stringify(row));
423 // Connection status log
424 $scope.gridOptionsConnectionStatusLog = {
425 paginationPageSizes: [25, 100, 1000, 10000],
426 paginationPageSize: 25,
427 useExternalPagination: true,
428 useExternalSorting: true,
429 enablePaginationControls: false,
430 enableFiltering: true,
431 useExternalFiltering: true,
434 // { field: 'id', type: 'number', displayName: 'No.', headerCellClass: $scope.highlightFilteredHeader, width : 50, cellClass: 'number', pinnedLeft : true },
435 { field: 'timestamp', type: 'string', displayName: 'Timestamp', headerCellClass: $scope.highlightFilteredHeader, width : 200, sort: {
436 direction: uiGridConstants.DESC,
439 { field: 'nodeName', type: 'string', displayName: 'Node name', headerCellClass: $scope.highlightFilteredHeader, width: 200 },
440 { field: 'connectionStatus', type: 'string', displayName: 'Connection status', headerCellClass: $scope.highlightFilteredHeader, width: 500, cellTemplate: requiredNesConnectionStatusCellTemplate }
443 onRegisterApi: function(gridApi) {
444 $scope.gridApi = gridApi;
445 $scope.gridApi.core.on.filterChanged( $scope, $scope.filter);
446 $scope.gridApi.core.on.sortChanged( $scope, $scope.sortChanged );
447 $scope.sortChanged($scope.gridApi.grid, [ $scope.gridOptionsConnectionStatusLog.columnDefs[1] ] );
449 $scope.gridApi.pagination.on.paginationChanged($scope, function (newPage, pageSize) {
450 $scope.paginationOptions.pageNumber = newPage;
451 $scope.paginationOptions.pageSize = pageSize;
457 // data visible in connection status log
469 $scope.filter = function() {
470 var grid = this.grid;
473 //get all columns where data was typed in
474 angular.forEach(grid.columns, function(value, key) {
475 if(value.filters[0].term) {
477 var col = findColumn(value.displayName);
478 var val = value.filters[0].term;
481 case 'event.timeStamp':
482 //convert timestamp to db format
483 val = $mwtnConnect.TimeStampToONFFormat(value.filters[0].term);
486 if ('connected'.startsWith(value.filters[0].term.toLowerCase())) {
487 val = 'ObjectCreationNotificationXml'.toLowerCase();
489 if ('disconnected'.startsWith(value.filters[0].term.toLowerCase())) {
490 val = 'ObjectDeletionNotificationXml'.toLowerCase();
494 columns.push({ column: col, value: val }); //create column object
498 if (columns.length ===0 ) { //all filter data cleared away
499 $scope.state.filter = false;
500 $scope.state.lastfilter = null;
502 //get unfiltered data
503 $mwtnConnect.getData(($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize,
504 $scope.paginationOptions.pageSize,
505 $scope.state.lastSort,
506 $scope.state.lastfilter).then(function(response) {
507 if (response.data.hits.hits) {
508 processResponseRecreateList(response);
513 var filter = {"query": {"bool":{"must":[]}}};
514 //create filter objects
515 var prefixs = columns.map(function(obj){
517 prefixObj[obj.column] = obj.value;//add like: {column: "fault.counter", value: "1"} => {"fault.counter":1}
518 return {prefix:prefixObj}; // => {"prefix":{...}}
520 prefixs.push({"match":{"event.nodeName":"SDN-Controller"}});
522 //add objects to must property
523 filter.query.bool.must = prefixs;
525 $scope.state.lastfilter=filter;
526 $scope.state.filter=true;
528 //send data to sdnevents/eventlog/_search
529 $mwtnConnect.getData(($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize,
530 $scope.paginationOptions.pageSize,
531 $scope.state.lastSort,
532 $scope.state.lastfilter).then(function(response) {
533 if (response.data.hits.total>0) { //only, when hits exist
534 processResponseRecreateList(response);
535 $scope.gridOptionsConnectionStatusLog.totalItems = response.data.hits.total;
537 //clear data from list
539 $scope.gridOptionsConnectionStatusLog.totalItems = 0;
540 $scope.gridOptionsConnectionStatusLog.maxCount = 0;
541 $scope.state.filter=false;
542 $scope.state.lastfilter=null;
549 $scope.sortChanged=function(grid, sortColumns){ // sortColumns is an array containing just the column sorted in the grid
550 if (sortColumns.length > 0) {
551 if (sortColumns[0].sort) {
552 var name = sortColumns[0].displayName; // the name of the column sorted
553 var direction = sortColumns[0].sort.direction; // the direction of the column sorted: "desc" or "asc"
554 sort(direction, findColumn(name) );
557 $scope.state.sort = false;
558 $scope.state.lastSort=null;
560 $mwtnConnect.getData( ($scope.paginationOptions.pageNumber-1) * $scope.paginationOptions.pageSize,
561 $scope.paginationOptions.pageSize,
562 $scope.state.lastSort,
563 $scope.state.lastfilter).then(function(response) {
564 processResponseRecreateList(response);
566 processResponseRecreateList([]);
571 var processResponseRecreateList = function(response) {
572 if (!response.data || !response.data.hits) {
574 $scope.gridOptionsConnectionStatusLog.totalItems = 0; // needed by ui-grid to calculate page number, always update!
575 $scope.gridOptionsConnectionStatusLog.maxCount = 0;
579 if($scope.gridOptionsConnectionStatusLog.maxCount < response.data.hits.total){
580 $scope.gridOptionsConnectionStatusLog.maxCount = response.data.hits.total; //only if total is higher (can be lower due to eg filtering)
582 var list = response.data.hits.hits.map(function(entry) {
584 var status = 'unknown';
585 if (entry._source.event.type === 'ObjectCreationNotificationXml' ) {
586 status = 'connected';
587 } else if (entry._source.event.type === 'ObjectDeletionNotificationXml' ) {
588 status = 'disconnected';
592 timestamp: $mwtnConnect.formatTimeStamp(entry._source.event.timeStamp),
593 nodeName: entry._source.event.objectId,
594 connectionStatus: status
598 $scope.gridOptionsConnectionStatusLog.totalItems = response.data.hits.total; // needed by ui-grid to calculate page number, always update!
601 $scope.paginationOptions = {
607 var getPage = function() {
608 //from, how many, sort, filter
609 $mwtnConnect.getData( ($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize,
610 $scope.paginationOptions.pageSize,
611 $scope.state.lastSort,
612 $scope.state.lastfilter).then(function (success) {
613 $scope.gridOptionsConnectionStatusLog.totalItems = success.data.hits.total;
614 processResponseRecreateList(success);
616 $scope.gridOptionsConnectionStatusLog.totalItems = success.data.hits.total;
617 processResponseRecreateList([]);
618 $mwtnLog.info({component: COMPONENT, message: JSON.stringify(error)});
622 var processResponseAddToList = function(response) {
623 if (response.data.hits.hits) {
624 if($scope.gridOptionsConnectionStatusLog.maxCount < response.data.hits.total) {
625 $scope.gridOptionsConnectionStatusLog.maxCount = response.data.hits.total; //only if total is higher (can be lower due to eg filtering)
627 response.data.hits.hits.map(function(entry) {
628 var status = 'disconnected';
629 if (entry._source.event.type === 'ObjectCreationNotificationXml' ) {
630 status = 'connected';
634 timestamp: $mwtnConnect.formatTimeStamp(entry._source.event.timeStamp),
635 nodeName: entry._source.event.objectId,
636 connectionStatus: status
638 $scope.data.push(log);
641 $scope.gridOptionsConnectionStatusLog.totalItems = response.data.hits.total; // needed by ui-grid to calculate page number, always update!
644 var sort = function (direction, columnName) {
647 var sort = [ sortObj ];
649 case uiGridConstants.ASC:
651 sortObj[columnName]={order : 'asc'};
654 $scope.state.lastSort=sort;
656 $mwtnConnect.getData(($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize,
657 $scope.paginationOptions.pageSize,
658 $scope.state.lastSort,
659 $scope.state.lastfilter).then(function(response) {
660 if (response.data.hits.hits) {
661 processResponseRecreateList(response);
662 $scope.state.sort=true;
667 case uiGridConstants.DESC:
668 sortObj[columnName]={order : 'desc'};
670 $scope.state.lastSort=sort;
672 $mwtnConnect.getData(($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize,$scope.paginationOptions.pageSize,$scope.state.lastSort,$scope.state.lastfilter).then(function(response) {
673 if (response.data.hits.hits) {
674 processResponseRecreateList(response);
675 $scope.state.sort=true;
682 $scope.state.sort=false;
683 $scope.state.lastSort=null;
685 $mwtnConnect.getData(($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize,
686 $scope.paginationOptions.pageSize,
687 $scope.state.lastSort,
688 $scope.state.lastfilter).then(function(response) {
689 processResponseRecreateList(response);
695 var findColumn= function(name) {
696 if(name === 'Timestamp'){ return 'event.timeStamp'; }
697 else if(name === 'Node name'){ return 'event.objectId'; }
698 else if(name === 'Connection status'){ return 'event.type'; }
701 $scope.paginationStatusMessage = function() {
703 var startnum=($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize+1;
704 var pagenednum=($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize+1+$scope.data.length;
705 if(pagenednum>$scope.gridOptionsConnectionStatusLog.totalItems) pagenednum=pagenednum-1; //reduce by initial added 1
707 if($scope.state.filter){
708 var filterTpl = 'Showing {0} to {1} of {2} items (filtered from {3} total items)';
709 return filterTpl.format(startnum, pagenednum, $scope.gridOptionsConnectionStatusLog.totalItems, $scope.gridOptionsConnectionStatusLog.maxCount);
712 var defaultTpl = 'Showing {0} to {1} of {2} total items';
713 return defaultTpl.format( startnum, pagenednum, $scope.gridOptionsConnectionStatusLog.maxCount);
717 $scope.refreshLog = function() {
720 var from = ($scope.paginationOptions.pageNumber-1)*$scope.paginationOptions.pageSize;
721 var size = $scope.paginationOptions.pageSize;
722 $scope.processing = true;
723 $scope.spinner.connectionStatusLog = true;
724 $mwtnConnect.getData(from, size, $scope.state.lastSort, $scope.state.lastfilter).then(function(logEntries){
725 $scope.processing = false;
726 $scope.spinner.connectionStatusLog = false;
727 processResponseRecreateList(logEntries);
729 $scope.processing = false;
730 $scope.spinner.connectionStatusLog = false;
731 console.error(JSON.stringify(error));
736 $scope.status = {requiredNes : true};
737 $scope.separator = $mwtnConnect.separator; //' '
738 $scope.$watch('status', function(status, oldValue) {
739 Object.keys(status).map(function(key){
740 if (status[key] && status[key] !== oldValue[key]) {
743 getRequiredNetworkElements();
746 getActualNetworkElements();
749 $scope.mountSuccess = undefined;
750 $scope.mountError = undefined;
752 case 'connectionStatusLog':
753 $window.dispatchEvent(new Event("resize"));
762 // actualNetworkElements - NE added/deleted
763 var listenToActualNetworkElementsNotifications = function(socketLocation) {
765 var notificatinSocket = new WebSocket(socketLocation);
767 notificatinSocket.onmessage = function(event) {
768 console.log('Event received.');
769 setTimeout(function() {
770 getActualNetworkElements();
773 notificatinSocket.onerror = function(error) {
774 console.error("Socket error: " + error);
776 notificatinSocket.onopen = function(event) {
777 console.info("Socket connection opened.");
779 notificatinSocket.onclose = function(event) {
780 console.info("Socket connection closed.");
783 console.error("Error when creating WebSocket" + e);
787 // var path = '/network-topology:network-topology/network-topology:topology[network-topology:topology-id = "topology-netconf"]';
788 // var path = "/opendaylight-inventory:nodes"; // [sko] works!
789 var path = '/network-topology:network-topology'; // for whatever reason it does not work, but work in Lithium.
790 $mwtnConnect.registerForOdlEvents(path, function(socketLocation) {
791 listenToActualNetworkElementsNotifications(socketLocation);
794 var listenToEventManagerNotifications = function() {
795 $mwtnConnect.getMwtnWebSocketUrl().then(function(success){
797 var notificationSocket = new WebSocket(success);
799 notificationSocket.onmessage = function(event) {
800 // we process our received event here
801 if (typeof event.data === 'string') {
802 // console.log("Client Received:\n" + event.data);
803 // console.log("---------------------------");
804 $mwtnConnect.formatData(event).then(function(formated) {
805 switch (formated.notifType) {
806 case 'ProblemNotification':
807 case 'AttributeValueChangedNotification':
810 case 'ObjectCreationNotification':
811 case 'ObjectDeletionNotification':
812 if (formated.nodeName === 'SDN-Controller') {
813 $timeout(function() {getActualNetworkElements();}, 500);
817 console.error('Missing implementation for', formated.notifType);
825 notificationSocket.onerror = function(error) {
826 console.log("Socket error: " + error);
829 notificationSocket.onopen = function(event) {
830 console.log("Socket connection opened.");
832 function subscribe() {
833 if (notificationSocket.readyState === notificationSocket.OPEN) {
836 'scopes' : [ 'ObjectCreationNotification', 'ObjectDeletionNotification' ]
838 notificationSocket.send(JSON.stringify(data));
844 notificationSocket.onclose = function(event) {
845 console.log("Socket connection closed.");
848 console.error("Error when creating WebSocket.\n" + e);
851 console.error("Error when creating WebSocket.\n" + error);
854 listenToEventManagerNotifications();
858 mwtnConnectApp.register.controller('AddToRequiredMessageCtrl', ['$scope', '$uibModalInstance', '$mwtnConnect', 'netconfServer',
859 function ($scope, $uibModalInstance, $mwtnConnect, netconfServer) {
861 $scope.netconfServer = netconfServer;
863 $mwtnConnect.getMountPoint(netconfServer['node-id']).then(
865 * @param {{'node-id':string, 'netconf-node-topology:tcp-only': boolean, 'netconf-node-topology:host', string, 'netconf-node-topology:keepalive-delay':number, 'netconf-node-topology:port':number, 'netconf-node-topology:username':string, 'netconf-node-topology:password': string}} mountpoint - The mointpoint form topology-netconf
867 function(mountpoint) {
868 $scope.netconfServer.username = mountpoint['netconf-node-topology:username'];
869 $scope.netconfServer.password = mountpoint['netconf-node-topology:password'];
872 console.log(JSON.stringify(error));
882 $mwtnConnect.getAllData('mwtn', 'site', 0, 20, sort).then(
884 // console.log(JSON.stringify(sites));
885 if (sites.data.hits.hits) {
886 sites.data.hits.hits.map(function(site){
887 $scope.sites.push({id:site._source.id, name:site._source.name});
889 // console.log($scope.sites);
897 $scope.ok = function () {
898 $uibModalInstance.close($scope.netconfServer);
901 $scope.cancel = function () {
902 $uibModalInstance.dismiss('cancel');
905 $scope.$watch('netconfServer.site', function(newValue, oldValue) {
906 if (newValue !== oldValue) {
918 $mwtnConnect.getFilteredSortedData('mwtn', 'site', 0, 20, sort, query).then(
920 // console.log(JSON.stringify(sites));
921 if (sites.data.hits.hits) {
922 $scope.sites = sites.data.hits.hits.map(function(site){
923 return {id:site._source.id, name:site._source.name};
925 // console.log($scope.sites);
936 mwtnConnectApp.register.controller('MountPointDetailsCtrl', ['$scope', '$uibModalInstance', '$uibModal', '$mwtnConnect', '$mwtnLog', 'currentNetworkElement',
937 function ($scope, $uibModalInstance, $uibModal, $mwtnConnect, $mwtnLog, currentNetworkElement) {
939 var COMPONENT = 'MountPointDetailsCtrl';
940 // $mwtnLog.info({component: COMPONENT, message: 'MountPointDetailsCtrl started!'});
943 ne: currentNetworkElement,
947 ipAddress: '127.0.0.1',
950 getLink : function() {
951 if (currentNetworkElement.webUri) {
952 return currentNetworkElement.webUri;
954 return [this.protocol,'://', this.ipAddress, this.url ].join('');
962 ipAddress: '127.0.0.1',
963 getCommand : function() {
964 if (currentNetworkElement.cliAddress) {
965 return currentNetworkElement.cliAddress;
967 return [this.protocol, ' ', this.user, '@', this.ipAddress].join('');
969 copyToClipboard : function () {
970 $scope.data.application.copied = false;
972 var message = 'Copied to clipboard! ' + this.getCommand();
973 $mwtnLog.info({component: COMPONENT, message: message});
979 commandTemplate: 'VendorApp --ne {0}',
980 ipAddress: '127.0.0.1',
981 getCommand : function() {
982 if (currentNetworkElement.appCommand) {
983 return currentNetworkElement.appCommand;
985 return this.commandTemplate.format(this.ipAddress);
987 copyToClipboard : function () {
988 $scope.data.terminal.copied = false;
989 $scope.data.application.copied = true;
990 var message = 'Copied to clipboard! ' + this.getCommand();
991 $mwtnLog.info({component: COMPONENT, message: message});
996 var nodeId = $scope.data.ne.name || $scope.data.ne['node-id'];
997 $mwtnConnect.getMountPoint(nodeId).then(function(success){
998 $scope.data.mountpoint = success;
1000 $scope.data.mountpoint = undefined;
1003 if (currentNetworkElement.webUri && currentNetworkElement.webUri !== '') {
1004 $scope.data.web.supported = true;
1005 $scope.data.web.protocol = currentNetworkElement.webUri.split(':')[0];
1006 var matches = currentNetworkElement.webUri.match(/^https?\:\/\/([^\/?#]+)(?:[\/?#]|$)/i);
1007 $scope.data.web.ipAddress = matches && matches[1]; // ipAddress will be null if no match is found
1009 if (currentNetworkElement.cliAddress && currentNetworkElement.cliAddress !== '') {
1010 $scope.data.terminal.supported = true;
1011 var matches = currentNetworkElement.cliAddress.match(/([^@]+)@([^@]+)/i);
1012 $scope.data.terminal.user = matches && matches[1];
1013 $scope.data.terminal.ipAddress = matches && matches[2];
1015 if (currentNetworkElement.appCommand && currentNetworkElement.appCommand !== '') {
1016 $scope.data.application.supported = true;
1017 // [sko] TODO once a mediator supports it
1020 $scope.yangCapabilitiesGridOptions = JSON.parse(JSON.stringify($mwtnConnect.gridOptions));
1021 $scope.yangCapabilitiesGridOptions.columnDefs = [
1022 { field: 'module', type: 'string', displayName: 'module', headerCellClass: $scope.highlightFilteredHeader, width : 600 },
1023 { field: 'revision', type: 'string', displayName: 'Revision', headerCellClass: $scope.highlightFilteredHeader, width : 150}
1025 $scope.yangCapabilitiesGridOptions.data = currentNetworkElement.onfCapabilities;
1028 $scope.supported = false;
1029 $scope.error = function (err) {
1030 $mwtnLog.error({component: COMPONENT, message: err});
1033 $scope.ok = function () {
1034 $uibModalInstance.close({ne: currentNetworkElement});
1037 $scope.hide = function (ne) {
1039 var modalInstance = $uibModal.open({
1041 ariaLabelledBy: 'modal-title',
1042 ariaDescribedBy: 'modal-body',
1043 templateUrl: 'src/app/mwtnConnect/templates/confirmHide.tpl.html',
1044 controller: 'MountPointHideCtrl',
1047 hideNe: function () {
1048 return $scope.hideNe;
1053 modalInstance.result.then(
1055 $mwtnConnect.getSingleDocument('mwtn', 'required-networkelement', neId).then(
1057 doc.required = false;
1058 $mwtnConnect.createSingleDocument('mwtn', 'required-networkelement', neId, doc).then(
1060 $uibModalInstance.close({hide: neId});
1063 $uibModalInstance.close({hide: neId});
1068 $uibModalInstance.close({hide: neId});
1071 $mwtnLog.info({component: COMPONENT, message: 'Confirm hide closed'});
1074 $mwtnLog.info({component: COMPONENT, message: 'Confirm hide dismissed!'});
1079 $scope.delete = function (ne) {
1080 $scope.deleteNe = ne;
1081 var modalInstance = $uibModal.open({
1083 ariaLabelledBy: 'modal-title',
1084 ariaDescribedBy: 'modal-body',
1085 templateUrl: 'src/app/mwtnConnect/templates/confirmDelete.tpl.html',
1086 controller: 'MountPointDeleteCtrl',
1089 deleteNe: function () {
1090 return $scope.deleteNe;
1095 modalInstance.result.then(function(success) {
1097 // $onapAai.deletePnf(success).then(function(deleted){
1098 // $mwtnLog.info({component: COMPONENT, message: success + ' deleted from AAI.'});
1099 // }, function(error){
1100 // $mwtnLog.info({component: COMPONENT, message: 'Deletion from AAI failed: ' + success + '\n' + error});
1103 $mwtnConnect.deleteSingleDocument('mwtn', 'required-networkelement', success).then(function(deleted){
1104 $mwtnLog.info({component: COMPONENT, message: success + ' deleted from database.'});
1105 $uibModalInstance.close({hide: success});
1107 $mwtnLog.info({component: COMPONENT, message: 'Deletion from database failed: ' + success + '\n' + error});
1109 }, function (error) {
1110 $mwtnLog.info({component: COMPONENT, message: 'Confirm delete dismissed!'});
1114 $scope.cancel = function () {
1115 $uibModalInstance.dismiss('cancel');
1119 mwtnConnectApp.register.controller('MountPointHideCtrl', ['$scope', '$uibModalInstance', '$mwtnConnect', '$mwtnLog', 'hideNe',
1120 function ($scope, $uibModalInstance, $mwtnConnect, $mwtnLog, hideNe) {
1121 $scope.hideNe = hideNe;
1122 $scope.ok = function () {
1123 $uibModalInstance.close($scope.hideNe.name);
1125 $scope.cancel = function () {
1126 $uibModalInstance.dismiss('cancel');
1131 mwtnConnectApp.register.controller('MountPointDeleteCtrl', ['$scope', '$uibModalInstance', '$mwtnConnect', '$mwtnLog', 'deleteNe',
1132 function ($scope, $uibModalInstance, $mwtnConnect, $mwtnLog, deleteNe) {
1133 $scope.deleteNe = deleteNe;
1134 $scope.ok = function () {
1135 $uibModalInstance.close($scope.deleteNe.name);
1137 $scope.cancel = function () {
1138 $uibModalInstance.dismiss('cancel');