Merge "vnf-id Data Dictionary source has circular dependendy."
authorDan Timoney <dtimoney@att.com>
Tue, 22 Oct 2019 17:44:06 +0000 (17:44 +0000)
committerGerrit Code Review <gerrit@onap.org>
Tue, 22 Oct 2019 17:44:06 +0000 (17:44 +0000)
109 files changed:
cds-ui/client/JointJS-POC-In-Progress/app-routing.module.ts [new file with mode: 0644]
cds-ui/client/JointJS-POC-In-Progress/app.component.html [new file with mode: 0644]
cds-ui/client/JointJS-POC-In-Progress/app.component.scss [new file with mode: 0644]
cds-ui/client/JointJS-POC-In-Progress/app.component.spec.ts [new file with mode: 0644]
cds-ui/client/JointJS-POC-In-Progress/app.component.ts [new file with mode: 0644]
cds-ui/client/JointJS-POC-In-Progress/app.module.ts [new file with mode: 0644]
cds-ui/client/src/app/app-routing.module.ts
cds-ui/client/src/app/common/constants/app-constants.ts
cds-ui/client/src/app/common/core/core.module.ts
cds-ui/client/src/app/common/core/store/actions/catalog.action.ts [new file with mode: 0644]
cds-ui/client/src/app/common/core/store/effects/catalog.effect.ts [new file with mode: 0644]
cds-ui/client/src/app/common/core/store/models/catalog-http.model.ts [new file with mode: 0644]
cds-ui/client/src/app/common/core/store/models/catalog.model.ts [new file with mode: 0644]
cds-ui/client/src/app/common/core/store/models/catalogState.model.ts [new file with mode: 0644]
cds-ui/client/src/app/common/core/store/reducers/app.reducer.ts
cds-ui/client/src/app/common/core/store/reducers/catalog.reducer.ts [new file with mode: 0644]
cds-ui/client/src/app/common/core/store/selectors/catalog.selectors.ts [new file with mode: 0644]
cds-ui/client/src/app/common/core/store/state/app.state.ts
cds-ui/client/src/app/common/core/store/state/catalog.state.ts [new file with mode: 0644]
cds-ui/client/src/app/common/shared/components/home/home.component.html
cds-ui/client/src/app/feature-modules/blueprint/modify-template/editor/editor.service.ts
cds-ui/client/src/app/feature-modules/blueprint/modify-template/modify-template.component.html
cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog-routing.module.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.html [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.scss [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.spec.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.module.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog-routing.module.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.html [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.scss [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.spec.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.module.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.service.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog-routing.module.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.html [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.scss [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.spec.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.module.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.service.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template-routing.module.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.html [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.scss [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.spec.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.module.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.html [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.scss [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.spec.ts [new file with mode: 0644]
cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.ts [new file with mode: 0644]
cds-ui/server/src/config/app-config.ts
cds-ui/server/src/controllers/blueprint-rest.controller.ts
cds-ui/server/src/datasources/blueprint.datasource-template.ts
cds-ui/server/src/datasources/resource-dictionary.datasource-template.ts
components/model-catalog/blueprint-model/service-blueprint/vLB/Definitions/data_types.json
components/model-catalog/blueprint-model/service-blueprint/vLB/Definitions/node_types.json
components/model-catalog/blueprint-model/service-blueprint/vLB/Definitions/resources_definition_types.json
components/model-catalog/blueprint-model/service-blueprint/vLB/Definitions/vLB_CDS.json [moved from components/model-catalog/blueprint-model/service-blueprint/vLB/Definitions/vDNS-CDS.json with 97% similarity]
components/model-catalog/blueprint-model/service-blueprint/vLB/Plans/CONFIG_ConfigDeploy.xml
components/model-catalog/blueprint-model/service-blueprint/vLB/Scripts/python/ConfigDeploy.py
components/model-catalog/blueprint-model/service-blueprint/vLB/TOSCA-Metadata/TOSCA.meta
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/base_template-mapping.json
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/base_template-template.vtl
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/baseconfig-mapping.json
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/incremental-config-mapping.json
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/nf-params-mapping.json
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/vdns-mapping.json
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/vdns-template.vtl
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/vlb-mapping.json
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/vlb-template.vtl
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/vnf-mapping.json [moved from components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/vdns-vnf-mapping.json with 97% similarity]
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/vnf-template.vtl [moved from components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/vdns-vnf-template.vtl with 98% similarity]
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/vpkg-mapping.json
components/model-catalog/blueprint-model/service-blueprint/vLB/Templates/vpkg-template.vtl
components/model-catalog/blueprint-model/test-blueprint/capability_cli/Scripts/kotlin/cba/capability/cli/CapabilityCli.kt
ms/blueprintsprocessor/application/pom.xml
ms/blueprintsprocessor/application/src/main/dc/docker-compose.yaml
ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/LoggingWebFilter.kt [new file with mode: 0644]
ms/blueprintsprocessor/application/src/main/resources/application-dev.properties
ms/blueprintsprocessor/application/src/main/resources/application.properties
ms/blueprintsprocessor/application/src/main/resources/logback.xml
ms/blueprintsprocessor/modules/commons/grpc-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/grpc/service/BluePrintGrpcLibPropertyService.kt
ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/BluePrintMessageLibData.kt
ms/blueprintsprocessor/modules/commons/message-lib/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/KafkaBasicAuthMessageConsumerService.kt
ms/blueprintsprocessor/modules/commons/message-lib/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/message/service/BlueprintMessageConsumerServiceTest.kt
ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/LoggerExtensions.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/service/BluePrintProcessorLoggingService.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/inbounds/designer-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/designer/api/BlueprintModelController.kt
ms/blueprintsprocessor/modules/inbounds/pom.xml
ms/blueprintsprocessor/modules/inbounds/selfservice-api/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/selfservice/api/ExecutionServiceController.kt
ms/blueprintsprocessor/modules/services/execution-service/pom.xml
ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/AbstractComponentFunction.kt
ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/ComponentFunctionScriptingService.kt
ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/StreamingRemoteExecutionService.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/services/execution-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/MockBluePrintProcessingServer.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/services/execution-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/StreamingRemoteExecutionServiceTest.kt [new file with mode: 0644]
ms/blueprintsprocessor/modules/services/execution-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/scripts/AbstractComponentFunctionTest.kt
ms/blueprintsprocessor/modules/services/execution-service/src/test/resources/logback-test.xml
ms/blueprintsprocessor/parent/pom.xml
ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/MDCContext.kt [new file with mode: 0644]
ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/MDCContextTest.kt [new file with mode: 0644]
ms/py-executor/blueprints_grpc/blueprint_processing_server.py
ms/py-executor/blueprints_grpc/executor_utils.py
ms/py-executor/dc/docker-compose.yaml [new file with mode: 0755]
ms/py-executor/docker/Dockerfile
ms/py-executor/docker/distribution.xml
ms/py-executor/requirements.txt

diff --git a/cds-ui/client/JointJS-POC-In-Progress/app-routing.module.ts b/cds-ui/client/JointJS-POC-In-Progress/app-routing.module.ts
new file mode 100644 (file)
index 0000000..d425c6f
--- /dev/null
@@ -0,0 +1,10 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+const routes: Routes = [];
+
+@NgModule({
+  imports: [RouterModule.forRoot(routes)],
+  exports: [RouterModule]
+})
+export class AppRoutingModule { }
diff --git a/cds-ui/client/JointJS-POC-In-Progress/app.component.html b/cds-ui/client/JointJS-POC-In-Progress/app.component.html
new file mode 100644 (file)
index 0000000..da05dd5
--- /dev/null
@@ -0,0 +1,31 @@
+<!-- <div id="myholder"></div> -->
+<div style="background-color: black; color: white; height: 75px; width:100%; font-size: 2em; margin-bottom: 3px">
+  CDS DESIGNER POC
+  <button (click)="convertGraphToJson()">Save</button>
+</div>
+<div style="display: flex;flex-direction:row; height: 700PX">
+  <div id="stencil" style="width: 30%;height: 100%;border: 1px solid; border-radius:0.5em; background-color: gainsboro"></div>
+  <div style="width: 70%; height: 100%;">
+    <div style="position: fixed;width: 200px;background-color: gainsboro;height: 36px;z-index: 2;">
+    <button *ngIf="!sourceMode" style="border-radius: 0.5em;width: 6em;height: 2.5em;border: 2px solid black;" (click)="convertGraphToJson()">Source</button>
+    <button  *ngIf="sourceMode" style="border-radius: 0.5em;width: 6em;height: 2.5em;border: 2px solid black;" (click)="convertJsonToGraph()">Graph</button>
+    <i (click) ="zoomIn()" class="fa fa-search-plus" aria-hidden="true"></i>
+    <i (click) ="zoomOut()" class="fa fa-search-minus" aria-hidden="true"></i>
+    </div>    
+    <div [hidden]="sourceMode" id="paper" style="height: 100%;"></div>
+    <div id="sourceJson" [hidden]="!sourceMode"style="width: 100%; height: 100%;"><textarea style="margin-top: 4em;
+      width: 100%;
+      height: 100%;">{{grapJson}}</textarea></div>
+  </div> 
+  <div id="propertyPanel" style="width: 20%; height: 100%; background-color: white">
+    <div style="background-color: gainsboro;height:28px">Attributes</div>
+    <div style="height: 100px;padding: 10px">
+      Action Name<br/>
+      <input type="text" [(ngModel)]="selectedElement.attributes.attrs.label.text" (change)="setNewValue($event)"/>
+    </div>
+    <div>
+      <div style="background-color: gainsboro;height:28px">Input</div>
+
+    </div>
+  </div>
+</div>
diff --git a/cds-ui/client/JointJS-POC-In-Progress/app.component.scss b/cds-ui/client/JointJS-POC-In-Progress/app.component.scss
new file mode 100644 (file)
index 0000000..68d06fb
--- /dev/null
@@ -0,0 +1,81 @@
+#stencil {
+    position: relative;
+    border: 1px solid gray;
+    display: inline-block;
+    background: transparent;
+    overflow: hidden;
+}
+#stencil svg {
+    background: transparent;
+}
+#stencil svg .link {
+    z-index: 2;
+}
+.html-element {
+    position: absolute;
+    background: #3498DB;
+    /* Make sure events are propagated to the JointJS element so, e.g. dragging works.*/
+    pointer-events: none;
+    -webkit-user-select: none;
+    border-radius: 4px;
+    border: 2px solid #2980B9;
+    box-shadow: inset 0 0 5px black, 2px 2px 1px gray;
+    padding: 5px;
+    box-sizing: border-box;
+    z-index: 2;
+}
+.html-element select,
+.html-element input,
+.html-element button {
+    /* Enable interacting with inputs only. */
+    pointer-events: auto;
+}
+.html-element button.delete {
+    color: white;
+    border: none;
+    background-color: #C0392B;
+    border-radius: 20px;
+    width: 15px;
+    height: 15px;
+    line-height: 15px;
+    text-align: middle;
+    position: absolute;
+    top: -15px;
+    left: -15px;
+    padding: 0;
+    margin: 0;
+    font-weight: bold;
+    cursor: pointer;
+}
+.html-element button.delete:hover {
+    width: 20px;
+    height: 20px;
+    line-height: 20px;
+}
+.html-element select {
+    position: absolute;
+    right: 2px;
+    bottom: 28px;
+}
+.html-element input {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    border: none;
+    color: #333;
+    padding: 5px;
+    height: 16px;
+}
+.html-element label {
+    color: #333;
+    text-shadow: 1px 0 0 lightgray;
+    font-weight: bold;
+}
+.html-element span {
+    position: absolute;
+    top: 2px;
+    right: 9px;
+    color: white;
+    font-size: 10px;
+}
\ No newline at end of file
diff --git a/cds-ui/client/JointJS-POC-In-Progress/app.component.spec.ts b/cds-ui/client/JointJS-POC-In-Progress/app.component.spec.ts
new file mode 100644 (file)
index 0000000..8de310a
--- /dev/null
@@ -0,0 +1,35 @@
+import { TestBed, async } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { AppComponent } from './app.component';
+
+describe('AppComponent', () => {
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      imports: [
+        RouterTestingModule
+      ],
+      declarations: [
+        AppComponent
+      ],
+    }).compileComponents();
+  }));
+
+  it('should create the app', () => {
+    const fixture = TestBed.createComponent(AppComponent);
+    const app = fixture.debugElement.componentInstance;
+    expect(app).toBeTruthy();
+  });
+
+  it(`should have as title 'jointJS-designer'`, () => {
+    const fixture = TestBed.createComponent(AppComponent);
+    const app = fixture.debugElement.componentInstance;
+    expect(app.title).toEqual('jointJS-designer');
+  });
+
+  it('should render title in a h1 tag', () => {
+    const fixture = TestBed.createComponent(AppComponent);
+    fixture.detectChanges();
+    const compiled = fixture.debugElement.nativeElement;
+    expect(compiled.querySelector('h1').textContent).toContain('Welcome to jointJS-designer!');
+  });
+});
diff --git a/cds-ui/client/JointJS-POC-In-Progress/app.component.ts b/cds-ui/client/JointJS-POC-In-Progress/app.component.ts
new file mode 100644 (file)
index 0000000..289a577
--- /dev/null
@@ -0,0 +1,869 @@
+declare var require: any
+import { Component, OnInit } from '@angular/core';
+import * as $ from 'jquery';
+import * as _ from 'lodash';
+const joint = require('../../node_modules/jointjs/dist/joint.js');
+
+
+@Component({
+  selector: 'app-root',
+  templateUrl: './app.component.html',
+  styleUrls: ['./app.component.scss']
+})
+export class AppComponent implements OnInit {
+  title = 'jointJS-designer';
+
+  public graph: any;
+  public paper: any;
+  public rect: any;
+  public rect2: any;
+  public link: any;
+
+  public stencilGraph: any;
+  public stencilPaper: any;
+
+  public selectedElement = {
+    attributes: {
+      attrs: {
+        label: {
+          text: 'abc'
+        }
+      }
+    }
+  };
+
+  grapJson: any;
+  sourceMode = false;
+
+  constructor() {
+
+  }
+
+  ngOnInit() {
+    // this.creatElementWithPorts();
+    // this.dragCopyPlainElements();
+    this.sourceMode = false;
+    this.dragCopyElementsWithPort();
+    // this.newDragCopy();
+
+    this.createContainerElements();
+  }
+
+  creatElementWithPorts() {
+    // working code
+
+    // create graph
+    let elementList: any[] = [];
+    // this.graph = new joint.dia.Graph;
+
+    // // create paper
+    // this.paper = new joint.dia.Paper({
+    //   el: document.getElementById('paper'),
+    //   width: 1000,
+    //   height: 1000,
+    //   model: this.graph,
+    //   gridSize: 2,
+    //   drawGrid: true
+    // });
+
+    // this.paper.setGrid({
+    //   name: 'dot',
+    //   args:
+    //     { color: 'black', thickness: 2, scaleFactor: 8 }
+
+    // }).drawGrid();
+
+    // create element
+    this.rect = new joint.shapes.basic.Rect({
+      position: { x: 100, y: 30 },
+      size: { width: 100, height: 100 },
+      attrs: { rect: { fill: 'white' }, text: { text: 'my box', fill: 'white' } }
+    });
+    this.rect.translate(100, 50);
+    elementList.push(this.rect);
+
+    this.rect.position(10, 10);
+    // clone element
+    // this.rect2 = this.rect.clone();
+    // this.rect2.translate(180);
+    // elementList.push(this.rect2);
+
+    // Create link
+    // this.link = new joint.dia.Link({
+    //   source: { id: this.rect.id },
+    //   target: { id: this.rect2.id }
+    // });
+
+
+    // create circle
+    var circle = new joint.shapes.standard.Circle();
+    circle.resize(100, 100);
+    circle.position(180, 10);
+    circle.attr('root/title', 'joint.shapes.standard.Circle');
+    circle.attr('label/text', 'Circle');
+    circle.attr('body/fill', 'lightblue');
+    elementList.push(circle);
+
+    // create link
+    var ellipse = new joint.shapes.standard.Ellipse();
+    ellipse.resize(150, 100);
+    ellipse.position(180, 150);
+    ellipse.attr('root/title', 'joint.shapes.standard.Ellipse');
+    ellipse.attr('label/text', 'Ellipse');
+    ellipse.attr('body/fill', 'lightblue');
+    elementList.push(ellipse);
+
+    // rectangle with header
+    var headeredRectangle = new joint.shapes.standard.HeaderedRectangle();
+    headeredRectangle.resize(150, 100);
+    headeredRectangle.position(10, 280);
+    headeredRectangle.attr('root/title', 'joint.shapes.standard.HeaderedRectangle');
+    headeredRectangle.attr('header/fill', 'lightgray');
+    headeredRectangle.attr('headerText/text', 'Header');
+    headeredRectangle.attr('bodyText/text', 'Headered\nRectangle');
+    elementList.push(headeredRectangle);
+
+    let m1 = new joint.shapes.devs.Model({
+      position: { x: 200, y: 280 },
+      size: { width: 90, height: 90 },
+      inPorts: ['in1', 'in2'],
+      outPorts: ['out', 'out2'],
+      ports: {
+        groups: {
+          'in': {
+            attrs: {
+              '.port-body': {
+                fill: '#16A085'
+              }
+            }
+          },
+          'out': {
+            attrs: {
+              '.port-body': {
+                fill: '#E74C3C'
+              }
+            }
+          }
+        }
+      },
+      attrs: {
+        '.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },
+        rect: { fill: 'white' }
+      }
+    });
+    elementList.push(m1);
+
+    //container element
+    let c1 = new joint.shapes.devs.Coupled({
+      position: {
+          x: 150,
+          y: 470
+      },
+      size: {
+          width: 200,
+          height: 200
+      }
+    });
+
+    c1.set('inPorts', ['in']);
+  c1.set('outPorts', ['out 1', 'out 2']);
+  c1.attr({
+    '.body': {
+        'rx': 6,
+        'ry': 6
+    }
+});
+  elementList.push(c1);
+  // circle.position(10, 150);
+  var a1 = new joint.shapes.devs.Atomic({
+    position: {
+        x: 10,
+        y: 150
+    },
+    inPorts: ['xy'],
+    outPorts: ['x', 'y']
+  });
+
+  a1.attr({
+    '.body': {
+        'rx': 6,
+        'ry': 6
+    }
+  });
+
+  elementList.push(a1);
+
+    
+    return elementList;
+  }
+
+  dragCopyPlainElements() {
+    // Canvas where sape are dropped
+    this.graph = new joint.dia.Graph,
+      this.paper = new joint.dia.Paper({
+        el: $('#paper'),
+        model: this.graph
+      });
+
+    // Canvas from which you take shapes
+    this.stencilGraph = new joint.dia.Graph,
+      this.stencilPaper = new joint.dia.Paper({
+        el: $('#stencil'),
+        height: 60,
+        model: this.stencilGraph,
+        interactive: false
+      });
+
+    var r1 = new joint.shapes.basic.Rect({
+      position: {
+        x: 10,
+        y: 10
+      },
+      size: {
+        width: 100,
+        height: 40
+      },
+      attrs: {
+        text: {
+          text: 'Rect1'
+        }
+      }
+    });
+    var r2 = new joint.shapes.basic.Rect({
+      position: {
+        x: 120,
+        y: 10
+      },
+      size: {
+        width: 100,
+        height: 40
+      },
+      attrs: {
+        text: {
+          text: 'Rect2'
+        }
+      }
+    });
+    this.stencilGraph.addCells([r1, r2]);
+
+    let _this = this;
+
+    this.stencilPaper.on('cell:pointerdown', function (cellView, e, x, y) {
+      $('body').append('<div id="flyPaper" style="position:fixed;z-index:100;opacity:.7;pointer-event:none;"></div>');
+      var flyGraph = new joint.dia.Graph,
+        flyPaper = new joint.dia.Paper({
+          el: $('#flyPaper'),
+          model: flyGraph,
+          interactive: false
+        }),
+        flyShape = cellView.model.clone(),
+        pos = cellView.model.position(),
+        offset = {
+          x: x - pos.x,
+          y: y - pos.y
+        };
+
+      flyShape.position(0, 0);
+      flyGraph.addCell(flyShape);
+      $("#flyPaper").offset({
+        left: e.pageX - offset.x,
+        top: e.pageY - offset.y
+      });
+      $('body').on('mousemove.fly', function (e) {
+        $("#flyPaper").offset({
+          left: e.pageX - offset.x,
+          top: e.pageY - offset.y
+        });
+      });
+      $('body').on('mouseup.fly', function (e) {
+        var x = e.pageX,
+          y = e.pageY,
+          target = _this.paper.$el.offset();
+
+        // Dropped over paper ?
+        if (x > target.left && x < target.left + _this.paper.$el.width() && y > target.top && y < target.top + _this.paper.$el.height()) {
+          var s = flyShape.clone();
+          s.position(x - target.left - offset.x, y - target.top - offset.y);
+          _this.graph.addCell(s);
+        }
+        $('body').off('mousemove.fly').off('mouseup.fly');
+        flyShape.remove();
+        $('#flyPaper').remove();
+      });
+    })
+  }
+
+  dragCopyElementsWithPort() {
+    // Canvas where sape are dropped
+    
+    this.graph = new joint.dia.Graph,
+      this.paper = new joint.dia.Paper({
+        el: $('#paper'),
+        model: this.graph,
+        height: 700,
+        width: 1000,
+        gridSize: 2,
+        drawGrid: true
+      });
+
+    // create paper
+    // this.paper = new joint.dia.Paper({
+    //   el: document.getElementById('paper'),
+    //   width: 1000,
+    //   height: 1000,
+    //   model: this.graph,
+    //   gridSize: 2,
+    //   drawGrid: true
+    // });
+
+    this.paper.setGrid({
+      name: 'dot',
+      args:
+        { color: 'black', thickness: 2, scaleFactor: 8 }
+
+    }).drawGrid();
+
+    // Canvas from which you take shapes
+    this.stencilGraph = new joint.dia.Graph,
+      this.stencilPaper = new joint.dia.Paper({
+        el: $('#stencil'),
+        height: 700,
+        width: 382,
+        model: this.stencilGraph,
+        interactive: false
+      });      
+    
+      let elementWithPort = this.creatElementWithPorts();
+      // let elementWithPort = this.createCustomElement();
+      // let elementWithPort = this.myCustomElementGenerator();
+
+      
+    
+    elementWithPort.forEach(element => {
+      this.stencilGraph.addCell(element);
+    });
+    
+    let _this = this;
+    this.stencilPaperEventListeners(_this);
+    this.drawAreapaperEventListerners();
+  }
+
+  resetAll(paper) {
+    this.paper.drawBackground({
+      color: 'white'
+    })
+
+    var elements = this.paper.model.getElements();
+    for (var i = 0, ii = elements.length; i < ii; i++) {
+      var currentElement = elements[i];
+      currentElement.attr('body/stroke', 'black');
+    }
+
+    var links = this.paper.model.getLinks();
+    for (var j = 0, jj = links.length; j < jj; j++) {
+      var currentLink = links[j];
+      currentLink.attr('line/stroke', 'black');
+      currentLink.label(0, {
+        attrs: {
+          body: {
+            stroke: 'black'
+          }
+        }
+      })
+    }
+  }
+
+  onDrag(evt) {
+    // transform client to paper coordinates
+    var p = evt.data.paper.snapToGrid({
+      x: evt.clientX,
+      y: evt.clientY
+    });
+    // manually execute the linkView mousemove handler
+    evt.data.view.pointermove(evt, p.x, p.y);
+  }
+
+  onDragEnd(evt) {
+    // manually execute the linkView mouseup handler
+    evt.data.view.pointerup(evt);
+    $(document).off('.example');
+  }
+
+  stencilPaperEventListeners(_this) {
+    this.stencilPaper.on('cell:pointerdown', function (cellView, e, x, y) {
+      $('body').append('<div id="flyPaper" style="position:fixed;z-index:100;opacity:.7;pointer-event:none;"></div>');
+      var flyGraph = new joint.dia.Graph,
+        flyPaper = new joint.dia.Paper({
+          el: $('#flyPaper'),
+          model: flyGraph,
+          interactive: true
+        }),
+        flyShape = cellView.model.clone(),
+        pos = cellView.model.position(),
+        offset = {
+          x: x - pos.x,
+          y: y - pos.y
+        };
+
+      flyShape.position(0, 0);
+      flyGraph.addCell(flyShape);
+      $("#flyPaper").offset({
+        left: e.pageX - offset.x,
+        top: e.pageY - offset.y
+      });
+      $('body').on('mousemove.fly', function (e) {
+        $("#flyPaper").offset({
+          left: e.pageX - offset.x,
+          top: e.pageY - offset.y
+        });
+      });
+      let elementabove, elementBelow;
+      $('body').on('mouseup.fly', function (e) {
+        console.log(this);        
+        var x = e.pageX,
+          y = e.pageY,
+          target = _this.paper.$el.offset();
+
+        // Dropped over paper ?
+        if (x > target.left && x < target.left + _this.paper.$el.width() && y > target.top && y < target.top + _this.paper.$el.height()) {
+          var s = flyShape.clone();
+
+          // var coordinates = new g.Point(x, y);
+          // elementabove = s;
+          // elementBelow =  _this.paper.model.findModelsFromPoint(coordinates).find(function(el) {
+          //   return (el.id !== elementabove.id);
+          // });
+          // elementBelow =_this.paper.findModelsFromPoint(coordinates).find(function(el) {
+          //     return (el.id !== elementabove.id);
+          //   });
+          // elementBelow.embed(elementabove);
+
+          s.position(x - target.left - offset.x, y - target.top - offset.y);
+          _this.graph.addCell(s);
+          // let elementssss = (_this.graph.getElements());
+          // console.log("elementsss", elementssss);
+          // let elementBelow = elementssss[0];
+          // let elementAbove;
+          // if(elementssss[1]) {
+          //   elementAbove = elementssss[1];
+          //   elementBelow.embed(elementabove);
+          // }
+        }
+        $('body').off('mousemove.fly').off('mouseup.fly');
+        flyShape.remove();
+        $('#flyPaper').remove();
+      });
+      _this.paper.on('mouse')
+    })
+  }
+
+  drawAreapaperEventListerners() {
+    // create event listerners
+    let _this = this;
+    this.paper.on('element:pointerdblclick', function (elementView) {
+      _this.resetAll(this);
+      _this.selectedElement = elementView.model;
+      var currentElement = elementView.model;
+      currentElement.attr('body/stroke', 'orange');
+      // currentElement.attr('label/text', "abc");
+    });
+
+    this.paper.on('blank:pointerdblclick', function () {
+      _this.resetAll(this);
+
+      this.drawBackground({
+        color: 'orange'
+      });
+    });
+
+    this.paper.on('link:pointerclick', function (linkView) {
+      _this.resetAll(this);
+      let currentElement = linkView.model;
+      currentElement.appendLabel({
+        attrs: {
+          text: {
+            text: "Hello to new link!"
+          }
+        }
+      });
+
+    });
+
+
+    this.paper.on('blank:pointerdown', function (evt, x, y) {
+      let linkView = this.getDefaultLink()
+        .set({
+          'source': { x: x, y: y },
+          'target': { x: x, y: y }
+        })
+        .addTo(this.model)
+        .findView(this);
+      linkView.startArrowheadMove('target');
+
+      $(document).on({
+        'mousemove.example': _this.onDrag,
+        'mouseup.example': _this.onDragEnd
+      }, {
+          // shared data between listeners
+          view: linkView,
+          paper: this
+        });
+    });
+
+    this.paper.on({
+      // 'element:pointerdown': function(elementView, evt) {
+
+      //   evt.data = elementView.model.position();
+      // },
+      'element:pointerup': function(elementView, evt, x, y) {
+        var coordinates = new g.Point(x, y);
+        var elementAbove = elementView.model;
+        var elementBelow = this.model.findModelsFromPoint(coordinates).find(function(el) {
+                return (el.id !== elementAbove.id);
+            });
+        if(elementBelow) elementBelow.embed(elementAbove);
+      }
+
+    }); //end of my event
+  }
+
+  createCustomElement() {
+    joint.shapes.html = {};
+    joint.shapes.html.Element = joint.shapes.basic.Rect.extend({
+      defaults: joint.util.deepSupplement({
+          type: 'html.Element',
+          attrs: {
+              rect: { stroke: 'none', 'fill-opacity': 0 }
+          }
+      }, joint.shapes.basic.Rect.prototype.defaults)
+    });
+
+    // / Create a custom view for that element that displays an HTML div above it.
+    // -------------------------------------------------------------------------
+
+    joint.shapes.html.ElementView = joint.dia.ElementView.extend({
+
+          template: [
+            '<div class="html-element">',
+            '<button class="delete">x</button>',
+            '<label></label>',
+            '<span></span>', '<br/>',
+            '<select><option>--</option><option>one</option><option>two</option></select>',
+            '<input type="text" value="I\'m HTML input" />',
+            '</div>'
+        ].join(''),
+
+        initialize: function() {
+          _.bindAll(this, 'updateBox');
+          joint.dia.ElementView.prototype.initialize.apply(this, arguments);
+
+          this.$box = $(_.template(this.template)());
+          // Prevent paper from handling pointerdown.
+          this.$box.find('input,select').on('mousedown click', function(evt) {
+              evt.stopPropagation();
+          });
+          // This is an example of reacting on the input change and storing the input data in the cell model.
+          this.$box.find('input').on('change', _.bind(function(evt) {
+              this.model.set('input', $(evt.target).val());
+          }, this));
+          this.$box.find('select').on('change', _.bind(function(evt) {
+              this.model.set('select', $(evt.target).val());
+          }, this));
+          this.$box.find('select').val(this.model.get('select'));
+          this.$box.find('.delete').on('click', _.bind(this.model.remove, this.model));
+          // Update the box position whenever the underlying model changes.
+          this.model.on('change', this.updateBox, this);
+          // Remove the box when the model gets removed from the graph.
+          this.model.on('remove', this.removeBox, this);
+
+          this.updateBox();
+        },
+
+        render: function() {
+          joint.dia.ElementView.prototype.render.apply(this, arguments);
+          this.paper.$el.prepend(this.$box);
+          this.updateBox();
+          return this;
+        },
+
+      updateBox: function() {
+        // Set the position and dimension of the box so that it covers the JointJS element.
+        var bbox = this.model.getBBox();
+        // Example of updating the HTML with a data stored in the cell model.
+        this.$box.find('label').text(this.model.get('label'));
+        this.$box.find('span').text(this.model.get('select'));
+        this.$box.css({
+            width: bbox.width,
+            height: bbox.height,
+            left: bbox.x,
+            top: bbox.y,
+            transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)'
+        });
+      },
+
+      removeBox: function(evt) {
+        this.$box.remove();
+      }
+    });
+
+    // Create JointJS elements and add them to the graph as usual.
+        // -----------------------------------------------------------
+
+        var el1 = new joint.shapes.html.Element({
+          position: { x: 10, y: 10 },
+          size: { width: 170, height: 100 },
+          label: 'I am HTML',
+          select: 'one'
+      });
+
+      var el2 = new joint.shapes.html.Element({
+        position: { x: 370, y: 160 },
+        size: { width: 170, height: 100 },
+        label: 'Me too',
+        select: 'two'
+    });
+    var l = new joint.dia.Link({
+        source: { id: el1.id },
+        target: { id: el2.id },
+        attrs: { '.connection': { 'stroke-width': 5, stroke: '#34495E' }}
+    });
+
+    let elementArray : any[] = [];
+    elementArray.push(el1, el2);
+    return elementArray;
+  }
+
+  myCustomElementGenerator() {
+    var Ellipse = joint.dia.Element.define('examples.Ellipse', {
+      // default attributes
+      markup: [{
+          tagName: 'ellipse',
+          selector: 'ellipse' // not necessary but faster
+      }],
+      attrs: {
+          ellipse: {
+              fill: 'white',
+              stroke: 'black',
+              strokeWidth: 4,
+              refRx: .5,
+              refRy: .5,
+              refCx: .5,
+              refCy: .5
+          }
+      }
+  });
+
+    var Rectangle = joint.shapes.standard.Rectangle.define('examples.CustomRectangle', {
+      markup: [{
+        tagName: 'body',
+        selector: 'body' // not necessary but faster
+      },
+      {
+        tagName: 'label',
+        selector: 'label'
+      }],
+      attrs: {
+        body: {
+          rx: 10, // add a corner radius
+          ry: 10,
+          strokeWidth: 1,
+          fill: 'cornflowerblue'
+        },
+        label: {
+          textAnchor: 'left', // align text to left
+          refX: 10, // offset text from right edge of model bbox
+          fill: 'white',
+          fontSize: 18,
+          text: 'mad mad mad'
+        }
+      }
+    })
+  
+
+  var customElement = (new joint.dia.Element.examples.Ellipse()).position(100, 100).size(120, 50);
+    let elementsArray = [];
+    elementsArray.push(customElement);
+
+  var customRect = new Rectangle().position(100, 200).size(120, 120);
+  elementsArray.push(customRect);
+    return elementsArray;
+  }
+
+  convertGraphToJson() {
+    this.grapJson = JSON.stringify(this.graph.toJSON());
+    // this.grapJson = this.graph.toJSON();
+    console.log(this.graph.toJSON());
+    console.log(this.grapJson);
+    this.sourceMode = true;
+  }
+
+  setNewValue(event) {
+    // this.selectedElement.attr('label/text', event.currentTarget.value);
+  }
+
+  convertJsonToGraph() {
+    this.sourceMode = false;
+  }
+
+  zoomIn() {
+    var graphScale = 1;
+    graphScale += 0.1;
+    this.paper.scale(graphScale, graphScale);
+  }
+
+  zoomOut() {
+    var graphScale = 1;
+    graphScale -= 0.1;
+    this.paper.scale(graphScale, graphScale);
+  }
+
+  createContainerElements() {
+    this.graph = new joint.dia.Graph;
+
+    this.paper = new joint.dia.Paper({
+
+      el: document.getElementById('paper'),
+      width: 800,
+      height: 400,
+      gridSize: 1,
+      model: this.graph,
+      snapLinks: true,
+      linkPinning: false,
+      embeddingMode: true,
+      clickThreshold: 5,
+      defaultConnectionPoint: { name: 'boundary' },
+      highlighting: {
+          'default': {
+              name: 'stroke',
+              options: {
+                  padding: 6
+              }
+          },
+          'embedding': {
+              name: 'addClass',
+              options: {
+                  className: 'highlighted-parent'
+              }
+          }
+      },
+  
+      validateEmbedding: function(childView, parentView) {
+          return parentView.model instanceof joint.shapes.devs.Coupled;
+      },
+  
+      validateConnection: function(sourceView, sourceMagnet, targetView, targetMagnet) {
+          return sourceMagnet != targetMagnet;
+      }
+  });
+
+  let c1 = new joint.shapes.devs.Coupled({
+    position: {
+        x: 230,
+        y: 50
+    },
+    size: {
+        width: 300,
+        height: 300
+    }
+});
+
+c1.set('inPorts', ['in']);
+c1.set('outPorts', ['out 1', 'out 2']);
+
+var a1 = new joint.shapes.devs.Atomic({
+  position: {
+      x: 360,
+      y: 260
+  },
+  inPorts: ['xy'],
+  outPorts: ['x', 'y']
+});
+
+var a2 = new joint.shapes.devs.Atomic({
+  position: {
+      x: 50,
+      y: 160
+  },
+  outPorts: ['out']
+});
+
+var a3 = new joint.shapes.devs.Atomic({
+  position: {
+      x: 650,
+      y: 50
+  },
+  size: {
+      width: 100,
+      height: 300
+  },
+  inPorts: ['a', 'b']
+});
+
+[c1, a1, a2, a3].forEach(function(element) {
+  element.attr({
+      '.body': {
+          'rx': 6,
+          'ry': 6
+      }
+  });
+});
+
+
+
+this.graph.addCells([c1, a1, a2, a3]);
+
+c1.embed(a1);
+
+this.connect(a2, 'out', c1, 'in');
+this.connect(c1, 'in', a1, 'xy');
+this.connect(a1, 'x', c1, 'out 1');
+this.connect(a1, 'y', c1, 'out 2');
+this.connect(c1, 'out 1', a3, 'a');
+this.connect(c1, 'out 2', a3, 'b');
+
+var strokeDasharrayPath = '.body/strokeDasharray';
+let _this = this;
+
+this.paper.on('element:pointerdblclick', function(elementView) {
+    var element = elementView.model;
+    if (element.get('type') === 'devs.Atomic') {
+      _this.toggleDelegation(element);
+    }
+});
+
+this.paper.setInteractivity(function(elementView) {
+    return {
+        stopDelegation: !elementView.model.attr(strokeDasharrayPath)
+    };
+});
+
+  
+} // function end
+
+  // function
+  connect(source, sourcePort, target, targetPort) {
+
+    var link = new joint.shapes.devs.Link({
+        source: {
+            id: source.id,
+            port: sourcePort
+        },
+        target: {
+            id: target.id,
+            port: targetPort
+        }
+    });
+
+    link.addTo(this.graph).reparent();
+  }
+
+  toggleDelegation(element) {
+    var strokeDasharrayPath = '.body/strokeDasharray';
+    element.attr(strokeDasharrayPath, element.attr(strokeDasharrayPath) ? '' : '15,1');
+}
+
+createContainerElemnetsByDragDrop() {
+  
+
+}
+}
diff --git a/cds-ui/client/JointJS-POC-In-Progress/app.module.ts b/cds-ui/client/JointJS-POC-In-Progress/app.module.ts
new file mode 100644 (file)
index 0000000..15eb6d5
--- /dev/null
@@ -0,0 +1,24 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { CommonModule } from '@angular/common';  
+
+import { AppRoutingModule } from './app-routing.module';
+import { AppComponent } from './app.component';
+import { DragCopyComponent } from './drag-copy/drag-copy.component';
+
+@NgModule({
+  declarations: [
+    AppComponent,
+    DragCopyComponent
+  ],
+  imports: [
+    BrowserModule,
+    AppRoutingModule,
+    FormsModule,
+    CommonModule
+  ],
+  providers: [],
+  bootstrap: [AppComponent]
+})
+export class AppModule { }
index 96dfce1..01ecfe4 100644 (file)
@@ -2,6 +2,8 @@
 ============LICENSE_START==========================================
 ===================================================================
 Copyright (C) 2018 IBM Intellectual Property. All rights reserved.
+
+Modifications Copyright (C) 2019 TechMahindra
 ===================================================================
 
 Unless otherwise specified, all software contained herein is licensed
@@ -36,6 +38,10 @@ const routes: Routes = [
     {
       path: 'resource-definition',
       loadChildren: './feature-modules/resource-definition/resource-definition.module#ResourceDefinitionModule'
+    },
+    {
+        path: 'controller-catalog',
+        loadChildren: './feature-modules/controller-catalog/controller-catalog.module#ControllerCatalogModule'
     }
   ]
 }
