update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b third try
[osm/UI.git] / skyquake / plugins / composer / api / composer.js
1 /*
2 *
3 * Copyright 2016 RIFT.IO Inc
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
19 var request = require('request');
20 var Promise = require('bluebird');
21 var rp = require('request-promise');
22 var utils = require('../../../framework/core/api_utils/utils.js');
23 var constants = require('../../../framework/core/api_utils/constants.js');
24 var _ = require('underscore');
25 var URL = require('url');
26 var uuid = require('uuid');
27 var APIVersion = '/v1';
28 var PackageFileHandler = require('./packageFileHandler.js');
29
30 var Composer = {};
31 var FileManager = {};
32 var PackageManager = {};
33 var DataCenters = {};
34 // Catalog module methods
35 Composer.get = function(req) {
36 var api_server = req.query['api_server'];
37 var results = {}
38 var projectPrefix = req.session.projectId ? "project-" : "";
39 return new Promise(function(resolve, reject) {
40 Promise.all([
41 rp({
42 uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/nsd-catalog/nsd?deep'),
43 method: 'GET',
44 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
45 'Authorization': req.session && req.session.authorization
46 }),
47 forever: constants.FOREVER_ON,
48 rejectUnauthorized: false,
49 resolveWithFullResponse: true
50 }),
51 rp({
52 uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/vnfd-catalog/vnfd?deep'),
53 method: 'GET',
54 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
55 'Authorization': req.session && req.session.authorization
56 }),
57 forever: constants.FOREVER_ON,
58 rejectUnauthorized: false,
59 resolveWithFullResponse: true
60 }),
61 rp({
62 uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/operational/ns-instance-opdata?deep'),
63 method: 'GET',
64 headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
65 'Authorization': req.session && req.session.authorization
66 }),
67 forever: constants.FOREVER_ON,
68 rejectUnauthorized: false,
69 resolveWithFullResponse: true
70 })
71 // Not enabled for now
72 // rp({
73 // uri: utils.confdPort(api_server) + '/api/config/pnfd-catalog/pnfd?deep',
74 // method: 'GET',
75 // headers: _.extend({},
76 // constants.HTTP_HEADERS.accept.collection,
77 // {
78 // 'Authorization': req.session && req.session.authorization
79 // }),
80 // forever: constants.FOREVER_ON,
81 // rejectUnauthorized: false,
82 // resolveWithFullResponse: true
83 // })
84 ]).then(function(result) {
85 var response = [{
86 "id": "GUID-1",
87 "name": "RIFT.ware™ NS Descriptors Catalog",
88 "short-name": "rift.ware-nsd-cat",
89 "description": "RIFT.ware™, an open source NFV development and deployment software platform that makes it simple to create, deploy and manage hyper-scale Virtual network functions and applications.",
90 "vendor": "RIFT.io",
91 "version": "",
92 "created-on": "",
93 "type": "nsd",
94 "meta": {
95 "icon-svg": "data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22iso-8859-1%22%3F%3E%0A%3C!--%20Generator%3A%20Adobe%20Illustrator%2018.0.0%2C%20SVG%20Export%20Plug-In%20.%20SVG%20Version%3A%206.00%20Build%200)%20%20--%3E%0A%3C!DOCTYPE%20svg%20PUBLIC%20%22-%2F%2FW3C%2F%2FDTD%20SVG%201.1%2F%2FEN%22%20%22http%3A%2F%2Fwww.w3.org%2FGraphics%2FSVG%2F1.1%2FDTD%2Fsvg11.dtd%22%3E%0A%3Csvg%20version%3D%221.1%22%20id%3D%22connection-icon-1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%20x%3D%220px%22%20y%3D%220px%22%0A%09%20viewBox%3D%220%200%2050%2050%22%20style%3D%22enable-background%3Anew%200%200%2050%2050%3B%22%20xml%3Aspace%3D%22preserve%22%3E%0A%09%3Cpath%20d%3D%22M15%2030c-2.8%200-5-2.2-5-5s2.2-5%205-5%205%202.2%205%205-2.2%205-5%205zm0-8c-1.7%200-3%201.3-3%203s1.3%203%203%203%203-1.3%203-3-1.3-3-3-3z%22%2F%3E%3Cpath%20d%3D%22M35%2020c-2.8%200-5-2.2-5-5s2.2-5%205-5%205%202.2%205%205-2.2%205-5%205zm0-8c-1.7%200-3%201.3-3%203s1.3%203%203%203%203-1.3%203-3-1.3-3-3-3z%22%2F%3E%3Cpath%20d%3D%22M35%2040c-2.8%200-5-2.2-5-5s2.2-5%205-5%205%202.2%205%205-2.2%205-5%205zm0-8c-1.7%200-3%201.3-3%203s1.3%203%203%203%203-1.3%203-3-1.3-3-3-3z%22%2F%3E%3Cpath%20d%3D%22M19.007%2025.885l12.88%206.44-.895%201.788-12.88-6.44z%22%2F%3E%3Cpath%20d%3D%22M30.993%2015.885l.894%201.79-12.88%206.438-.894-1.79z%22%2F%3E%3C%2Fsvg%3E"
96 },
97 "descriptors": []
98 }, {
99 "id": "GUID-2",
100 "name": "RIFT.ware™ VNF Descriptors Catalog",
101 "short-name": "rift.ware-vnfd-cat",
102 "description": "RIFT.ware™, an open source NFV development and deployment software platform that makes it simple to create, deploy and manage hyper-scale Virtual network functions and applications.",
103 "vendor": "RIFT.io",
104 "version": "",
105 "created-on": "",
106 "type": "vnfd",
107 "meta": {
108 "icon-svg": "data:image/svg+xml,<?xml version=\"1.0\" encoding=\"utf-8\"?> <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"> <svg version=\"1.1\" id=\"Layer_3\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" width=\"100px\" height=\"100px\" viewBox=\"0 0 100 100\" enable-background=\"new 0 0 100 100\" xml:space=\"preserve\"> <g> <path d=\"M58.852,62.447l-4.662-1.033c-0.047-3.138-0.719-6.168-1.996-9.007l3.606-2.92c0.858-0.695,0.99-1.954,0.296-2.813 l-4.521-5.584c-0.334-0.413-0.818-0.675-1.346-0.731c-0.525-0.057-1.056,0.102-1.468,0.435L45.25,43.64v0 c-2.486-1.907-5.277-3.259-8.297-4.019v-4.458c0-1.104-0.896-2-2-2H27.77c-1.104,0-2,0.896-2,2v4.461 c-3.08,0.777-5.922,2.171-8.447,4.144l-3.545-2.82c-0.415-0.33-0.94-0.479-1.472-0.422c-0.527,0.06-1.009,0.327-1.339,0.743 l-4.472,5.623c-0.688,0.864-0.544,2.123,0.32,2.81l3.642,2.896v0c-1.25,2.848-1.895,5.88-1.916,9.011l-4.666,1.078 c-1.076,0.249-1.747,1.322-1.499,2.398l1.616,7.001c0.249,1.077,1.325,1.747,2.399,1.499l4.813-1.111v0 c1.429,2.681,3.344,5.017,5.691,6.943l-2.17,4.55c-0.476,0.997-0.054,2.19,0.943,2.666l6.484,3.094 c0.271,0.129,0.566,0.195,0.861,0.195c0.226,0,0.451-0.038,0.668-0.115c0.5-0.177,0.909-0.545,1.138-1.024l2.198-4.611 c2.923,0.563,5.966,0.554,8.879-0.033l2.236,4.585c0.484,0.994,1.685,1.403,2.675,0.921l6.456-3.148 c0.992-0.484,1.405-1.682,0.921-2.674l-2.206-4.524c2.335-1.946,4.231-4.301,5.639-6.999l4.812,1.067 c1.076,0.237,2.146-0.441,2.385-1.52l1.556-7.014c0.115-0.518,0.02-1.06-0.266-1.508C59.82,62.878,59.369,62.562,58.852,62.447z M40.18,61.761c0,4.859-3.953,8.812-8.813,8.812c-4.858,0-8.811-3.953-8.811-8.812s3.952-8.812,8.811-8.812 C36.227,52.949,40.18,56.902,40.18,61.761z\"/> <path d=\"M64.268,45.324c0.746,0,1.463-0.42,1.806-1.139l1.054-2.208c1.826,0.353,3.736,0.345,5.551-0.021l1.07,2.195 c0.484,0.992,1.682,1.405,2.675,0.921l2.691-1.313c0.477-0.233,0.842-0.646,1.015-1.147c0.172-0.501,0.139-1.051-0.095-1.528 l-1.052-2.155c1.458-1.214,2.645-2.686,3.527-4.377l2.278,0.504c1.075,0.238,2.146-0.442,2.386-1.52l0.647-2.923 c0.238-1.078-0.442-2.146-1.521-2.385l-2.184-0.484c-0.028-1.962-0.449-3.857-1.248-5.632l1.673-1.355 c0.412-0.334,0.675-0.818,0.73-1.345s-0.102-1.056-0.436-1.468l-1.884-2.327c-0.697-0.859-1.957-0.99-2.813-0.295l-1.614,1.307 c-1.554-1.193-3.299-2.038-5.188-2.513v-2.039c0-1.104-0.896-2-2-2h-2.994c-1.104,0-2,0.896-2,2v2.04 c-1.927,0.486-3.703,1.358-5.28,2.592l-1.634-1.298c-0.862-0.687-2.12-0.543-2.81,0.32l-1.864,2.344 c-0.33,0.416-0.481,0.945-0.422,1.472c0.061,0.527,0.327,1.009,0.743,1.339l1.69,1.345c-0.78,1.779-1.184,3.676-1.197,5.636 l-2.189,0.505c-0.517,0.119-0.965,0.439-1.246,0.889c-0.281,0.45-0.372,0.993-0.252,1.51l0.675,2.918 c0.249,1.076,1.323,1.747,2.398,1.498l2.28-0.527c0.892,1.676,2.089,3.137,3.559,4.343l-1.035,2.17 c-0.228,0.479-0.257,1.028-0.08,1.528c0.178,0.5,0.546,0.91,1.024,1.138l2.703,1.289C63.686,45.261,63.979,45.324,64.268,45.324z M64.334,27.961c0-3.039,2.473-5.51,5.512-5.51c3.038,0,5.51,2.472,5.51,5.51c0,3.039-2.472,5.511-5.51,5.511 C66.807,33.472,64.334,31,64.334,27.961z\"/> <path d=\"M96.107,66.441l-2.182-0.484c-0.028-1.961-0.449-3.856-1.25-5.632l1.675-1.355c0.412-0.334,0.675-0.818,0.73-1.346 c0.056-0.527-0.102-1.056-0.436-1.468l-1.885-2.327c-0.695-0.859-1.956-0.99-2.813-0.295l-1.614,1.307 c-1.555-1.193-3.3-2.038-5.188-2.513v-2.039c0-1.104-0.896-2-2-2h-2.994c-1.104,0-2,0.896-2,2v2.041 c-1.929,0.486-3.706,1.358-5.282,2.592l-0.001,0l-1.631-1.298c-0.415-0.331-0.938-0.482-1.472-0.422 c-0.527,0.06-1.009,0.327-1.339,0.742l-1.863,2.343c-0.688,0.865-0.544,2.123,0.32,2.811l1.691,1.345 c-0.782,1.784-1.186,3.68-1.199,5.636l-2.188,0.505c-0.517,0.12-0.965,0.439-1.246,0.889c-0.281,0.45-0.372,0.993-0.252,1.51 l0.675,2.918c0.249,1.076,1.327,1.744,2.397,1.498l2.281-0.526c0.893,1.677,2.09,3.138,3.558,4.343h0.001l-1.035,2.168 c-0.229,0.479-0.258,1.029-0.081,1.529c0.178,0.5,0.546,0.909,1.024,1.138l2.702,1.289c0.278,0.132,0.571,0.195,0.86,0.195 c0.746,0,1.463-0.42,1.806-1.139l1.054-2.208c1.828,0.353,3.739,0.347,5.552-0.021l1.071,2.194 c0.484,0.992,1.682,1.405,2.675,0.921l2.69-1.312c0.477-0.233,0.842-0.645,1.014-1.147c0.173-0.501,0.14-1.051-0.093-1.528 l-1.052-2.155c1.459-1.215,2.645-2.688,3.525-4.377l2.278,0.505c0.52,0.116,1.061,0.02,1.508-0.266 c0.447-0.285,0.763-0.736,0.878-1.254l0.647-2.923C97.866,67.748,97.186,66.681,96.107,66.441z M85.162,66.174 c0,3.039-2.471,5.511-5.508,5.511c-3.039,0-5.512-2.472-5.512-5.511c0-3.039,2.473-5.511,5.512-5.511 C82.691,60.664,85.162,63.136,85.162,66.174z\"/> </g> </svg> "
109 },
110 "descriptors": []
111 }, {
112 "id": "GUID-3",
113 "name": "RIFT.ware™ PNF Descriptors Catalog",
114 "short-name": "rift.ware-pnfd-cat",
115 "description": "RIFT.ware™, an open source NFV development and deployment software platform that makes it simple to create, deploy and manage hyper-scale Virtual network functions and applications.",
116 "vendor": "RIFT.io",
117 "version": "",
118 "created-on": "",
119 "type": "pnfd",
120 "meta": {
121 "icon-svg": "data:image/svg+xml,<?xml version=\"1.0\" encoding=\"utf-8\"?> <!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"> <svg version=\"1.1\" id=\"Layer_4\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" width=\"100px\" height=\"100px\" viewBox=\"0 0 100 100\" enable-background=\"new 0 0 100 100\" xml:space=\"preserve\"> <path d=\"M86.334,47.444V35.759H13.666v11.686h3.561v5.111h-3.561v11.686h72.668V52.556h-4.108v-5.111H86.334z M26.628,59.454h-5.051 v-4.941h5.051V59.454z M26.628,52.404h-5.051v-4.941h5.051V52.404z M26.628,45.486h-5.051v-4.941h5.051V45.486z M34.094,59.454 h-5.051v-4.941h5.051V59.454z M34.094,52.404h-5.051v-4.941h5.051V52.404z M34.094,45.486h-5.051v-4.941h5.051V45.486z M41.452,59.454h-5.051v-4.941h5.051V59.454z M41.452,52.404h-5.051v-4.941h5.051V52.404z M41.452,45.486h-5.051v-4.941h5.051 V45.486z M48.733,59.454h-5.051v-4.941h5.051V59.454z M48.733,52.404h-5.051v-4.941h5.051V52.404z M48.733,45.486h-5.051v-4.941 h5.051V45.486z M56.2,59.454h-5.051v-4.941H56.2V59.454z M56.2,52.404h-5.051v-4.941H56.2V52.404z M56.2,45.486h-5.051v-4.941H56.2 V45.486z M63.558,59.454h-5.05v-4.941h5.05V59.454z M63.558,52.404h-5.05v-4.941h5.05V52.404z M63.558,45.486h-5.05v-4.941h5.05 V45.486z M74.858,59.312h-6.521v-3.013h6.521V59.312z M71.572,50.854c-2.875,0-5.204-2.33-5.204-5.203s2.329-5.203,5.204-5.203 s5.204,2.33,5.204,5.203S74.446,50.854,71.572,50.854z M74.858,45.618c0,1.801-1.46,3.261-3.261,3.261 c-1.8,0-3.261-1.46-3.261-3.261s1.46-3.26,3.261-3.26C73.398,42.358,74.858,43.817,74.858,45.618z\"/> </svg>"
122 },
123 "descriptors": []
124 }];
125 if (result[0].body) {
126 response[0].descriptors = utils.dataToJsonSansPropNameNamespace(result[0].body).collection['nsd'];
127 if (result[2].body) {
128 var data = utils.dataToJsonSansPropNameNamespace(result[2].body);
129 if (data && data["nsr:ns-instance-opdata"]) {
130 response[0].descriptors.map(function(nsd) {
131 if (!nsd["meta"]) {
132 nsd["meta"] = {};
133 }
134 if (typeof nsd['meta'] == 'string') {
135 nsd['meta'] = JSON.parse(nsd['meta']);
136 }
137 });
138 }
139 }
140 };
141 if (result[1].body) {
142 response[1].descriptors = utils.dataToJsonSansPropNameNamespace(result[1].body).collection['vnfd'];
143 };
144 resolve({
145 statusCode: response.statusCode || 200,
146 data: JSON.stringify(response)
147 });
148 }).catch(function(error) {
149 // Todo: Need better logic than all or nothing.
150 // Right now even if one of the southbound APIs fails - all fail
151 var res = {};
152 console.log('Problem with Composer.get', error);
153 res.statusCode = error.statusCode || 500;
154 res.errorMessage = {
155 error: 'Failed to get catalogs' + error
156 };
157 reject(res);
158 });
159 });
160 };
161 Composer.delete = function(req) {
162 var api_server = req.query['api_server'];
163 var catalogType = req.params.catalogType;
164 var id = req.params.id;
165 console.log('Deleting', catalogType, id, 'from', api_server);
166 return new Promise(function(resolve, reject) {
167 request({
168 uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog/' + catalogType + '/' + encodeURIComponent(id)),
169 method: 'DELETE',
170 headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
171 'Authorization': req.session && req.session.authorization
172 }),
173 forever: constants.FOREVER_ON,
174 rejectUnauthorized: false,
175 }, function(error, response, body) {
176 if (utils.validateResponse('Composer.delete', error, response, body, resolve, reject)) {
177 resolve({
178 statusCode: response.statusCode
179 });
180 }
181 });
182 });
183 };
184 Composer.getVNFD = function(req) {
185 var api_server = req.query['api_server'];
186 var vnfdID = req.body.data;
187 var authorization = req.session && req.session.authorization;
188 var VNFDs = [];
189 if (typeof(vnfdID) == "object" && vnfdID.constructor.name == "Array") {
190 vnfdID.map(function(id) {
191 VNFDs.push(requestVNFD(id));
192 });
193 } else {
194 VNFDs.push(requestVNFD(vnfdID));
195 }
196 return new Promise(function(resolve, reject) {
197 Promise.all(VNFDs).then(function(data) {
198 resolve(data)
199 }).catch(function(error) {
200 // Todo: Need better logic than all or nothing.
201 // Right now even if one of the southbound APIs fails - all fail
202 var res = {};
203 console.log('Problem with Composer.getVNFD', error);
204 res.statusCode = 404;
205 res.errorMessage = {
206 error: 'Failed to get VNFDs' + error
207 };
208 reject(res);
209 });
210 });
211
212 function requestVNFD(id) {
213 return new Promise(function(resolve, reject) {
214 var url = utils.confdPort(api_server) + APIVersion + '/api/config/vnfd-catalog/vnfd' + (id ? '/' + encodeURIComponent(id) : '') + '?deep';
215 request({
216 uri: utils.projectContextUrl(req, url),
217 method: 'GET',
218 headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
219 'Authorization': authorization
220 }),
221 forever: constants.FOREVER_ON,
222 rejectUnauthorized: false,
223 }, function(error, response, body) {
224 if (utils.validateResponse('Composer.create', error, response, body, resolve, reject)) {
225 var data;
226 //Is this still needed?
227 try {
228 data = JSON.parse(response.body)
229 } catch (e) {
230 reject({
231 statusCode: response ? response.statusCode : 400,
232 errorMessage: 'Issue parsing VNFD ' + id + 'from ' + utils.confdPort(api_server) + '/api/config/vnfd-catalog/vnfd/' + id + '?deep'
233 });
234 }
235 resolve(data);
236 }
237 });
238 });
239 }
240 };
241 Composer.create = function(req) {
242 var api_server = req.query['api_server'];
243 var catalogType = req.params.catalogType;
244 var data = req.body;
245 console.log('Creating', catalogType, 'on', api_server);
246 var jsonData = {};
247 jsonData[catalogType] = [];
248 jsonData[catalogType].push(data);
249 return new Promise(function(resolve, reject) {
250 var requestHeaders = {};
251 _.extend(requestHeaders, constants.HTTP_HEADERS.accept.data, constants.HTTP_HEADERS.content_type.data, {
252 'Authorization': req.session && req.session.authorization
253 });
254 request({
255 uri: utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/config/' + catalogType + '-catalog'),
256 method: 'POST',
257 headers: requestHeaders,
258 forever: constants.FOREVER_ON,
259 rejectUnauthorized: false,
260 json: jsonData
261 }, function(error, response, body) {
262 if (utils.validateResponse('Composer.create', error, response, body, resolve, reject)) {
263 resolve({
264 statusCode: response.statusCode
265 });
266 }
267 });
268 });
269 };
270 Composer.updateSave = function(req) {
271 var api_server = req.query['api_server'];
272 var catalogType = req.params.catalogType;
273 var id = req.params.id;
274 var data = req.body;
275 console.log('Updating', catalogType, 'id', id, 'on', api_server);
276 var jsonData = {};
277 jsonData[catalogType] = {};
278 jsonData[catalogType] = data;
279 return new Promise(function(resolve, reject) {
280 var requestHeaders = {};
281 _.extend(requestHeaders, constants.HTTP_HEADERS.accept.data, constants.HTTP_HEADERS.content_type.data, {
282 'Authorization': req.session && req.session.authorization
283 });
284 request({
285 uri: utils.projectContextUrl(req, utils.confdPort(api_server) + APIVersion + '/api/config/' + catalogType + '-catalog' + '/' + catalogType + '/' + encodeURIComponent(id)),
286 method: 'PUT',
287 headers: requestHeaders,
288 forever: constants.FOREVER_ON,
289 rejectUnauthorized: false,
290 json: jsonData
291 }, function(error, response, body) {
292 if (utils.validateResponse('Composer.update', error, response, body, resolve, reject)) {
293 resolve({
294 statusCode: response.statusCode
295 });
296 }
297 });
298 });
299 }
300
301 PackageManager.upload = function(req) {
302 console.log(' Uploading file', req.file.originalname, 'as', req.file.filename);
303 var api_server = req.query['api_server'];
304 // dev_download_server is for testing purposes.
305 // It is the direct IP address of the Node server where the
306 // package will be hosted.
307 var download_host = req.query['dev_download_server'];
308
309 if (!download_host) {
310 download_host = req.protocol + '://' + req.get('host');//req.api_server + ':' + utils.getPortForProtocol(req.protocol);
311 }
312
313 var input = {
314 'external-url': download_host + '/composer/' + constants.BASE_PACKAGE_UPLOAD_DESTINATION + '/' + req.file.filename,
315 'package-type': 'VNFD',
316 'package-id': uuid()
317 }
318
319 var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/package-create');
320
321 input = utils.addProjectContextToRPCPayload(req, uri, input);
322
323 var authorization = {};
324 if (req.session && req.session.authorization) {
325 authorization = {
326 'Authorization': req.session && req.session.authorization
327 };
328 } else {
329 // For RIFT-16894: onboard_pkg script | Upload packages through command line
330 authorization = {
331 'Authorization': req.get('Authorization')
332 };
333 }
334
335 return new Promise(function(resolve, reject) {
336 Promise.all([
337 rp({
338 uri: uri,
339 method: 'POST',
340 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, authorization),
341 forever: constants.FOREVER_ON,
342 rejectUnauthorized: false,
343 resolveWithFullResponse: true,
344 json: true,
345 body: {
346 input: input
347 }
348 })
349 ]).then(function(result) {
350 var data = {};
351 data['transaction_id'] = result[0].body['output']['transaction-id'];
352
353 // Add a status checker on the transaction and then to delete the file later
354 PackageFileHandler.checkCreatePackageStatusAndHandleFile(req, data['transaction_id'], 'create');
355
356 // Return status to composer UI to update the status.
357 resolve({
358 statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK,
359 data: data
360 });
361 }).catch(function(error) {
362 var res = {};
363 console.log('Problem with PackageManager.upload', error);
364 res.statusCode = error.statusCode || 500;
365 res.errorMessage = {
366 error: 'Failed to upload package ' + req.file.originalname + '. Error: ' + error
367 };
368 reject(res);
369 });
370 });
371 };
372
373 PackageManager.update = function(req) {
374 console.log(' Updating file', req.file.originalname, 'as', req.file.filename);
375 var api_server = req.query['api_server'];
376 // dev_download_server is for testing purposes.
377 // It is the direct IP address of the Node server where the
378 // package will be hosted.
379 var download_host = req.query['dev_download_server'];
380
381 if (!download_host) {
382 download_host = req.protocol + '://' + req.get('host');//api_server + ':' + utils.getPortForProtocol(req.protocol);
383 }
384 var input = {
385 'external-url': download_host + '/composer/' + constants.BASE_PACKAGE_UPLOAD_DESTINATION + '/' + req.file.filename,
386 'package-type': 'VNFD',
387 'package-id': uuid()
388 };
389
390 var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/package-update');
391
392 input = utils.addProjectContextToRPCPayload(req, uri, input);
393
394 return new Promise(function(resolve, reject) {
395 Promise.all([
396 rp({
397 uri: uri,
398 method: 'POST',
399 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
400 'Authorization': req.session && req.session.authorization
401 }),
402 forever: constants.FOREVER_ON,
403 rejectUnauthorized: false,
404 resolveWithFullResponse: true,
405 json: true,
406 body: {
407 input: input
408 }
409 })
410 ]).then(function(result) {
411 var data = {};
412 data['transaction_id'] = result[0].body['output']['transaction-id'];
413
414 // Add a status checker on the transaction and then to delete the file later
415 PackageFileHandler.checkCreatePackageStatusAndHandleFile(req, data['transaction_id'], 'update');
416
417 // Return status to composer UI to update the status.
418 resolve({
419 statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK,
420 data: data
421 });
422 }).catch(function(error) {
423 var res = {};
424 console.log('Problem with Composer.upload', error);
425 res.statusCode = error.statusCode || 500;
426 res.errorMessage = {
427 error: 'Failed to upload package ' + req.file.originalname + '. Error: ' + error
428 };
429 reject(res);
430 });
431 });
432 };
433
434 PackageManager.export = function(req) {
435 // /api/operations/package-export
436 var api_server = req.query['api_server'];
437 var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/package-export');
438 var input = req.body;
439 input = utils.addProjectContextToRPCPayload(req, uri, input);
440 return new Promise(function(resolve, reject) {
441 Promise.all([
442 rp({
443 uri: uri,
444 method: 'POST',
445 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
446 'Authorization': req.session && req.session.authorization
447 }),
448 forever: constants.FOREVER_ON,
449 rejectUnauthorized: false,
450 resolveWithFullResponse: true,
451 json: true,
452 body: { "input": input }
453 })
454 ]).then(function(result) {
455 var data = {};
456 resolve({
457 statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK,
458 data: result[0].body
459 });
460 }).catch(function(error) {
461 var res = {};
462 console.log('Problem with PackageManager.export', error);
463 res.statusCode = error.statusCode || 500;
464 res.errorMessage = {
465 error: error
466 };
467 reject(res);
468 });
469 });
470 }
471
472 PackageManager.copy = function(req) {
473 // /api/operations/package-copy
474 var api_server = req.query['api_server'];
475 var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/package-copy');
476 var input = req.body;
477 input = utils.addProjectContextToRPCPayload(req, uri, input);
478
479 return new Promise(function(resolve, reject) {
480 Promise.all([
481 rp({
482 uri: uri,
483 method: 'POST',
484 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
485 'Authorization': req.session && req.session.authorization
486 }),
487 forever: constants.FOREVER_ON,
488 rejectUnauthorized: false,
489 resolveWithFullResponse: true,
490 json: true,
491 body: { "input": input}
492 })
493 ]).then(function(result) {
494 var data = {};
495 resolve({
496 statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK,
497 data: result[0].body
498 });
499 }).catch(function(error) {
500 var res = {};
501 console.log('Problem with PackageManager.copy', error);
502 res.statusCode = error.statusCode || 500;
503 res.errorMessage = {
504 error: error
505 };
506 reject(res);
507 });
508 });
509 }
510
511 /**
512 * These methods retrieves the status of package operations. It takes an optional
513 * transaction id (id) this if present will return only that status otherwise
514 * an array of status' will be response.
515 */
516 PackageManager.getJobStatus = function(req, jobType) {
517 var api_server = req.query["api_server"];
518 var uri = utils.confdPort(api_server);
519 var id = req.params['id'];
520 var url = utils.projectContextUrl(req, uri + '/api/operational/' + jobType + (id ? '/job/' + id : ''));
521 return new Promise(function(resolve, reject) {
522 request({
523 url: url,
524 method: 'GET',
525 headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
526 'Authorization': req.session && req.session.authorization
527 }),
528 forever: constants.FOREVER_ON,
529 rejectUnauthorized: false
530 }, function(error, response, body) {
531 if (utils.validateResponse('PackageManager.getJobStatus', error, response, body, resolve, reject)) {
532 var returnData;
533 var jsonResponse = JSON.parse(response.body);
534 if (id) {
535 returnData = jsonResponse['rw-pkg-mgmt:job'];
536 if (!returnData){
537 returnData = {
538 status: 'failure',
539 errors: [{value: "Internal error"}]
540 }
541 }
542 } else {
543 var data = jsonResponse['rw-pkg-mgmt:' + jobType];
544 returnData = (data && data.job) || [];
545 }
546 resolve({
547 statusCode: response.statusCode,
548 data: returnData
549 });
550 }
551 })
552 })
553 }
554 PackageManager.getCopyJobStatus = function(req) {
555 return PackageManager.getJobStatus(req, 'copy-jobs');
556 }
557 PackageManager.getImportJobStatus = function(req) {
558 return PackageManager.getJobStatus(req, 'create-jobs');
559 }
560 PackageManager.getUpdateJobStatus = function(req) {
561 return PackageManager.getJobStatus(req, 'update-jobs');
562 }
563
564 function makeAssetTypeParamName (type) {
565 return type.toLowerCase() + '-file-type';
566 }
567 FileManager.addFile = function(req) {
568 console.log(' Uploading file', req.file.originalname, 'as', req.file.filename);
569 var api_server = req.query['api_server'];
570 var download_host = req.query['dev_download_server'];
571 var package_id = req.query['package_id'];
572 var package_type = req.query['package_type'].toUpperCase();
573 var package_path = req.query['package_path'];
574 if (!download_host) {
575 download_host = req.protocol + '://' + req.get('host');//api_server + ':' + utils.getPortForProtocol(req.protocol);
576 }
577 var filename = req.file.filename;
578 var assetName = req.file.originalname;
579 var input = {
580 'external-url': download_host + '/composer/' + constants.BASE_PACKAGE_UPLOAD_DESTINATION + '/' + filename,
581 'package-type': package_type,
582 'package-id': package_id,
583 'package-path': package_path ? package_path + '/' + assetName : assetName
584 };
585
586 var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/package-file-add');
587
588 input = utils.addProjectContextToRPCPayload(req, uri, input);
589
590 var assetType = req.query['asset_type'].toUpperCase();
591 input[makeAssetTypeParamName(package_type)] = assetType;
592 return new Promise(function(resolve, reject) {
593 Promise.all([
594 rp({
595 uri: uri,
596 method: 'POST',
597 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
598 'Authorization': req.session && req.session.authorization
599 }),
600 forever: constants.FOREVER_ON,
601 rejectUnauthorized: false,
602 resolveWithFullResponse: true,
603 json: true,
604 body: {
605 input: input
606 }
607 })
608 ]).then(function(result) {
609 var data = {};
610 data['transaction_id'] = result[0].body['output']['task-id'];
611 // Add a status checker on the transaction and then to delete the file later
612 PackageFileHandler.checkCreatePackageStatusAndHandleFile(req, data['transaction_id'], 'download');
613 resolve({
614 statusCode: constants.HTTP_RESPONSE_CODES.SUCCESS.OK,
615 data: data
616 });
617 }).catch(function(error) {
618 var res = {};
619 console.log('Problem with Composer.upload', error);
620 res.statusCode = error.statusCode || 500;
621 res.errorMessage = {
622 error: 'Failed to upload package ' + req.file.originalname + '. Error: ' + error
623 };
624 reject(res);
625 });
626 });
627 }
628
629 FileManager.get = function(req) {
630 var api_server = req.query['api_server'];
631 var type = req.query['package_type'] && req.query['package_type'].toUpperCase();
632 var packageId = req.query['package_id'];
633 var downloadUrl = req.query['url'];
634 var path = req.query['package_path'];
635 var assetType = req.query['asset_type'];
636 var input = {
637 "package-type": type,
638 "package-id": packageId
639 }
640 var payload = {input: input};
641 if(req.method == 'GET') {
642 if(downloadUrl && path) {
643 payload.input['external-url'] = downloadUrl;
644 payload.input['package-path'] = path;
645 payload.input[makeAssetTypeParamName(type)] = assetType;
646 return download(payload);
647 } else {
648 return list(payload);
649 }
650 }
651 if(req.method == 'DELETE') {
652 payload.input['package-path'] = path;
653 payload.input[makeAssetTypeParamName(type)] = assetType;
654 return deleteFile(payload)
655 }
656
657 function deleteFile(payload) {
658 var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/rw-pkg-mgmt:package-file-delete');
659 payload.input = utils.addProjectContextToRPCPayload(req, uri, payload.input);
660 return new Promise(function(resolve, reject) {
661 rp({
662 uri: uri,
663 method: 'POST',
664 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
665 'Authorization': req.session && req.session.authorization
666 }),
667 json: payload,
668 forever: constants.FOREVER_ON,
669 rejectUnauthorized: false,
670 resolveWithFullResponse: true
671 }).then(function(data) {
672 if (utils.validateResponse('FileManager.delete', data.error, data, data.body, resolve, reject)) {
673 resolve({
674 statusCode: data.statusCode,
675 data: data.body
676 });
677 }
678 })
679 })
680 }
681 function download(payload) {
682 var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/rw-pkg-mgmt:package-file-add');
683 payload.input = utils.addProjectContextToRPCPayload(req, uri, payload.input);
684 return new Promise(function(resolve, reject) {
685 rp({
686 uri: uri,
687 method: 'POST',
688 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
689 'Authorization': req.session && req.session.authorization
690 }),
691 json: payload,
692 forever: constants.FOREVER_ON,
693 rejectUnauthorized: false,
694 resolveWithFullResponse: true
695 }).then(function(data) {
696 if (utils.validateResponse('FileManager.get', data.error, data, data.body, resolve, reject)) {
697 resolve({
698 statusCode: data.statusCode,
699 data: data.body
700 });
701 }
702 })
703 })
704 }
705 function list(payload) {
706 var uri = utils.projectContextUrl(req, utils.confdPort(api_server) + '/api/operations/get-package-endpoint');
707 payload.input = utils.addProjectContextToRPCPayload(req, uri, payload.input);
708 return new Promise(function(resolve, reject) {
709 rp({
710 uri: uri,
711 method: 'POST',
712 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
713 'Authorization': req.session && req.session.authorization
714 }),
715 json: payload,
716 forever: constants.FOREVER_ON,
717 rejectUnauthorized: false,
718 resolveWithFullResponse: true
719 }).then(function(data) {
720 if (utils.validateResponse('FileManager.get', data.error, data, data.body, resolve, reject)) {
721 var endpoint = null;
722 var parsedEndpoint = null;
723 try {
724 endpoint = data.body.output.endpoint
725 } catch(e) {
726 console.log('Something went wrong with the FileManager.get data that was returned');
727 reject({});
728 }
729 parsedEndpoint = URL.parse(endpoint);
730 rp({
731 uri: utils.projectContextUrl(req, api_server + ':' + parsedEndpoint.port + parsedEndpoint.path),
732 method: 'GET',
733 headers: _.extend({}, constants.HTTP_HEADERS.accept.collection, {
734 'Authorization': req.session && req.session.authorization
735 }),
736 forever: constants.FOREVER_ON,
737 rejectUnauthorized: false,
738 resolveWithFullResponse: true
739 }).then(function(data) {
740 if (utils.validateResponse('FileManager.get', data.error, data, data.body, resolve, reject)) {
741 resolve({
742 statusCode: data.statusCode,
743 data: data.body
744 });
745 }
746 }).catch(function(err) {
747 console.log('Failed to retrieve FileManager.list')
748 reject({
749 statusCode: constants.HTTP_RESPONSE_CODES.ERROR.INTERNAL_SERVER_ERROR,
750 error: {
751 errorMessage: JSON.stringify(err)
752 }
753 });
754 })
755 }
756 })
757 })
758 }
759 }
760 FileManager.job = function(req) {
761 var api_server = req.query["api_server"];
762 var uri = utils.confdPort(api_server);
763 var url = '/api/operational/download-jobs';
764 var id = req.params['id'];
765 return new Promise(function(resolve, reject) {
766 request({
767 url: utils.projectContextUrl(req, uri + url + '?deep'),
768 method: 'GET',
769 headers: _.extend({}, constants.HTTP_HEADERS.accept.data, {
770 'Authorization': req.session && req.session.authorization
771 }),
772 forever: constants.FOREVER_ON,
773 rejectUnauthorized: false,
774 }, function(error, response, body) {
775 if (utils.validateResponse('FileManager.job', error, response, body, resolve, reject)) {
776 var data = JSON.parse(response.body)['rw-pkg-mgmt:download-jobs'];
777 var returnData = [];
778 data && data.job.map(function(d) {
779 if(d['package-id'] == id) {
780 returnData.push(d)
781 }
782 })
783 resolve({
784 statusCode: response.statusCode,
785 data: returnData
786 })
787 };
788 })
789 })
790 }
791 module.exports = {
792 Composer:Composer,
793 FileManager: FileManager,
794 PackageManager: PackageManager
795 };