blob: 728769364b3cdefa4b91858b71231d0a5e1131d8 [file] [log] [blame]
Matteo Scandolod2044a42017-08-07 16:08:28 -07001
2/*
3 * Copyright 2017-present Open Networking Foundation
4
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8
9 * http://www.apache.org/licenses/LICENSE-2.0
10
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
Matteo Scandolo8a64fa42016-01-21 11:21:03 -080019(function () {
20 'use strict';
21
Matteo Scandolo04564952016-02-24 11:22:48 -080022 angular.module('xos.diagnostic')
Matteo Scandolo8a64fa42016-01-21 11:21:03 -080023 .service('Services', function($resource){
Matteo Scandolo4ac9a0b2016-05-23 15:31:25 -070024 return $resource('/api/core/services/:id', {id: '@id'});
Matteo Scandolof16b3792016-01-21 14:23:28 -080025 })
26 .service('Tenant', function($resource){
Matteo Scandolo4ac9a0b2016-05-23 15:31:25 -070027 return $resource('/api/core/tenants', {id: '@id'}, {
Matteo Scandolo51031482016-02-17 13:54:11 -080028 queryVsgInstances: {
29 method: 'GET',
30 isArray: true,
31 interceptor: {
32 response: (res) => {
33
34 // NOTE
35 // Note that VCPETenant is now VSGTenant.
36
37 let instances = [];
38
39 angular.forEach(res.data, (tenant) => {
40 let info = JSON.parse(tenant.service_specific_attribute);
41 if(info && info.instance_id){
42 instances.push(info.instance_id);
43 }
44 });
45
46 return instances;
47 }
48 }
Matteo Scandolo45fba732016-02-22 14:53:44 -080049 },
50 getSubscriberTag: {
51 method: 'GET',
52 isArray: true,
53 interceptor: {
54 response: (res) => {
55 // NOTE we should receive only one vOLT tenant here
56 return JSON.parse(res.data[0].service_specific_attribute);
57 }
58 }
Matteo Scandolo51031482016-02-17 13:54:11 -080059 }
60 });
61 })
62 .service('Ceilometer', function($http, $q, Instances) {
63
64 /**
65 * Get stats for a single instance
66 */
67 this.getInstanceStats = (instanceUuid) => {
68 let deferred = $q.defer();
69
Matteo Scandolof0d6e692016-02-24 11:14:01 -080070 $http.get('/xoslib/xos-instance-statistics', {params: {'instance-uuid': instanceUuid}})
Matteo Scandolo51031482016-02-17 13:54:11 -080071 .then((res) => {
72 deferred.resolve(res.data);
73 })
74 .catch((e) => {
75 deferred.reject(e);
76 })
77
78 return deferred.promise;
79 };
80
81 /**
82 * Collect stats for an array of instances
83 */
84 this.getInstancesStats = (instances) => {
85 let deferred = $q.defer();
86 let instancePromises = [];
87 let instanceList = [];
88
89 // retrieve instance details
90 instances.forEach((instanceId) => {
91 instancePromises.push(Instances.get({id: instanceId}).$promise);
92 });
93
94 // get all instance data
95 $q.all(instancePromises)
96 .then((_instanceList) => {
97 instanceList = _instanceList;
98 let promises = [];
99 // foreach instance query stats
100 instanceList.forEach((instance) => {
101 promises.push(this.getInstanceStats(instance.instance_uuid));
102 });
103 return $q.all(promises);
104 })
105 .then(stats => {
106 // augment instance with stats information
107 instanceList.map((instance, i) => {
108 instance.stats = stats[i];
109 });
110 deferred.resolve(instanceList);
111 })
112 .catch(deferred.reject);
113
114 return deferred.promise;
115 };
Matteo Scandolof0d6e692016-02-24 11:14:01 -0800116
117 this.getContainerStats = (containerName) => {
118 const deferred = $q.defer();
119
120 let res = {};
121
122 $http.get('/xoslib/meterstatistics', {params: {'resource': containerName}})
123 .then((containerStats) => {
124 res.stats = containerStats.data;
125 return $http.get('/xoslib/meterstatistics', {params: {'resource': `${containerName}-eth0`}})
126 })
127 .then((portStats) => {
128 res.port = {
129 eth0: portStats.data
130 };
131 return $http.get('/xoslib/meterstatistics', {params: {'resource': `${containerName}-eth1`}})
132 })
133 .then((portStats) => {
134 res.port.eth1 = portStats.data;
135 deferred.resolve(res);
136 })
137 .catch((e) => {
138 deferred.reject(e);
139 })
140
141 return deferred.promise;
142 }
Matteo Scandolof16b3792016-01-21 14:23:28 -0800143 })
Matteo Scandolo06f45d62016-01-21 15:38:06 -0800144 .service('Slice', function($resource){
Matteo Scandolo4ac9a0b2016-05-23 15:31:25 -0700145 return $resource('/api/core/slices', {id: '@id'});
Matteo Scandolo06f45d62016-01-21 15:38:06 -0800146 })
147 .service('Instances', function($resource){
Matteo Scandolo4ac9a0b2016-05-23 15:31:25 -0700148 return $resource('/api/core/instances/:id', {id: '@id'});
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800149 })
150 .service('Node', function($resource, $q, Instances){
Matteo Scandolo4ac9a0b2016-05-23 15:31:25 -0700151 return $resource('/api/core/nodes', {id: '@id'}, {
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800152 queryWithInstances: {
153 method: 'GET',
154 isArray: true,
155 interceptor: {
156 response: function(res){
157
158 // TODO update the API to include instances in nodes
159 // http://stackoverflow.com/questions/14573102/how-do-i-include-related-model-fields-using-django-rest-framework
160
161 const deferred = $q.defer();
162
163 let requests = [];
164
165 angular.forEach(res.data, (node) => {
166 requests.push(Instances.query({node: node.id}).$promise);
167 })
168
169 $q.all(requests)
170 .then((list) => {
171 res.data.map((node, i) => {
172 node.instances = list[i];
173 return node;
174 });
Matteo Scandolo170d3be2016-02-11 08:58:04 -0800175 deferred.resolve(res.data);
176 })
177
178 return deferred.promise;
179 }
180 }
181 }
182 });
Matteo Scandolo06f45d62016-01-21 15:38:06 -0800183 })
Matteo Scandoloe64dcc02016-08-02 11:53:22 -0700184 // TODO extend the resource in xosLib
185 .service('SubscribersWithDevice', function($http, $q, Subscribers){
Matteo Scandolo219b1a72016-02-09 11:19:22 -0800186
Matteo Scandoloe64dcc02016-08-02 11:53:22 -0700187 this.get = (s) => {
188 const d = $q.defer();
189 let subscriber;
Matteo Scandolo219b1a72016-02-09 11:19:22 -0800190
Matteo Scandoloe64dcc02016-08-02 11:53:22 -0700191 Subscribers.get({id: s.id}).$promise
192 .then(res => {
193 subscriber = res;
194 return $http.get(`/api/tenant/cord/subscriber/${subscriber.id}/devices/`);
195 })
196 .then(res => {
197 res.data.map(d => d.type = 'device');
198 subscriber.devices = res.data;
199 subscriber.type = 'subscriber';
200 d.resolve(subscriber);
201 })
202 .catch(err => {
203 d.reject(err);
204 });
205 return {$promise: d.promise};
206 };
Matteo Scandolo7547f042016-02-09 09:13:30 -0800207
Matteo Scandoloff7df762016-01-22 16:36:34 -0800208 })
Matteo Scandolofe307b12016-05-17 14:29:01 -0700209 .service('ServiceRelation', function($q, _, Services, Tenant, Slice, Instances){
Matteo Scandolof16b3792016-01-21 14:23:28 -0800210
Matteo Scandolof2c99012016-01-25 10:10:38 -0800211 // count the mas depth of an object
212 const depthOf = (obj) => {
213 var depth = 0;
214 if (obj.children) {
215 obj.children.forEach(function (d) {
216 var tmpDepth = depthOf(d);
217 if (tmpDepth > depth) {
218 depth = tmpDepth
219 }
220 })
221 }
222 return 1 + depth
223 };
224
Matteo Scandolof16b3792016-01-21 14:23:28 -0800225 // find all the relation defined for a given root
226 const findLevelRelation = (tenants, rootId) => {
Matteo Scandolofe307b12016-05-17 14:29:01 -0700227 return _.filter(tenants, service => {
Matteo Scandolof16b3792016-01-21 14:23:28 -0800228 return service.subscriber_service === rootId;
229 });
230 };
231
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800232 const findSpecificInformation = (tenants, rootId) => {
Matteo Scandolofe307b12016-05-17 14:29:01 -0700233 var tenants = _.filter(tenants, service => {
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800234 return service.provider_service === rootId && service.subscriber_tenant;
235 });
236
237 var info;
238
239 tenants.forEach((tenant) => {
240 if(tenant.service_specific_attribute){
241 info = JSON.parse(tenant.service_specific_attribute);
242 }
243 });
244
245 return info;
246 };
247
Matteo Scandolof16b3792016-01-21 14:23:28 -0800248 // find all the service defined by a given array of relations
249 const findLevelServices = (relations, services) => {
250 const levelServices = [];
Matteo Scandolofe307b12016-05-17 14:29:01 -0700251 _.forEach(relations, (tenant) => {
252 var service = _.find(services, {id: tenant.provider_service});
Matteo Scandolof16b3792016-01-21 14:23:28 -0800253 levelServices.push(service);
254 });
255 return levelServices;
256 };
257
Matteo Scandolo012dddb2016-02-22 16:53:22 -0800258 const buildLevel = (tenants, services, rootService, rootTenant, parentName = null) => {
Matteo Scandolof16b3792016-01-21 14:23:28 -0800259
Matteo Scandolof16b3792016-01-21 14:23:28 -0800260 // build an array of unlinked services
261 // these are the services that should still placed in the tree
Matteo Scandolofe307b12016-05-17 14:29:01 -0700262 var unlinkedServices = _.difference(services, [rootService]);
Matteo Scandolof16b3792016-01-21 14:23:28 -0800263
264 // find all relations relative to this rootElement
265 const levelRelation = findLevelRelation(tenants, rootService.id);
Matteo Scandolof16b3792016-01-21 14:23:28 -0800266 // find all items related to rootElement
267 const levelServices = findLevelServices(levelRelation, services);
268
269 // remove this item from the list (performance
Matteo Scandolofe307b12016-05-17 14:29:01 -0700270 unlinkedServices = _.difference(unlinkedServices, levelServices);
Matteo Scandolof16b3792016-01-21 14:23:28 -0800271
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800272 rootService.service_specific_attribute = findSpecificInformation(tenants, rootService.id);
273
Matteo Scandolo384ff562016-03-07 17:58:34 -0800274 if(rootService.humanReadableName === 'service_vbng'){
275 rootService.humanReadableName = 'service_vrouter'
276 }
277
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800278 const tree = {
279 name: rootService.humanReadableName,
280 parent: parentName,
281 type: 'service',
282 service: rootService,
Matteo Scandolo012dddb2016-02-22 16:53:22 -0800283 tenant: rootTenant,
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800284 children: []
285 };
286
Matteo Scandolofe307b12016-05-17 14:29:01 -0700287 _.forEach(levelServices, (service) => {
Matteo Scandolo930e4fd2016-03-07 16:41:25 -0800288 if(service.humanReadableName === 'service_ONOS_vBNG' || service.humanReadableName === 'service_ONOS_vOLT'){
289 // remove ONOSes from service chart
290 return;
291 }
Matteo Scandolofe307b12016-05-17 14:29:01 -0700292 let tenant = _.find(tenants, {subscriber_tenant: rootTenant.id, provider_service: service.id});
Matteo Scandolo012dddb2016-02-22 16:53:22 -0800293 tree.children.push(buildLevel(tenants, unlinkedServices, service, tenant, rootService.humanReadableName));
Matteo Scandolof16b3792016-01-21 14:23:28 -0800294 });
295
Matteo Scandolof2c99012016-01-25 10:10:38 -0800296 // if it is the last element append internet
297 if(tree.children.length === 0){
298 tree.children.push({
Matteo Scandolo9fe01af2016-02-09 16:01:49 -0800299 name: 'Router',
300 type: 'router',
Matteo Scandolof2c99012016-01-25 10:10:38 -0800301 children: []
302 });
303 }
304
Matteo Scandolof16b3792016-01-21 14:23:28 -0800305 return tree;
306 };
307
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800308 const buildSubscriberServiceTree = (services, tenants, subscriber = {id: 1, name: 'fakeSubs'}) => {
Matteo Scandolof16b3792016-01-21 14:23:28 -0800309
310 // find the root service
311 // it is the one attached to subsriber_root
312 // as now we have only one root so this can work
Matteo Scandolofe307b12016-05-17 14:29:01 -0700313 const rootTenant = _.find(tenants, {subscriber_root: subscriber.id});
314 const rootService = _.find(services, {id: rootTenant.provider_service});
Matteo Scandolof16b3792016-01-21 14:23:28 -0800315
Matteo Scandolo012dddb2016-02-22 16:53:22 -0800316 const serviceTree = buildLevel(tenants, services, rootService, rootTenant);
Matteo Scandolof16b3792016-01-21 14:23:28 -0800317
Matteo Scandoloff7df762016-01-22 16:36:34 -0800318 return {
Matteo Scandolod4ea8772016-03-01 15:20:29 -0800319 name: subscriber.name || subscriber.humanReadableName,
Matteo Scandoloff7df762016-01-22 16:36:34 -0800320 parent: null,
Matteo Scandolof2c99012016-01-25 10:10:38 -0800321 type: 'subscriber',
Matteo Scandoloff7df762016-01-22 16:36:34 -0800322 children: [serviceTree]
323 };
324
Matteo Scandolof16b3792016-01-21 14:23:28 -0800325 };
326
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800327 // applying domain knowledge to build the global service tree
328 const buildServiceTree = (services, tenants) => {
329
330 // TODO refactor
331 const buildChild = (services, tenants, currentService) => {
Matteo Scandolo45fba732016-02-22 14:53:44 -0800332
Matteo Scandolo384ff562016-03-07 17:58:34 -0800333 if(currentService.humanReadableName === 'service_vbng'){
334 currentService.humanReadableName = 'service_vrouter'
335 }
336
Matteo Scandolo45fba732016-02-22 14:53:44 -0800337 const response = {
338 type: 'service',
339 name: currentService.humanReadableName,
340 service: currentService
341 };
342
Matteo Scandolofe307b12016-05-17 14:29:01 -0700343 let tenant = _.find(tenants, {subscriber_service: currentService.id});
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800344 if(tenant){
Matteo Scandolofe307b12016-05-17 14:29:01 -0700345 let next = _.find(services, {id: tenant.provider_service});
Matteo Scandolo45fba732016-02-22 14:53:44 -0800346 response.children = [buildChild(services, tenants, next)];
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800347 }
348 else {
Matteo Scandolo45fba732016-02-22 14:53:44 -0800349 response.children = [
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800350 {
351 name: 'Router',
352 type: 'router',
353 children: []
354 }
355 ]
356 }
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800357 delete currentService.id; // conflict with d3
Matteo Scandolo45fba732016-02-22 14:53:44 -0800358 return response;
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800359 }
Matteo Scandolo70ac2162016-02-24 15:40:22 -0800360
Matteo Scandolofe307b12016-05-17 14:29:01 -0700361 let baseService = _.find(services, {id: 3});
Matteo Scandolo70ac2162016-02-24 15:40:22 -0800362
363 if(!angular.isDefined(baseService)){
364 console.error('Missing Base service!');
365 return;
366 }
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800367
368 const baseData = {
369 name: 'Subscriber',
370 type: 'subscriber',
371 parent: null,
372 children: [buildChild(services, tenants, baseService)]
373 };
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800374 return baseData;
375 };
376
377 const getBySubscriber = (subscriber) => {
Matteo Scandolof16b3792016-01-21 14:23:28 -0800378 var deferred = $q.defer();
379 var services, tenants;
380 Services.query().$promise
381 .then((res) => {
382 services = res;
383 return Tenant.query().$promise;
384 })
385 .then((res) => {
386 tenants = res;
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800387 deferred.resolve(buildSubscriberServiceTree(services, tenants, subscriber));
Matteo Scandolof16b3792016-01-21 14:23:28 -0800388 })
389 .catch((e) => {
390 throw new Error(e);
391 });
392
393 return deferred.promise;
Matteo Scandolof2c99012016-01-25 10:10:38 -0800394 };
Matteo Scandoloff7df762016-01-22 16:36:34 -0800395
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800396 const get = () => {
397 var deferred = $q.defer();
398 var services, tenants;
399 Services.query().$promise
400 .then((res) => {
401 services = res;
402 return Tenant.query({kind: 'coarse'}).$promise;
403 })
404 .then((res) => {
405 tenants = res;
406 deferred.resolve(buildServiceTree(services, tenants));
407 })
408 .catch((e) => {
409 throw new Error(e);
410 });
411
412 return deferred.promise;
413 }
414
Matteo Scandolof2c99012016-01-25 10:10:38 -0800415 // export APIs
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800416 return {
417 get: get,
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800418 buildServiceTree: buildServiceTree,
Matteo Scandolo77d8fa02016-02-16 17:43:00 -0800419 getBySubscriber: getBySubscriber,
420 buildLevel: buildLevel,
421 buildSubscriberServiceTree: buildSubscriberServiceTree,
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800422 findLevelRelation: findLevelRelation,
423 findLevelServices: findLevelServices,
424 depthOf: depthOf,
Matteo Scandoloc9ebd922016-01-28 12:02:57 -0800425 findSpecificInformation: findSpecificInformation
Matteo Scandolo5bf04572016-01-25 17:36:08 -0800426 }
Matteo Scandolo8a64fa42016-01-21 11:21:03 -0800427 });
428
429}());