index 78fefd8..5beb6af 100644 (file)
@@ -2,6 +2,8 @@
 ============LICENSE_START==========================================
 ===================================================================
 Copyright (C) 2018 IBM Intellectual Property. All rights reserved.
+
+Modifications Copyright (C) 2019 TechMahindra
 ===================================================================
 
 Unless otherwise specified, all software contained herein is licensed
@@ -110,4 +112,11 @@ export const ResourceDictionaryURLs = {
     getSources: '/resourcedictionary/source-mapping',
     getModelType: '/resourcedictionary/model-type',
     getDataType: '/resourcedictionary/model-type/by-definition/data_type'
+}
+
+export const ControllerCatalogURLs = {
+                searchControllerCatalogByTags: '/controllercatalog/search',
+                saveControllerCatalog: '/controllercatalog/save',
+                getDefinition: '/controllercatalog/model-type/by-definition',
+                getDerivedFrom: '/controllercatalog/model-type/by-derivedfrom'
 }
\ No newline at end of file
index 7207178..3743ab3 100644 (file)
@@ -25,13 +25,13 @@ import { StoreModule, Store } from '@ngrx/store';
 import { EffectsModule } from '@ngrx/effects';
 import { StoreRouterConnectingModule } from '@ngrx/router-store';
 import { HttpClientModule } from '@angular/common/http';
-
 import { appReducers } from './store/reducers/app.reducer';
 import { BlueprintEffects } from './store/effects/blueprint.effects';
 import { ResourcesEffects } from './store/effects/resources.effects';
 import { ApiService } from './services/api.service';
 import { NotificationHandlerService } from './services/notification-handler.service';
 import { LoaderService } from './services/loader.service';
