2 Copyright 2020 TATA ELXSI
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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
16 Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in)
19 * @file Info Compose Package Model
21 import { HttpClient, HttpHeaders } from '@angular/common/http';
22 import { Component, ElementRef, Injector, Input, OnInit, ViewChild } from '@angular/core';
23 import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
24 import { Router } from '@angular/router';
25 import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
26 import { TranslateService } from '@ngx-translate/core';
27 import { NotifierService } from 'angular-notifier';
28 import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA, URLPARAMS } from 'CommonModel';
29 import { DataService } from 'DataService';
30 import { environment } from 'environment';
31 import * as jsyaml from 'js-yaml';
32 import { NSConfigData } from 'NSCONFIGTEMPLATEMODEL';
33 import { NSDDetails } from 'NSDModel';
34 import * as pako from 'pako';
35 import { RestService } from 'RestService';
36 import { SharedService, isNullOrUndefined } from 'SharedService';
38 /** This is added globally by the tar.js library */
39 // eslint-disable-next-line @typescript-eslint/no-explicit-any
40 declare const Tar: any;
44 * @Component takes ComposePackages.html as template url
47 templateUrl: './ComposePackages.html',
48 styleUrls: ['./ComposePackages.scss']
50 /** Exporting a class @exports ComposePackages */
51 // eslint-disable-next-line @angular-eslint/component-class-suffix
52 export class ComposePackages implements OnInit {
53 /** Invoke service injectors @public */
54 public injector: Injector;
56 /** dataService to pass the data from one component to another @public */
57 public dataService: DataService;
59 /** Varaibles to hold http client @public */
60 public httpClient: HttpClient;
62 /** Instance for active modal service @public */
63 public activeModal: NgbActiveModal;
65 /** FormGroup instance added to the form @ html @public */
66 public packagesForm: FormGroup;
68 /** Form submission Add */
69 public submitted = false;
71 /** To handle loader status for API call @public */
72 public isLoadingResults = false;
74 /** Give the message for the loading @public */
75 public message = 'PLEASEWAIT';
77 /** contains NSD name @public */
78 public nsName: {}[] = [];
80 /** contains NSD details @public */
81 public nsdDetails: {}[];
83 /** contains NSD details filtered by id @public */
84 public nsdName: string;
86 /** Contains config details @public */
87 public config: string;
89 /** contains NSD details filtered by name @public */
92 /** Check if template or not @public */
93 public template = false;
95 /** Data of NS config @public */
96 public details: NSConfigData;
98 /** Data of NF packages @public */
99 public nsConfigData: NSConfigData[] = [];
101 /** Element ref for fileInputConfig @public */
102 @ViewChild('fileInputConfig') fileInputConfig: ElementRef<HTMLInputElement>;
104 /** Element ref for fileInputConfigLabel @public */
105 @ViewChild('fileInputConfigLabel') fileInputConfigLabel: ElementRef<HTMLLabelElement>;
107 /** FormBuilder instance added to the formBuilder @private */
108 private formBuilder: FormBuilder;
110 /** Instance of the rest service @private */
111 private restService: RestService;
113 /** Notifier service to popup notification @private */
114 private notifierService: NotifierService;
116 /** Controls the header form @private */
117 private headers: HttpHeaders;
119 /** Input contains component objects @public */
120 @Input() public params: URLPARAMS;
122 /** Holds the end point @private */
123 private endPoint: string;
125 /** ModalData instance of modal @private */
126 private modalData: MODALCLOSERESPONSEDATA;
128 /** Contains all methods related to shared @private */
129 private sharedService: SharedService;
131 /** Holds teh instance of AuthService class of type AuthService @private */
132 private router: Router;
134 /** Contains tranlsate instance @private */
135 private translateService: TranslateService;
137 constructor(injector: Injector) {
138 this.injector = injector;
139 this.dataService = this.injector.get(DataService);
140 this.restService = this.injector.get(RestService);
141 this.activeModal = this.injector.get(NgbActiveModal);
142 this.notifierService = this.injector.get(NotifierService);
143 this.formBuilder = this.injector.get(FormBuilder);
144 this.router = this.injector.get(Router);
145 this.translateService = this.injector.get(TranslateService);
146 this.sharedService = this.injector.get(SharedService);
149 /** convenience getter for easy access to form fields */
150 get f(): FormGroup['controls'] { return this.packagesForm.controls; }
153 * Lifecyle Hooks the trigger before component is instantiate
155 public ngOnInit(): void {
156 this.initializeForm();
157 if (this.params.page === 'ns-config-template') {
158 this.template = true;
159 this.getNsdPackageDetails();
160 } else if (this.params.page === 'ns-config-template-edit') {
161 this.template = true;
162 this.getNsdPackageDetails();
163 this.getFormControl('nsdId').disable();
165 this.getFormControl('nsdId').disable();
166 this.getFormControl('config').disable();
170 /** initialize Forms @public */
171 public initializeForm(): void {
172 this.packagesForm = this.formBuilder.group({
173 name: ['', [Validators.required]],
174 nsdId: [null, [Validators.required]],
179 /** Get NSD Package details @public */
180 public getNsdPackageDetails(): void {
181 this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL)
182 .subscribe((nsdPackageData: NSDDetails[]): void => {
183 nsdPackageData.forEach((nsData: NSDDetails): void => {
188 this.nsName.push(names);
190 this.nsdDetails = this.nsName;
191 if (this.params.page === 'ns-config-template-edit') {
192 this.getNSConfigDetails(environment.NSCONFIGTEMPLATE_URL + '/' + this.params.id, this.nsdDetails);
194 }, (error: ERRORDATA): void => {
195 this.restService.handleError(error, 'get');
199 /** Get the NSD Content List & patch value in edit form @public */
200 public getNSConfigDetails(URL: string, name: {}[]): void {
201 this.restService.getResource(URL).subscribe((content: NSConfigData): void => {
202 this.nsConfigData.push(content);
203 this.details = this.nsConfigData[0];
204 const nsId: string = 'nsId';
205 // eslint-disable-next-line security/detect-object-injection
206 const nsdId: {}[] = name.filter((nsdData: {}[]): boolean => nsdData[nsId] === this.details.nsdId);
207 const nsName: string = 'nsName';
208 for (const data of nsdId) {
209 // eslint-disable-next-line security/detect-object-injection
210 this.nsdName = data[nsName];
212 if (!isNullOrUndefined(this.details.config)) {
213 this.config = jsyaml.dump(this.details.config);
215 this.packagesForm.patchValue({ name: this.details.name, nsdId: this.nsdName, config: this.config });
216 this.isLoadingResults = false;
217 }, (error: ERRORDATA): void => {
218 this.restService.handleError(error, 'get');
219 this.isLoadingResults = false;
223 /** Create packages @public */
224 public createPackages(): void {
225 this.submitted = true;
229 this.sharedService.cleanForm(this.packagesForm);
230 if (!this.packagesForm.invalid) {
231 this.isLoadingResults = true;
232 if (this.params.page === 'ns-package' || this.params.page === 'vnf-package') {
233 if (this.params.page === 'ns-package') {
234 this.endPoint = environment.NSDESCRIPTORSCONTENT_URL;
235 } else if (this.params.page === 'vnf-package') {
236 this.endPoint = environment.VNFPACKAGESCONTENT_URL;
238 const descriptor: string = this.packageYaml(this.params.page);
240 // eslint-disable-next-line @typescript-eslint/no-explicit-any
241 const tar: any = new Tar();
242 const out: Uint8Array = tar.append(this.packagesForm.value.name + '/' + this.packagesForm.value.name + '.yaml',
243 descriptor, { type: '0' });
244 const gzipContent: Uint8Array = pako.gzip(out);
245 this.createPackageApi(gzipContent.buffer);
247 this.isLoadingResults = false;
248 this.notifierService.notify('error', this.translateService.instant('ERROR'));
252 this.headers = new HttpHeaders({
253 Accept: 'application/json',
254 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
256 if (this.params.page === 'ns-config-template') {
257 this.endPoint = environment.NSCONFIGTEMPLATE_URL;
258 this.createTemplate(this.endPoint);
259 } else if (this.params.page === 'ns-config-template-edit') {
260 this.endPoint = environment.NSCONFIGTEMPLATE_URL + '/' + this.params.id + '/' + 'template_content';
261 this.editTemplate(this.endPoint);
264 this.isLoadingResults = false;
265 this.notifierService.notify('error', this.translateService.instant('ERROR'));
271 /** Post config template @public */
272 public createTemplate(urlHeader: string): void {
273 this.isLoadingResults = true;
274 const apiURLHeader: APIURLHEADER = {
276 httpOptions: { headers: this.headers }
278 if (isNullOrUndefined(this.packagesForm.value.config) || this.packagesForm.value.config === '') {
279 delete this.packagesForm.value.config;
281 const validJSON: boolean = this.sharedService.checkJson(this.packagesForm.value.config);
283 this.packagesForm.value.config = JSON.parse(this.packagesForm.value.config);
285 const getConfigJson: string = jsyaml.load(this.packagesForm.value.config, { json: true });
286 this.packagesForm.value.config = getConfigJson;
289 const nsName: string = 'nsName';
290 // eslint-disable-next-line security/detect-object-injection
291 const nsdId: {}[] = this.nsdDetails.filter((nsdData: {}[]): boolean => nsdData[nsName] === this.packagesForm.value.nsdId);
292 for (const data of nsdId) {
293 // eslint-disable-next-line @typescript-eslint/dot-notation
294 this.nsId = data['nsId'];
296 this.packagesForm.value.nsdId = this.nsId;
297 this.restService.postResource(apiURLHeader, (this.packagesForm.value)).subscribe((result: {}): void => {
298 this.activeModal.close(this.modalData);
299 this.isLoadingResults = false;
300 this.notifierService.notify('success', this.translateService.instant('PAGE.NSCONFIGTEMPLATE.TEMPLATECREATEDSUCCESSFULLY'));
301 }, (error: ERRORDATA): void => {
302 this.restService.handleError(error, 'post');
303 this.isLoadingResults = false;
307 /** Edit config template @public */
308 public editTemplate(urlHeader: string): void {
309 this.isLoadingResults = true;
310 const apiURLHeader: APIURLHEADER = {
312 httpOptions: { headers: this.headers }
314 if (isNullOrUndefined(this.packagesForm.value.config) || this.packagesForm.value.config === '') {
315 delete this.packagesForm.value.config;
317 const validJSON: boolean = this.sharedService.checkJson(this.packagesForm.value.config);
319 this.packagesForm.value.config = JSON.parse(this.packagesForm.value.config);
321 const getConfigJson: string = jsyaml.load(this.packagesForm.value.config, { json: true });
322 this.packagesForm.value.config = getConfigJson;
325 this.restService.putResource(apiURLHeader, (this.packagesForm.value)).subscribe((result: {}): void => {
326 this.activeModal.close(this.modalData);
327 this.isLoadingResults = false;
328 this.notifierService.notify('success', this.translateService.instant('PAGE.NSCONFIGTEMPLATE.TEMPLATEEDITEDSUCCESSFULLY'));
329 }, (error: ERRORDATA): void => {
330 this.restService.handleError(error, 'post');
331 this.isLoadingResults = false;
334 /** Create packages @public */
335 private createPackageApi(packageContent: ArrayBuffer | SharedArrayBuffer): void {
336 this.headers = new HttpHeaders({
337 'Content-Type': 'application/gzip',
338 Accept: 'application/json',
339 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
341 const apiURLHeader: APIURLHEADER = {
343 httpOptions: { headers: this.headers }
345 this.restService.postResource(apiURLHeader, packageContent).subscribe((result: { id: string }): void => {
346 this.isLoadingResults = false;
347 this.activeModal.close();
348 this.composeNSPackages(result.id);
349 }, (error: ERRORDATA): void => {
350 this.isLoadingResults = false;
351 this.restService.handleError(error, 'post');
354 /** Config file process @private */
355 public configFile(files: FileList): void {
356 if (files && files.length === 1) {
357 const fileFormat: string = this.sharedService.fetchFileExtension(files).toLocaleLowerCase();
358 if (fileFormat === 'yaml' || fileFormat === 'yml') {
359 this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => {
360 this.packagesForm.get('config').setValue(fileContent);
361 }).catch((err: string): void => {
362 if (err === 'typeError') {
363 this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR'));
365 this.notifierService.notify('error', this.translateService.instant('ERROR'));
367 this.fileInputConfigLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
368 this.fileInputConfig.nativeElement.value = null;
370 } else if (fileFormat === 'json') {
371 this.sharedService.getFileString(files, 'json').then((fileContent: string): void => {
372 const getConfigJson: string = jsyaml.load(fileContent, { json: true });
373 this.packagesForm.get('config').setValue(JSON.stringify(getConfigJson));
374 }).catch((err: string): void => {
375 if (err === 'typeError') {
376 this.notifierService.notify('error', this.translateService.instant('JSONFILETYPEERRROR'));
378 this.notifierService.notify('error', this.translateService.instant('ERROR'));
380 this.fileInputConfigLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE');
381 this.fileInputConfig.nativeElement.value = null;
384 } else if (files && files.length > 1) {
385 this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION'));
387 this.fileInputConfigLabel.nativeElement.innerText = files[0].name;
388 this.fileInputConfig.nativeElement.value = null;
390 /** Compose NS Packages @private */
391 private composeNSPackages(id: string): void {
392 let packageUrl: string;
393 if (this.params.page === 'ns-package') {
394 packageUrl = '/packages/ns/compose/';
395 this.notifierService.notify('success', this.packagesForm.value.name + ' ' +
396 this.translateService.instant('PAGE.NSPACKAGE.CREATEDSUCCESSFULLY'));
397 } else if (this.params.page === 'vnf-package') {
398 packageUrl = '/packages/vnf/compose/';
399 this.notifierService.notify('success', this.packagesForm.value.name + ' ' +
400 this.translateService.instant('PAGE.VNFPACKAGE.CREATEDSUCCESSFULLY'));
402 this.router.navigate([packageUrl, id]).catch((): void => {
403 // Catch Navigation Error
406 /** Deafult template for NS and VNF Packages @private */
407 private packageYaml(descriptorType: string): string {
408 let packageYaml: {} = {};
409 const composerName: string = 'NGUI Composer';
410 const composerDefaultVersion: string = '1.0';
411 if (descriptorType === 'ns-package') {
416 id: this.packagesForm.value.name,
417 name: this.packagesForm.value.name,
418 version: composerDefaultVersion,
419 description: this.packagesForm.value.name + ' descriptor',
420 designer: composerName,
434 id: this.packagesForm.value.name,
435 'product-name': this.packagesForm.value.name,
436 version: composerDefaultVersion,
437 description: this.packagesForm.value.name + ' descriptor',
438 provider: composerName,
442 'instantiation-level': [],
449 'virtual-storage-desc': []
453 return jsyaml.dump(packageYaml, { sortKeys: true });
456 /** Used to get the AbstractControl of controlName passed @private */
457 private getFormControl(controlName: string): AbstractControl {
458 // eslint-disable-next-line security/detect-object-injection
459 return this.packagesForm.controls[controlName];