diff options
35 files changed, 520 insertions, 413 deletions
diff --git a/cds-ui/client/src/app/feature-modules/blueprint/modify-template/editor/editor.component.ts b/cds-ui/client/src/app/feature-modules/blueprint/modify-template/editor/editor.component.ts index 7b2eaeb17..cfd83f7c5 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/modify-template/editor/editor.component.ts +++ b/cds-ui/client/src/app/feature-modules/blueprint/modify-template/editor/editor.component.ts @@ -331,18 +331,7 @@ export class EditorComponent implements OnInit { download() { console.log(this.artifactName); // status = this.editorService.downloadCBA("/download-blueprint/" + this.artifactName + "/" + this.artifactVersion); - status = this.editorService.downloadCBA("/"+this.artifactName + "/" + this.artifactVersion); - window.alert(status); - // .subscribe(response => { - // console.log(response); - // var blob = new Blob([response], { type: 'application/zip' }); - // const fileName = 'CBA'; - // saveAs(blob, fileName); - // }, - // error => { - // console.log(error); - // } - // ); + this.editorService.downloadCBA("/"+this.artifactName + "/" + this.artifactVersion); } setEditorMode() { diff --git a/cds-ui/client/src/app/feature-modules/blueprint/modify-template/editor/editor.service.ts b/cds-ui/client/src/app/feature-modules/blueprint/modify-template/editor/editor.service.ts index 025fc95d4..f1d1d148c 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/modify-template/editor/editor.service.ts +++ b/cds-ui/client/src/app/feature-modules/blueprint/modify-template/editor/editor.service.ts @@ -1,7 +1,7 @@ /* ============LICENSE_START========================================== =================================================================== -Copyright (C) 2018 IBM Intellectual Property. All rights reserved. +Copyright (C) 2018-19 IBM Intellectual Property. All rights reserved. =================================================================== Unless otherwise specified, all software contained herein is licensed @@ -26,10 +26,12 @@ import { Observable, observable } from 'rxjs'; import { ApiService } from '../../../../common/core/services/api.service'; import { saveAs } from 'file-saver'; import { BlueprintURLs } from '../../../../common/constants/app-constants'; +import { NotificationHandlerService } from 'src/app/common/core/services/notification-handler.service'; @Injectable() export class EditorService { - constructor(private _http: HttpClient, private api: ApiService) { + constructor(private _http: HttpClient, private api: ApiService, + private alertService: NotificationHandlerService,) { } enrich(body: FormData): Observable<any> { @@ -40,7 +42,7 @@ export class EditorService { .subscribe(response => { let blob = new Blob([response], { 'type': "application/octet-stream" }); saveAs(blob, "CBA.zip"); - window.alert('Blueprint download successfull' ); + this.alertService.success('Blueprint downloaded successfully' ); }); return "Download Success"; diff --git a/cds-ui/client/src/app/feature-modules/blueprint/select-template/metadata/metadata.component.ts b/cds-ui/client/src/app/feature-modules/blueprint/select-template/metadata/metadata.component.ts index 174bdf183..f49517017 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/select-template/metadata/metadata.component.ts +++ b/cds-ui/client/src/app/feature-modules/blueprint/select-template/metadata/metadata.component.ts @@ -48,7 +48,7 @@ export class MetadataComponent implements OnInit { blueprintName: string; uploadedFileName: string; entryDefinition: string; - + constructor(private formBuilder: FormBuilder, private store: Store<IAppState>, private loader: LoaderService, private dataService: SelectTemplateService) { this.bpState = this.store.select('blueprint'); @@ -60,12 +60,17 @@ export class MetadataComponent implements OnInit { template_version: ['', Validators.required], template_tags: ['', Validators.required] }); + } ngOnInit() { - this.dataService.getCbaOption().subscribe( - res => {console.log("data from service " + res);} + this.dataService.currentMessage.subscribe( + res => { + let options = res; + console.log(options + " data from service ngoninit" + res); + } ); + this.bpState.subscribe( blueprintdata => { var blueprintState: IBlueprintState = { blueprint: blueprintdata.blueprint, isLoadSuccess: blueprintdata.isLoadSuccess, isSaveSuccess: blueprintdata.isSaveSuccess, isUpdateSuccess: blueprintdata.isUpdateSuccess }; @@ -76,8 +81,6 @@ export class MetadataComponent implements OnInit { this.uploadedFileName = blueprintdata.uploadedFileName; this.entryDefinition = blueprintdata.entryDefinition; - - var blueprintState: IBlueprintState = { blueprint: blueprintdata.blueprint, isLoadSuccess: blueprintdata.isLoadSuccess, isSaveSuccess: blueprintdata.isSaveSuccess, isUpdateSuccess: blueprintdata.isUpdateSuccess }; this.metadata = blueprintState.blueprint.metadata; this.blueprint = blueprintState.blueprint; @@ -99,11 +102,7 @@ export class MetadataComponent implements OnInit { }); }) } -ngAfterInit(){ - this.dataService.getCbaOption().subscribe( - res => {console.log("data from service after init" + res);} - ); -} + UploadMetadata() { this.loader.showLoader(); this.metadata = Object.assign({}, this.CBAMetadataForm.value); diff --git a/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-from-database/search-from-database.component.html b/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-from-database/search-from-database.component.html index 648271028..9cab6c44d 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-from-database/search-from-database.component.html +++ b/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-from-database/search-from-database.component.html @@ -41,9 +41,9 @@ limitations under the License. <br>{{option.blueprintModel.updatedBy}} </mat-card-content> <mat-card-actions class="flexBox"> - <button matStepperNext mat-menu-item (click)="editCBA(option.blueprintModel.artifactName,option.blueprintModel.artifactVersion,edit)">Edit</button> - <button matStepperNext mat-menu-item (click)="editCBA(option.blueprintModel.artifactName,option.blueprintModel.artifactVersion,clone)">Clone</button> - <button matStepperNext mat-menu-item (click)="editCBA(option.blueprintModel.artifactName,option.blueprintModel.artifactVersion,info)">Info</button> + <button matStepperNext mat-menu-item (click)="editCBA(option.blueprintModel.artifactName,option.blueprintModel.artifactVersion,1)">Edit</button> + <button matStepperNext mat-menu-item (click)="editCBA(option.blueprintModel.artifactName,option.blueprintModel.artifactVersion,2)">Clone</button> + <button matStepperNext mat-menu-item (click)="editCBA(option.blueprintModel.artifactName,option.blueprintModel.artifactVersion,3)">Info</button> </mat-card-actions> </mat-card> </div> diff --git a/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-from-database/search-from-database.component.ts b/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-from-database/search-from-database.component.ts index 588854f6b..47771a7aa 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-from-database/search-from-database.component.ts +++ b/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-from-database/search-from-database.component.ts @@ -33,7 +33,7 @@ import { IBlueprint } from '../../../../../common/core/store/models/blueprint.mo import { IBlueprintState } from '../../../../../common/core/store/models/blueprintState.model'; import { IAppState } from '../../../../../common/core/store/state/app.state'; import { SetBlueprintState } from '../../../../../common/core/store/actions/blueprint.action'; - +import { SelectTemplateService } from '../../select-template.service'; @Component({ selector: 'app-search-from-database', templateUrl: './search-from-database.component.html', @@ -61,8 +61,8 @@ export class SearchFromDatabaseComponent implements OnInit { searchText: string = ''; constructor(private _formBuilder: FormBuilder, - private searchService: SearchTemplateService, private alertService: NotificationHandlerService, - private loader: LoaderService, private store: Store<IAppState>) { } + private searchService: SearchTemplateService, private alertService: NotificationHandlerService, + private loader: LoaderService, private store: Store<IAppState>, private cbEditOption: SelectTemplateService) { } ngOnInit() { this.myControl = this._formBuilder.group({ @@ -85,7 +85,8 @@ export class SearchFromDatabaseComponent implements OnInit { }) } - editCBA(artifactName: string,artifactVersion:string, option: string) { + editCBA(artifactName: string, artifactVersion: string, option: string) { + this.cbEditOption.setCbaOption(option); this.zipFile.generateAsync({ type: "blob" }) .then(blob => { const formData = new FormData(); diff --git a/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-template.module.ts b/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-template.module.ts index 9bafaebdc..a4e30a494 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-template.module.ts +++ b/cds-ui/client/src/app/feature-modules/blueprint/select-template/search-template/search-template.module.ts @@ -26,7 +26,7 @@ import { SearchTemplateComponent } from './search-template.component'; import { ReactiveFormsModule } from '@angular/forms'; import { AppMaterialModule } from 'src/app/common/modules/app-material.module'; import { SharedModule} from 'src/app/common/shared/shared.module'; -import { SelectTemplateService } from 'src/app/feature-modules/blueprint/select-template/select-template.service'; +// import { SelectTemplateService } from 'src/app/feature-modules/blueprint/select-template/select-template.service'; @NgModule({ declarations: [ @@ -42,6 +42,6 @@ import { SelectTemplateService } from 'src/app/feature-modules/blueprint/select- SearchTemplateComponent, SearchFromDatabaseComponent ], - providers:[ SelectTemplateService] + // providers:[ SelectTemplateService] }) export class SearchTemplateModule { } diff --git a/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.module.ts b/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.module.ts index f66b78c08..085da7247 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.module.ts +++ b/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.module.ts @@ -27,15 +27,15 @@ import { MetadataComponent } from './metadata/metadata.component'; import { SelectTemplateComponent } from './select-template.component'; import { SelectTemplateRoutingModule } from './select-template-routing.module'; import { AppMaterialModule } from 'src/app/common/modules/app-material.module'; -import { SearchTemplateModule} from './search-template/search-template.module'; - +import { SearchTemplateModule } from './search-template/search-template.module'; +import { SelectTemplateService } from './select-template.service'; @NgModule({ declarations: [ TemplateOptionsComponent, - MetadataComponent, - SelectTemplateComponent + MetadataComponent, + SelectTemplateComponent ], - exports: [ + exports: [ TemplateOptionsComponent, SearchTemplateComponent, MetadataComponent, @@ -47,6 +47,9 @@ import { SearchTemplateModule} from './search-template/search-template.module'; ReactiveFormsModule, AppMaterialModule, SearchTemplateModule + ], + providers: [ + SelectTemplateService ] }) export class SelectTemplateModule { } diff --git a/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.service.ts b/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.service.ts index fa18cbd25..d6bcfb33b 100644 --- a/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.service.ts +++ b/cds-ui/client/src/app/feature-modules/blueprint/select-template/select-template.service.ts @@ -20,21 +20,29 @@ limitations under the License. */ import { Injectable } from '@angular/core'; -import { Observable, of } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class SelectTemplateService { cbaOption: string; + private messageSource = new BehaviorSubject('default message'); + currentMessage = this.messageSource.asObservable(); constructor() { } setCbaOption(option: string) { - this.cbaOption = option; - } - - getCbaOption(): Observable<string> { - return of(this.cbaOption); + this.messageSource.next(option); } + // setCbaOption(option: string) { + // this.cbaOption = option; + // console.log("CBA option set to"+this.cbaOption+":"+option); + // } + + // getCbaOption(): Observable<any> { + // console.log("CBA option is "+this.cbaOption); + // // return of(this.cbaOption); + // return this.cbaOption.asObservable(); + // } } diff --git a/cds-ui/server/src/datasources/rest.datasource.json b/cds-ui/server/src/datasources/rest.datasource.json deleted file mode 100644 index 86f33fbd4..000000000 --- a/cds-ui/server/src/datasources/rest.datasource.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "restConfig", - "connector": "rest", - "options": { - "headers": { - "accept": "application/json", - "content-type": "application/json" - } - }, - "operations": [ - { - "template": { - "method": "GET", - "url": "" - }, - "functions": { - "getEnricheddata": [""] - } - }, - { - "template": { - "method": "POST", - "url": "" - }, - "functions": { - "saveBlueprint": [""] - } - }, - { - "template": { - "method": "POST", - "url": "" - }, - "functions": { - "test": [""] - } - } -] -}
\ No newline at end of file diff --git a/cds-ui/server/src/datasources/rest.datasource.ts b/cds-ui/server/src/datasources/rest.datasource.ts deleted file mode 100644 index 1b5a44d79..000000000 --- a/cds-ui/server/src/datasources/rest.datasource.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* -============LICENSE_START========================================== -=================================================================== -Copyright (C) 2018-19 IBM Intellectual Property. All rights reserved. -=================================================================== - -Unless otherwise specified, all software contained herein is licensed -under the Apache License, Version 2.0 (the License); -you may not use this software except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -============LICENSE_END============================================ -*/ - - -import { juggler } from '@loopback/service-proxy'; -import * as config from './rest.datasource.json'; - - -export class RestDataSource extends juggler.DataSource { - static dataSourceName = 'rest'; - constructor(dsConfig: object = config) { - super(dsConfig); - } -} diff --git a/cds-ui/server/src/services/rest.service.ts b/cds-ui/server/src/services/rest.service.ts deleted file mode 100644 index b94ea4dd3..000000000 --- a/cds-ui/server/src/services/rest.service.ts +++ /dev/null @@ -1,46 +0,0 @@ -/* -============LICENSE_START========================================== -=================================================================== -Copyright (C) 2018-19 IBM Intellectual Property. All rights reserved. -=================================================================== - -Unless otherwise specified, all software contained herein is licensed -under the Apache License, Version 2.0 (the License); -you may not use this software except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -============LICENSE_END============================================ -*/ - -import {getService, juggler} from '@loopback/service-proxy'; -import {inject, Provider} from '@loopback/core'; -import {RestDataSource} from '../datasources/rest.datasource'; - - -export interface RestResponseData { - userId: number; - id: number; - title: string; - completed: boolean; -} - -export interface RestService { - getrestdata(id?: number): Promise<RestResponseData>; -} -export class RestProvider implements Provider<RestService> { - constructor( - @inject('datasources.rest') - protected dataSource: juggler.DataSource = new RestDataSource(), - ) {} - - value(): Promise<RestService> { - return getService(this.dataSource); - } -}
\ No newline at end of file diff --git a/components/model-catalog/blueprint-model/uat-blueprints/pnf_config/Tests/uat.yaml b/components/model-catalog/blueprint-model/uat-blueprints/pnf_config/Tests/uat.yaml index 789659eb2..3a5903c49 100644 --- a/components/model-catalog/blueprint-model/uat-blueprints/pnf_config/Tests/uat.yaml +++ b/components/model-catalog/blueprint-model/uat-blueprints/pnf_config/Tests/uat.yaml @@ -96,7 +96,8 @@ external-services: - request: method: PUT path: &configUri [ restconf/config, &nodeIdentifier [network-topology:network-topology/topology/topology-netconf/node, *pnfId]] - content-type: application/json + headers: + Content-Type: application/json body: node: - node-id: *pnfId @@ -124,7 +125,8 @@ external-services: - request: method: PATCH path: [*configUri, *configletResourcePath] - content-type: application/yang.patch+json + headers: + Content-Type: application/yang.patch+json body: *assignPatch - request: method: DELETE diff --git a/docs/datadictionary/complexResponse.rst b/docs/datadictionary/complexResponse.rst index aa39ff235..d32d13de5 100644 --- a/docs/datadictionary/complexResponse.rst +++ b/docs/datadictionary/complexResponse.rst @@ -5,16 +5,17 @@ complex Response code ===================== -{ - "id": 4, - "address": "192.168.10.2/32", - "vrf": null, - "tenant": null, - "status": 1, - "role": null, - "interface": null, - "description": "", - "nat_inside": null, - "created": "2018-08-30", - "last_updated": "2018-08-30T14:59:05.277820Z" -} +.. code-block:: json + :linenos: + + "id": 4, + "address": "192.168.10.2/32", + "vrf": null, + "tenant": null, + "status": 1, + "role": null, + "interface": null, + "description": "", + "nat_inside": null, + "created": "2018-08-30", + "last_updated": "2018-08-30T14:59:05.277820Z"
\ No newline at end of file diff --git a/docs/datadictionary/create_netbox_ip_address.rst b/docs/datadictionary/create_netbox_ip_address.rst index 5d9a9be87..f17ddb407 100644 --- a/docs/datadictionary/create_netbox_ip_address.rst +++ b/docs/datadictionary/create_netbox_ip_address.rst @@ -5,32 +5,35 @@ create_netbox_ip_address code ============================= -{ - "tags" : "oam-local-ipv4-address", - "name" : "create_netbox_ip", - "property" : { - "description" : "netbox ip", - "type" : "dt-netbox-ip" - }, - "updated-by" : "adetalhouet", - "sources" : { - "primary-config-data" : { - "type" : "source-rest", - "properties" : { - "type" : "JSON", - "verb" : "POST", - "endpoint-selector" : "ipam-1", - "url-path" : "/api/ipam/prefixes/$prefixId/available-ips/", - "path" : "", - "input-key-mapping" : { - "prefixId" : "prefix-id" - }, - "output-key-mapping" : { - "address" : "address", - "id" : "id" - }, - "key-dependencies" : [ "prefix-id" ] - } - } - } - }
\ No newline at end of file +.. code-block:: json + :linenos: + + { + "tags" : "oam-local-ipv4-address", + "name" : "create_netbox_ip", + "property" : { + "description" : "netbox ip", + "type" : "dt-netbox-ip" + }, + "updated-by" : "adetalhouet", + "sources" : { + "primary-config-data" : { + "type" : "source-rest", + "properties" : { + "type" : "JSON", + "verb" : "POST", + "endpoint-selector" : "ipam-1", + "url-path" : "/api/ipam/prefixes/$prefixId/available-ips/", + "path" : "", + "input-key-mapping" : { + "prefixId" : "prefix-id" + }, + "output-key-mapping" : { + "address" : "address", + "id" : "id" + }, + "key-dependencies" : [ "prefix-id" ] + } + } + } + }
\ No newline at end of file diff --git a/docs/datadictionary/dbsystemcode.rst b/docs/datadictionary/dbsystemcode.rst index 5051d1e7d..d6cda5b6c 100644 --- a/docs/datadictionary/dbsystemcode.rst +++ b/docs/datadictionary/dbsystemcode.rst @@ -4,12 +4,14 @@ Dbsystemcode ============ - -"dsl_definitions": { - "dynamic-db-source": { +.. code-block:: json + :linenos: + + "dsl_definitions": { + "dynamic-db-source": { "type": "maria-db", "url": "jdbc:mysql://localhost:3306/sdnctl", - "username": "sdnctl", - "password": "sdnctl" - } -}
\ No newline at end of file + "username": <username>, + "password": <password> + } + }
\ No newline at end of file diff --git a/docs/datadictionary/dt-netbox-ip.rst b/docs/datadictionary/dt-netbox-ip.rst index 9410580fb..6dc3c8464 100644 --- a/docs/datadictionary/dt-netbox-ip.rst +++ b/docs/datadictionary/dt-netbox-ip.rst @@ -5,18 +5,21 @@ dt-netbox-ip code ================= -{ - "version": "1.0.0", - "description": "This is Netbox IP Data Type", - "properties": { - "address": { - "required": true, - "type": "string" - }, - "id": { - "required": true, - "type": "integer" - } - }, - "derived_from": "tosca.datatypes.Root" -} +.. code-block:: none + :linenos: + + { + "version": "1.0.0", + "description": "This is Netbox IP Data Type", + "properties": { + "address": { + "required": true, + "type": "string" + }, + "id": { + "required": true, + "type": "integer" + } + }, + "derived_from": "tosca.datatypes.Root" + } diff --git a/docs/datadictionary/index.rst b/docs/datadictionary/index.rst index 3ac8587ee..4039cca6d 100644 --- a/docs/datadictionary/index.rst +++ b/docs/datadictionary/index.rst @@ -40,7 +40,7 @@ Here is how input-key-mapping, output-key-mapping and key-dependencies can be us .. toctree:: :maxdepth: 1 - resourcedefinitioncodesnip + resourcedefinitioncodesnip Resource source: diff --git a/docs/datadictionary/resourcedefinitioncodesnip.rst b/docs/datadictionary/resourcedefinitioncodesnip.rst index a91767678..6504a07c3 100644 --- a/docs/datadictionary/resourcedefinitioncodesnip.rst +++ b/docs/datadictionary/resourcedefinitioncodesnip.rst @@ -5,44 +5,45 @@ Source Capability Code ====================== -{ - "description": "This is Component Resource Source Node Type", - "version": "1.0.0", - "properties": { - "script-type": { - "required": true, - "type": "string", - "default": "kotlin", - "constraints": [ - { - "valid_values": [ - "kotlin", - "jython" - ] - } - ] - }, - "script-class-reference": { - "description": "Capability reference name for internal and kotlin, for jython script file path", - "required": true, - "type": "string" - }, - "instance-dependencies": { - "required": false, - "description": "Instance dependency Names to Inject to Kotlin / Jython Script.", - "type": "list", - "entry_schema": { - "type": "string" - } - }, - "key-dependencies": { - "description": "Resource Resolution dependency dictionary names.", - "required": true, - "type": "list", - "entry_schema": { - "type": "string" - } - } - }, - "derived_from": "tosca.nodes.ResourceSource" -} +.. code-block:: json + :linenos: + + "description": "This is Component Resource Source Node Type", + "version": "1.0.0", + "properties": { + "script-type": { + "required": true, + "type": "string", + "default": "kotlin", + "constraints": [ + { + "valid_values": [ + "kotlin", + "jython" + ] + } + ] + }, + "script-class-reference": { + "description": "Capability reference name for internal and kotlin, for jython script file path", + "required": true, + "type": "string" + }, + "instance-dependencies": { + "required": false, + "description": "Instance dependency Names to Inject to Kotlin / Jython Script.", + "type": "list", + "entry_schema": { + "type": "string" + } + }, + "key-dependencies": { + "description": "Resource Resolution dependency dictionary names.", + "required": true, + "type": "list", + "entry_schema": { + "type": "string" + } + } + }, + "derived_from": "tosca.nodes.ResourceSource"
\ No newline at end of file diff --git a/docs/datadictionary/restauth.rst b/docs/datadictionary/restauth.rst index 40c179375..9f628696c 100644 --- a/docs/datadictionary/restauth.rst +++ b/docs/datadictionary/restauth.rst @@ -7,36 +7,48 @@ Resource Rest Authentication ---------------------------- token-auth: - -"dsl_definitions": { - "dynamic-rest-source": { - "type" : "token-auth", - "url" : "http://localhost:32778", - "token" : "Token 0123456789abcdef0123456789abcdef01234567" - } -} - +~~~~~~~~~~~ + +.. code-block:: json + :linenos: + + "dsl_definitions": { + "dynamic-rest-source": { + "type" : "token-auth", + "url" : "http://localhost:32778", + "token" : <token> + } + } + basic-auth: - -"dsl_definitions": { - "dynamic-rest-source": { - "type" : "basic-auth", - "url" : "http://localhost:32778", - "username" : "bob", - "password": "marley" - } -} - +~~~~~~~~~~~ + +.. code-block:: json + :linenos: + + "dsl_definitions": { + "dynamic-rest-source": { + "type" : "basic-auth", + "url" : "http://localhost:32778", + "username" : <username>, + "password": <password> + } + } + ssl-basic-auth: - -"dsl_definitions": { - "dynamic-rest-source": { - "type" : "ssl-basic-auth", - "url" : "http://localhost:32778", - "keyStoreInstance": "JKS or PKCS12", - "sslTrust": "trusture", - "sslTrustPassword": "trustore password", - "sslKey": "keystore", - "sslKeyPassword: "keystore password" - } -}
\ No newline at end of file +~~~~~~~~~~~~~~~ + +.. code-block:: json + :linenos: + + "dsl_definitions": { + "dynamic-rest-source": { + "type" : "ssl-basic-auth", + "url" : "http://localhost:32778", + "keyStoreInstance": "JKS or PKCS12", + "sslTrust": "trusture", + "sslTrustPassword": <password>, + "sslKey": "keystore", + "sslKeyPassword: <password> + } + }
\ No newline at end of file diff --git a/docs/microservices/bluePrintsProcessorMS.rst b/docs/microservices/bluePrintsProcessorMS.rst index bd0b6997d..292f99e51 100644 --- a/docs/microservices/bluePrintsProcessorMS.rst +++ b/docs/microservices/bluePrintsProcessorMS.rst @@ -84,4 +84,4 @@ Testing the environment: Point your browser to http://localhost:8000/api/v1/execution-service/ping (please note that the port is 8000, not 8080) -To authenticate, use ccsdkapps / ccsdkapps as login / password.
\ No newline at end of file +To authenticate, use login user id and password.
\ No newline at end of file diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintsAcceptanceTest.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintsAcceptanceTest.kt index ad4173c9e..dfa0a8563 100644 --- a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintsAcceptanceTest.kt +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/BlueprintsAcceptanceTest.kt @@ -35,6 +35,7 @@ import org.junit.ClassRule import org.junit.Rule import org.junit.runner.RunWith import org.junit.runners.Parameterized +import org.mockito.Answers import org.onap.ccsdk.cds.blueprintsprocessor.rest.RestLibConstants import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BluePrintRestLibPropertyService import org.onap.ccsdk.cds.blueprintsprocessor.rest.service.BlueprintWebClientService @@ -105,7 +106,7 @@ class BlueprintsAcceptanceTest(private val blueprintName: String, private val fi @JvmField val springMethodRule = SpringMethodRule() - @MockBean(name = RestLibConstants.SERVICE_BLUEPRINT_REST_LIB_PROPERTY) + @MockBean(name = RestLibConstants.SERVICE_BLUEPRINT_REST_LIB_PROPERTY, answer = Answers.RETURNS_SMART_NULLS) lateinit var restClientFactory: BluePrintRestLibPropertyService @Autowired @@ -130,10 +131,10 @@ class BlueprintsAcceptanceTest(private val blueprintName: String, private val fi uploadBlueprint(blueprintName) - // Configure mocked external services - val expectationPerClient = uat.externalServices.associateBy( + // Configure mocked external services and save their expected requests for further validation + val requestsPerClient = uat.externalServices.associateBy( { service -> createRestClientMock(service.selector, service.expectations) }, - { service -> service.expectations } + { service -> service.expectations.map { it.request } } ) // Run processes @@ -143,14 +144,14 @@ class BlueprintsAcceptanceTest(private val blueprintName: String, private val fi JsonNormalizer.getNormalizer(mapper, process.responseNormalizerSpec)) } - // Validate request payloads to external services - for ((mockClient, expectations) in expectationPerClient) { - expectations.forEach { expectation -> + // Validate requests to external services + for ((mockClient, requests) in requestsPerClient) { + requests.forEach { request -> verify(mockClient, atLeastOnce()).exchangeResource( - eq(expectation.request.method), - eq(expectation.request.path), - argThat { assertJsonEqual(expectation.request.body, this) }, - expectation.request.requestHeadersMatcher()) + eq(request.method), + eq(request.path), + argThat { assertJsonEqual(request.body, this) }, + argThat(RequiredMapEntriesMatcher(request.headers))) } // Don't mind the invocations to the overloaded exchangeResource(String, String, String) verify(mockClient, atLeast(0)).exchangeResource(any(), any(), any()) @@ -160,7 +161,8 @@ class BlueprintsAcceptanceTest(private val blueprintName: String, private val fi private fun createRestClientMock(selector: String, restExpectations: List<ExpectationDefinition>) : BlueprintWebClientService { - val restClient = mock<BlueprintWebClientService>(verboseLogging = true) + val restClient = mock<BlueprintWebClientService>(verboseLogging = true, + defaultAnswer = Answers.RETURNS_SMART_NULLS) // Delegates to overloaded exchangeResource(String, String, String, Map<String, String>) whenever(restClient.exchangeResource(any(), any(), any())) diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/MoreMatchers.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/MoreMatchers.kt new file mode 100644 index 000000000..71e07ab4c --- /dev/null +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/MoreMatchers.kt @@ -0,0 +1,34 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ +package org.onap.ccsdk.cds.blueprintsprocessor + +import com.google.common.collect.Maps +import org.mockito.ArgumentMatcher + +class RequiredMapEntriesMatcher<K, V>(private val requiredEntries: Map<K, V>) : ArgumentMatcher<Map<K, V>> { + override fun matches(argument: Map<K, V>?): Boolean { + val missingEntries = Maps.difference(requiredEntries, argument).entriesOnlyOnLeft() + return missingEntries.isEmpty() + } + + override fun toString(): String { + return requiredEntries.toString() + } +} diff --git a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/UatDefinition.kt b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/UatDefinition.kt index ce2061168..abb1dfcd1 100644 --- a/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/UatDefinition.kt +++ b/ms/blueprintsprocessor/application/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/UatDefinition.kt @@ -24,8 +24,6 @@ import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.node.MissingNode -import com.nhaarman.mockitokotlin2.any -import com.nhaarman.mockitokotlin2.eq import org.yaml.snakeyaml.Yaml import java.nio.file.Path @@ -35,13 +33,8 @@ data class ProcessDefinition(val name: String, val request: JsonNode, val expect data class RequestDefinition(val method: String, @JsonDeserialize(using = PathDeserializer::class) val path: String, - @JsonAlias("content-type") - val contentType: String? = null, - val body: JsonNode = MissingNode.getInstance()) { - fun requestHeadersMatcher(): Map<String, String> { - return if (contentType != null) eq(mapOf("Content-Type" to contentType)) else any() - } -} + val headers: Map<String, String> = emptyMap(), + val body: JsonNode = MissingNode.getInstance()) data class ResponseDefinition(val status: Int = 200, val body: JsonNode = MissingNode.getInstance()) { companion object { diff --git a/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/ApiDataExtensions.kt b/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/ApiDataExtensions.kt new file mode 100644 index 000000000..47b55b018 --- /dev/null +++ b/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/ApiDataExtensions.kt @@ -0,0 +1,28 @@ +/* + * Copyright © 2019 IBM. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.onap.ccsdk.cds.blueprintsprocessor.core + +import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput +import org.onap.ccsdk.cds.controllerblueprints.core.asType +import kotlin.reflect.KClass + + +fun <T : Any> ExecutionServiceInput.payloadAsType(clazzType: KClass<T>): T { + val actionName = this.actionIdentifiers.actionName + val requestJsonNode = this.payload.get("$actionName-request") + return requestJsonNode.asType(clazzType.java) +}
\ No newline at end of file diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractComponentFunction.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractComponentFunction.kt index 408bb58ed..8759338b7 100644 --- a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractComponentFunction.kt +++ b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractComponentFunction.kt @@ -19,6 +19,7 @@ package org.onap.ccsdk.cds.blueprintsprocessor.services.execution import com.fasterxml.jackson.databind.JsonNode +import kotlinx.coroutines.withTimeout import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutput import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.Status @@ -47,6 +48,7 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode<ExecutionServic lateinit var interfaceName: String lateinit var operationName: String lateinit var nodeTemplateName: String + var timeout: Int = 180 var operationInputs: MutableMap<String, JsonNode> = hashMapOf() override fun getName(): String { @@ -87,6 +89,9 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode<ExecutionServic this.operationInputs.putAll(operationResolvedProperties) + val timeout = this.operationInputs.getOptionalAsInt(BluePrintConstants.PROPERTY_CURRENT_TIMEOUT) + timeout?.let { this.timeout = timeout } + return executionRequest } @@ -118,7 +123,9 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode<ExecutionServic override suspend fun applyNB(executionServiceInput: ExecutionServiceInput): ExecutionServiceOutput { try { prepareRequestNB(executionServiceInput) - processNB(executionServiceInput) + withTimeout((timeout * 1000).toLong()) { + processNB(executionServiceInput) + } } catch (runtimeException: RuntimeException) { log.error("failed in ${getName()} : ${runtimeException.message}", runtimeException) recoverNB(runtimeException, executionServiceInput) diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt index 2a14be216..6bee17f4b 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/ImperativeWorkflowExecutionService.kt @@ -44,10 +44,8 @@ class ImperativeWorkflowExecutionService( val graph = bluePrintContext.workflowByName(workflowName).asGraph() - val deferredOutput = CompletableDeferred<ExecutionServiceOutput>() - imperativeBluePrintWorkflowService.executeWorkflow(graph, bluePrintRuntimeService, - executionServiceInput, deferredOutput) - return deferredOutput.await() + return imperativeBluePrintWorkflowService.executeWorkflow(graph, bluePrintRuntimeService, + executionServiceInput) } } @@ -60,35 +58,41 @@ open class ImperativeBluePrintWorkflowService(private val nodeTemplateExecutionS lateinit var bluePrintRuntimeService: BluePrintRuntimeService<*> lateinit var executionServiceInput: ExecutionServiceInput lateinit var workflowName: String - lateinit var deferredExecutionServiceOutput: CompletableDeferred<ExecutionServiceOutput> override suspend fun executeWorkflow(graph: Graph, bluePrintRuntimeService: BluePrintRuntimeService<*>, - input: ExecutionServiceInput, - output: CompletableDeferred<ExecutionServiceOutput>) { + input: ExecutionServiceInput): ExecutionServiceOutput { this.graph = graph this.bluePrintRuntimeService = bluePrintRuntimeService this.executionServiceInput = input this.workflowName = this.executionServiceInput.actionIdentifiers.actionName - this.deferredExecutionServiceOutput = output this.workflowId = bluePrintRuntimeService.id() + val output = CompletableDeferred<ExecutionServiceOutput>() val startMessage = WorkflowExecuteMessage(input, output) - workflowActor().send(startMessage) + val workflowActor = workflowActor() + if (!workflowActor.isClosedForSend) { + workflowActor.send(startMessage) + } else { + throw BluePrintProcessorException("workflow($workflowActor) actor is closed") + } + return output.await() } override suspend fun initializeWorkflow(input: ExecutionServiceInput): EdgeLabel { return EdgeLabel.SUCCESS } - override suspend fun prepareWorkflowOutput(exception: BluePrintProcessorException?): ExecutionServiceOutput { - val wfStatus = if (exception != null) { - val status = Status() - status.message = BluePrintConstants.STATUS_FAILURE - status.errorMessage = exception.message - status - } else { - val status = Status() - status.message = BluePrintConstants.STATUS_SUCCESS - status + override suspend fun prepareWorkflowOutput(): ExecutionServiceOutput { + val wfStatus = Status().apply { + if (exceptions.isNotEmpty()) { + exceptions.forEach { + val errorMessage = it.message ?: "" + bluePrintRuntimeService.getBluePrintError().addError(errorMessage) + log.error("workflow($workflowId) exception :", it) + } + message = BluePrintConstants.STATUS_FAILURE + } else { + message = BluePrintConstants.STATUS_SUCCESS + } } return ExecutionServiceOutput().apply { commonHeader = executionServiceInput.commonHeader diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt index 89732e300..b64177aab 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/NodeTemplateExecutionService.kt @@ -22,7 +22,7 @@ import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceOutp import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.StepData import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractComponentFunction import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants -import org.onap.ccsdk.cds.controllerblueprints.core.putJsonElement +import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintRuntimeService import org.slf4j.LoggerFactory @@ -37,15 +37,22 @@ open class NodeTemplateExecutionService { executionServiceInput: ExecutionServiceInput): ExecutionServiceOutput { // Get the Blueprint Context val blueprintContext = bluePrintRuntimeService.bluePrintContext() + + val nodeTemplate = blueprintContext.nodeTemplateByName(nodeTemplateName) // Get the Component Name, NodeTemplate type is mapped to Component Name - val componentName = blueprintContext.nodeTemplateByName(nodeTemplateName).type + val componentName = nodeTemplate.type val interfaceName = blueprintContext.nodeTemplateFirstInterfaceName(nodeTemplateName) val operationName = blueprintContext.nodeTemplateFirstInterfaceFirstOperationName(nodeTemplateName) + val nodeTemplateImplementation = blueprintContext + .nodeTemplateOperationImplementation(nodeTemplateName, interfaceName, operationName) + + val timeout: Int = nodeTemplateImplementation?.timeout ?: 180 + log.info("executing node template($nodeTemplateName) component($componentName) " + - "interface($interfaceName) operation($operationName)") + "interface($interfaceName) operation($operationName) with timeout($timeout) sec.") // Get the Component Instance val plugin = BluePrintDependencyService.instance<AbstractComponentFunction>(componentName) @@ -62,9 +69,10 @@ open class NodeTemplateExecutionService { // Populate Step Meta Data val stepInputs: MutableMap<String, JsonNode> = hashMapOf() - stepInputs.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE, nodeTemplateName) - stepInputs.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_INTERFACE, interfaceName) - stepInputs.putJsonElement(BluePrintConstants.PROPERTY_CURRENT_OPERATION, operationName) + stepInputs[BluePrintConstants.PROPERTY_CURRENT_NODE_TEMPLATE] = nodeTemplateName.asJsonPrimitive() + stepInputs[BluePrintConstants.PROPERTY_CURRENT_INTERFACE] = interfaceName.asJsonPrimitive() + stepInputs[BluePrintConstants.PROPERTY_CURRENT_OPERATION] = operationName.asJsonPrimitive() + stepInputs[BluePrintConstants.PROPERTY_CURRENT_TIMEOUT] = timeout.asJsonPrimitive() val stepInputData = StepData().apply { name = nodeTemplateName properties = stepInputs diff --git a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/DGWorkflowExecutionServiceTest.kt b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/DGWorkflowExecutionServiceTest.kt index ac2d7d62c..6e7e3cb8d 100644 --- a/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/DGWorkflowExecutionServiceTest.kt +++ b/ms/blueprintsprocessor/modules/services/workflow-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/workflow/DGWorkflowExecutionServiceTest.kt @@ -18,14 +18,18 @@ package org.onap.ccsdk.cds.blueprintsprocessor.services.workflow import kotlinx.coroutines.runBlocking +import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput import org.onap.ccsdk.cds.blueprintsprocessor.services.workflow.executor.ComponentExecuteNodeExecutor import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintConstants +import org.onap.ccsdk.cds.controllerblueprints.core.service.BluePrintDependencyService import org.onap.ccsdk.cds.controllerblueprints.core.utils.BluePrintMetadataUtils import org.onap.ccsdk.cds.controllerblueprints.core.utils.JacksonReactorUtils import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.ApplicationContext +import org.springframework.test.annotation.DirtiesContext import org.springframework.test.context.ContextConfiguration import org.springframework.test.context.junit4.SpringRunner import kotlin.test.assertEquals @@ -36,9 +40,17 @@ import kotlin.test.assertNotNull class DGWorkflowExecutionServiceTest { @Autowired + lateinit var applicationContext: ApplicationContext + + @Autowired lateinit var dgWorkflowExecutionService: DGWorkflowExecutionService + @Before + fun init() { + BluePrintDependencyService.inject(applicationContext) + } + @Test fun testExecuteDirectedGraph() { runBlocking { diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintConstants.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintConstants.kt index 064c196ed..ba5815bb6 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintConstants.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/BluePrintConstants.kt @@ -180,6 +180,7 @@ object BluePrintConstants { const val PROPERTY_CURRENT_NODE_TEMPLATE = "current-node-template" const val PROPERTY_CURRENT_INTERFACE = "current-interface" const val PROPERTY_CURRENT_OPERATION = "current-operation" + const val PROPERTY_CURRENT_TIMEOUT = "current-timeout" const val PROPERTY_CURRENT_IMPLEMENTATION = "current-implementation" const val PROPERTY_EXECUTION_REQUEST = "execution-request" diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt index 93ba15e99..08bc6c3fd 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/CustomFunctions.kt @@ -242,6 +242,22 @@ fun Map<String, JsonNode>.getAsDouble(key: String): Double { return this[key]?.asDouble() ?: throw BluePrintException("couldn't find value for key($key)") } +fun Map<String, JsonNode>.getOptionalAsString(key: String): String? { + return if (this.containsKey(key)) this[key]!!.asText() else null +} + +fun Map<String, JsonNode>.getOptionalAsBoolean(key: String): Boolean? { + return if (this.containsKey(key)) this[key]!!.asBoolean() else null +} + +fun Map<String, JsonNode>.getOptionalAsInt(key: String): Int? { + return if (this.containsKey(key)) this[key]!!.asInt() else null +} + +fun Map<String, JsonNode>.getOptionalAsDouble(key: String): Double? { + return if (this.containsKey(key)) this[key]!!.asDouble() else null +} + // Checks inline fun checkEquals(value1: String?, value2: String?, lazyMessage: () -> Any): Boolean { diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BluePrintGraph.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BluePrintGraph.kt index 9e1b7498e..fc796c9ed 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BluePrintGraph.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/data/BluePrintGraph.kt @@ -33,7 +33,8 @@ enum class NodeStatus(val id: String) { READY("ready"), EXECUTING("executing"), EXECUTED("executed"), - SKIPPED("skipped") + SKIPPED("skipped"), + TERMINATED("terminated") } class Graph { diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintContext.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintContext.kt index 066516fcc..b368c01aa 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintContext.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintContext.kt @@ -216,6 +216,11 @@ class BluePrintContext(val serviceTemplate: ServiceTemplate) { ?: throw BluePrintException("could't get NodeTemplate($nodeTemplateName)'s first InterfaceAssignment's first OperationAssignment name") } + fun nodeTemplateOperationImplementation(nodeTemplateName: String, interfaceName: String, operationName: String) + : Implementation? { + return nodeTemplateInterfaceOperation(nodeTemplateName, interfaceName, operationName).implementation + } + fun nodeTemplateInterfaceOperationInputs(nodeTemplateName: String, interfaceName: String, operationName: String): MutableMap<String, JsonNode>? { return nodeTemplateInterfaceOperation(nodeTemplateName, interfaceName, operationName).inputs } diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowService.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowService.kt index 905150213..5cec3c947 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowService.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowService.kt @@ -30,13 +30,12 @@ import kotlin.coroutines.CoroutineContext interface BluePrintWorkFlowService<In, Out> { /** Executes imperative workflow graph [graph] for the bluePrintRuntimeService [bluePrintRuntimeService] - * and workflow input [input], response will be retrieve from output [output]*/ - suspend fun executeWorkflow(graph: Graph, bluePrintRuntimeService: BluePrintRuntimeService<*>, - input: In, output: CompletableDeferred<Out>) + * and workflow input [input]*/ + suspend fun executeWorkflow(graph: Graph, bluePrintRuntimeService: BluePrintRuntimeService<*>, input: In): Out suspend fun initializeWorkflow(input: In): EdgeLabel - suspend fun prepareWorkflowOutput(exception: BluePrintProcessorException?): Out + suspend fun prepareWorkflowOutput(): Out /** Prepare the message for the Node */ suspend fun prepareNodeExecutionMessage(node: Graph.Node): NodeExecuteMessage<In, Out> @@ -91,6 +90,8 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP lateinit var workflowId: String + var exceptions: MutableList<Exception> = arrayListOf() + final override val coroutineContext: CoroutineContext get() = job + CoroutineName("Wf") @@ -100,7 +101,7 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP throw CancellationException("Workflow($workflowId) cancelled as requested") } - fun workflowActor() = actor<WorkflowMessage<In, Out>>(coroutineContext, Channel.UNLIMITED) { + suspend fun workflowActor() = actor<WorkflowMessage<In, Out>>(coroutineContext, Channel.UNLIMITED) { /** Process the workflow execution message */ suspend fun executeMessageActor(workflowExecuteMessage: WorkflowExecuteMessage<In, Out>) { @@ -119,13 +120,11 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP // Wait for workflow completion or Error nodeActor.invokeOnClose { exception -> launch { - log.info("End Node Completed, processing completion message") - val bluePrintProcessorException: BluePrintProcessorException? = - if (exception != null) BluePrintProcessorException(exception) else null - - val workflowOutput = prepareWorkflowOutput(bluePrintProcessorException) + if (exception != null) exceptions.add(BluePrintProcessorException(exception)) + log.info("workflow($workflowId) nodes completed with (${exceptions.size})exceptions") + val workflowOutput = prepareWorkflowOutput() workflowExecuteMessage.output.complete(workflowOutput) - channel.close(exception) + channel.close() } } } @@ -135,7 +134,11 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP when (message) { is WorkflowExecuteMessage<In, Out> -> { launch { - executeMessageActor(message) + try { + executeMessageActor(message) + } catch (e: Exception) { + exceptions.add(e) + } } } is WorkflowRestartMessage<In, Out> -> { @@ -153,7 +156,7 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP } - private fun nodeActor() = actor<NodeMessage<In, Out>>(coroutineContext, Channel.UNLIMITED) { + private suspend fun nodeActor() = actor<NodeMessage<In, Out>>(coroutineContext, Channel.UNLIMITED) { /** Send message to process from one state to other state */ fun sendNodeMessage(nodeMessage: NodeMessage<In, Out>) = launch { @@ -164,7 +167,6 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP fun processNextNodes(node: Graph.Node, nodeState: EdgeLabel) { // Process only Next Success Node val stateEdges = graph.outgoingEdges(node.id, arrayListOf(nodeState)) - log.debug("Next Edges :$stateEdges") if (stateEdges.isNotEmpty()) { stateEdges.forEach { stateEdge -> // Prepare next node ready message and Send NodeReadyMessage @@ -213,7 +215,7 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP } triggerToExecuteOrSkip(newMessage) } else { - log.info("node(${node.id}) waiting for not completed edges($notCompletedEdges)") + log.info("node(${node.id}) is waiting for incoming edges($notCompletedEdges)") } } else { triggerToExecuteOrSkip(message) @@ -233,15 +235,19 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP } // Update Node Completed node.status = NodeStatus.EXECUTED - log.info("Execute Node($node) -> Executed State($nodeState)") + log.info("Execute node(${node.id}) -> executed state($nodeState)") + // Check if the Node status edge is there, If not close processing + val edgePresent = graph.outgoingEdges(node.id, nodeState).isNotEmpty() // If End Node, Send End Message if (graph.isEndNode(node)) { // Close the current channel channel.close() + } else if (!edgePresent) { + throw BluePrintProcessorException("node(${node.id}) outgoing edge($nodeState) is missing.") } else { val skippingEdges = graph.outgoingEdgesNotInLabels(node.id, arrayListOf(nodeState)) - log.debug("Skipping node($node) outgoing Edges($skippingEdges)") + log.debug("Skipping node($node)'s outgoing edges($skippingEdges)") // Process Skip Edges skippingEdges.forEach { skippingEdge -> // Prepare next node ready message and Send NodeReadyMessage @@ -266,7 +272,7 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP log.debug("$$$$$ Skipping workflow($workflowId) node($node) $$$$$") // Call the Extension Function val nodeState = skipNode(node, message.nodeInput, message.nodeOutput) - log.info("Skip Node($node) -> Executed State($nodeState)") + log.info("Skip node(${node.id}) -> executed state($nodeState)") // Mark the Current node as Skipped node.status = NodeStatus.SKIPPED // Look for next possible skip nodes @@ -283,7 +289,7 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP fun cancelNodeWorker(messageWorkflow: WorkflowCancelMessage<In, Out>) = launch { channel.close() - throw CancellationException("Workflow($workflowId) actor cancelled as requested ...") + throw CancellationException("Workflow($workflowId) actor cancelled as requested.") } /** Process each actor message received based on type **/ @@ -294,7 +300,8 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP try { readyNodeWorker(nodeMessage) } catch (e: Exception) { - channel.close(e) + exceptions.add(e) + channel.close() } } is NodeExecuteMessage<In, Out> -> { @@ -302,7 +309,9 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP try { executeNodeWorker(nodeMessage) } catch (e: Exception) { - channel.close(e) + nodeMessage.node.status = NodeStatus.TERMINATED + exceptions.add(e) + channel.close() } } } @@ -311,7 +320,9 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP try { skipNodeWorker(nodeMessage) } catch (e: Exception) { - channel.close(e) + nodeMessage.node.status = NodeStatus.TERMINATED + exceptions.add(e) + channel.close() } } } @@ -320,20 +331,12 @@ abstract class AbstractBluePrintWorkFlowService<In, Out> : CoroutineScope, BlueP try { restartNodeWorker(nodeMessage) } catch (e: Exception) { - channel.close(e) + exceptions.add(e) + channel.close() } } } } } } - - override suspend fun executeWorkflow(graph: Graph, bluePrintRuntimeService: BluePrintRuntimeService<*>, - input: In, output: CompletableDeferred<Out>) { - log.info("Executing Graph : $graph") - this.graph = graph - this.workflowId = bluePrintRuntimeService.id() - val startMessage = WorkflowExecuteMessage(input, output) - workflowActor().send(startMessage) - } }
\ No newline at end of file diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowServiceTest.kt b/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowServiceTest.kt index b8d8cea3e..4d97f8bc3 100644 --- a/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowServiceTest.kt +++ b/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/service/BluePrintWorkflowServiceTest.kt @@ -18,13 +18,13 @@ package org.onap.ccsdk.cds.controllerblueprints.core.service import io.mockk.every import io.mockk.mockk -import kotlinx.coroutines.CompletableDeferred -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.* import org.junit.Test import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException import org.onap.ccsdk.cds.controllerblueprints.core.data.EdgeLabel import org.onap.ccsdk.cds.controllerblueprints.core.data.Graph +import org.onap.ccsdk.cds.controllerblueprints.core.logger import org.onap.ccsdk.cds.controllerblueprints.core.toGraph import kotlin.test.assertNotNull @@ -36,10 +36,66 @@ class BluePrintWorkflowServiceTest { .toGraph() val simpleWorkflow = TestBluePrintWorkFlowService() simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null) - val deferredOutput = CompletableDeferred<String>() val input = "123456" - simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input, deferredOutput) - val response = deferredOutput.await() + val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input) + assertNotNull(response, "failed to get response") + } + } + + @Test + fun testMultipleFlows() { + runBlocking { + coroutineScope { + val wfs = listOf("12345", "12346").map { + async { + val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]" + .toGraph() + val simpleWorkflow = TestBluePrintWorkFlowService() + simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D"), null) + val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(it), it) + assertNotNull(response, "failed to get response") + } + } + wfs.awaitAll() + } + } + } + + @Test + fun testMissingEdgeForBFailureState() { + runBlocking { + val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]" + .toGraph() + val simpleWorkflow = TestBluePrintWorkFlowService() + simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "C", "D", "E"), arrayListOf("B")) + val input = "123456" + val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input) + assertNotNull(response, "failed to get response") + } + } + + @Test + fun testBExceptionFlow() { + runBlocking { + val graph = "[START>A/SUCCESS, A>B/SUCCESS, B>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]" + .toGraph() + val simpleWorkflow = TestBluePrintWorkFlowService() + simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "C", "D", "E"), null) + val input = "123456" + val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input) + assertNotNull(response, "failed to get response") + } + } + + @Test + fun testTimeoutExceptionFlow() { + runBlocking { + val graph = "[START>A/SUCCESS, A>TO/SUCCESS, TO>C/SUCCESS, C>D/SUCCESS, D>END/SUCCESS]" + .toGraph() + val simpleWorkflow = TestBluePrintWorkFlowService() + simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "TO", "C", "D", "E"), null) + val input = "123456" + val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input) assertNotNull(response, "failed to get response") } } @@ -51,10 +107,8 @@ class BluePrintWorkflowServiceTest { .toGraph() val simpleWorkflow = TestBluePrintWorkFlowService() simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null) - val deferredOutput = CompletableDeferred<String>() val input = "123456" - simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input, deferredOutput) - val response = deferredOutput.await() + val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input) assertNotNull(response, "failed to get response") } } @@ -68,10 +122,8 @@ class BluePrintWorkflowServiceTest { val failurePathWorkflow = TestBluePrintWorkFlowService() failurePathWorkflow.simulatedState = prepareSimulation(arrayListOf("B", "C", "D", "E"), arrayListOf("A")) - val failurePathWorkflowDeferredOutput = CompletableDeferred<String>() val failurePathWorkflowInput = "123456" - failurePathWorkflow.executeWorkflow(failurePatGraph, mockBluePrintRuntimeService(), failurePathWorkflowInput, failurePathWorkflowDeferredOutput) - val failurePathResponse = failurePathWorkflowDeferredOutput.await() + val failurePathResponse = failurePathWorkflow.executeWorkflow(failurePatGraph, mockBluePrintRuntimeService(), failurePathWorkflowInput) assertNotNull(failurePathResponse, "failed to get response") } } @@ -83,10 +135,8 @@ class BluePrintWorkflowServiceTest { .toGraph() val simpleWorkflow = TestBluePrintWorkFlowService() simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D", "E"), null) - val deferredOutput = CompletableDeferred<String>() val input = "123456" - simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input, deferredOutput) - val response = deferredOutput.await() + val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input) assertNotNull(response, "failed to get response") } } @@ -98,17 +148,19 @@ class BluePrintWorkflowServiceTest { .toGraph() val simpleWorkflow = TestBluePrintWorkFlowService() simpleWorkflow.simulatedState = prepareSimulation(arrayListOf("A", "B", "C", "D"), null) - val deferredOutput = CompletableDeferred<String>() val input = "123456" - simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input, deferredOutput) - val response = deferredOutput.await() + val response = simpleWorkflow.executeWorkflow(graph, mockBluePrintRuntimeService(), input) assertNotNull(response, "failed to get response") } } private fun mockBluePrintRuntimeService(): BluePrintRuntimeService<*> { + return mockBluePrintRuntimeService("123456") + } + + private fun mockBluePrintRuntimeService(id: String): BluePrintRuntimeService<*> { val bluePrintRuntimeService = mockk<BluePrintRuntimeService<*>>() - every { bluePrintRuntimeService.id() } returns "123456" + every { bluePrintRuntimeService.id() } returns id return bluePrintRuntimeService } @@ -126,6 +178,7 @@ class BluePrintWorkflowServiceTest { class TestBluePrintWorkFlowService : AbstractBluePrintWorkFlowService<String, String>() { + val log = logger(TestBluePrintWorkFlowService::class) lateinit var simulatedState: MutableMap<String, EdgeLabel> @@ -133,6 +186,21 @@ class TestBluePrintWorkFlowService return EdgeLabel.SUCCESS } + override suspend fun executeWorkflow(graph: Graph, bluePrintRuntimeService: BluePrintRuntimeService<*>, input: String): String { + log.info("Executing Graph : $graph") + this.graph = graph + this.workflowId = bluePrintRuntimeService.id() + val output = CompletableDeferred<String>() + val startMessage = WorkflowExecuteMessage(input, output) + val workflowActor = workflowActor() + if (!workflowActor.isClosedForSend) { + workflowActor().send(startMessage) + } else { + throw BluePrintProcessorException("workflow actor is closed for send $workflowActor") + } + return startMessage.output.await() + } + override suspend fun prepareNodeExecutionMessage(node: Graph.Node) : NodeExecuteMessage<String, String> { return NodeExecuteMessage(node, "$node Input", "") @@ -140,23 +208,26 @@ class TestBluePrintWorkFlowService override suspend fun executeNode(node: Graph.Node, nodeInput: String, nodeOutput: String): EdgeLabel { -// val random = (1..10).random() * 1000 -// println("will reply in $random ms") +// val random = (1..10).random() * 100 +// log.info("workflow($workflowId) node(${node.id}) will reply in $random ms") // kotlinx.coroutines.delay(random.toLong()) - val status = simulatedState[node.id] ?: throw BluePrintException("failed to get status for the node($node)") - return status +// //Simulation for timeout + if (node.id == "TO") { + withTimeout(1) { + kotlinx.coroutines.delay(2) + } + } + return simulatedState[node.id] ?: throw BluePrintException("failed to get status for the node($node)") } override suspend fun prepareNodeSkipMessage(node: Graph.Node): NodeSkipMessage<String, String> { val nodeOutput = "" - val nodeSkipMessage = NodeSkipMessage(node, "$node Skip Input", nodeOutput) - return nodeSkipMessage + return NodeSkipMessage(node, "$node Skip Input", nodeOutput) } override suspend fun skipNode(node: Graph.Node, nodeInput: String, nodeOutput: String): EdgeLabel { - val status = simulatedState[node.id] ?: throw BluePrintException("failed to get status for the node($node)") - return status + return simulatedState[node.id] ?: throw BluePrintException("failed to get status for the node($node)") } override suspend fun cancelNode(node: Graph.Node, nodeInput: String, @@ -169,7 +240,12 @@ class TestBluePrintWorkFlowService TODO("not implemented") //To change body of created functions use File | Settings | File Templates. } - override suspend fun prepareWorkflowOutput(exception: BluePrintProcessorException?): String { + override suspend fun prepareWorkflowOutput(): String { + if (exceptions.isNotEmpty()) { + exceptions.forEach { + log.error("workflow($workflowId) exceptions :", it) + } + } return "Final Response" } }
\ No newline at end of file diff --git a/ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/controller/ControllerBlueprintExeptionHandler.kt b/ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/controller/ControllerBlueprintExceptionHandler.kt index de8ba93e3..5b92369f8 100644 --- a/ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/controller/ControllerBlueprintExeptionHandler.kt +++ b/ms/controllerblueprints/modules/service/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/service/controller/ControllerBlueprintExceptionHandler.kt @@ -20,6 +20,7 @@ import org.springframework.web.bind.annotation.RestControllerAdvice import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException import org.onap.ccsdk.cds.controllerblueprints.core.data.ErrorCode import org.onap.ccsdk.cds.controllerblueprints.service.common.ErrorMessage +import org.slf4j.LoggerFactory import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.ExceptionHandler @@ -32,19 +33,26 @@ import org.springframework.web.bind.annotation.ExceptionHandler * @version 1.0 */ @RestControllerAdvice("org.onap.ccsdk.cds.controllerblueprints") -open class ControllerBlueprintExeptionHandler { +open class ControllerBlueprintExceptionHandler { + + companion object ControllerBlueprintExeptionHandler { + val LOG = LoggerFactory.getLogger(ControllerBlueprintExceptionHandler::class.java) + } @ExceptionHandler - fun ControllerBlueprintException(e: BluePrintException): ResponseEntity<ErrorMessage> { + fun ControllerBlueprintExceptionHandler(e: BluePrintException): ResponseEntity<ErrorMessage> { var errorCode = ErrorCode.valueOf(e.code) val errorMessage = ErrorMessage(errorCode?.message(e.message!!), errorCode?.value, "ControllerBluePrint_Error_Message") + LOG.error("Error: $errorCode ${e.message}") return ResponseEntity(errorMessage, HttpStatus.resolve(errorCode!!.httpCode)) } @ExceptionHandler - fun ControllerBlueprintException(e: Exception): ResponseEntity<ErrorMessage> { + fun ControllerBlueprintExceptionHandler(e: Exception): ResponseEntity<ErrorMessage> { var errorCode = ErrorCode.GENERIC_FAILURE val errorMessage = ErrorMessage(errorCode?.message(e.message!!), errorCode?.value, "ControllerBluePrint_Error_Message") + LOG.error("Error: $errorCode ${e.message}") return ResponseEntity(errorMessage, HttpStatus.resolve(errorCode!!.httpCode)) } -}
\ No newline at end of file +} + |