+import { CatalogEffects } from './store/effects/catalog.effect';
 // import { BlueprintService } from './services/blueprint.service';
 
 @NgModule({
@@ -40,7 +40,7 @@ import { LoaderService } from './services/loader.service';
   imports: [
     CommonModule,
     StoreModule.forRoot(appReducers),
-    EffectsModule.forRoot([BlueprintEffects, ResourcesEffects]),
+    EffectsModule.forRoot([BlueprintEffects, ResourcesEffects, CatalogEffects]),
     StoreRouterConnectingModule.forRoot({ stateKey: 'router' }),
     HttpClientModule
   ],
diff --git a/cds-ui/client/src/app/common/core/store/actions/catalog.action.ts b/cds-ui/client/src/app/common/core/store/actions/catalog.action.ts
new file mode 100644 (file)
index 0000000..938cdb1
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { Injectable } from '@angular/core';
+import { Action, Store } from '@ngrx/store';
+import { ICatalog } from '../models/catalog.model';
+import { ICatalogState } from '../models/catalogState.model';
+
+export const LOAD_CATALOG = 'LOAD_CATALOG';
+export const LOAD_CATALOG_SUCCESS = 'LOAD_CATALOG_SUCCESS';
+export const LOAD_CATALOG_FAILURE = 'LOAD_CATALOG_FAILURE';
+export const UPDATE_CATALOG ='UPDATE_CATALOG';
+export const UPDATE_CATALOG_SUCCESS = 'UPDATE_CATALOG_SUCCESS';
+export const UPDATE_CATALOG_FAILURE = 'UPDATE_CATALOG_FAILURE';
+export const SAVE_CATALOG = 'SAVE_CATALOG';
+export const SAVE_CATALOG_SUCCESS = 'SAVE_CATALOG_SUCCESS';
+export const SAVE_CATALOG_FAILURE = 'SAVE_CATALOG_FAILURE';
+
+export const SET_CATALOG = 'SET CATALOG';
+export const REMOVE_CATALOG = 'Remove CATALOG';
+
+export const SET_CATALOG_STATE = 'SET CATALOG state';
+
+
+export class LoadCatalog implements Action {
+    readonly type = LOAD_CATALOG;
+    constructor(public startLoadSuccess?: boolean) {}
+}
+
+export class LoadCatalogSuccess implements Action {
+    readonly type = LOAD_CATALOG_SUCCESS;
+    constructor(public payload: ICatalog) {}
+}
+
+export class LoadCatalogFailure implements Action {
+    readonly type = LOAD_CATALOG_FAILURE;
+    constructor(public error: any) {}
+}
+
+export class SetCatalogState implements Action {
+    readonly type = SET_CATALOG_STATE;
+    constructor(public payload: ICatalogState) {}
+}
+
+// export class SetCatalog implements Action {
+//     readonly type = SET_CATALOG;
+//     constructor(public payload: Catalog) {}
+// }
+
+// export class RemoveCatalog implements Action {
+//     readonly type = REMOVE_CATALOG;
+//     constructor(public payload: Catalog) {}
+// }
+
+export class UpdateCatalog implements Action {
+    readonly type = UPDATE_CATALOG;
+    constructor(public payload: ICatalog) {}
+}
+
+export type Actions = LoadCatalog | LoadCatalogSuccess | LoadCatalogFailure | SetCatalogState;
\ No newline at end of file
diff --git a/cds-ui/client/src/app/common/core/store/effects/catalog.effect.ts b/cds-ui/client/src/app/common/core/store/effects/catalog.effect.ts
new file mode 100644 (file)
index 0000000..db2296e
--- /dev/null
@@ -0,0 +1,37 @@
+/*\r
+* ============LICENSE_START=======================================================\r
+* ONAP : CDS\r
+* ================================================================================\r
+* Copyright (C) 2019 TechMahindra\r
+*=================================================================================\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+*     http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+* ============LICENSE_END=========================================================\r
+*/\r
+\r
+import { Injectable } from '@angular/core';\r
+import { Effect, ofType, Actions } from '@ngrx/effects';\r
+import { Store, select } from '@ngrx/store';\r
+import { of } from 'rxjs';\r
+import { switchMap, map, withLatestFrom, catchError } from 'rxjs/operators';\r
+\r
+import { IAppState } from '../state/app.state';\r
+import * as CatalogActions from '../actions/catalog.action';\r
+\r
+@Injectable()\r
+export class CatalogEffects {\r
+\r
+  constructor(\r
+    private _actions$: Actions,\r
+    private _store: Store<IAppState>\r
+  ) {}\r
+}
\ No newline at end of file
diff --git a/cds-ui/client/src/app/common/core/store/models/catalog-http.model.ts b/cds-ui/client/src/app/common/core/store/models/catalog-http.model.ts
new file mode 100644 (file)
index 0000000..dde1f97
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { ICatalog } from './catalog.model';
+
+export interface ICatalogHttp {
+  catalog: ICatalog;
+}
\ No newline at end of file
diff --git a/cds-ui/client/src/app/common/core/store/models/catalog.model.ts b/cds-ui/client/src/app/common/core/store/models/catalog.model.ts
new file mode 100644 (file)
index 0000000..2344f33
--- /dev/null
@@ -0,0 +1,29 @@
+/*\r
+* ============LICENSE_START=======================================================\r
+* ONAP : CDS\r
+* ================================================================================\r
+* Copyright (C) 2019 TechMahindra\r
+*=================================================================================\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+*     http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+* ============LICENSE_END=========================================================\r
+*/\r
+\r
+export interface ICatalog { \r
+      Model_Name: string;\r
+      User_id: string;\r
+      _tags: string;\r
+      _type: string;\r
+      Derived_From: string;\r
+      _description : string;\r
+      definition: object[];\r
+}
\ No newline at end of file
diff --git a/cds-ui/client/src/app/common/core/store/models/catalogState.model.ts b/cds-ui/client/src/app/common/core/store/models/catalogState.model.ts
new file mode 100644 (file)
index 0000000..937dd87
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { ICatalog } from './catalog.model';
+
+export interface ICatalogState {
+    catalog: ICatalog,
+    isLoadSuccess?: boolean;
+    isUpdateSuccess?: boolean;
+    isSaveSuccess?: boolean;
+}
\ No newline at end of file
index 6f58320..7859390 100644 (file)
@@ -21,13 +21,14 @@ limitations under the License.
 
 import { ActionReducerMap } from '@ngrx/store';
 import { routerReducer } from '@ngrx/router-store';
-
 import { IAppState } from '../state/app.state';
 import { blueprintReducer } from '../reducers/blueprint.reducer';
 import { resourcesReducer } from '../reducers/resources.reducer';
+import { catalogReducer } from '../reducers/catalog.reducer';
 
 export const appReducers: ActionReducerMap<IAppState, any> = {
     router: routerReducer,
     blueprint: blueprintReducer,
-    resources:resourcesReducer
+    resources:resourcesReducer,
+    catalog: catalogReducer
 };
\ No newline at end of file
diff --git a/cds-ui/client/src/app/common/core/store/reducers/catalog.reducer.ts b/cds-ui/client/src/app/common/core/store/reducers/catalog.reducer.ts
new file mode 100644 (file)
index 0000000..ae5ca4e
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { Action } from '@ngrx/store';
+import { initialCatalogState } from '../state/catalog.state';
+import * as CatalogActions from '../actions/catalog.action';
+import { ICatalogState } from '../models/catalogState.model';
+
+export function catalogReducer(state: ICatalogState = initialCatalogState, action: CatalogActions.Actions) : ICatalogState {
+    switch(action.type) {
+        case CatalogActions.LOAD_CATALOG_SUCCESS:
+            return {...state,
+                    catalog: action.payload
+                    }
+        case CatalogActions.SET_CATALOG_STATE:
+            return {...state,
+                    catalog: action.payload.catalog
+                    }
+        default:
+            return state;
+    }
+}
diff --git a/cds-ui/client/src/app/common/core/store/selectors/catalog.selectors.ts b/cds-ui/client/src/app/common/core/store/selectors/catalog.selectors.ts
new file mode 100644 (file)
index 0000000..172448f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { createSelector } from '@ngrx/store';
+
+import { IAppState } from '../state/app.state';
+import { ICatalogState } from '../models/catalogState.model';
+
+const selectCatalogFromAppState = (state: IAppState) => state.catalog;
+
+export const selectCatalog = createSelector(
+    selectCatalogFromAppState,
+  (state: ICatalogState) => state.catalog
+);
\ No newline at end of file
index 052eb2c..c08edce 100644 (file)
@@ -24,14 +24,17 @@ import { IBlueprintState } from '../models/blueprintState.model';
 import { initialBlueprintState } from './blueprint.state';
 import { IResourcesState } from '../models/resourcesState.model';
 import { initialResourcesState } from './resources.state';
+import { ICatalogState } from '../models/catalogState.model';
+import { initialCatalogState } from './catalog.state';
 
 export interface IAppState {
     router? : RouterReducerState,
     blueprint: IBlueprintState,
-    resources: IResourcesState
+    resources: IResourcesState,
+    catalog: ICatalogState
 }
-
 export const initialAppState: IAppState = {
     blueprint: initialBlueprintState,
-    resources: initialResourcesState
+    resources: initialResourcesState,
+    catalog: initialCatalogState
 }
\ No newline at end of file
diff --git a/cds-ui/client/src/app/common/core/store/state/catalog.state.ts b/cds-ui/client/src/app/common/core/store/state/catalog.state.ts
new file mode 100644 (file)
index 0000000..a780269
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { ICatalogState } from '../models/catalogState.model';
+import { ICatalog } from '../models/catalog.model';
+
+export const initialCatalogState : ICatalogState = {
+    catalog : {} as ICatalog,
+    isLoadSuccess: false,
+    isUpdateSuccess: false,
+    isSaveSuccess: false,
+}
\ No newline at end of file
index f73f0e8..beff353 100644 (file)
@@ -1,6 +1,8 @@
 <!-- ============LICENSE_START==========================================
 ===================================================================
 Copyright (C) 2018 IBM Intellectual Property. All rights reserved.
+
+Modifications Copyright (C) 2019 TechMahindra
 ===================================================================
 
 Unless otherwise specified, all software contained herein is licensed
@@ -50,6 +52,7 @@ limitations under the License.
                 </ul>
             </nav> -->
             <a mat-list-item [routerLink]="['/resource-definition']">Resource Definition</a>
+            <a mat-list-item [routerLink]="['/controller-catalog']">Controller Catalog</a>
         </mat-nav-list>
     </mat-sidenav>
 
index f1d1d14..ceaace3 100644 (file)
@@ -49,11 +49,11 @@ export class EditorService {
     }
     saveBlueprint(body: any | null, options?: any): Observable<any> {
 
-        return this.api.post(BlueprintURLs.save, body, options);
+        return this.api.post(BlueprintURLs.save, body, { responseType: 'text' });
     }
     publishBlueprint(body: any | null, options?: any): Observable<any> {
 
-        return this.api.post(BlueprintURLs.publish, body, options);
+        return this.api.post(BlueprintURLs.publish, body, { responseType: 'text' });
     }
 
     deployPost(body: any | null, options?: any): Observable<any> {
index a6612d5..3740ced 100644 (file)
@@ -38,7 +38,7 @@ limitations under the License.
                 <button mat-menu-item (click)="saveToBlueprintProcessor()">Deploy</button>
                 <!-- <button mat-menu-item (click)="processBlueprint()">Test</button> -->
             </mat-menu>
-            <button class="btn-active" (click)="publishToControllerBlueprint()">Publish</button>
+            <!-- <button class="btn-active" (click)="publishToControllerBlueprint()">Publish</button> -->
             <button class="btn-active" (click)="saveToControllerBlueprint()">Save</button>
             <button class="btn-active" (click)="getEnriched()">Enrich</button>
 
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog-routing.module.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog-routing.module.ts
new file mode 100644 (file)
index 0000000..e8bf86c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { NgModule } from '@angular/core';
+import { ControllerCatalogComponent } from './controller-catalog.component';
+import { Routes, RouterModule } from '@angular/router';
+
+const routes: Routes = [
+    {
+        path: '',
+        component: ControllerCatalogComponent
+    }
+];
+@NgModule({
+       imports: [RouterModule.forChild(routes)],
+       exports: [RouterModule]
+})
+export class ControllerCatalogRoutingModule { }
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.html b/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.html
new file mode 100644 (file)
index 0000000..06dfade
--- /dev/null
@@ -0,0 +1,41 @@
+<!--/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/-->
+
+<mat-card class="RDform">
+  <mat-card-content>
+    <mat-horizontal-stepper [linear]="isLinear" #stepper>
+      <mat-step [stepControl]="firstFormGroup">
+        <ng-template matStepLabel>Catalog Creation  Method</ng-template>
+       <app-select-template (option)="selectedOption($event)"></app-select-template><br><br>
+        <div>
+          <button mat-button matStepperNext class="matStepNextBtn">Proceed</button>
+        </div>
+      </mat-step>
+      <mat-step [stepControl]="secondFormGroup">
+        <ng-template matStepLabel>Catalog Create/Search</ng-template>
+        <app-create-catalog *ngIf="selectedValue == 1"></app-create-catalog><br>
+        <app-search-catalog *ngIf="selectedValue == 2"></app-search-catalog><br>
+        <div>
+          <button mat-button matStepperPrevious class="matStepNextBtn">Back</button>
+        </div>
+      </mat-step>
+    </mat-horizontal-stepper>
+  </mat-card-content>
+</mat-card>
\ No newline at end of file
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.scss b/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.scss
new file mode 100644 (file)
index 0000000..ea304fb
--- /dev/null
@@ -0,0 +1,32 @@
+/*\r
+* ============LICENSE_START=======================================================\r
+* ONAP : CDS\r
+* ================================================================================\r
+* Copyright (C) 2019 TechMahindra\r
+*=================================================================================\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+*     http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+* ============LICENSE_END=========================================================\r
+*/\r
+\r
+.mat-card {\r
+    padding: 0px !important;\r
+}\r
+\r
+.matStepNextBtn{\r
+    color:white;\r
+    background:#3f51b5;\r
+    margin-top: 10px;\r
+    position: absolute;\r
+    margin-bottom: 5px;\r
+    border-radius: 4px;\r
+}\r
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.spec.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.spec.ts
new file mode 100644 (file)
index 0000000..69b7027
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ControllerCatalogComponent } from './controller-catalog.component';
+
+describe('ControllerCatalogComponent', () => {
+  let component: ControllerCatalogComponent;
+  let fixture: ComponentFixture<ControllerCatalogComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ControllerCatalogComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ControllerCatalogComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.component.ts
new file mode 100644 (file)
index 0000000..ed08869
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'app-controller-catalog',
+  templateUrl: './controller-catalog.component.html',
+  styleUrls: ['./controller-catalog.component.scss']
+})
+export class ControllerCatalogComponent implements OnInit {
+
+  selectedValue: any;
+  constructor() { }
+
+  ngOnInit() {
+  }
+  
+  selectedOption(value){
+    this.selectedValue=value;
+    console.log(this.selectedValue);        
+ }
+
+}
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.module.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/controller-catalog.module.ts
new file mode 100644 (file)
index 0000000..9f5e140
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { ControllerCatalogRoutingModule } from './controller-catalog-routing.module';
+import { ControllerCatalogComponent } from './controller-catalog.component';
+import { SharedModule } from '../../../app/common/shared/shared.module';
+import { MatToolbarModule, MatButtonModule, MatSidenavModule,  MatListModule, MatGridListModule, MatCardModule, MatMenuModule, MatTableModule, MatPaginatorModule, MatSortModule, MatInputModule, MatSelectModule, MatRadioModule, MatFormFieldModule, MatStepperModule, MatAutocompleteModule} from '@angular/material';
+import { MatIconModule } from '@angular/material/icon';
+import { SelectTemplateComponent } from './select-template/select-template.component';
+import { TemplateOptionsComponent } from './select-template/template-options/template-options.component';
+import { SearchCatalogComponent } from './search-catalog/search-catalog.component';
+import { CreateCatalogComponent } from './create-catalog/create-catalog.component';
+import { CreateCatalogModule } from './create-catalog/create-catalog.module';
+import { SearchCatalogModule } from './search-catalog/search-catalog.module';
+import { FormsModule,ReactiveFormsModule } from '@angular/forms';
+import { NgJsonEditorModule } from 'ang-jsoneditor';
+
+@NgModule({
+  declarations: [ ControllerCatalogComponent, SelectTemplateComponent, TemplateOptionsComponent, SearchCatalogComponent, CreateCatalogComponent ],
+  imports: [
+    CommonModule,
+    ControllerCatalogRoutingModule,
+    CreateCatalogModule,
+    SearchCatalogModule,
+    SharedModule,
+    MatToolbarModule,
+    MatButtonModule,
+    MatSidenavModule,
+    MatIconModule,
+    MatListModule,
+    MatGridListModule,
+    MatCardModule,
+    MatMenuModule,
+    MatTableModule,
+    MatPaginatorModule,
+    MatSortModule,
+    MatInputModule,
+    MatSelectModule, 
+    MatRadioModule, 
+    MatFormFieldModule, 
+    MatStepperModule,
+    MatAutocompleteModule,
+    FormsModule,
+    ReactiveFormsModule,
+    NgJsonEditorModule
+  ]
+})
+export class ControllerCatalogModule { }
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog-routing.module.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog-routing.module.ts
new file mode 100644 (file)
index 0000000..68d13b2
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { CreateCatalogComponent } from './create-catalog.component';
+
+const routes: Routes = [
+  {
+      path: '',
+      component: CreateCatalogComponent
+  }
+];
+@NgModule({
+imports: [RouterModule.forChild(routes)],
+exports: [RouterModule]
+})
+export class CreateCatalogRoutingModule { }
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.html b/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.html
new file mode 100644 (file)
index 0000000..8c71edf
--- /dev/null
@@ -0,0 +1,56 @@
+<!--/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/-->
+<mat-card class="ver-card">
+  <mat-card-header><div class="mat-card-header">Create Catalog</div>
+  </mat-card-header>
+  <mat-card-content>
+<form [formGroup]="CatalogFormData" (ngSubmit)="CreateCatalog()">
+  <mat-form-field class="form-field">
+   <input matInput placeholder="Model Name" formControlName="Model_Name">
+ </mat-form-field>
+ <mat-form-field class="form-field" >
+  <input matInput placeholder="User Id" formControlName="User_id">
+</mat-form-field>
+ <mat-form-field class="form-field">
+   <input matInput placeholder="Tags" formControlName="_tags">
+ </mat-form-field>
+ <mat-form-field class="form-field">
+   <mat-select matInput placeholder="Definition Type" formControlName="_type">
+     <mat-option [value]="item" *ngFor="let item of definitionType">{{item.definitionType}}</mat-option>
+   </mat-select>
+ </mat-form-field>
+ <mat-form-field class="form-field" >
+   <mat-select matInput placeholder="Derived From" formControlName="Derived_From">
+    <mat-option [value]="item" *ngFor="let item of derivedFrom">{{item.derivedFrom}}</mat-option>
+   </mat-select>
+ </mat-form-field>
+ <mat-form-field class="form-field" >
+   <textarea matInput placeholder="Description" formControlName="_description"></textarea>
+ </mat-form-field>
+  <br>
+  <div >
+      <json-editor  placeholder="Definition" class="jsoneditor" [options]="options" [data]="resources" on-change="onChange($event)"></json-editor>
+  </div>
+ <div>
+   <button mat-button class="matStepNextBtn" type="submit">Save</button>
+ </div>  
+</form>
+</mat-card-content>
+</mat-card>
\ No newline at end of file
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.scss b/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.scss
new file mode 100644 (file)
index 0000000..cc8e292
--- /dev/null
@@ -0,0 +1,60 @@
+/*\r
+* ============LICENSE_START=======================================================\r
+* ONAP : CDS\r
+* ================================================================================\r
+* Copyright (C) 2019 TechMahindra\r
+*=================================================================================\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+*     http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+* ============LICENSE_END=========================================================\r
+*/\r
+.matStepNextBtn{\r
+    color:white;\r
+    background:#3f51b5;\r
+    margin-top: 10px;\r
+    position: absolute;\r
+    margin-bottom: 5px;\r
+    border-radius: 4px;\r
+}\r
+.meta-form {\r
+  width: 100%;\r
+}\r
+\r
+.form-field {\r
+  width: 40%;\r
+  padding:20px;\r
+}\r
+\r
+.form-table {\r
+  width: 100%;\r
+}\r
+.ver-card {\r
+    width: 100%;  \r
+    background-color: #f1f1f1;\r
+     padding: 0.01em 16px;\r
+      margin: 20px 0;\r
+      box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)!important;\r
+      height: 800px;\r
+  }\r
+  .mat-card-header{\r
+      height:35px;  \r
+      padding-top: 4px;\r
+  }\r
+  .mat-card-content{\r
+      width: auto;\r
+      background-color: #fff;\r
+      padding: 8px 8px;\r
+      // border-left: 4px solid #4CAF50;\r
+      word-wrap: break-word;\r
+      min-height:350px;\r
+      height: auto;\r
+  }
\ No newline at end of file
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.spec.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.spec.ts
new file mode 100644 (file)
index 0000000..8a96b6d
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { CreateCatalogComponent } from './create-catalog.component';
+
+describe('CreateCatalogComponent', () => {
+  let component: CreateCatalogComponent;
+  let fixture: ComponentFixture<CreateCatalogComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ CreateCatalogComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(CreateCatalogComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.component.ts
new file mode 100644 (file)
index 0000000..91c6f28
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { Component, OnInit, ViewChild, ɵConsole } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { JsonEditorComponent, JsonEditorOptions } from 'ang-jsoneditor';
+import { Observable } from 'rxjs';
+import { ICatalogState } from 'src/app/common/core/store/models/catalogState.model';
+import { ICatalog } from 'src/app/common/core/store/models/catalog.model';
+import { Store } from '@ngrx/store';
+import { IAppState } from 'src/app/common/core/store/state/app.state';
+import { SetCatalogState } from 'src/app/common/core/store/actions/catalog.action';
+import { CreateCatalogService } from './create-catalog.service';
+import { NotificationHandlerService } from 'src/app/common/core/services/notification-handler.service';
+
+@Component({
+  selector: 'app-create-catalog',
+  templateUrl: './create-catalog.component.html',
+  styleUrls: ['./create-catalog.component.scss']
+})
+export class CreateCatalogComponent implements OnInit {
+  
+  CatalogFormData: FormGroup;
+  @ViewChild(JsonEditorComponent) editor: JsonEditorComponent;
+  options = new JsonEditorOptions();
+  data:any;
+  derivedFrom: any[] = [{derivedFrom: 'tosca.nodes.Component'},{derivedFrom:'tosca.nodes.VNF'},{derivedFrom:'tosca.nodes.Artifact'},{derivedFrom:'tosca.nodes.ResourceSource'}, {derivedFrom:'tosca.nodes.Workflow'},{derivedFrom:'tosca.nodes.Root'}];
+  definitionType: any[] = [{definitionType: 'node_type'}];
+  ccState: Observable<ICatalogState>;
+  catalog: ICatalog;
+
+  constructor(private formBuilder: FormBuilder, private store: Store<IAppState>, private catalogCreateService: CreateCatalogService, private alertService: NotificationHandlerService) { 
+    this.ccState = this.store.select('catalog');
+    this.CatalogFormData = this.formBuilder.group({
+      Model_Name: ['', Validators.required],
+      User_id: ['', Validators.required],
+      _tags: ['', Validators.required],
+      _type: ['', Validators.required],
+      Derived_From: ['', Validators.required],
+      _description : ['', Validators.required]
+    });   
+  }
+  ngOnInit() {
+    this.options.mode = 'text';
+    this.options.modes = [ 'text', 'tree', 'view'];
+    this.options.statusBar = false; 
+
+    this.ccState.subscribe(
+      catalogdata => {
+        var catalogState: ICatalogState = { catalog: catalogdata.catalog, isLoadSuccess: catalogdata.isLoadSuccess, isSaveSuccess: catalogdata.isSaveSuccess, isUpdateSuccess: catalogdata.isUpdateSuccess };
+        this.catalog = catalogState.catalog;
+        console.log( this.catalog );
+      });
+
+//    this.catalogCreateService.getDefinition()
+//    .subscribe(data=>{
+//        console.log(data);
+//        data.forEach(element => {
+//          this.definitionType.push(element)
+//        });          
+//    }, error=>{
+//      window.alert('error' + error);
+//    })
+//
+//    this.catalogCreateService.getDerivedFrom()
+//    .subscribe(data=>{
+//        console.log(data);
+//        data.forEach(element => {
+//          this.derivedFrom.push(element)
+//        });          
+//    }, error=>{
+//      window.alert('error' + error);
+//    })
+  }
+  CreateCatalog(){
+    this.catalog = Object.assign({}, this.CatalogFormData.value);
+    this.catalog.definition=this.data;
+    let catalogState = {
+      catalog: this.catalog
+    }
+    this.store.dispatch(new SetCatalogState(catalogState));
+    
+      this.catalogCreateService.saveCatalog(this.catalog)
+      .subscribe(response=>{
+        this.alertService.success("save success")
+      },
+      error=>{
+        this.alertService.error('Error saving resources');
+      })
+  }
+
+  onChange($event) {
+    this.data=JSON.parse($event.srcElement.value); 
+    console.log(this.data);
+  };
+}
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.module.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.module.ts
new file mode 100644 (file)
index 0000000..e0ae0dc
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { CreateCatalogRoutingModule } from './create-catalog-routing.module';
+import { MatToolbarModule, MatButtonModule, MatSidenavModule,  MatListModule, MatGridListModule, MatCardModule, MatMenuModule, MatTableModule, MatPaginatorModule, MatSortModule, MatInputModule, MatSelectModule, MatRadioModule, MatFormFieldModule, MatStepperModule} from '@angular/material';
+import { MatIconModule } from '@angular/material/icon';
+import { SharedModule } from 'src/app/common/shared/shared.module';
+import { NgJsonEditorModule } from 'ang-jsoneditor';
+import { CreateCatalogService } from './create-catalog.service';
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule,
+    CreateCatalogRoutingModule,
+    SharedModule,
+    MatToolbarModule,
+    MatButtonModule,
+    MatSidenavModule,
+    MatIconModule,
+    MatListModule,
+    MatGridListModule,
+    MatCardModule,
+    MatMenuModule,
+    MatTableModule,
+    MatPaginatorModule,
+    MatSortModule,
+    MatInputModule,
+    MatSelectModule, 
+    MatRadioModule, 
+    MatFormFieldModule, 
+    MatStepperModule,
+    NgJsonEditorModule
+  ],
+  providers: [ CreateCatalogService ]
+})
+
+export class CreateCatalogModule { }
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.service.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/create-catalog/create-catalog.service.ts
new file mode 100644 (file)
index 0000000..fd582cc
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { ApiService } from 'src/app/common/core/services/api.service';
+import { ControllerCatalogURLs } from 'src/app/common/constants/app-constants';
+
+@Injectable()
+export class CreateCatalogService {
+  
+
+  constructor(private _http: HttpClient, private api: ApiService) {
+  }
+
+  saveCatalog(catalog) {
+     return this.api.post(ControllerCatalogURLs.saveControllerCatalog, catalog);
+  }
+
+  getDefinition() {
+    return this.api.get(ControllerCatalogURLs.getDefinition);
+  }
+  getDerivedFrom() {
+    return this.api.get(ControllerCatalogURLs.getDerivedFrom);
+  }
+}
+
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog-routing.module.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog-routing.module.ts
new file mode 100644 (file)
index 0000000..1785ef8
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { SearchCatalogComponent } from './search-catalog.component';
+
+const routes: Routes = [
+  {
+      path: '',
+      component: SearchCatalogComponent
+  }
+];
+@NgModule({
+imports: [RouterModule.forChild(routes)],
+exports: [RouterModule]
+})
+export class SearchCatalogRoutingModule { }
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.html b/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.html
new file mode 100644 (file)
index 0000000..4781382
--- /dev/null
@@ -0,0 +1,41 @@
+<!-- /*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/--> 
+<form class="search-form" [formGroup]="myControl">
+  <mat-form-field class="search-full-width">
+      <input matInput type="text" [(ngModel)]="searchText" placeholder="Search Resources" formControlName="search_input">
+      <button matSuffix mat-icon-button (click)="fetchCatalogByName()">
+    <mat-icon>search</mat-icon>
+  </button>
+  </mat-form-field>
+</form>
+<div class="searchcontainer">
+  <div class="flexBox">
+      <div *ngFor="let option of options" style="position: relative !important;width:20% !important">
+          <mat-card class="example-card">
+              <mat-card-content class="card-content">
+                  {{option.modelName}}
+              </mat-card-content>
+              <mat-card-actions class="flexBox">
+                  <button matStepperNext mat-menu-item (click)="editInfo(option.blueprintModel.artifactName,option.blueprintModel.artifactVersion,3)">Info</button>
+              </mat-card-actions>
+          </mat-card>
+      </div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.scss b/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.scss
new file mode 100644 (file)
index 0000000..a24aebe
--- /dev/null
@@ -0,0 +1,78 @@
+/*\r
+* ============LICENSE_START=======================================================\r
+* ONAP : CDS\r
+* ================================================================================\r
+* Copyright (C) 2019 TechMahindra\r
+*=================================================================================\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+*     http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+* ============LICENSE_END=========================================================\r
+*/\r
+\r
+.example-card {\r
+  // min-width: 300px;\r
+  max-height: 200px;\r
+  background-color: #ebebeb;\r
+  position: relative;\r
+  width: 250px;\r
+  margin: 5px;\r
+}\r
+\r
+.mat-grid-tile {\r
+  position: absolute;\r
+  width: 240px !important;\r
+}\r
+\r
+.mat-grid-list div {\r
+  position: relative;\r
+}\r
+\r
+button.mat-menu-item {\r
+  width: auto;\r
+  float: left;\r
+  border-radius: 4px;\r
+  background-color: #3f51b5;\r
+  margin: 5px;\r
+  cursor: pointer;\r
+  color: white;\r
+}\r
+\r
+.flexBox {\r
+  display: flex;\r
+  flex-flow: row;\r
+  flex-wrap: wrap;\r
+}\r
+\r
+.card-deck-container {\r
+  position: relative;\r
+  border-radius: 1px;\r
+  padding: 2px;\r
+  margin: 2px;\r
+  // background-color: #f5f5f5;\r
+}\r
+\r
+.searchcontainer {\r
+  // min-height: 300px;\r
+  overflow-x: hidden;\r
+  overflow-y: scroll;\r
+}\r
+\r
+.card-content {\r
+  text-align: center;\r
+  margin: 5px;\r
+}\r
+\r
+.mat-card-actions {\r
+  margin-left: 0px !important;\r
+  margin-right: 0px !important;\r
+  padding: 0px 0 !important;\r
+}
\ No newline at end of file
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.spec.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.spec.ts
new file mode 100644 (file)
index 0000000..661246e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SearchCatalogComponent } from './search-catalog.component';
+
+describe('SearchCatalogComponent', () => {
+  let component: SearchCatalogComponent;
+  let fixture: ComponentFixture<SearchCatalogComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ SearchCatalogComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(SearchCatalogComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.component.ts
new file mode 100644 (file)
index 0000000..b30fc3a
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { SearchCatalogService } from './search-catalog.service';
+import { MatAutocompleteTrigger } from '@angular/material';
+
+@Component({
+  selector: 'app-search-catalog',
+  templateUrl: './search-catalog.component.html',
+  styleUrls: ['./search-catalog.component.scss']
+})
+export class SearchCatalogComponent implements OnInit {
+  myControl: FormGroup;
+  searchText: string = '';
+  options: any[]   = [];
+  @ViewChild('catalogSelect', { read: MatAutocompleteTrigger }) catalogSelect: MatAutocompleteTrigger;
+  constructor(private _formBuilder: FormBuilder, private searchCatalogService: SearchCatalogService)  { }
+  
+ ngOnInit() {
+    this.myControl = this._formBuilder.group({
+      search_input: ['', Validators.required]
+    });
+  }
+  fetchCatalogByName() {
+    this.searchCatalogService.searchByTags(this.searchText)
+    .subscribe(data=>{
+        console.log(data);
+        data.forEach(element => {
+          this.options.push(element)
+        });          
+      this.catalogSelect.openPanel();
+    }, error=>{
+      window.alert('Catalog not matching the search tag' + error);
+    })
+   }
+
+   editInfo(artifactName: string, artifactVersion: string, option: string) {
+  }
+}
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.module.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.module.ts
new file mode 100644 (file)
index 0000000..2aa1a50
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { SearchCatalogRoutingModule } from './search-catalog-routing.module';
+import { MatToolbarModule, MatButtonModule, MatSidenavModule,  MatListModule, MatGridListModule, MatCardModule, MatMenuModule, MatTableModule, MatPaginatorModule, MatSortModule, MatInputModule, MatSelectModule, MatRadioModule, MatFormFieldModule, MatStepperModule, MatAutocompleteModule} from '@angular/material';
+import { MatIconModule } from '@angular/material/icon';
+import { SharedModule } from 'src/app/common/shared/shared.module';
+import { FormsModule,ReactiveFormsModule } from '@angular/forms';
+import { SearchCatalogService } from './search-catalog.service';
+
+@NgModule({
+  declarations: [],
+  imports: [
+    CommonModule,
+    SearchCatalogRoutingModule,
+    FormsModule,
+    ReactiveFormsModule,
+    SharedModule,
+    MatToolbarModule,
+    MatButtonModule,
+    MatSidenavModule,
+    MatIconModule,
+    MatListModule,
+    MatGridListModule,
+    MatCardModule,
+    MatMenuModule,
+    MatTableModule,
+    MatPaginatorModule,
+    MatSortModule,
+    MatInputModule,
+    MatSelectModule, 
+    MatRadioModule, 
+    MatFormFieldModule, 
+    MatStepperModule,
+    MatAutocompleteModule
+  ],
+  providers: [ SearchCatalogService ]
+})
+export class SearchCatalogModule { }
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.service.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/search-catalog/search-catalog.service.ts
new file mode 100644 (file)
index 0000000..4789605
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable, observable } from 'rxjs';
+import { ControllerCatalogURLs } from 'src/app/common/constants/app-constants';
+import { ApiService } from 'src/app/common/core/services/api.service';
+
+@Injectable()
+export class SearchCatalogService {
+
+  constructor(private _http: HttpClient, private api: ApiService) {
+  }
+
+  searchByTags(tag) {
+    return this.api.get(ControllerCatalogURLs.searchControllerCatalogByTags + '/' + tag);
+  }
+}
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template-routing.module.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template-routing.module.ts
new file mode 100644 (file)
index 0000000..0da5b16
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+import { SelectTemplateComponent } from './select-template.component';
+import { TemplateOptionsComponent } from './template-options/template-options.component';
+
+const routes: Routes = [
+    {
+        path: '',
+        component: SelectTemplateComponent
+    }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+
+export class SelectTemplateRoutingModule { }
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.html b/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.html
new file mode 100644 (file)
index 0000000..8a51b4e
--- /dev/null
@@ -0,0 +1,33 @@
+<!--/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/-->
+
+<mat-card class="ver-card">
+<mat-card-header>
+</mat-card-header>
+<mat-card-content>
+<mat-vertical-stepper linear>
+  <mat-step [stepControl]="step1FormGroup">
+    <ng-template matStepLabel>Choose Option</ng-template>
+    <br>
+    <app-template-options (option)="selectedOption($event)"></app-template-options>
+  </mat-step>
+ </mat-vertical-stepper>
+ </mat-card-content>
+</mat-card>
\ No newline at end of file
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.scss b/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.scss
new file mode 100644 (file)
index 0000000..62b6f5d
--- /dev/null
@@ -0,0 +1,52 @@
+/*\r
+* ============LICENSE_START=======================================================\r
+* ONAP : CDS\r
+* ================================================================================\r
+* Copyright (C) 2019 TechMahindra\r
+*=================================================================================\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+*     http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+* ============LICENSE_END=========================================================\r
+*/\r
+.matStepNextBtn{\r
+    color:white;\r
+    background:#3f51b5; \r
+    margin-top: 10px; \r
+    position: absolute;\r
+    border-radius: 4px;\r
+}\r
+.ver-card {\r
+  width: 100%;  \r
+  background-color: #f1f1f1;\r
+   padding: 0.01em 16px;\r
+    margin: 20px 0;\r
+    box-shadow: 0 2px 2px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)!important;\r
+    height: auto;\r
+}\r
+.mat-card-header{\r
+    height:35px;\r
+}\r
+.mat-card-content{\r
+    width: auto;\r
+    background-color: #fff;\r
+    padding: 8px 8px;\r
+    // border-left: 4px solid #4CAF50;\r
+    word-wrap: break-word;\r
+    min-height:350px;\r
+    height: auto;\r
+}\r
+.success{\r
+color:green;\r
+}\r
+.comp-disabled {\r
+    display: none;\r
+}
\ No newline at end of file
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.spec.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.spec.ts
new file mode 100644 (file)
index 0000000..c0c7b50
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { SelectTemplateComponent } from './select-template.component';
+
+describe('SelectTemplateComponent', () => {
+  let component: SelectTemplateComponent;
+  let fixture: ComponentFixture<SelectTemplateComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ SelectTemplateComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(SelectTemplateComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.component.ts
new file mode 100644 (file)
index 0000000..ed44e0c
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { Component, OnInit, Output, EventEmitter } from '@angular/core';
+
+@Component({
+  selector: 'app-select-template',
+  templateUrl: './select-template.component.html',
+  styleUrls: ['./select-template.component.scss']
+})
+export class SelectTemplateComponent implements OnInit {
+
+  selectedValue: any;
+  @Output() option = new EventEmitter();
+  
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+  selectedOption(value){
+    this.selectedValue=value;
+    this.option.emit(value);      
+ }
+}
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.module.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/select-template.module.ts
new file mode 100644 (file)
index 0000000..8853b5b
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+* ============LICENSE_START=======================================================
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { TemplateOptionsComponent } from './template-options/template-options.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 { MatAutocompleteModule,MatToolbarModule,MatIconModule, MatButtonModule, MatSidenavModule,  MatCheckboxModule, MatListModule, MatGridListModule, MatCardModule, MatMenuModule, MatTableModule, MatPaginatorModule, MatSortModule, MatInputModule, MatSelectModule, MatRadioModule, MatFormFieldModule, MatStepperModule} from '@angular/material';
+import { SharedModule } from '../../../../app/common/shared/shared.module';
+import { FormsModule,ReactiveFormsModule } from '@angular/forms';
+
+@NgModule({
+  declarations: [
+    TemplateOptionsComponent,
+    SelectTemplateComponent
+  ],
+  exports: [
+    TemplateOptionsComponent,
+    SelectTemplateComponent
+  ],
+  imports: [
+    CommonModule,
+    SelectTemplateRoutingModule,
+    ReactiveFormsModule,
+    AppMaterialModule,
+    FormsModule,
+    ReactiveFormsModule,
+    MatToolbarModule,
+    MatIconModule, 
+    MatButtonModule, 
+    MatSidenavModule,  
+    MatCheckboxModule, 
+    MatListModule, 
+    MatGridListModule, 
+    MatCardModule, 
+    MatMenuModule, 
+    MatTableModule, 
+    MatPaginatorModule, 
+    MatSortModule, 
+    MatInputModule, 
+    MatSelectModule, 
+    MatRadioModule, 
+    MatFormFieldModule, 
+    MatStepperModule,
+    MatAutocompleteModule
+  ],
+  providers: [
+  ]
+})
+export class SelectTemplateModule { }
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.html b/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.html
new file mode 100644 (file)
index 0000000..185a112
--- /dev/null
@@ -0,0 +1,24 @@
+<!--/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/-->
+
+<mat-radio-group>
+  <mat-radio-button value="1" (click)="selected(1)">Create New Catalog</mat-radio-button><br><br>
+  <mat-radio-button value="2" (click)="selected(2)">Search existing catalog</mat-radio-button><br><br>
+</mat-radio-group>
\ No newline at end of file
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.scss b/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.scss
new file mode 100644 (file)
index 0000000..d0f182d
--- /dev/null
@@ -0,0 +1,19 @@
+/*\r
+* ============LICENSE_START=======================================================\r
+* ONAP : CDS\r
+* ================================================================================\r
+* Copyright (C) 2019 TechMahindra\r
+*=================================================================================\r
+* Licensed under the Apache License, Version 2.0 (the "License");\r
+* you may not use this file except in compliance with the License.\r
+* You may obtain a copy of the License at\r
+*\r
+*     http://www.apache.org/licenses/LICENSE-2.0\r
+*\r
+* Unless required by applicable law or agreed to in writing, software\r
+* distributed under the License is distributed on an "AS IS" BASIS,\r
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+* See the License for the specific language governing permissions and\r
+* limitations under the License.\r
+* ============LICENSE_END=========================================================\r
+*/
\ No newline at end of file
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.spec.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.spec.ts
new file mode 100644 (file)
index 0000000..03e7998
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TemplateOptionsComponent } from './template-options.component';
+
+describe('TemplateOptionsComponent', () => {
+  let component: TemplateOptionsComponent;
+  let fixture: ComponentFixture<TemplateOptionsComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ TemplateOptionsComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(TemplateOptionsComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.ts b/cds-ui/client/src/app/feature-modules/controller-catalog/select-template/template-options/template-options.component.ts
new file mode 100644 (file)
index 0000000..dc9513b
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+* ============LICENSE_START=======================================================
+* ONAP : CDS
+* ================================================================================
+* Copyright (C) 2019 TechMahindra
+*=================================================================================
+* 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.
+* ============LICENSE_END=========================================================
+*/
+
+import { Component, OnInit, Output, EventEmitter } from '@angular/core';
+
+@Component({
+  selector: 'app-template-options',
+  templateUrl: './template-options.component.html',
+  styleUrls: ['./template-options.component.scss']
+})
+export class TemplateOptionsComponent implements OnInit {
+
+  @Output() option = new EventEmitter();
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+  selected(value){
+           this.option.emit(value);
+  }
+}
index 0c02381..a2cebe5 100644 (file)
@@ -21,16 +21,16 @@ export const appConfig = Object.freeze({
     })
 });
 
-export const controllerApiConfig = Object.freeze({
-    http: Object.freeze({
-        url: process.env.API_BLUEPRINT_CONTROLLER_HTTP_BASE_URL || "http://localhost:8080/api/v1",
-        authToken: process.env.API_BLUEPRINT_CONTROLLER_HTTP_AUTH_TOKEN || "Basic Y2NzZGthcHBzOmNjc2RrYXBwcw=="
-    })
-});
+// export const controllerApiConfig = Object.freeze({
+//     http: Object.freeze({
+//         url: process.env.API_BLUEPRINT_PROCESSOR_HTTP_BASE_URL || "http://localhost:8081/api/v1",
+//         authToken: process.env.API_BLUEPRINT_PROCESSOR_HTTP_AUTH_TOKEN || "Basic Y2NzZGthcHBzOmNjc2RrYXBwcw=="
+//     })
+// });
 
 export const processorApiConfig = Object.freeze({
     http: Object.freeze({
-        url: process.env.API_BLUEPRINT_PROCESSOR_HTTP_BASE_URL || "http://localhost:8080/api/v1",
+        url: process.env.API_BLUEPRINT_PROCESSOR_HTTP_BASE_URL || "http://localhost:8081/api/v1",
         authToken: process.env.API_BLUEPRINT_PROCESSOR_HTTP_AUTH_TOKEN || "Basic Y2NzZGthcHBzOmNjc2RrYXBwcw=="
     }),
     grpc: Object.freeze({
index c73f7a6..7895898 100644 (file)
@@ -48,7 +48,7 @@ import { BlueprintService } from '../services';
 import * as fs from 'fs';
 import * as multiparty from 'multiparty';
 import * as request_lib from 'request';
-import { controllerApiConfig, processorApiConfig, appConfig } from '../config/app-config';
+import { processorApiConfig, appConfig } from '../config/app-config';
 import { bluePrintManagementServiceGrpcClient } from '../clients/blueprint-management-service-grpc-client';
 
 export class BlueprintRestController {
@@ -220,7 +220,7 @@ export class BlueprintRestController {
   }
 
   async uploadFileToBlueprintController(file: multiparty.File, uri: string, response: Response): Promise<Response> {
-    return this.uploadFileToBlueprintService(file, controllerApiConfig.http.url + uri, controllerApiConfig.http.authToken, response);
+    return this.uploadFileToBlueprintService(file, processorApiConfig.http.url + uri, processorApiConfig.http.authToken, response);
   }
 
   async uploadFileToBlueprintProcessor(file: multiparty.File, uri: string, response: Response): Promise<Response> {
@@ -267,7 +267,7 @@ export class BlueprintRestController {
   }
 
   async downloadFileFromBlueprintController(uri: string, response: Response): Promise<Response> {
-    return this.downloadFileFromBlueprintService(controllerApiConfig.http.url + uri, controllerApiConfig.http.authToken, response);
+    return this.downloadFileFromBlueprintService(processorApiConfig.http.url + uri, processorApiConfig.http.authToken, response);
   }
 
   async downloadFileFromBlueprintService(url: string, authToken: string, response: Response): Promise<Response> {
index 1188d9b..85e0aa3 100644 (file)
@@ -1,19 +1,19 @@
-import {controllerApiConfig} from '../config/app-config';
+import {processorApiConfig} from '../config/app-config';
 
 export default {
     "name": "blueprint",
     "connector": "rest",
-    "baseURL": controllerApiConfig.http.url,
+    "baseURL": processorApiConfig.http.url,
     "crud": false,
     "debug": true,
     "operations": [{
         "template": {
             "method": "GET",
-            "url": controllerApiConfig.http.url + "/blueprint-model/",
+            "url": processorApiConfig.http.url + "/blueprint-model/",
             "headers": {
                 "accepts": "application/json",
                 "content-type": "application/json",
-                "authorization": controllerApiConfig.http.authToken
+                "authorization": processorApiConfig.http.authToken
             },
             "responsePath": "$.*"
         },
@@ -25,11 +25,11 @@ export default {
     {
         "template": {
             "method": "GET",
-            "url": controllerApiConfig.http.url + "/blueprint-model/search/{tags}",
+            "url": processorApiConfig.http.url + "/blueprint-model/search/{tags}",
             "headers": {
                 "accepts": "application/json",
                 "content-type": "application/json",
-                "authorization": controllerApiConfig.http.authToken
+                "authorization": processorApiConfig.http.authToken
             },
             "responsePath": "$.*"
         },
index 9f9d754..f839bb2 100644 (file)
@@ -1,19 +1,19 @@
-import {controllerApiConfig} from '../config/app-config';
+import {processorApiConfig} from '../config/app-config';
 
 export default {
     "name": "resourceDictionary",
     "connector": "rest",
-    "baseURL": controllerApiConfig.http.url + "/dictionary",
+    "baseURL": processorApiConfig.http.url + "/dictionary",
     "crud": false,
     "debug": true,
     "operations": [{
             "template": {
                 "method": "GET",
-                "url": controllerApiConfig.http.url + "/dictionary/{name}",
+                "url": processorApiConfig.http.url + "/dictionary/{name}",
                 "headers": {
                     "accepts": "application/json",
                     "content-type": "application/json",
-                    "authorization": controllerApiConfig.http.authToken
+                    "authorization": processorApiConfig.http.authToken
                 },
                 "responsePath": "$.*"
             },
@@ -25,11 +25,11 @@ export default {
         {
             "template": {
                 "method": "GET",
-                "url": controllerApiConfig.http.url + "/dictionary/source-mapping",
+                "url": processorApiConfig.http.url + "/dictionary/source-mapping",
                 "headers": {
                     "accepts": "application/json",
                     "content-type": "application/json",
-                    "authorization": controllerApiConfig.http.authToken
+                    "authorization": processorApiConfig.http.authToken
                 },
                 "responsePath": "$.*"
             },
@@ -41,11 +41,11 @@ export default {
         {
             "template": {
                 "method": "GET",
-                "url": controllerApiConfig.http.url + "/dictionary/search/{tags}",
+                "url": processorApiConfig.http.url + "/dictionary/search/{tags}",
                 "headers": {
                     "accepts": "application/json",
                     "content-type": "application/json",
-                    "authorization": controllerApiConfig.http.authToken
+                    "authorization": processorApiConfig.http.authToken
                 },
                 "responsePath": "$.*"
             },
@@ -57,11 +57,11 @@ export default {
         {
             "template": {
                 "method": "POST",
-                "url": controllerApiConfig.http.url + "/dictionary",
+                "url": processorApiConfig.http.url + "/dictionary",
                 "headers": {
                     "accepts": "application/json",
                     "content-type": "application/json",
-                    "authorization": controllerApiConfig.http.authToken
+                    "authorization": processorApiConfig.http.authToken
                 },
                 "body": "{resourceDictionary}",
                 "responsePath": "$.*"
@@ -74,11 +74,11 @@ export default {
         {
             "template": {
                 "method": "POST",
-                "url": controllerApiConfig.http.url + "/dictionary/by-names",
+                "url": processorApiConfig.http.url + "/dictionary/by-names",
                 "headers": {
                     "accepts": "application/json",
                     "content-type": "application/json",
-                    "authorization": controllerApiConfig.http.authToken
+                    "authorization": processorApiConfig.http.authToken
                 },
                 "body": "{resourceDictionaryList}",
                 "responsePath": "$.*"
@@ -91,11 +91,11 @@ export default {
         {
             "template": {
                 "method": "GET",
-                "url": controllerApiConfig.http.url + "/model-type/{source}",
+                "url": processorApiConfig.http.url + "/model-type/{source}",
                 "headers": {
                     "accepts": "application/json",
                     "content-type": "application/json",
-                    "authorization": controllerApiConfig.http.authToken
+                    "authorization": processorApiConfig.http.authToken
                 },
                 "responsePath": "$.*"
             },
@@ -107,11 +107,11 @@ export default {
         {
             "template": {
                 "method": "GET",
-                "url": controllerApiConfig.http.url + "/model-type/by-definition/data_type",
+                "url": processorApiConfig.http.url + "/model-type/by-definition/data_type",
                 "headers": {
                     "accepts": "application/json",
                     "content-type": "application/json",
-                    "authorization": controllerApiConfig.http.authToken
+                    "authorization": processorApiConfig.http.authToken
                 },
                 "responsePath": "$.*"
             },
index 346bc4b..b3d719f 100644 (file)
           "type" : "string",
           "status" : "",
           "constraints" : [ { } ],
-          "default" : "",
           "entry_schema" : {
             "type" : ""
           }
             "type" : ""
           }
         },
+        "flavor_name" : {
+          "description" : "",
+          "required" : false,
+          "type" : "string",
+          "status" : "",
+          "constraints" : [ { } ],
+          "entry_schema" : {
+            "type" : ""
+          }
+        },
         "dcae_collector_ip" : {
           "description" : "",
           "required" : false,
           "type" : "string",
           "status" : "",
           "constraints" : [ { } ],
-          "default" : "",
           "entry_schema" : {
             "type" : ""
           }
             "type" : ""
           }
         },
-        "vf_module_name" : {
+        "vf-module-name" : {
           "description" : "",
           "required" : false,
           "type" : "string",
           "status" : "",
           "constraints" : [ { } ],
-          "default" : "${vf_module_name}",
+          "default" : "${vf-module-name}",
           "entry_schema" : {
             "type" : ""
           }
           "type" : "string",
           "status" : "",
           "constraints" : [ { } ],
-          "default" : "m1.medium",
           "entry_schema" : {
             "type" : ""
           }
           "type" : "string",
           "status" : "",
           "constraints" : [ { } ],
-          "default" : "m1.medium",
           "entry_schema" : {
             "type" : ""
           }
           "type" : "string",
           "status" : "",
           "constraints" : [ { } ],
-          "default" : "",
           "entry_schema" : {
             "type" : ""
           }
           "type" : "string",
           "status" : "",
           "constraints" : [ { } ],
-          "default" : "",
           "entry_schema" : {
             "type" : ""
           }
index 7a44860..e3f915e 100644 (file)
@@ -3,6 +3,12 @@
     "component-netconf-executor" : {
       "description" : "This is Netconf Transaction Configuration Component API",
       "version" : "1.0.0",
+      "attributes" : {
+        "response-data" : {
+          "required" : false,
+          "type" : "json"
+        }
+      },
       "capabilities" : {
         "component-node" : {
           "type" : "tosca.capabilities.Node"
                   "required" : false,
                   "type" : "string"
                 },
+                "occurrence" : {
+                  "description" : "Number of time to perform the resolution.",
+                  "required" : false,
+                  "type" : "integer",
+                  "default" : 1
+                },
                 "store-result" : {
                   "description" : "Whether or not to store the output.",
                   "required" : false,
       },
       "derived_from" : "tosca.nodes.ResourceSource"
     },
-    "source-default" : {
-      "description" : "This is Default Resource Source Node Type",
-      "version" : "1.0.0",
-      "properties" : { },
-      "derived_from" : "tosca.nodes.ResourceSource"
-    },
-    "source-input" : {
-      "description" : "This is Input Resource Source Node Type",
-      "version" : "1.0.0",
-      "properties" : { },
-      "derived_from" : "tosca.nodes.ResourceSource"
-    },
     "source-db" : {
       "description" : "This is Database Resource Source Node Type",
       "version" : "1.0.0",
       },
       "derived_from" : "tosca.nodes.ResourceSource"
     },
+    "source-default" : {
+      "description" : "This is Default Resource Source Node Type",
+      "version" : "1.0.0",
+      "properties" : { },
+      "derived_from" : "tosca.nodes.ResourceSource"
+    },
+    "source-input" : {
+      "description" : "This is Input Resource Source Node Type",
+      "version" : "1.0.0",
+      "properties" : { },
+      "derived_from" : "tosca.nodes.ResourceSource"
+    },
     "source-rest" : {
       "description" : "This is Rest Resource Source Node Type",
       "version" : "1.0.0",
       "derived_from" : "tosca.nodes.Vnf"
     }
   }
-}
+}
\ No newline at end of file
index 15a8a37..f7da409 100644 (file)
@@ -75,7 +75,7 @@
           "key-dependencies" : [ "vf-module-id", "service-instance-id", "vnf-id" ]
         }
       },
-      "aai-data" : {
+      "primary-aai-data" : {
         "type" : "source-rest",
         "properties" : {
           "verb" : "PATCH",
       }
     }
   },
+  "flavor_name" : {
+    "tags" : "flavor_name",
+    "name" : "flavor_name",
+    "property" : {
+      "description" : "flavor_name",
+      "type" : "string"
+    },
+    "updated-by" : "MALAKOV, YURIY <yuriy.malakov@att.com>",
+    "sources" : {
+      "input" : {
+        "type" : "source-input"
+      },
+      "default" : {
+        "type" : "source-default",
+        "properties" : { }
+      },
+      "sdnc" : {
+        "type" : "source-rest",
+        "properties" : {
+          "verb" : "GET",
+          "type" : "JSON",
+          "url-path" : "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/flavor_name",
+          "path" : "/param/0/value",
+          "input-key-mapping" : {
+            "service-instance-id" : "service-instance-id",
+            "vnf-id" : "vnf-id"
+          },
+          "output-key-mapping" : {
+            "flavor_name" : "value"
+          },
+          "key-dependencies" : [ "service-instance-id", "vnf-id" ]
+        }
+      }
+    }
+  },
   "gre_ipaddr" : {
     "tags" : "gre_ipaddr",
     "name" : "gre_ipaddr",
       "any-db" : {
         "type" : "source-db",
         "properties" : {
-          "query" : "SELECT artifact_name FROM BLUEPRINT_MODEL where artifact_version=\"1.0.0\"",
+          "query" : "SELECT artifact_name FROM BLUEPRINT_RUNTIME where artifact_version=\"1.0.0\"",
           "input-key-mapping" : { },
           "output-key-mapping" : {
             "service-instance-id" : "artifact_name"
       "processor-db" : {
         "type" : "source-db",
         "properties" : {
-          "query" : "SELECT artifact_name FROM BLUEPRINT_MODEL where artifact_version=\"1.0.0\"",
+          "query" : "SELECT artifact_name FROM BLUEPRINT_RUNTIME where artifact_version=\"1.0.0\"",
           "input-key-mapping" : { },
           "output-key-mapping" : {
             "service-instance-id" : "artifact_name"
       }
     }
   },
-  "vdns_flavor_name" : {
-    "tags" : "vdns_flavor_name",
-    "name" : "vdns_flavor_name",
-    "property" : {
-      "description" : "vdns_flavor_name",
-      "type" : "string"
-    },
-    "updated-by" : "MALAKOV, YURIY <yuriy.malakov@att.com>",
-    "sources" : {
-      "input" : {
-        "type" : "source-input"
-      },
-      "default" : {
-        "type" : "source-default",
-        "properties" : { }
-      },
-      "sdnc" : {
-        "type" : "source-rest",
-        "properties" : {
-          "verb" : "GET",
-          "type" : "JSON",
-          "url-path" : "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/vdns_flavor_name",
-          "path" : "/param/0/value",
-          "input-key-mapping" : {
-            "service-instance-id" : "service-instance-id",
-            "vnf-id" : "vnf-id"
-          },
-          "output-key-mapping" : {
-            "vdns_flavor_name" : "value"
-          },
-          "key-dependencies" : [ "service-instance-id", "vnf-id" ]
-        }
-      }
-    }
-  },
   "vdns_int_private_ip_0" : {
     "tags" : "vdns_int_private_ip_0",
     "name" : "vdns_int_private_ip_0",
           "key-dependencies" : [ "service-instance-id", "vnf-id" ]
         }
       },
-      "aai-data" : {
+      "primary-aai-data" : {
         "type" : "source-rest",
         "properties" : {
           "verb" : "GET",
       }
     }
   },
-  "vf_module_name" : {
-    "tags" : "vf_module_name",
-    "name" : "vf_module_name",
+  "vf-module-name" : {
+    "tags" : "vf-module-name",
+    "name" : "vf-module-name",
     "property" : {
-      "description" : "vf_module_name",
+      "description" : "vf-module-name",
       "type" : "string"
     },
     "updated-by" : "Singal, Kapil <ks220y@att.com>",
       }
     }
   },
-  "vlb_flavor_name" : {
-    "tags" : "vlb_flavor_name",
-    "name" : "vlb_flavor_name",
-    "property" : {
-      "description" : "vlb_flavor_name",
-      "type" : "string"
-    },
-    "updated-by" : "MALAKOV, YURIY <yuriy.malakov@att.com>",
-    "sources" : {
-      "input" : {
-        "type" : "source-input"
-      },
-      "default" : {
-        "type" : "source-default",
-        "properties" : { }
-      },
-      "sdnc" : {
-        "type" : "source-rest",
-        "properties" : {
-          "verb" : "GET",
-          "type" : "JSON",
-          "url-path" : "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/vlb_flavor_name",
-          "path" : "/param/0/value",
-          "input-key-mapping" : {
-            "service-instance-id" : "service-instance-id",
-            "vnf-id" : "vnf-id"
-          },
-          "output-key-mapping" : {
-            "vlb_flavor_name" : "value"
-          },
-          "key-dependencies" : [ "service-instance-id", "vnf-id" ]
-        }
-      }
-    }
-  },
   "vlb_int_pktgen_private_ip_0" : {
     "tags" : "vlb_int_pktgen_private_ip_0",
     "name" : "vlb_int_pktgen_private_ip_0",
         "type" : "source-default",
         "properties" : { }
       },
-      "processor-db" : {
-        "type" : "source-db",
-        "properties" : {
-          "endpoint-selector" : "dynamic-db-source",
-          "type" : "SQL",
-          "query" : "select sdnctl.IPAM_IP_POOL.prefix as prefix from sdnctl.IPAM_IP_POOL where description = \"private1\"",
-          "input-key-mapping" : { },
-          "output-key-mapping" : {
-            "vlb_private_net_cidr" : "prefix"
-          }
-        }
-      },
       "sdnc" : {
         "type" : "source-rest",
         "properties" : {
           },
           "key-dependencies" : [ "service-instance-id", "vnf-id" ]
         }
+      },
+      "processor-db" : {
+        "type" : "source-db",
+        "properties" : {
+          "endpoint-selector" : "dynamic-db-source",
+          "type" : "SQL",
+          "query" : "select sdnctl.IPAM_IP_POOL.prefix as prefix from sdnctl.IPAM_IP_POOL where description = \"private1\"",
+          "input-key-mapping" : { },
+          "output-key-mapping" : {
+            "vlb_private_net_cidr" : "prefix"
+          }
+        }
       }
     }
   },
       "processor-db" : {
         "type" : "source-db",
         "properties" : {
-          "endpoint-selector" : "dynamic-db-source",
           "type" : "SQL",
           "query" : "select VFC_MODEL.version as vnfc_model_version from VFC_MODEL where customization_uuid=:vfccustomizationuuid",
-          "input-key-mapping" : {
-            "vfccustomizationuuid" : "vfccustomizationuuid"
-          },
           "output-key-mapping" : {
             "vnfc-model-version" : "vnfc_model_version"
           },
-          "key-dependencies" : [ "vfccustomizationuuid" ]
-        }
-      }
-    }
-  },
-  "vpg_flavor_name" : {
-    "tags" : "vpg_flavor_name",
-    "name" : "vpg_flavor_name",
-    "property" : {
-      "description" : "vpg_flavor_name",
-      "type" : "string"
-    },
-    "updated-by" : "MALAKOV, YURIY <yuriy.malakov@att.com>",
-    "sources" : {
-      "input" : {
-        "type" : "source-input"
-      },
-      "default" : {
-        "type" : "source-default",
-        "properties" : { }
-      },
-      "sdnc" : {
-        "type" : "source-rest",
-        "properties" : {
-          "verb" : "GET",
-          "type" : "JSON",
-          "url-path" : "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/vpg_flavor_name",
-          "path" : "/param/0/value",
+          "endpoint-selector" : "dynamic-db-source",
           "input-key-mapping" : {
-            "service-instance-id" : "service-instance-id",
-            "vnf-id" : "vnf-id"
-          },
-          "output-key-mapping" : {
-            "vpg_flavor_name" : "value"
+            "vfccustomizationuuid" : "vfccustomizationuuid"
           },
-          "key-dependencies" : [ "service-instance-id", "vnf-id" ]
+          "key-dependencies" : [ "vfccustomizationuuid" ]
         }
       }
     }
       }
     }
   }
-}
+}
\ No newline at end of file
@@ -4,7 +4,7 @@
     "template_author" : "Abdelmuhaimen Seaudi",
     "author-email" : "abdelmuhaimen.seaudi@orange.com",
     "user-groups" : "ADMIN, OPERATION",
-    "template_name" : "test",
+    "template_name" : "vLB_CDS",
     "template_version" : "1.0.0",
     "template_tags" : "test, vDNS-CDS, SCALE-OUT, MARCO"
   },
             "type" : "artifact-mapping-resource",
             "file" : "Templates/vdns-mapping.json"
           },
-          "vdns-vnf-template" : {
+          "vnf-template" : {
             "type" : "artifact-template-velocity",
-            "file" : "Templates/vdns-vnf-template.vtl"
+            "file" : "Templates/vnf-template.vtl"
           },
-          "vdns-vnf-mapping" : {
+          "vnf-mapping" : {
             "type" : "artifact-mapping-resource",
-            "file" : "Templates/vdns-vnf-mapping.json"
+            "file" : "Templates/vnf-mapping.json"
           },
           "vlb-template" : {
             "type" : "artifact-template-velocity",
index 519aecf..92fb2aa 100644 (file)
@@ -1,27 +1,27 @@
-<service-logic
-        xmlns='http://www.onap.org/sdnc/svclogic'
-        xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
-        xsi:schemaLocation='http://www.onap.org/sdnc/svclogic ./svclogic.xsd' module='CONFIG' version='1.0.0'>
-    <method rpc='ConfigDeploy' mode='sync'>
-        <block atomic="true">
-            <execute plugin="nf-account-collection" method="process">
-                <outcome value='failure'>
-                    <return status="failure">
-                    </return>
-                </outcome>
-                <outcome value='success'>
-                    <execute plugin="execute" method="process">
-                        <outcome value='failure'>
-                            <return status="failure">
-                            </return>
-                        </outcome>
-                        <outcome value='success'>
-                            <return status='success'>
-                            </return>
-                        </outcome>
-                    </execute>
-                </outcome>
-            </execute>
-        </block>
-    </method>
+<service-logic\r
+  xmlns='http://www.onap.org/sdnc/svclogic'\r
+  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\r
+  xsi:schemaLocation='http://www.onap.org/sdnc/svclogic ./svclogic.xsd' module='CONFIG' version='1.0.0'>\r
+    <method rpc='ConfigDeploy' mode='sync'>\r
+        <block atomic="true">\r
+            <execute plugin="nf-account-collection" method="process">\r
+                <outcome value='failure'>\r
+                    <return status="failure">\r
+                    </return>\r
+                </outcome>\r
+                <outcome value='success'>\r
+                    <execute plugin="execute" method="process">\r
+                        <outcome value='failure'>\r
+                            <return status="failure">\r
+                            </return>\r
+                        </outcome>\r
+                        <outcome value='success'>\r
+                            <return status='success'>\r
+                            </return>\r
+                        </outcome>\r
+                    </execute>\r
+                </outcome>\r
+            </execute>\r
+        </block>\r
+    </method>\r
 </service-logic>
\ No newline at end of file
index 04ea82e..34fd140 100644 (file)
@@ -1,54 +1,54 @@
-#  Copyright (c) 2019 Bell Canada.
-#
-#  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.
-
-import netconf_constant
-from common import ResolutionHelper
-from time import sleep 
-from netconfclient import NetconfClient
-from org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor import \
-  NetconfComponentFunction
-
-
-class ConfigDeploy(NetconfComponentFunction):
-
-  def process(self, execution_request):      
-      log = globals()[netconf_constant.SERVICE_LOG]      
-      print(globals())
-      print("Waiting 4 minutes until NETCONF server is UP on vLB ...")
-      sleep (240)
-      nc = NetconfClient(log, self, "netconf-connection")
-      rr = ResolutionHelper(self)
-
-      # Get meshed template from DB
-      resolution_key = self.getDynamicProperties("resolution-key").asText()
-      payloadHostname = rr.retrieve_resolved_template_from_database(resolution_key, "baseconfig")
-      payloadInterface = rr.retrieve_resolved_template_from_database(resolution_key, "incremental-config")
-
-      nc.connect()
-      nc.lock()
-      #if not response.isSuccess():
-      #  og.error(response.errorMessage)
-      nc.discard_change()
-      nc.edit_config(message_content=payloadInterface, edit_default_peration="none")
-      nc.edit_config(message_content=payloadHostname, edit_default_peration="none")
-      nc.validate()
-      nc.commit()
-      #nc.commit(confirmed = True, confirm_timeout=15)
-      nc.unlock()
-      nc.disconnect()
-
-  def recover(self, runtime_exception, execution_request):
-        log.error("Exception in the script {}", runtime_exception)
-        print self.addError(runtime_exception.cause.message)
+#  Copyright (c) 2019 Bell Canada.\r
+#\r
+#  Licensed under the Apache License, Version 2.0 (the "License");\r
+#  you may not use this file except in compliance with the License.\r
+#  You may obtain a copy of the License at\r
+#\r
+#      http://www.apache.org/licenses/LICENSE-2.0\r
+#\r
+#  Unless required by applicable law or agreed to in writing, software\r
+#  distributed under the License is distributed on an "AS IS" BASIS,\r
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+#  See the License for the specific language governing permissions and\r
+#  limitations under the License.\r
+\r
+import netconf_constant\r
+from common import ResolutionHelper\r
+from time import sleep \r
+from netconfclient import NetconfClient\r
+from org.onap.ccsdk.cds.blueprintsprocessor.functions.netconf.executor import \\r
+  NetconfComponentFunction\r
+\r
+\r
+class ConfigDeploy(NetconfComponentFunction):\r
+\r
+  def process(self, execution_request):      \r
+      log = globals()[netconf_constant.SERVICE_LOG]      \r
+      print(globals())\r
+#      print("Waiting 4 minutes until NETCONF server is UP on vLB ...")\r
+#     sleep (240)\r
+      nc = NetconfClient(log, self, "netconf-connection")\r
+      rr = ResolutionHelper(self)\r
+\r
+      # Get meshed template from DB\r
+      resolution_key = self.getDynamicProperties("resolution-key").asText()\r
+      payloadHostname = rr.retrieve_resolved_template_from_database(resolution_key, "baseconfig")\r
+      payloadInterface = rr.retrieve_resolved_template_from_database(resolution_key, "incremental-config")\r
+\r
+      nc.connect()\r
+      nc.lock()\r
+      #if not response.isSuccess():\r
+      #  og.error(response.errorMessage)\r
+      nc.discard_change()\r
+      nc.edit_config(message_content=payloadInterface, edit_default_peration="none")\r
+      nc.edit_config(message_content=payloadHostname, edit_default_peration="none")\r
+      nc.validate()\r
+      nc.commit()\r
+      #nc.commit(confirmed = True, confirm_timeout=15)\r
+      nc.unlock()\r
+      nc.disconnect()\r
+\r
+  def recover(self, runtime_exception, execution_request):\r
+        log.error("Exception in the script {}", runtime_exception)\r
+        print self.addError(runtime_exception.cause.message)\r
         return None
\ No newline at end of file
index ea1a903..37c59ee 100644 (file)
@@ -1,6 +1,6 @@
 TOSCA-Meta-File-Version: 1.0.0
 CSAR-Version: 1.0
 Created-By: PLATANIA, MARCO <platania@research.att.com>
-Entry-Definitions: Definitions/vDNS-CDS.json
+Entry-Definitions: Definitions/vLB_CDS.json
 Template-Tags: vDNS-CDS-test1
 Content-Type: application/vnd.oasis.bpmn
\ No newline at end of file
index 62d1b96..43b0f9d 100644 (file)
@@ -20,7 +20,7 @@
     "version": 0
   },
     {
-    "name": "vf_module_name",
+    "name": "vf-module-name",
     "property": {
       "description": "",
       "required": false,
       "entry_schema": {
         "type": ""
       },
-      "default": "${vf_module_name}"
+      "default": "${vf-module-name}"
     },
     "input-param": false,
-    "dictionary-name": "vf_module_name",
+    "dictionary-name": "vf-module-name",
     "dictionary-source": "default",
     "dependencies": [],
     "version": 0
     ],
     "version": 0
   }
-]
+]
\ No newline at end of file
index 8055030..58512be 100644 (file)
           "payload": [
             {
               "param-name": "resource-name",
-              "param-value": "vf_module_name"
+              "param-value": "vf-module-name"
             },
             {
               "param-name": "resource-value",
-              "param-value": "${vf_module_name}"
+              "param-value": "${vf-module-name}"
             },
             {
               "param-name": "external-key",
-              "param-value": "${vf-module-id}_vf_module_name"
+              "param-value": "${vf-module-id}_vf-module-name"
             },
             {
               "param-name": "policy-instance-name",
           ],
           "output-key-mapping": [
             {
-              "resource-name": "vf_module_name",
-              "resource-value": "${vf_module_name}"
+              "resource-name": "vf-module-name",
+              "resource-value": "${vf-module-name}"
             }
           ]
         }
index cf30994..2dee19c 100644 (file)
     "version": 0
   },
   {
-    "name": "vf_module_name",
+    "name": "vf-module-name",
     "property": {
       "description": "",
       "required": false,
       "entry_schema": {
         "type": ""
       },
-      "default": "${vf_module_name}"
+      "default": "${vf-module-name}"
     },
     "input-param": false,
-    "dictionary-name": "vf_module_name",
+    "dictionary-name": "vf-module-name",
     "dictionary-source": "default",
     "dependencies": [],
     "version": 0
       "default": "m1.medium"
     },
     "input-param": false,
-    "dictionary-name": "vdns_flavor_name",
-    "dictionary-source": "default",
-    "dependencies": [],
+   "dictionary-name": "flavor_name",
+    "dictionary-source": "sdnc",
+    "dependencies": [
+         "service-instance-id",
+      "vnf-id"
+       ],
     "version": 0
   },
   
     ],
     "version": 0
   }
-]
+]
\ No newline at end of file
index 9c493dc..84fab0d 100644 (file)
           "payload": [
             {
               "param-name": "resource-name",
-              "param-value": "vf_module_name"
+              "param-value": "vf-module-name"
             },
             {
               "param-name": "resource-value",
-              "param-value": "${vf_module_name}"
+              "param-value": "${vf-module-name}"
             },
             {
               "param-name": "external-key",
-              "param-value": "${vf-module-id}_vf_module_name"
+              "param-value": "${vf-module-id}_vf-module-name"
             },
             {
               "param-name": "policy-instance-name",
           ],
           "output-key-mapping": [
             {
-              "resource-name": "vf_module_name",
-              "resource-value": "${vf_module_name}"
+              "resource-name": "vf-module-name",
+              "resource-value": "${vf-module-name}"
             }
           ]
         }
index 9e3b693..0104579 100644 (file)
@@ -21,7 +21,7 @@
     "version": 0
   },
   {
-    "name": "vf_module_name",
+    "name": "vf-module-name",
     "property": {
       "description": "",
       "required": false,
       "entry_schema": {
         "type": ""
       },
-      "default": "${vf_module_name}"
+      "default": "${vf-module-name}"
     },
     "input-param": false,
-    "dictionary-name": "vf_module_name",
+    "dictionary-name": "vf-module-name",
     "dictionary-source": "default",
     "dependencies": [],
     "version": 0
       ],
       "entry_schema": {
         "type": ""
-      },
-      "default": "m1.medium"
-    },
+      }
+         },
     "input-param": false,
-    "dictionary-name": "vlb_flavor_name",
-    "dictionary-source": "default",
-    "dependencies": [],
+    "dictionary-name": "flavor_name",
+    "dictionary-source": "sdnc",
+    "dependencies": [
+         "service-instance-id",
+      "vnf-id"
+       ],
     "version": 0
   },
   {
     "dependencies": [],
     "version": 0
   }
-]
+]
\ No newline at end of file
index bc495bd..458423e 100644 (file)
           "payload": [
             {
               "param-name": "resource-name",
-              "param-value": "vf_module_name"
+              "param-value": "vf-module-name"
             },
             {
               "param-name": "resource-value",
-              "param-value": "${vf_module_name}"
+              "param-value": "${vf-module-name}"
             },
             {
               "param-name": "external-key",
-              "param-value": "${vf-module-id}_vf_module_name"
+              "param-value": "${vf-module-id}_vf-module-name"
             },
             {
               "param-name": "policy-instance-name",
           ],
           "output-key-mapping": [
             {
-              "resource-name": "vf_module_name",
-              "resource-value": "${vf_module_name}"
+              "resource-name": "vf-module-name",
+              "resource-value": "${vf-module-name}"
             }
           ]
         }
     "dictionary-source": "input",
     "dependencies": [],
     "version": 0
+  },
+    {
+    "name": "flavor_name",
+    "property": {
+      "description": "",
+      "required": false,
+      "type": "string",
+      "status": "",
+      "constraints": [
+        {}
+      ],
+      "entry_schema": {
+        "type": ""
+      }
+    },
+    "input-param": false,
+    "dictionary-name": "flavor_name",
+    "dictionary-source": "input",
+    "dependencies": [],
+    "version": 0
   },
   {
     "name": "image_name",
     {
       "param-name": "cloud_env",
       "param-value": "${cloud_env}"
+    },
+          {
+      "param-name": "flavor_name",
+      "param-value": "${flavor_name}"
     },
     {
       "param-name": "install_script_version",
index 554d45f..25721e2 100644 (file)
@@ -21,7 +21,7 @@
     "version": 0
   },
   {
-    "name": "vf_module_name",
+    "name": "vf-module-name",
     "property": {
       "description": "",
       "required": false,
       "entry_schema": {
         "type": ""
       },
-      "default": "${vf_module_name}"
+      "default": "${vf-module-name}"
     },
     "input-param": false,
-    "dictionary-name": "vf_module_name",
+    "dictionary-name": "vf-module-name",
     "dictionary-source": "default",
     "dependencies": [],
     "version": 0
       ],
       "entry_schema": {
         "type": ""
-      },
-      "default": "m1.medium"
+      }
     },
     "input-param": false,
-    "dictionary-name": "vpg_flavor_name",
-    "dictionary-source": "default",
-    "dependencies": [],
+   "dictionary-name": "flavor_name",
+    "dictionary-source": "sdnc",
+    "dependencies": [
+         "service-instance-id",
+      "vnf-id"
+       ],
     "version": 0
   },
   {
     ],
     "version": 0
   }
-]
+]
\ No newline at end of file
index 98d541d..bd745b1 100644 (file)
           "payload": [
             {
               "param-name": "resource-name",
-              "param-value": "vf_module_name"
+              "param-value": "vf-module-name"
             },
             {
               "param-name": "resource-value",
-              "param-value": "${vf_module_name}"
+              "param-value": "${vf-module-name}"
             },
             {
               "param-name": "external-key",
-              "param-value": "${vf-module-id}_vf_module_name"
+              "param-value": "${vf-module-id}_vf-module-name"
             },
             {
               "param-name": "policy-instance-name",
           ],
           "output-key-mapping": [
             {
-              "resource-name": "vf_module_name",
-              "resource-value": "${vf_module_name}"
+              "resource-name": "vf-module-name",
+              "resource-value": "${vf-module-name}"
             }
           ]
         }
index d29abb0..9552b61 100644 (file)
@@ -35,7 +35,8 @@ open class Check : AbstractScriptComponentFunction() {
     override suspend fun processNB(executionRequest: ExecutionServiceInput) {
         log.info("Executing process : ${executionRequest.payload}")
 
-        val data = executionRequest.payload.at("/check-request/data")
+        val data = requestPayloadActionProperty("data")?.first()
+            ?: throw BluePrintProcessorException("Failed to load payload data properties.")
 
         log.info("Data : ${data.asJsonString()}")
 
index cd13c9c..ed1b67d 100755 (executable)
             <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId>
             <artifactId>configs-api</artifactId>
         </dependency>
+        <!--
         <dependency>
             <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId>
             <artifactId>health-api</artifactId>
         </dependency>
+        -->
 
         <!-- Functions -->
         <dependency>
index 407aa6b..e4bb007 100755 (executable)
@@ -41,6 +41,25 @@ services:
     restart: always
     volumes:
       - blueprints-deploy:/opt/app/onap/blueprints/deploy
+  py-executor:
+    depends_on:
+      - db
+    image: onap/ccsdk-py-script-executor
+    container_name: bp-py-executor
+    ports:
+      - "50052:50052"
+    restart: always
+    volumes:
+      - blueprints-deploy:/opt/app/onap/blueprints/deploy
+    environment:
+      APPLICATIONNAME: PythonExecutor
+      BUNDLEVERSION: 1.0.0
+      APP_CONFIG_HOME: /opt/app/onap/config
+      STICKYSELECTORKEY:
+      ENVCONTEXT: dev
+      APP_PORT: 50052
+      BASIC_AUTH: Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==
+      LOG_FILE: /opt/app/onap/logs/application.log
 
 volumes:
   blueprints-deploy:
diff --git a/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/LoggingWebFilter.kt b/ms/blueprintsprocessor/application/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/LoggingWebFilter.kt
new file mode 100644 (file)
index 0000000..5ed5ff4
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright © 2018-2019 AT&T Intellectual Property.
+ *
+ * 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
+
+import org.onap.ccsdk.cds.blueprintsprocessor.core.service.LoggingService
+import org.onap.ccsdk.cds.controllerblueprints.core.MDCContext
+import org.springframework.stereotype.Component
+import org.springframework.web.server.ServerWebExchange
+import org.springframework.web.server.WebFilter
+import org.springframework.web.server.WebFilterChain
+import reactor.core.publisher.Mono
+import reactor.util.context.Context
+
+@Component
+open class LoggingWebFilter : WebFilter {
+    override fun filter(serverWebExchange: ServerWebExchange, webFilterChain: WebFilterChain): Mono<Void> {
+
+        val loggingService = LoggingService()
+        loggingService.entering(serverWebExchange.request)
+        val filterChain = webFilterChain.filter(serverWebExchange).subscriberContext(
+                Context.of(MDCContext,  MDCContext()))
+        loggingService.exiting(serverWebExchange.request, serverWebExchange.response)
+        return filterChain
+    }
+}
\ No newline at end of file
index e40ccba..faabb80 100755 (executable)
@@ -36,7 +36,7 @@ blueprintsprocessor.blueprintArchivePath=blueprints/archive
 blueprintsprocessor.blueprintWorkingPath=blueprints/work
 # Controller Blueprint Load Configurations
 # blueprints.load.initial-data may be overridden by ENV variables
-blueprintsprocessor.loadInitialData=true
+blueprintsprocessor.loadInitialData=false
 blueprintsprocessor.loadBluePrint=false
 blueprintsprocessor.loadBluePrintPaths=./../../../components/model-catalog/blueprint-model/service-blueprint
 blueprintsprocessor.loadModelType=true
index 1378c62..b8f0d23 100755 (executable)
@@ -66,8 +66,8 @@ security.user.password: {bcrypt}$2a$10$duaUzVUVW0YPQCSIbGEkQOXwafZGwQ/b32/Ys4R1i
 security.user.name: ccsdkapps
 
 # Used in Health Check
-endpoints.user.name=ccsdkapps
-endpoints.user.password=ccsdkapps
+#endpoints.user.name=ccsdkapps
+#endpoints.user.password=ccsdkapps
 
 # Executor Options
 blueprintsprocessor.resourceResolution.enabled=true
index 6f91709..9d2b82f 100644 (file)
   -->
 
 <configuration>
+
+    <property name="localPattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n"/>
+    <property name="defaultPattern"
+              value="%date{ISO8601,UTC}|%X{RequestID}|%X{InvocationID}|%thread|%X{ServiceName}|%X{ClientIPAddress}|%logger{50}| %msg%n"/>
+
     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
         <!-- encoders are assigned the type
              ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
         <encoder>
-            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
+            <pattern>${defaultPattern}</pattern>
         </encoder>
     </appender>
 
index 088533a..a1d2188 100644 (file)
@@ -73,7 +73,7 @@ open class BluePrintGrpcLibPropertyService(private var bluePrintProperties: Blue
         }
     }
 
-    private fun blueprintGrpcClientService(grpcClientProperties: GrpcClientProperties):
+    fun blueprintGrpcClientService(grpcClientProperties: GrpcClientProperties):
             BluePrintGrpcClientService {
         when (grpcClientProperties) {
             is TokenAuthGrpcClientProperties -> {
index ab04054..1cd8a2a 100644 (file)
@@ -36,6 +36,7 @@ open class KafkaMessageConsumerProperties : MessageConsumerProperties() {
     var clientId: String? = null
     var topic: String? = null
     var pollMillSec: Long = 1000
+    var pollRecords: Int = -1
 }
 
 open class KafkaBasicAuthMessageConsumerProperties : KafkaMessageConsumerProperties()
index 5a9e61b..b5d444a 100644 (file)
@@ -51,6 +51,10 @@ class KafkaBasicAuthMessageConsumerService(
         if (messageConsumerProperties.clientId != null) {
             configProperties[ConsumerConfig.CLIENT_ID_CONFIG] = messageConsumerProperties.clientId!!
         }
+        /** To handle Back pressure, Get only configured record for processing */
+        if (messageConsumerProperties.pollRecords > 0) {
+            configProperties[ConsumerConfig.MAX_POLL_RECORDS_CONFIG] = messageConsumerProperties.pollRecords
+        }
         // TODO("Security Implementation based on type")
         /** add or override already set properties */
         additionalConfig?.let { configProperties.putAll(it) }
@@ -84,6 +88,7 @@ class KafkaBasicAuthMessageConsumerService(
             kafkaConsumer!!.use { kc ->
                 while (keepGoing) {
                     val consumerRecords = kc.poll(Duration.ofMillis(messageConsumerProperties.pollMillSec))
+                    log.info("Consumed Records : ${consumerRecords.count()}")
                     runBlocking {
                         consumerRecords?.forEach { consumerRecord ->
                             /** execute the command block */
index 2b84eaa..f4e85a9 100644 (file)
@@ -52,6 +52,7 @@ import kotlin.test.assertTrue
     "blueprintsprocessor.messageconsumer.sample.topic=default-topic",
     "blueprintsprocessor.messageconsumer.sample.clientId=default-client-id",
     "blueprintsprocessor.messageconsumer.sample.pollMillSec=10",
+    "blueprintsprocessor.messageconsumer.sample.pollRecords=1",
 
     "blueprintsprocessor.messageproducer.sample.type=kafka-basic-auth",
     "blueprintsprocessor.messageproducer.sample.bootstrapServers=127.0.0.1:9092",
@@ -129,11 +130,11 @@ open class BlueprintMessageConsumerServiceTest {
                     .blueprintMessageProducerService("sample") as KafkaBasicAuthMessageProducerService
             launch {
                 repeat(5) {
-                    delay(1000)
+                    delay(100)
                     blueprintMessageProducerService.sendMessage("this is my message($it)")
                 }
             }
-            delay(10000)
+            delay(5000)
             blueprintMessageConsumerService.shutDown()
         }
     }
diff --git a/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/LoggerExtensions.kt b/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/LoggerExtensions.kt
new file mode 100644 (file)
index 0000000..cdf6ce1
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2018-2019 AT&T Intellectual Property.
+ *
+ * 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 kotlinx.coroutines.*
+import kotlinx.coroutines.reactor.ReactorContext
+import kotlinx.coroutines.reactor.asCoroutineContext
+import org.onap.ccsdk.cds.blueprintsprocessor.core.service.MonoMDCCoroutine
+import org.onap.ccsdk.cds.controllerblueprints.core.MDCContext
+import reactor.core.publisher.Mono
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.EmptyCoroutineContext
+
+/** Used in Rest controller API methods to populate MDC context to nested coroutines from reactor web filter context. */
+@UseExperimental(InternalCoroutinesApi::class)
+fun <T> monoMdc(context: CoroutineContext = EmptyCoroutineContext,
+                block: suspend CoroutineScope.() -> T?): Mono<T> = Mono.create { sink ->
+
+    val reactorContext = (context[ReactorContext]?.context?.putAll(sink.currentContext())
+            ?: sink.currentContext()).asCoroutineContext()
+    /** Populate MDC context only if present in Reactor Context */
+    val newContext = if (!reactorContext.context.isEmpty
+            && reactorContext.context.hasKey(MDCContext)) {
+        val mdcContext = reactorContext.context.get<MDCContext>(MDCContext)
+        GlobalScope.newCoroutineContext(context + reactorContext + mdcContext)
+    } else GlobalScope.newCoroutineContext(context + reactorContext)
+
+    val coroutine = MonoMDCCoroutine(newContext, sink)
+    sink.onDispose(coroutine)
+    coroutine.start(CoroutineStart.DEFAULT, coroutine, block)
+}
\ No newline at end of file
diff --git a/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/service/BluePrintProcessorLoggingService.kt b/ms/blueprintsprocessor/modules/commons/processor-core/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/core/service/BluePrintProcessorLoggingService.kt
new file mode 100644 (file)
index 0000000..4da7dcd
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2018-2019 AT&T Intellectual Property.
+ *
+ * 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.service
+
+import kotlinx.coroutines.AbstractCoroutine
+import kotlinx.coroutines.InternalCoroutinesApi
+import kotlinx.coroutines.handleCoroutineException
+import org.onap.ccsdk.cds.controllerblueprints.core.logger
+import org.slf4j.MDC
+import org.springframework.http.server.reactive.ServerHttpRequest
+import org.springframework.http.server.reactive.ServerHttpResponse
+import reactor.core.Disposable
+import reactor.core.publisher.MonoSink
+import java.time.ZoneOffset
+import java.time.ZonedDateTime
+import java.time.format.DateTimeFormatter
+import java.util.*
+import kotlin.coroutines.CoroutineContext
+
+class LoggingService {
+    private val log = logger(LoggingService::class)
+
+    companion object {
+        const val ONAP_REQUEST_ID = "X-ONAP-RequestID"
+        const val ONAP_INVOCATION_ID = "X-ONAP-InvocationID"
+        const val ONAP_PARTNER_NAME = "X-ONAP-PartnerName"
+    }
+
+    fun entering(request: ServerHttpRequest) {
+        val headers = request.headers
+        val requestID = defaultToUUID(headers.getFirst(ONAP_REQUEST_ID))
+        val invocationID = defaultToUUID(headers.getFirst(ONAP_INVOCATION_ID))
+        val partnerName = defaultToEmpty(headers.getFirst(ONAP_PARTNER_NAME))
+        MDC.put("InvokeTimestamp", ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT))
+        MDC.put("RequestID", requestID)
+        MDC.put("InvocationID", invocationID)
+        MDC.put("PartnerName", partnerName)
+        MDC.put("ClientIPAddress", defaultToEmpty(request.remoteAddress?.address?.hostAddress))
+        MDC.put("ServerFQDN", defaultToEmpty(request.remoteAddress?.hostString))
+        if (MDC.get("ServiceName") == null || MDC.get("ServiceName").equals("", ignoreCase = true)) {
+            MDC.put("ServiceName", request.uri.path)
+        }
+    }
+
+    fun exiting(request: ServerHttpRequest, response: ServerHttpResponse) {
+        try {
+            val reqHeaders = request.headers
+            val resHeaders = response.headers
+            resHeaders[ONAP_REQUEST_ID] = MDC.get("RequestID")
+            resHeaders[ONAP_INVOCATION_ID] = MDC.get("InvocationID")
+        } catch (e: Exception) {
+            log.warn("couldn't set response headers", e)
+        } finally {
+            MDC.clear()
+        }
+    }
+
+    private fun defaultToEmpty(input: Any?): String {
+        return input?.toString() ?: ""
+    }
+
+    private fun defaultToUUID(input: String?): String {
+        return input ?: UUID.randomUUID().toString()
+    }
+}
+
+
+@InternalCoroutinesApi
+class MonoMDCCoroutine<in T>(
+        parentContext: CoroutineContext,
+        private val sink: MonoSink<T>
+) : AbstractCoroutine<T>(parentContext, true), Disposable {
+    private var disposed = false
+
+    override fun onCompleted(value: T) {
+        if (!disposed) {
+            if (value == null) sink.success() else sink.success(value)
+        }
+    }
+
+    override fun onCancelled(cause: Throwable, handled: Boolean) {
+        if (!disposed) {
+            sink.error(cause)
+        } else if (!handled) {
+            handleCoroutineException(context, cause)
+        }
+    }
+
+    override fun dispose() {
+        disposed = true
+        cancel()
+    }
+
+    override fun isDisposed(): Boolean = disposed
+}
index 4d13486..a6bff70 100644 (file)
@@ -19,7 +19,7 @@ package org.onap.ccsdk.cds.blueprintsprocessor.designer.api
 
 import io.swagger.annotations.ApiOperation
 import io.swagger.annotations.ApiParam
-import kotlinx.coroutines.runBlocking
+import org.onap.ccsdk.cds.blueprintsprocessor.core.monoMdc
 import org.onap.ccsdk.cds.blueprintsprocessor.db.primary.domain.BlueprintModelSearch
 import org.onap.ccsdk.cds.blueprintsprocessor.designer.api.handler.BluePrintModelHandler
 import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
@@ -29,6 +29,7 @@ import org.springframework.http.ResponseEntity
 import org.springframework.http.codec.multipart.FilePart
 import org.springframework.security.access.prepost.PreAuthorize
 import org.springframework.web.bind.annotation.*
+import reactor.core.publisher.Mono
 
 /**
  * BlueprintModelController Purpose: Handle controllerBlueprint API request
@@ -44,7 +45,7 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint
     @ResponseBody
     @Throws(BluePrintException::class)
     @PreAuthorize("hasRole('USER')")
-    fun saveBlueprint(@RequestPart("file") filePart: FilePart): BlueprintModelSearch = runBlocking {
+    fun saveBlueprint(@RequestPart("file") filePart: FilePart): Mono<BlueprintModelSearch> = monoMdc {
         bluePrintModelHandler.saveBlueprintModel(filePart)
     }
 
@@ -67,8 +68,9 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint
     @Throws(BluePrintException::class)
     @PreAuthorize("hasRole('USER')")
     fun getBlueprintByNameAndVersion(@PathVariable(value = "name") name: String,
-                                     @PathVariable(value = "version") version: String): BlueprintModelSearch {
-        return this.bluePrintModelHandler.getBlueprintModelSearchByNameAndVersion(name, version)
+                                     @PathVariable(value = "version") version: String)
+            : Mono<BlueprintModelSearch> = monoMdc {
+        bluePrintModelHandler.getBlueprintModelSearchByNameAndVersion(name, version)
     }
 
     @GetMapping("/download/by-name/{name}/version/{version}", produces = [MediaType.APPLICATION_JSON_VALUE])
@@ -76,8 +78,9 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint
     @Throws(BluePrintException::class)
     @PreAuthorize("hasRole('USER')")
     fun downloadBlueprintByNameAndVersion(@PathVariable(value = "name") name: String,
-                                          @PathVariable(value = "version") version: String): ResponseEntity<Resource> {
-        return this.bluePrintModelHandler.downloadBlueprintModelFileByNameAndVersion(name, version)
+                                          @PathVariable(value = "version") version: String)
+            : Mono<ResponseEntity<Resource>> = monoMdc {
+        bluePrintModelHandler.downloadBlueprintModelFileByNameAndVersion(name, version)
     }
 
     @GetMapping("/{id}", produces = [MediaType.APPLICATION_JSON_VALUE])
@@ -92,8 +95,8 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint
     @ResponseBody
     @Throws(BluePrintException::class)
     @PreAuthorize("hasRole('USER')")
-    fun downloadBluePrint(@PathVariable(value = "id") id: String): ResponseEntity<Resource> {
-        return this.bluePrintModelHandler.downloadBlueprintModelFile(id)
+    fun downloadBluePrint(@PathVariable(value = "id") id: String): Mono<ResponseEntity<Resource>> = monoMdc {
+        bluePrintModelHandler.downloadBlueprintModelFile(id)
     }
 
     @PostMapping("/enrich", produces = [MediaType.APPLICATION_JSON_VALUE], consumes = [MediaType
@@ -101,7 +104,7 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint
     @ResponseBody
     @Throws(BluePrintException::class)
     @PreAuthorize("hasRole('USER')")
-    fun enrichBlueprint(@RequestPart("file") file: FilePart): ResponseEntity<Resource> = runBlocking {
+    fun enrichBlueprint(@RequestPart("file") file: FilePart): Mono<ResponseEntity<Resource>> = monoMdc {
         bluePrintModelHandler.enrichBlueprint(file)
     }
 
@@ -109,7 +112,7 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint
     @ResponseBody
     @Throws(BluePrintException::class)
     @PreAuthorize("hasRole('USER')")
-    fun publishBlueprint(@RequestPart("file") file: FilePart): BlueprintModelSearch = runBlocking {
+    fun publishBlueprint(@RequestPart("file") file: FilePart): Mono<BlueprintModelSearch> = monoMdc {
         bluePrintModelHandler.publishBlueprint(file)
     }
 
@@ -128,7 +131,7 @@ open class BlueprintModelController(private val bluePrintModelHandler: BluePrint
     fun deleteBlueprint(@ApiParam(value = "Name of the CBA.", required = true)
                         @PathVariable(value = "name") name: String,
                         @ApiParam(value = "Version of the CBA.", required = true)
-                        @PathVariable(value = "version") version: String) = runBlocking {
+                        @PathVariable(value = "version") version: String) = monoMdc {
         bluePrintModelHandler.deleteBlueprintModel(name, version)
     }
 }
index 1729f2f..81ffea1 100644 (file)
@@ -35,7 +35,7 @@
         <module>designer-api</module>
         <module>resource-api</module>
         <module>selfservice-api</module>
-        <module>health-api</module>
+        <!--<module>health-api</module>-->
     </modules>
 
     <dependencies>
index 4441d2b..f14f61e 100644 (file)
 
 package org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api
 
-import com.fasterxml.jackson.databind.JsonNode
 import io.swagger.annotations.Api
 import io.swagger.annotations.ApiOperation
 import io.swagger.annotations.ApiParam
-import kotlinx.coroutines.runBlocking
 import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ACTION_MODE_ASYNC
 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.monoMdc
 import org.onap.ccsdk.cds.blueprintsprocessor.selfservice.api.utils.determineHttpStatusCode
 import org.onap.ccsdk.cds.controllerblueprints.core.asJsonPrimitive
+import org.onap.ccsdk.cds.controllerblueprints.core.logger
 import org.springframework.beans.factory.annotation.Autowired
 import org.springframework.http.MediaType
 import org.springframework.http.ResponseEntity
 import org.springframework.security.access.prepost.PreAuthorize
 import org.springframework.web.bind.annotation.*
+import reactor.core.publisher.Mono
 
 @RestController
 @RequestMapping("/api/v1/execution-service")
 @Api(value = "/api/v1/execution-service",
         description = "Interaction with CBA.")
 open class ExecutionServiceController {
+    val log = logger(ExecutionServiceController::class)
 
     @Autowired
     lateinit var executionServiceHandler: ExecutionServiceHandler
@@ -47,7 +49,8 @@ open class ExecutionServiceController {
             produces = [MediaType.APPLICATION_JSON_VALUE])
     @ResponseBody
     @ApiOperation(value = "Health Check", hidden = true)
-    fun executionServiceControllerHealthCheck(): JsonNode = runBlocking {
+    fun executionServiceControllerHealthCheck() = monoMdc {
+        log.info("Health check success...")
         "Success".asJsonPrimitive()
     }
 
@@ -59,12 +62,13 @@ open class ExecutionServiceController {
     @ResponseBody
     @PreAuthorize("hasRole('USER')")
     fun process(@ApiParam(value = "ExecutionServiceInput payload.", required = true)
-                @RequestBody executionServiceInput: ExecutionServiceInput): ResponseEntity<ExecutionServiceOutput> =
-            runBlocking {
-                if (executionServiceInput.actionIdentifiers.mode == ACTION_MODE_ASYNC) {
-                    throw IllegalStateException("Can't process async request through the REST endpoint. Use gRPC for async processing.")
-                }
-                val processResult = executionServiceHandler.doProcess(executionServiceInput)
-                ResponseEntity(processResult, determineHttpStatusCode(processResult.status.code))
-            }
+                @RequestBody executionServiceInput: ExecutionServiceInput)
+            : Mono<ResponseEntity<ExecutionServiceOutput>> = monoMdc {
+
+        if (executionServiceInput.actionIdentifiers.mode == ACTION_MODE_ASYNC) {
+            throw IllegalStateException("Can't process async request through the REST endpoint. Use gRPC for async processing.")
+        }
+        val processResult = executionServiceHandler.doProcess(executionServiceInput)
+        ResponseEntity(processResult, determineHttpStatusCode(processResult.status.code))
+    }
 }
index 8bee7c9..f3044c8 100644 (file)
             <groupId>org.onap.ccsdk.sli.core</groupId>
             <artifactId>sli-provider</artifactId>
         </dependency>
+
+        <dependency>
+            <groupId>io.grpc</groupId>
+            <artifactId>grpc-testing</artifactId>
+        </dependency>
     </dependencies>
 </project>
index 5163a93..bee9192 100644 (file)
@@ -167,9 +167,9 @@ abstract class AbstractComponentFunction : BlueprintFunctionNode<ExecutionServic
      */
     fun requestPayloadActionProperty(expression: String?): JsonNode? {
         val requestExpression = if (expression.isNullOrBlank()) {
-            "$operationName-request"
+            "$workflowName-request"
         } else {
-            "$operationName-request.$expression"
+            "$workflowName-request.$expression"
         }
         return executionServiceInput.payload.jsonPathParse(".$requestExpression")
     }
index a16c520..062d370 100644 (file)
@@ -54,6 +54,7 @@ class ComponentFunctionScriptingService(private val applicationContext: Applicat
         scriptComponent.operationName = componentFunction.operationName
         scriptComponent.nodeTemplateName = componentFunction.nodeTemplateName
         scriptComponent.operationInputs = componentFunction.operationInputs
+        scriptComponent.executionServiceInput = componentFunction.executionServiceInput
         scriptComponent.scriptType = scriptType
 
         // Populate Instance Properties
diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/StreamingRemoteExecutionService.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/main/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/StreamingRemoteExecutionService.kt
new file mode 100644 (file)
index 0000000..adb1d67
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright © 2018-2019 AT&T Intellectual Property.
+ *
+ * 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.services.execution
+
+import com.fasterxml.jackson.databind.JsonNode
+import com.github.marcoferrer.krotoplus.coroutines.client.ClientBidiCallChannel
+import com.github.marcoferrer.krotoplus.coroutines.client.clientCallBidiStreaming
+import io.grpc.ManagedChannel
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.flow.consumeAsFlow
+import org.onap.ccsdk.cds.blueprintsprocessor.grpc.GrpcClientProperties
+import org.onap.ccsdk.cds.blueprintsprocessor.grpc.service.BluePrintGrpcClientService
+import org.onap.ccsdk.cds.blueprintsprocessor.grpc.service.BluePrintGrpcLibPropertyService
+import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
+import org.onap.ccsdk.cds.controllerblueprints.core.logger
+import org.onap.ccsdk.cds.controllerblueprints.processing.api.BluePrintProcessingServiceGrpc
+import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput
+import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceOutput
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
+import org.springframework.stereotype.Service
+
+interface StreamingRemoteExecutionService<ReqT, ResT> {
+
+    suspend fun openSubscription(selector: Any, txId: String): Flow<ResT>
+
+    suspend fun sendNonInteractive(selector: Any, txId: String, input: ReqT, timeOutMill: Long): ResT
+
+    suspend fun send(txId: String, input: ReqT)
+
+    suspend fun cancelSubscription(txId: String)
+
+    suspend fun closeChannel(selector: Any)
+}
+
+@Service
+@ConditionalOnProperty(prefix = "blueprintsprocessor.streamingRemoteExecution", name = ["enabled"],
+        havingValue = "true", matchIfMissing = false)
+class StreamingRemoteExecutionServiceImpl(private val bluePrintGrpcLibPropertyService: BluePrintGrpcLibPropertyService)
+    : StreamingRemoteExecutionService<ExecutionServiceInput, ExecutionServiceOutput> {
+
+    private val log = logger(StreamingRemoteExecutionServiceImpl::class)
+
+    private val grpcChannels: MutableMap<String, ManagedChannel> = hashMapOf()
+
+    private val commChannels: MutableMap<String,
+            ClientBidiCallChannel<ExecutionServiceInput, ExecutionServiceOutput>> = hashMapOf()
+
+
+    /**
+     * Open new channel to send and receive for grpc properties [selector] for [txId],
+     * Create the only one GRPC channel per host port and reuse for further communication.
+     * Create request communication channel to send and receive requests and responses.
+     * We can send multiple request with same txId.
+     * Consume the flow for responses,
+     * Client should cancel the subscription for the request Id once no longer response is needed.
+     * */
+    @FlowPreview
+    override suspend fun openSubscription(selector: Any, txId: String): Flow<ExecutionServiceOutput> {
+
+        if (!commChannels.containsKey(txId)) {
+            /** Get GRPC Channel*/
+            val grpcChannel = grpcChannel(selector)
+
+            /** Get Send and Receive Channel for bidirectional process method*/
+            val channels = clientCallBidiStreaming(BluePrintProcessingServiceGrpc.getProcessMethod(), grpcChannel)
+            commChannels[txId] = channels
+        }
+
+        val commChannel = commChannels[txId]
+                ?: throw BluePrintException("failed to create response subscription for transactionId($txId) channel")
+
+        log.info("created subscription for transactionId($txId)")
+
+        return commChannel.responseChannel.consumeAsFlow()
+    }
+
+    /**
+     * Send the [input] request, by reusing same GRPC channel and Communication channel
+     * for the request Id.
+     */
+    override suspend fun send(txId: String, input: ExecutionServiceInput) {
+        val sendChannel = commChannels[txId]?.requestChannel
+                ?: throw BluePrintException("failed to get transactionId($txId) send channel")
+        coroutineScope {
+            launch {
+                sendChannel.send(input)
+                log.trace("Message sent for transactionId($txId)")
+            }
+        }
+    }
+
+    /**
+     * Simplified version of Streaming calls, Use this API only listing for actual response for [input]
+     * for the GRPC [selector] with execution [timeOutMill].
+     * Other state of the request will be skipped.
+     * The assumption here is you can call this API with same request Id and unique subrequest Id,
+     * so the correlation is sub request id to receive the response.
+     */
+    @ExperimentalCoroutinesApi
+    override suspend fun sendNonInteractive(selector: Any, txId: String, input: ExecutionServiceInput, timeOutMill: Long)
+            : ExecutionServiceOutput {
+
+        var output: ExecutionServiceOutput? = null
+        val flow = openSubscription(selector, txId)
+
+        /** Send the request */
+        val sendChannel = commChannels[txId]?.requestChannel
+                ?: throw BluePrintException("failed to get transactionId($txId) send channel")
+        sendChannel.send(input)
+
+        /** Receive the response with timeout */
+        withTimeout(timeOutMill) {
+            flow.collect {
+                log.trace("Received non-interactive transactionId($txId) response : ${it.status.eventType}")
+                if (it.status.eventType == EventType.EVENT_COMPONENT_EXECUTED) {
+                    output = it
+                    cancelSubscription(txId)
+                }
+            }
+        }
+        return output!!
+    }
+
+    /** Cancel the Subscription for the [txId], This closes communication channel **/
+    @ExperimentalCoroutinesApi
+    override suspend fun cancelSubscription(txId: String) {
+        commChannels[txId]?.let {
+            if (!it.requestChannel.isClosedForSend)
+                it.requestChannel.close()
+            /** If receive channel has to close immediately, once the subscription has cancelled, then enable this */
+            //it.responseChannel.cancel(CancellationException("subscription cancelled"))
+            commChannels.remove(txId)
+            log.info("closed subscription for transactionId($txId)")
+        }
+    }
+
+    /** Close the GRPC channel for the host port poperties [selector]*/
+    override suspend fun closeChannel(selector: Any) {
+        val grpcProperties = grpcProperties(selector)
+        val selectorName = "${grpcProperties.host}:${grpcProperties.port}"
+        if (grpcChannels.containsKey(selectorName)) {
+            grpcChannels[selectorName]!!.shutdownNow()
+            grpcChannels.remove(selectorName)
+            log.info("grpc channel($selectorName) shutdown completed")
+        }
+    }
+
+    /** Check GRPC channel has been cached and not shutdown, If not re create channel and chache it. */
+    private suspend fun grpcChannel(selector: Any): ManagedChannel {
+        val grpcProperties = grpcProperties(selector)
+        val selectorName = "${grpcProperties.host}:${grpcProperties.port}"
+        val isGrpcChannelCached = grpcChannels.containsKey(selectorName)
+        val grpcChannel = if (isGrpcChannelCached) {
+            if (grpcChannels[selectorName]!!.isShutdown) {
+                createGrpcChannel(grpcProperties)
+            } else {
+                grpcChannels[selectorName]!!
+            }
+        } else {
+            createGrpcChannel(grpcProperties)
+        }
+        grpcChannels[selectorName] = grpcChannel
+        return grpcChannel
+    }
+
+    suspend fun createGrpcChannel(grpcProperties: GrpcClientProperties): ManagedChannel {
+        val grpcClientService: BluePrintGrpcClientService = bluePrintGrpcLibPropertyService
+                .blueprintGrpcClientService(grpcProperties)
+        return grpcClientService.channel()
+    }
+
+    private fun grpcProperties(selector: Any): GrpcClientProperties {
+        return when (selector) {
+            is String -> {
+                bluePrintGrpcLibPropertyService.grpcClientProperties(selector.toString())
+            }
+            is JsonNode -> {
+                bluePrintGrpcLibPropertyService.grpcClientProperties(selector)
+            }
+            is GrpcClientProperties -> {
+                selector
+            }
+            else -> {
+                throw BluePrintException("couldn't process selector($selector)")
+            }
+        }
+    }
+}
diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/MockBluePrintProcessingServer.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/MockBluePrintProcessingServer.kt
new file mode 100644 (file)
index 0000000..e291aa7
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright © 2018-2019 AT&T Intellectual Property.
+ *
+ * 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.services.execution.scripts
+
+import io.grpc.ServerBuilder
+import io.grpc.stub.StreamObserver
+import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
+import org.onap.ccsdk.cds.controllerblueprints.common.api.Status
+import org.onap.ccsdk.cds.controllerblueprints.core.logger
+import org.onap.ccsdk.cds.controllerblueprints.processing.api.BluePrintProcessingServiceGrpc
+import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput
+import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceOutput
+
+private val log = logger(MockBluePrintProcessingServer::class)
+
+
+class MockBluePrintProcessingServer : BluePrintProcessingServiceGrpc.BluePrintProcessingServiceImplBase() {
+
+    override fun process(responseObserver: StreamObserver<ExecutionServiceOutput>): StreamObserver<ExecutionServiceInput> {
+
+        return object : StreamObserver<ExecutionServiceInput> {
+            override fun onNext(executionServiceInput: ExecutionServiceInput) {
+                log.info("Received requestId(${executionServiceInput.commonHeader.requestId})  " +
+                        "subRequestId(${executionServiceInput.commonHeader.subRequestId})")
+                responseObserver.onNext(buildNotification(executionServiceInput))
+                responseObserver.onNext(buildResponse(executionServiceInput))
+                responseObserver.onCompleted()
+            }
+
+            override fun onError(error: Throwable) {
+                log.debug("Fail to process message", error)
+                responseObserver.onError(io.grpc.Status.INTERNAL
+                        .withDescription(error.message)
+                        .asException())
+            }
+
+            override fun onCompleted() {
+                log.info("Completed")
+            }
+        }
+    }
+
+
+    private fun buildNotification(input: ExecutionServiceInput): ExecutionServiceOutput {
+        val status = Status.newBuilder()
+                .setEventType(EventType.EVENT_COMPONENT_NOTIFICATION)
+                .build()
+        return ExecutionServiceOutput.newBuilder()
+                .setCommonHeader(input.commonHeader)
+                .setActionIdentifiers(input.actionIdentifiers)
+                .setStatus(status)
+                .build()
+    }
+
+    private fun buildResponse(input: ExecutionServiceInput): ExecutionServiceOutput {
+
+        val status = Status.newBuilder().setCode(200)
+                .setEventType(EventType.EVENT_COMPONENT_EXECUTED)
+                .build()
+        return ExecutionServiceOutput.newBuilder()
+                .setCommonHeader(input.commonHeader)
+                .setActionIdentifiers(input.actionIdentifiers)
+                .setStatus(status)
+                .build()
+
+    }
+}
+
+/** For Integration testing stat this server */
+fun main() {
+    try {
+        val server = ServerBuilder
+                .forPort(50052)
+                .addService(MockBluePrintProcessingServer())
+                .build()
+        server.start()
+        log.info("GRPC Serve started(${server.isShutdown}) on port(${server.port})...")
+        server.awaitTermination()
+    } catch (e: Exception) {
+        e.printStackTrace()
+    }
+
+}
\ No newline at end of file
diff --git a/ms/blueprintsprocessor/modules/services/execution-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/StreamingRemoteExecutionServiceTest.kt b/ms/blueprintsprocessor/modules/services/execution-service/src/test/kotlin/org/onap/ccsdk/cds/blueprintsprocessor/services/execution/StreamingRemoteExecutionServiceTest.kt
new file mode 100644 (file)
index 0000000..29d24c6
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright © 2018-2019 AT&T Intellectual Property.
+ *
+ * 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.services.execution
+
+import io.grpc.inprocess.InProcessChannelBuilder
+import io.grpc.inprocess.InProcessServerBuilder
+import io.grpc.testing.GrpcCleanupRule
+import io.mockk.coEvery
+import io.mockk.mockk
+import io.mockk.spyk
+import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.collect
+import org.junit.Rule
+import org.junit.Test
+import org.onap.ccsdk.cds.blueprintsprocessor.grpc.GRPCLibConstants
+import org.onap.ccsdk.cds.blueprintsprocessor.grpc.TokenAuthGrpcClientProperties
+import org.onap.ccsdk.cds.blueprintsprocessor.grpc.service.BluePrintGrpcLibPropertyService
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.MockBluePrintProcessingServer
+import org.onap.ccsdk.cds.controllerblueprints.common.api.ActionIdentifiers
+import org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader
+import org.onap.ccsdk.cds.controllerblueprints.common.api.EventType
+import org.onap.ccsdk.cds.controllerblueprints.core.logger
+import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput
+import java.util.*
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+
+
+class StreamingRemoteExecutionServiceTest {
+
+    val log = logger(StreamingRemoteExecutionServiceTest::class)
+
+    @get:Rule
+    val grpcCleanup = GrpcCleanupRule()
+    private val serverName = InProcessServerBuilder.generateName()
+    private val serverBuilder = InProcessServerBuilder.forName(serverName).directExecutor()
+    private val channelBuilder = InProcessChannelBuilder.forName(serverName).directExecutor()
+
+    private val tokenAuthGrpcClientProperties = TokenAuthGrpcClientProperties().apply {
+        host = "127.0.0.1"
+        port = 50052
+        type = GRPCLibConstants.TYPE_TOKEN_AUTH
+        token = "Basic Y2NzZGthcHBzOmNjc2RrYXBwcw=="
+    }
+
+    @Test
+    @ExperimentalCoroutinesApi
+    @FlowPreview
+    fun testStreamingChannel() {
+        grpcCleanup.register(serverBuilder.addService(MockBluePrintProcessingServer()).build().start())
+        val channel = grpcCleanup.register(channelBuilder.maxInboundMessageSize(1024).build())
+
+        runBlocking {
+            val bluePrintGrpcLibPropertyService = BluePrintGrpcLibPropertyService(mockk())
+
+            val streamingRemoteExecutionService = StreamingRemoteExecutionServiceImpl(bluePrintGrpcLibPropertyService)
+
+            val spyStreamingRemoteExecutionService = spyk(streamingRemoteExecutionService)
+            /** To test with real server, uncomment below line */
+            coEvery() { spyStreamingRemoteExecutionService.createGrpcChannel(any()) } returns channel
+
+            /** Test Send and Receive non interactive transaction */
+            val nonInteractiveDeferred = arrayListOf<Deferred<*>>()
+            repeat(2) { count ->
+                val requestId = "1234-$count"
+                val request = getRequest(requestId)
+                val invocationId = request.commonHeader.subRequestId
+                val deferred = async {
+                    val response = spyStreamingRemoteExecutionService.sendNonInteractive(tokenAuthGrpcClientProperties,
+                            invocationId, request, 1000L)
+                    assertNotNull(response, "failed to get non interactive response")
+                    assertEquals(response.commonHeader.requestId, requestId,
+                            "failed to match non interactive response id")
+                    assertEquals(response.status.eventType, EventType.EVENT_COMPONENT_EXECUTED,
+                            "failed to match non interactive response type")
+                }
+                nonInteractiveDeferred.add(deferred)
+
+            }
+            nonInteractiveDeferred.awaitAll()
+
+            /** Test Send and Receive interactive transaction */
+            val responseFlowsDeferred = arrayListOf<Deferred<*>>()
+            repeat(2) { count ->
+                val requestId = "12345-$count"
+                val request = getRequest(requestId)
+                val invocationId = request.commonHeader.requestId
+                val responseFlow = spyStreamingRemoteExecutionService
+                        .openSubscription(tokenAuthGrpcClientProperties, invocationId)
+
+                val deferred = async {
+                    responseFlow.collect {
+                        log.info("Received $count-response ($invocationId) : ${it.status.eventType}")
+                        if (it.status.eventType == EventType.EVENT_COMPONENT_EXECUTED) {
+                            spyStreamingRemoteExecutionService.cancelSubscription(invocationId)
+                        }
+                    }
+                }
+                responseFlowsDeferred.add(deferred)
+                /** Sending Multiple messages with same requestId  and different subRequestId */
+                spyStreamingRemoteExecutionService.send(invocationId, request)
+            }
+            responseFlowsDeferred.awaitAll()
+            streamingRemoteExecutionService.closeChannel(tokenAuthGrpcClientProperties)
+        }
+
+    }
+
+    private fun getRequest(requestId: String): ExecutionServiceInput {
+        val commonHeader = CommonHeader.newBuilder()
+                .setTimestamp("2012-04-23T18:25:43.511Z")
+                .setOriginatorId("System")
+                .setRequestId(requestId)
+                .setSubRequestId("$requestId-" + UUID.randomUUID().toString()).build()
+
+
+        val actionIdentifier = ActionIdentifiers.newBuilder()
+                .setActionName("SampleScript")
+                .setBlueprintName("sample-cba")
+                .setBlueprintVersion("1.0.0")
+                .build()
+
+        return ExecutionServiceInput.newBuilder()
+                .setCommonHeader(commonHeader)
+                .setActionIdentifiers(actionIdentifier)
+                //.setPayload(payloadBuilder.build())
+                .build()
+
+    }
+}
\ No newline at end of file
index 16e4e61..2fc9a99 100644 (file)
@@ -95,7 +95,7 @@ class AbstractComponentFunctionTest {
     @Test
     fun testComponentFunctionPayload() {
         val sampleComponent = SampleComponent()
-        sampleComponent.operationName = "sample-action"
+        sampleComponent.workflowName = "sample-action"
         sampleComponent.executionServiceInput = JacksonUtils.readValueFromClassPathFile(
             "payload/requests/sample-execution-request.json", ExecutionServiceInput::class.java)!!
         val payload = sampleComponent.requestPayload()
index 703a526..afe10b3 100644 (file)
@@ -19,7 +19,7 @@
         <!-- encoders are assigned the type
              ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
         <encoder>
-            <pattern>%d{HH:mm:ss.SSS} %-5level %logger{100} - %msg%n</pattern>
+            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
         </encoder>
     </appender>
 
index ac123cb..37a0712 100755 (executable)
                 <version>${project.version}</version>
             </dependency>
 
+            <!--
             <dependency>
                 <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId>
                 <artifactId>health-api</artifactId>
                 <version>${project.version}</version>
             </dependency>
+            -->
 
             <!-- North Bound -->
             <dependency>
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/MDCContext.kt b/ms/controllerblueprints/modules/blueprint-core/src/main/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/MDCContext.kt
new file mode 100644 (file)
index 0000000..001ec75
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2018-2019 AT&T Intellectual Property.
+ *
+ * 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.controllerblueprints.core
+
+import kotlinx.coroutines.ThreadContextElement
+import org.slf4j.MDC
+import kotlin.coroutines.AbstractCoroutineContextElement
+import kotlin.coroutines.CoroutineContext
+
+typealias MDCContextMap = Map<String, String>?
+
+class MDCContext(private val contextMap: MDCContextMap = MDC.getCopyOfContextMap()) :
+        ThreadContextElement<MDCContextMap>, AbstractCoroutineContextElement(Key) {
+    /**
+     * Key of [MDCContext] in [CoroutineContext].
+     */
+    companion object Key : CoroutineContext.Key<MDCContext>
+
+    override fun updateThreadContext(context: CoroutineContext): MDCContextMap {
+        val oldState = MDC.getCopyOfContextMap()
+        setCurrent(contextMap)
+        return oldState
+    }
+
+    override fun restoreThreadContext(context: CoroutineContext, oldState: MDCContextMap) {
+        setCurrent(oldState)
+    }
+
+    private fun setCurrent(contextMap: MDCContextMap) {
+        if (contextMap == null) {
+            MDC.clear()
+        } else {
+            MDC.setContextMap(contextMap)
+        }
+    }
+}
\ No newline at end of file
diff --git a/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/MDCContextTest.kt b/ms/controllerblueprints/modules/blueprint-core/src/test/kotlin/org/onap/ccsdk/cds/controllerblueprints/core/MDCContextTest.kt
new file mode 100644 (file)
index 0000000..2ddb450
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2018-2019 AT&T Intellectual Property.
+ *
+ * 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.controllerblueprints.core
+
+import kotlinx.coroutines.GlobalScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.junit.After
+import org.junit.Before
+import org.slf4j.MDC
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
+class MDCContextTest {
+    val log = logger(MDCContextTest::class)
+    @Before
+    fun setup() {
+        MDC.clear()
+    }
+
+    @After
+    fun tearDow() {
+        MDC.clear()
+    }
+
+    @Test
+    fun testContextCanBePassedBetweenCoroutines() {
+        MDC.put(BluePrintConstants.RESPONSE_HEADER_TRANSACTION_ID, "12345")
+        runBlocking {
+            GlobalScope.launch {
+                assertEquals(null, MDC.get(BluePrintConstants.RESPONSE_HEADER_TRANSACTION_ID))
+            }
+            launch(MDCContext()) {
+                assertEquals("12345", MDC.get(BluePrintConstants.RESPONSE_HEADER_TRANSACTION_ID),
+                        "couldn't get request id")
+
+                MDC.put("client_id", "client-1")
+                assertEquals("client-1", MDC.get("client_id"), "couldn't get client id")
+            }
+        }
+    }
+}
\ No newline at end of file
index 0c432d4..f1f29a0 100644 (file)
@@ -46,4 +46,4 @@ class BluePrintProcessingServer(BluePrintProcessing_pb2_grpc.BluePrintProcessing
             # Get the Dynamic Process Instance based on request
             instance: AbstractScriptFunction = instance_for_input(self.configuration, request)
             instance.set_context(context)
-            return instance.process(request)
+            yield from instance.process(request)
index 224e35e..44b6d8e 100644 (file)
@@ -29,7 +29,7 @@ logger = logging.getLogger("Utils")
 
 def current_time():
     ts = time.time()
-    return datetime.datetime.fromtimestamp(ts).strftime("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
+    return datetime.datetime.fromtimestamp(ts).strftime("%Y-%m-%dT%H:%M:%S.%fZ")
 
 
 def blueprint_id(input: ExecutionServiceInput):
diff --git a/ms/py-executor/dc/docker-compose.yaml b/ms/py-executor/dc/docker-compose.yaml
new file mode 100755 (executable)
index 0000000..7600941
--- /dev/null
@@ -0,0 +1,23 @@
+version: '3.3'
+
+services:
+  py-executor:
+    image: onap/ccsdk-py-executor
+    container_name: bp-py-executor
+    ports:
+      - "50052:50052"
+    restart: always
+    volumes:
+      - blueprints-deploy:/opt/app/onap/blueprints/deploy
+    environment:
+      APPLICATIONNAME: PythonExecutor
+      BUNDLEVERSION: 1.0.0
+      APP_CONFIG_HOME: /opt/app/onap/config
+      STICKYSELECTORKEY:
+      ENVCONTEXT: dev
+      APP_PORT: 50052
+      BASIC_AUTH: Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==
+      LOG_FILE: /opt/app/onap/logs/application.log
+
+volumes:
+  blueprints-deploy:
index 1121805..b49daf6 100644 (file)
@@ -11,8 +11,8 @@ RUN tar -xzf /source.tar.gz -C /tmp \
  && rm -rf /source.tar.gz \
  && rm -rf /tmp/@project.build.finalName@
 
-RUN pip install --no-cache-dir -r /opt/app/onap/requirements.txt
+RUN pip install --no-cache-dir -r /opt/app/onap/python/requirements.txt
 
 VOLUME /opt/app/onap/blueprints/deploy/
 
-ENTRYPOINT /opt/app/onap/start.sh
\ No newline at end of file
+ENTRYPOINT /opt/app/onap/python/start.sh
\ No newline at end of file
index 8bd06c8..6235a7b 100755 (executable)
         </fileSet>
         <fileSet>
             <directory>${project.basedir}</directory>
-            <outputDirectory>opt/app/onap</outputDirectory>
+            <outputDirectory>opt/app/onap/python</outputDirectory>
             <includes>
                 <include>requirements.txt</include>
                 <include>configuration.ini</include>
             </includes>
             <useDefaultExcludes>true</useDefaultExcludes>
+            <fileMode>0666</fileMode>
         </fileSet>
         <fileSet>
             <directory>${project.basedir}/docker</directory>
-            <outputDirectory>opt/app/onap</outputDirectory>
+            <outputDirectory>opt/app/onap/python</outputDirectory>
             <includes>
                 <include>*.sh</include>
             </includes>
             <useDefaultExcludes>true</useDefaultExcludes>
+            <fileMode>0755</fileMode>
         </fileSet>
     </fileSets>
 </assembly>
\ No newline at end of file
index 6051e04..b556369 100644 (file)
@@ -2,5 +2,4 @@ grpcio==1.23.0
 grpcio-tools==1.23.0
 configparser==4.0.2
 requests==2.22.0
-ncclient==0.6.6
-ciscoconfparse==1.4.7
\ No newline at end of file
+ncclient==0.6.6
\ No newline at end of file