<goal>execute</goal>
</goals>
<configuration>
- <source>../TagVersion.groovy</source>
+ <source>${project.basedir}/../../TagVersion.groovy</source>
</configuration>
</execution>
</executions>
<name>${image.name}</name>
<build>
<cleanup>try</cleanup>
- <dockerFileDir>..</dockerFileDir>
<tags>
<tag>${project.docker.latestminortag.version}</tag>
<tag>${project.docker.latestfulltag.version}</tag>
<!-- <div style="width:inherit; height: inherit; position: fixed;z-index: 1; background-color: rgb(0,0,0);background-color: rgba(0,0,0,0.4);"></div> -->
<div style="display: flex;">
<div>
- <i class="fa fa-folder" aria-hidden="true" style="color:#3f51b5; font-size: 20px;margin: 3px; cursor: pointer;" (click)="enableNameInputEl('createFolder')"></i>
- <i class="fa fa-file" aria-hidden="true" style="color:#3f51b5; font-size: 18px; margin: 3px; cursor: pointer;" (click)="enableNameInputEl('createFile')"></i>
- <i class="fa fa-trash" aria-hidden="true" style="color:#3f51b5; font-size: 20px; margin: 3px; cursor: pointer;" (click)="deleteFolderOrFile('deleteFile')"></i>
+ <i class="fa fa-folder" aria-hidden="true" style="color:#3f51b5; font-size: 20px;margin: 3px; cursor: pointer;" [ngClass] ="{'fa-disabled': selectedFileObj.type == 'file' || selectedFileObj.type == ''}" (click)="enableNameInputEl('createFolder')"></i>
+ <i class="fa fa-file" aria-hidden="true" style="color:#3f51b5; font-size: 18px; margin: 3px; cursor: pointer;" [ngClass] ="{'fa-disabled' : selectedFileObj.type == 'file' ||selectedFileObj.type == ''}" (click)="enableNameInputEl('createFile')"></i>
+ <i class="fa fa-trash" aria-hidden="true" style="color:#3f51b5; font-size: 20px; margin: 3px; cursor: pointer;" [ngClass] ="{'fa-disabled' : selectedFileObj.type == ''}" (click)="deleteFolderOrFile('deleteFile')"></i>
</div>
<div>
<input *ngIf="isNameTextboxEnablled" type="text" (focusout)="createFolderOrFile($event)"/>
.background-highlight {
background-color: #3f51b5 !important;
color: white !important;
+ }
+
+ .fa-disabled {
+ opacity: 0.6;
+ pointer-events: none;
+ }
+
+ .mat-tree-node {
+ min-height: 40px !important;
}
\ No newline at end of file
activeNode: any;
selectedFolder: string;
activationBlueprint: string;
- isNameTextboxEnablled : boolean = false;
- fileAction : string;
- filetoDelete : string;
+ isNameTextboxEnablled: boolean = false;
+ fileAction: string;
+ filetoDelete: string;
+ currentFilePath: string = '';
+ selectedFileObj = { name: '', type: '' };
private transformer = (node: Node, level: number) => {
return {
this.dataSource.data = this.filesTree;
}
- fileClicked(file) {
- console.log('selected file:' + file);
- }
editorContent() {
this.editor.setTheme("eclipse");
this.editor.getEditor().setOptions({
this.filesData.forEach(fileNode => {
if (this.selectedFile && fileNode.name.includes(this.blueprintName.trim()) && fileNode.name.includes(this.selectedFile.trim())) {
fileNode.data = this.text;
- } else if (this.selectedFile && fileNode.name.includes(this.selectedFile.trim())) {
+ } else if (this.selectedFile && fileNode.name.includes(this.currentFilePath)) {
+ // this.selectedFile && fileNode.name.includes(this.selectedFile.trim())) {
fileNode.data = this.text;
}
});
}
selectFileToView(file) {
+ this.currentFilePath = '';
+ this.expandParents(file);
+ this.selectedFileObj.name = file.name;
+ this.selectedFileObj.type = 'file';
this.selectedFile = file.name;
this.filetoDelete = file.name;
+ this.currentFilePath = this.currentFilePath + this.selectedFile;
this.filesData.forEach((fileNode) => {
if (fileNode.name.includes(file.name)) {
this.text = fileNode.data;
}
selectFolder(node) {
+ this.currentFilePath = '';
+ this.expandParents(node);
this.selectedFolder = node.name;
this.filetoDelete = node.name;
- console.log(node);
- // this.createFolderOrFile(node.name, 'folder');
+ this.selectedFileObj.name = node.name;
+ this.selectedFileObj.type = 'folder';
+ this.currentFilePath = this.currentFilePath + this.selectedFolder + '/';
}
createFolderOrFile(name) {
- let newFilesData: [any] = this.filesData;
- let newFileNode = {
- name: '',
- data: ''
- }
- let newFileNode1 = {
- name: '',
- data: ''
- }
- for(let i=0; i< this.filesData.length; i++) {
- if (this.filesData[i].name.includes(this.selectedFolder)) {
- if(this.fileAction == 'createFolder') {
- newFileNode.name = this.filesData[i].name + name.srcElement.value + '/';
- newFileNode.data = '';
-
- newFileNode1.name = this.filesData[i].name + name.srcElement.value + '/README.md'
- newFileNode1.data = name.srcElement.value + ' Folder';
- } else {
- newFileNode.name = this.filesData[i].name + name.srcElement.value;
- newFileNode.data = '';
- }
- break;
+ if (name && name.srcElement.value !== null && name.srcElement.value !== '') {
+ let newFilesData: [any] = this.filesData;
+ let newFileNode = {
+ name: '',
+ data: ''
+ }
+ let newFileNode1 = {
+ name: '',
+ data: ''
+ }
+ if (this.fileAction == 'createFolder') {
+ newFileNode.name = this.currentFilePath + name.srcElement.value + '/'
+ newFileNode.data = '';
+ newFileNode1.name = this.currentFilePath + name.srcElement.value + '/README.md'
+ newFileNode1.data = name.srcElement.value + ' Folder';
+ this.filesData.push(newFileNode);
+ this.filesData.push(newFileNode1);
+ } else {
+ newFileNode.name = this.currentFilePath + name.srcElement.value;
+ newFileNode.data = '';
+ this.filesData.push(newFileNode);
}
+ this.arrangeTreeData(this.filesData);
}
-
- this.filesData.splice(this.findIndexForNewNode()+1, 0, newFileNode);
- this.filesData.splice(this.findIndexForNewNode()+1, 0, newFileNode1);
- this.arrangeTreeData(this.filesData);
}
findIndexForNewNode() {
let indexForNewNode;
- for(let i=0; i< this.filesData.length; i++) {
+ for (let i = 0; i < this.filesData.length; i++) {
if (this.filesData[i].name.includes(this.selectedFolder)) {
- indexForNewNode = i;
+ indexForNewNode = i;
}
}
return indexForNewNode;
paths.forEach((path) => {
const pathParts = path.name.split('/');
- // pathParts.shift();
let currentLevel = tree;
pathParts.forEach((part) => {
name: part,
children: [],
data: path.data,
- path : path.name
+ path: path.name
};
- if(part.trim() == this.blueprintName.trim()) {
- this.activationBlueprint = path.data;
- newPart.data = JSON.parse(this.activationBlueprint.toString());
+ if (part.trim() == this.blueprintName.trim()) {
+ this.activationBlueprint = path.data;
+ newPart.data = JSON.parse(this.activationBlueprint.toString());
console.log('newpart', newPart);
}
- if(newPart.name !== '') {
- currentLevel.push(newPart);
- currentLevel = newPart.children;
+ if (newPart.name !== '') {
+ currentLevel.push(newPart);
+ currentLevel = newPart.children;
}
}
});
this.updateBlueprint();
}
- enableNameInputEl(action) {
+ enableNameInputEl(action) {
this.fileAction = action;
- if (action == 'createFolder' || action == 'createFile') {
+ if (action == 'createFolder' || action == 'createFile') {
this.isNameTextboxEnablled = true;
}
}
deleteFolderOrFile(action) {
- for(let i=0;i< this.filesData.length ; i++) {
- if(this.filesData[i].name.includes(this.filetoDelete.trim())) {
+ for (let i = 0; i < this.filesData.length; i++) {
+ if (this.filesData[i].name.includes(this.filetoDelete.trim()) && this.filesData[i].name.includes(this.currentFilePath)) {
this.filesData.splice(i, 1);
- i = i-1;
+ i = i - 1;
}
}
this.arrangeTreeData(this.filesData);
}
+
+ expandParents(node) {
+ const parent = this.getParent(node);
+ this.treeControl.expand(parent);
+
+ if (parent && parent.level > 0) {
+ this.expandParents(parent);
+ }
+
+ console.log(this.currentFilePath);
+ }
+
+ getParent(node) {
+ const { treeControl } = this;
+ const currentLevel = treeControl.getLevel(node);
+
+ if (currentLevel < 1) {
+ // this.currentFilePath = this.currentFilePath + this.selectedFolder;
+ return null;
+ }
+
+ const startIndex = treeControl.dataNodes.indexOf(node) - 1;
+
+ for (let i = startIndex; i >= 0; i--) {
+ const currentNode = treeControl.dataNodes[i];
+
+ if (treeControl.getLevel(currentNode) < currentLevel) {
+ this.currentFilePath = currentNode.name + '/' + this.currentFilePath;
+ return currentNode;
+ }
+ }
+ }
}
<div style="width: 100%;height: 3em;">
<div style="display: flex;flex-direction: row-reverse">
<button class="btn-active" (click)="downloadCBA()">Download</button>
- <button [disabled]="!isEnriched" [ngClass]="{ 'mat-button-active': isEnriched, 'mat-button-disablled': !isEnriched}" mat-button [matMenuTriggerFor]="menu">Deploy</button>
+ <button class="mat-button-active" mat-button [matMenuTriggerFor]="menu">Deploy</button>
<mat-menu #menu="matMenu">
<button mat-menu-item>Deploy</button>
<button mat-menu-item>Test</button>
</mat-menu>
- <button [disabled]="!isEnriched" [ngClass]="{ 'btn-active': isEnriched, 'btn-disablled': !isEnriched}" class="btn-active">Publish</button>
+ <button [disabled]="!isEnriched" class="btn-active">Publish</button>
<button class="btn-active">Save</button>
<button class="btn-active">Enrich</button>
<parent>
<groupId>org.onap.ccsdk.parent</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
- <version>1.2.1-SNAPSHOT</version>
+ <version>1.2.2-SNAPSHOT</version>
<relativePath/>
</parent>
"version": "1.0.0",
"derived_from": "tosca.nodes.Root"
},
- "tosca.nodes.DG": {
+ "tosca.nodes.Workflow": {
"description": "This is Directed Graph Node Type",
"version": "1.0.0",
"derived_from": "tosca.nodes.Root"
}
}
},
- "derived_from": "tosca.nodes.DG"
+ "derived_from": "tosca.nodes.Workflow"
},
"artifact-config-template": {
"description": "This is Configuration Velocity Template",
}
}
},
- "derived_from": "tosca.nodes.DG"
+ "derived_from": "tosca.nodes.Workflow"
},
"source-capability": {
"description": "This is Component Resource Source Node Type",
"version": "1.0.0",
"derived_from": "tosca.nodes.Root"
},
- "tosca.nodes.DG": {
+ "tosca.nodes.Workflow": {
"description": "This is Directed Graph Node Type",
"version": "1.0.0",
"derived_from": "tosca.nodes.Root"
}
}
},
- "derived_from" : "tosca.nodes.DG"
+ "derived_from" : "tosca.nodes.Workflow"
},
"source-input" : {
"description" : "This is Input Resource Source Node Type",
"version" : "1.0.0",
"derived_from" : "tosca.nodes.Root"
},
- "tosca.nodes.DG" : {
+ "tosca.nodes.Workflow" : {
"description" : "This is Directed Graph Node Type",
"version" : "1.0.0",
"derived_from" : "tosca.nodes.Root"
}
}
},
- "derived_from" : "tosca.nodes.DG"
+ "derived_from" : "tosca.nodes.Workflow"
},
"source-input" : {
"description" : "This is Input Resource Source Node Type",
"version" : "1.0.0",
"derived_from" : "tosca.nodes.Root"
},
- "tosca.nodes.DG" : {
+ "tosca.nodes.Workflow" : {
"description" : "This is Directed Graph Node Type",
"version" : "1.0.0",
"derived_from" : "tosca.nodes.Root"
# limitations under the License.
# ============LICENSE_END=========================================================
-from time import sleep
-
from org.onap.ccsdk.cds.blueprintsprocessor.functions.restconf.executor import \
RestconfComponentFunction
from java.lang import Exception as JavaException
+from restconf_client import RestconfClient
+
class RestconfConfigDeploy(RestconfComponentFunction):
log = globals()["log"]
- odl_status_check_limit = 10
- odl_status_check_pause = 1
- odl_status_check_url = "restconf/operational/network-topology:network-topology/topology/topology-netconf/node/"
- base_odl_url = "restconf/config/network-topology:network-topology/topology/topology-netconf/node/"
- server_identifier = "sdncodl"
configlet_template_name = "config-assign"
- configlet_odl_resource = "/yang-ext:mount/mynetconf:netconflist"
+ configlet_resource_path = "/yang-ext:mount/mynetconf:netconflist"
+ restconf_server_identifier = "sdncodl"
def process(self, execution_request):
self.log.info("Started execution of process method")
try:
+ restconf_client = RestconfClient(self.log, self)
pnf_id, resolution_key = self.retrieve_parameters(execution_request)
- self.interact_with_odl(pnf_id, resolution_key)
+ web_client_service = self.restClientService(self.restconf_server_identifier)
+
+ try:
+ mount_payload = self.resolveAndGenerateMessage("config-deploy-mapping", "config-deploy-template")
+ restconf_client.mount_device(web_client_service, pnf_id, mount_payload)
+
+ configlet = self.resolveFromDatabase(resolution_key, self.configlet_template_name)
+ restconf_client.configure_device(web_client_service, pnf_id, self.configlet_resource_path, configlet)
+ except Exception, err:
+ self.log.error("an error occurred while configuring device {}", err)
+ raise err
+ finally:
+ restconf_client.unmount_device(web_client_service, pnf_id)
+
except JavaException, err:
self.log.error("Java Exception in the script", err)
raise err
self.log.info("pnf-id: {}", pnf_id)
return pnf_id, resolution_key
- def interact_with_odl(self, pnf_id, resolution_key):
- try:
- self.mount(pnf_id)
- self.log_current_configlet(pnf_id)
- self.apply_configuration(pnf_id, resolution_key, self.configlet_template_name)
- except Exception, err:
- self.log.error("an error occurred while configuring device {}", err)
- raise err
- finally:
- self.log.info("unmounting device {}", pnf_id)
- self.unmount(pnf_id)
-
- def mount(self, pnf_id):
- self.log.info("mounting device {}", pnf_id)
- mount_payload = self.resolveAndGenerateMessage("config-deploy-mapping", "config-deploy-template")
- self.log.info("mount payload: \n {}", mount_payload)
- headers = {"Content-Type": "application/xml"} # defining custom header
- url = self.base_odl_url + str(pnf_id)
- self.log.info("sending mount request, url: {}", url)
- web_client_service = self.restClientService(self.server_identifier)
- web_client_service.exchangeResource("PUT", url, mount_payload, headers)
- self.wait_for_odl_to_mount(pnf_id)
-
- def wait_for_odl_to_mount(self, pnf_id):
- counter = 0
- url = self.odl_status_check_url + pnf_id
- self.log.info("url for ODL status check: {}", url)
- web_client_service = self.restClientService(self.server_identifier)
- expected_result = '"netconf-node-topology:connection-status":"connected"'
- while counter < self.odl_status_check_limit:
- result = web_client_service.exchangeResource("GET", url, "")
- self.log.info("ODL status check result: {}", result)
- if expected_result in result:
- self.log.info("PNF was mounted successfully on ODL")
- return None
- sleep(1)
- counter += 1
- raise JavaException("PNF was not mounted on ODL, aborting configuration procedure")
-
- def log_current_configlet(self, pnf_id):
- self.log.info("retrieving configuration for device {}", pnf_id)
- url = self.base_odl_url + pnf_id + self.configlet_odl_resource
- self.log.info("sending GET request, url: {}", url)
- web_client_service = self.restClientService(self.server_identifier)
- result = web_client_service.exchangeResource("GET", url, "")
- self.log.info("Current configuration: {}", result)
-
- def apply_configuration(self, pnf_id, resolution_key, template_name):
- self.log.info("configuring device {}", pnf_id)
- self.log.info("Retrieving configlet from database (resolution-key: {}, template_name: {}",
- resolution_key, template_name)
- configlet = self.resolveFromDatabase(resolution_key, template_name)
- self.log.info("Configlet: {}", configlet)
- headers = { "Content-Type": "application/yang.patch+json" } # defining custom header
- url = self.base_odl_url + pnf_id + self.configlet_odl_resource
- self.log.info("sending patch request, url: {}", url)
- web_client_service = self.restClientService(self.server_identifier)
- result = web_client_service.exchangeResource("PATCH", url, configlet, headers)
- self.log.info("Configuration application result: {}", result)
-
- def unmount(self, pnf_id):
- url = self.base_odl_url + str(pnf_id)
- self.log.info("sending unmount request, url: {}", url)
- web_client_service = self.restClientService(self.server_identifier)
- web_client_service.exchangeResource("DELETE", url, "")
-
def recover(self, runtime_exception, execution_request):
self.log.info("Recover function called!")
- self.log.error(runtime_exception.getMessage())
+ self.log.info("Execution request", execution_request)
+ self.log.error("Exception", runtime_exception)
print self.bluePrintRuntimeService.getBluePrintError().addError(runtime_exception.getMessage())
- return None
\ No newline at end of file
+ return None
+++ /dev/null
-{
- "artifact_types" : { }
-}
\ No newline at end of file
+++ /dev/null
-{
- "tosca_definitions_version": "controller_blueprint_1_0_0",
- "metadata": {
- "template_author": "Brinda Santh <brindasanth@in.ibm.com>",
- "template_name": "component_invoke",
- "template_version": "1.0.0",
- "template_tags": "brinda, component_invoke"
- },
- "imports": [
- {
- "file": "Definitions/data_types.json"
- },
- {
- "file": "Definitions/relationship_types.json"
- },
- {
- "file": "Definitions/artifact_types.json"
- },
- {
- "file": "Definitions/node_types.json"
- },
- {
- "file": "Definitions/policy_types.json"
- }
- ],
- "topology_template": {
- "workflows": {
- "component-invoke": {
- "steps": {
- "activate-process": {
- "description": "Sample Component Invocation flow",
- "target": "sample-component",
- "activities": [
- {
- "call_operation": "sample-component"
- }
- ]
- }
- },
- "inputs": {
- "request-id": {
- "required": true,
- "type": "string"
- },
- "action-name": {
- "required": true,
- "type": "string"
- },
- "scope-type": {
- "required": true,
- "type": "string"
- },
- "hostname": {
- "required": true,
- "type": "string"
- }
- },
- "outputs": {
- "response-property1": {
- "type": "string",
- "value": "executed"
- },
- "response-property2": {
- "type": "string",
- "value": {
- "get_input": "action-name"
- }
- }
- }
- }
- },
- "node_templates": {
- "sample-component": {
- "type": "component-sample-executor",
- "interfaces": {
- "ComponentSampleExecutor": {
- "operations": {
- "process": {
- "inputs": {
- "sample-property": "sample-value",
- "sample-list-property": [
- "json-parser-service"
- ],
- "dynamic-properties": {
- "prop1": "prop1-value",
- "prop2": "prop2-value"
- }
- },
- "outputs": {
- "response-data": "",
- "status": ""
- }
- }
- }
- }
- }
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-{
- "data_types" : { }
-}
\ No newline at end of file
+++ /dev/null
-{
- "node_types": {
- "component-sample-executor": {
- "description": "This is Sample Component API",
- "version": "1.0.0",
- "interfaces": {
- "ComponentSampleExecutor": {
- "operations": {
- "process": {
- "inputs": {
- "sample-property": {
- "description": "Sample Property.",
- "required": true,
- "type": "string"
- },
- "sample-list-property": {
- "description": "Dependent Step Components NodeTemplate name.",
- "required": true,
- "type": "list",
- "entry_schema": {
- "type": "string"
- }
- },
- "dynamic-properties": {
- "description": "Dynamic Json Content or DSL Json reference.",
- "required": false,
- "type": "json"
- }
- },
- "outputs": {
- "response-data": {
- "description": "Execution Response Data in JSON format.",
- "required": false,
- "type": "string"
- },
- "status": {
- "description": "Status of the Component Execution ( success or failure )",
- "required": true,
- "type": "string"
- }
- }
- }
- }
- }
- },
- "derived_from": "tosca.nodes.Component"
- },
- "tosca.nodes.Component": {
- "description": "This is default Component Node",
- "version": "1.0.0",
- "derived_from": "tosca.nodes.Root"
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-{
- "policy_types" : { }
-}
\ No newline at end of file
+++ /dev/null
-{
- "relationship_types" : { }
-}
\ No newline at end of file
+++ /dev/null
-{ }
\ No newline at end of file
+++ /dev/null
-TOSCA-Meta-File-Version: 1.0.0
-CSAR-Version: 1.0
-Created-By: Brinda Santh <brindasanth@in.ibm.com>
-Entry-Definitions: Definitions/component_invoke.json
-Template-Tags: Brinda Santh, component_invoke
\ No newline at end of file
}
}
},
- "derived_from" : "tosca.nodes.DG"
+ "derived_from" : "tosca.nodes.Workflow"
},
"source-capability" : {
"description" : "This is Component Resource Source Node Type",
"version" : "1.0.0",
"derived_from" : "tosca.nodes.Root"
},
- "tosca.nodes.DG" : {
+ "tosca.nodes.Workflow" : {
"description" : "This is Directed Graph Node Type",
"version" : "1.0.0",
"derived_from" : "tosca.nodes.Root"
+++ /dev/null
-{\r
- "description": "This is Configuration Velocity Template",\r
- "version": "1.0.0",\r
- "properties": {\r
- "action-names": {\r
- "required": true,\r
- "type": "list",\r
- "entry_schema": {\r
- "type": "string"\r
- }\r
- }\r
- },\r
- "capabilities": {\r
- "content": {\r
- "type": "tosca.capabilities.Content",\r
- "properties": {\r
- "content": {\r
- "required": true,\r
- "type": "string"\r
- }\r
- }\r
- },\r
- "mapping": {\r
- "type": "tosca.capabilities.Mapping",\r
- "properties": {\r
- "mapping": {\r
- "required": false,\r
- "type": "list",\r
- "entry_schema": {\r
- "type": "datatype-resource-assignment"\r
- }\r
- }\r
- }\r
- }\r
- },\r
- "derived_from": "tosca.nodes.Artifact"\r
-}
\ No newline at end of file
+++ /dev/null
-{\r
- "description": "This is Generate Configuration Component API",\r
- "version": "1.0.0",\r
- "capabilities": {\r
- "component-node": {\r
- "type": "tosca.capabilities.Node"\r
- }\r
- },\r
- "interfaces": {\r
- "ConfigGeneratorComponent": {\r
- "operations": {\r
- "process": {\r
- "inputs": {\r
- "template-data": {\r
- "description": "Conditional : JSON string which is used to mash with template. Either template-data or ( resource-id and resource-type ) should be present",\r
- "required": false,\r
- "type": "string"\r
- },\r
- "template-content": {\r
- "description": "Conditional : Dynamic Template used to generate Configuration.",\r
- "required": false,\r
- "type": "string"\r
- },\r
- "resource-type": {\r
- "description": "Conditional : resource-type used to pull the data content from the data base. Either template-data or ( resource-id and resource-type ) should be present",\r
- "required": false,\r
- "type": "string"\r
- },\r
- "request-id": {\r
- "description": "Request Id used to store the generated configuration, in the database along with the template-name",\r
- "required": true,\r
- "type": "string"\r
- },\r
- "resource-id": {\r
- "description": "Conditional : Id used to pull the data content from the data base. Either template-data or ( resource-id and resource-type ) should be present",\r
- "required": false,\r
- "type": "string"\r
- },\r
- "action-name": {\r
- "description": "Conditional : Action Name to get from Database, Either (message & mask-info ) or ( resource-id & resource-type & action-name & template-name ) should be present. Message will be given higest priority",\r
- "required": false,\r
- "type": "string"\r
- },\r
- "template-name": {\r
- "description": "Conditional : Name of the Artifact Node Template, to get the template Content. If template-content is present, then content wont be reterived from the Artifact Node Template.",\r
- "required": true,\r
- "type": "string"\r
- }\r
- },\r
- "outputs": {\r
- "generated-config": {\r
- "description": "Generated Configuration for the Template adn Resource Data",\r
- "required": true,\r
- "type": "string"\r
- },\r
- "mask-info": {\r
- "description": "If template contains mask encription keys, then this mask-info field will be generated, This JSON Content alligns to the bean org.onap.ccsdk.cds.controllerblueprints.core.data.custom.MaskInfo ",\r
- "required": false,\r
- "type": "string"\r
- },\r
- "status": {\r
- "description": "Status of the Component Execution ( success or failure )",\r
- "required": true,\r
- "type": "string"\r
- }\r
- }\r
- }\r
- }\r
- }\r
- },\r
- "derived_from": "tosca.nodes.Component"\r
-}
\ No newline at end of file
}
}
},
- "derived_from": "tosca.nodes.component.Jython"
+ "derived_from": "tosca.nodes.Component"
}
\ No newline at end of file
+++ /dev/null
-{
- "description": "This is Sample Component API",
- "version": "1.0.0",
- "interfaces": {
- "ComponentSampleExecutor": {
- "operations": {
- "process": {
- "inputs": {
- "sample-property": {
- "description": "Sample Property.",
- "required": true,
- "type": "string"
- },
- "sample-list-property": {
- "required": true,
- "description": "Dependent Step Components NodeTemplate name.",
- "type": "list",
- "entry_schema": {
- "type": "string"
- }
- },
- "dynamic-properties": {
- "description": "Dynamic Json Content or DSL Json reference.",
- "required": false,
- "type": "json"
- }
- },
- "outputs": {
- "response-data": {
- "description": "Execution Response Data in JSON format.",
- "required": false,
- "type": "string"
- },
- "status": {
- "description": "Status of the Component Execution ( success or failure )",
- "required": true,
- "type": "string"
- }
- }
- }
- }
- }
- },
- "derived_from": "tosca.nodes.Component"
-}
\ No newline at end of file
}
}
},
- "derived_from": "tosca.nodes.DG"
+ "derived_from": "tosca.nodes.Workflow"
}
\ No newline at end of file
{
"description": "This is Default Resource Source Node Type",
"version": "1.0.0",
- "properties": {
- "key": {
- "required": false,
- "type": "string"
- },
- "key-dependencies": {
- "required": true,
- "type": "list",
- "entry_schema": {
- "type": "string"
- }
- }
- },
+ "properties": { },
"derived_from": "tosca.nodes.ResourceSource"
}
\ No newline at end of file
{
"description": "This is Input Resource Source Node Type",
"version": "1.0.0",
- "properties": {
- "key": {
- "required": false,
- "type": "string"
- },
- "key-dependencies": {
- "required": true,
- "type": "list",
- "entry_schema": {
- "type": "string"
- }
- }
- },
+ "properties": { },
"derived_from": "tosca.nodes.ResourceSource"
}
\ No newline at end of file
"properties": {
"type": {
"required": true,
+ "default": "SQL",
"type": "string",
"constraints": [
{
"valid_values": [
- "SQL",
- "PLSQL"
+ "SQL"
]
}
]
"version": "1.0.0",
"properties": {
"type": {
- "required": false,
+ "required": true,
"type": "string",
"default": "JSON",
"constraints": [
]
},
"verb": {
- "required": false,
+ "required": true,
"type": "string",
"default": "GET",
"constraints": [
-{\r
- "description": "This is Directed Graph Node Type",\r
- "version": "1.0.0",\r
- "derived_from": "tosca.nodes.Root"\r
+{
+ "description": "This is Directed Graph Node Type",
+ "version": "1.0.0",
+ "derived_from": "tosca.nodes.Root"
}
\ No newline at end of file
+++ /dev/null
-{\r
- "description": "This is Jython Component",\r
- "version": "1.0.0",\r
- "derived_from": "tosca.nodes.Root"\r
-}
\ No newline at end of file
+++ /dev/null
-{
- "description": "This is Kotlin Component",
- "version": "1.0.0",
- "derived_from": "tosca.nodes.Root"
-}
\ No newline at end of file
+++ /dev/null
-{\r
- "description": "This is Python Component",\r
- "version": "1.0.0",\r
- "derived_from": "tosca.nodes.Root"\r
-}
\ No newline at end of file
--- /dev/null
+#
+# ============LICENSE_START=======================================================
+# Copyright (C) 2019 Nordix Foundation.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+from time import sleep
+
+
+class RestconfClient:
+
+ __odl_status_check_limit = 10
+ __odl_status_check_pause = 1
+ __odl_status_check_url = "restconf/operational/network-topology:network-topology/topology/topology-netconf/node/"
+ __base_odl_url = "restconf/config/network-topology:network-topology/topology/topology-netconf/node/"
+
+ def __init__(self, log, restconf_component_function):
+ self.__log = log
+ self.__component_function = restconf_component_function
+
+ def mount_device(self, web_client_service, pnf_id, mount_payload):
+ self.__log.debug("mounting device {}", pnf_id)
+ headers = {"Content-Type": "application/xml"}
+ url = self.__base_odl_url + pnf_id
+ self.__log.debug("sending mount request, url: {}", url)
+ web_client_service.exchangeResource("PUT", url, mount_payload, headers)
+ self.__wait_for_odl_to_mount(web_client_service, pnf_id)
+
+ def __wait_for_odl_to_mount(self, web_client_service, pnf_id):
+ counter = 0
+ url = self.__odl_status_check_url + pnf_id
+ self.__log.info("url for ODL status check: {}", url)
+ expected_result = '"netconf-node-topology:connection-status":"connected"'
+ while counter < self.__odl_status_check_limit:
+ result = web_client_service.exchangeResource("GET", url, "")
+ if expected_result in result:
+ self.__log.info("PNF was mounted successfully on ODL")
+ return None
+ sleep(self.__odl_status_check_pause)
+ counter += 1
+ raise Exception("PNF was not mounted on ODL, aborting configuration procedure")
+
+ def configure_device(self, web_client_service, pnf_id, configlet_resource_path, configlet_to_apply):
+ self.log_current_configlet(web_client_service, pnf_id, configlet_resource_path)
+ self.__log.info("configuring device: {}, Configlet: {}", pnf_id, configlet_to_apply)
+ headers = {"Content-Type": "application/yang.patch+json"}
+ url = self.__base_odl_url + pnf_id + configlet_resource_path
+ self.__log.debug("sending patch request, url: {}", url)
+ result = web_client_service.exchangeResource("PATCH", url, configlet_to_apply, headers)
+ self.__log.info("Configuration application result: {}", result)
+
+ def log_current_configlet(self, web_client_service, pnf_id, configlet_resource_path):
+ url = self.__base_odl_url + pnf_id + configlet_resource_path
+ self.__log.debug("sending GET request, url: {}", url)
+ result = web_client_service.exchangeResource("GET", url, "")
+ self.__log.info("Current configuration: {}", result)
+
+ def unmount_device(self, web_client_service, pnf_id):
+ url = self.__base_odl_url + str(pnf_id)
+ self.__log.debug("sending unmount request, url: {}", url)
+ web_client_service.exchangeResource("DELETE", url, "")
MicroServices:
==============
- * Controller Blueprints Studio Processor
- * Blueprints Processor
+.. toctree::
+ :maxdepth: 1
+ :glob:
+
+ controllerBlueprintStudioProcessor
+ bluePrintsProcessor
Architecture:
=============
package org.onap.ccsdk.cds.blueprintsprocessor;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory;
-import org.springframework.boot.web.reactive.server.ReactiveWebServerFactory;
-import org.springframework.boot.web.server.WebServer;
-import org.springframework.http.server.reactive.HttpHandler;
+import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;
@Component
-public class BlueprintHttpServer {
-
- private static Logger log = LoggerFactory.getLogger(BlueprintHttpServer.class);
+public class BlueprintHttpServer implements WebServerFactoryCustomizer<NettyReactiveWebServerFactory> {
@Value("${blueprintsprocessor.httpPort}")
private Integer httpPort;
- @Autowired
- HttpHandler httpHandler;
-
- WebServer http;
-
- @PostConstruct
- public void start() {
- ReactiveWebServerFactory factory = new NettyReactiveWebServerFactory(httpPort);
- this.http = factory.getWebServer(this.httpHandler);
- this.http.start();
- }
-
- @PreDestroy
- public void stop() {
- this.http.stop();
+ @Override
+ public void customize(NettyReactiveWebServerFactory serverFactory) {
+ serverFactory.setPort(httpPort);
}
-}
+}
\ No newline at end of file
# Python executor
blueprints.processor.functions.python.executor.executionPath=/opt/app/onap/scripts/jython/ccsdk_blueprints
-blueprints.processor.functions.python.executor.modulePaths=/opt/app/onap/scripts/jython/ccsdk_blueprints,/opt/app/onap/scripts/jython/ccsdk_netconf
+blueprints.processor.functions.python.executor.modulePaths=/opt/app/onap/scripts/jython/ccsdk_blueprints,/opt/app/onap/scripts/jython/ccsdk_netconf,/opt/app/onap/scripts/jython/ccsdk_restconf
security.user.password: {bcrypt}$2a$10$duaUzVUVW0YPQCSIbGEkQOXwafZGwQ/b32/Ys4R1iwSSawFgz7QNu
security.user.name: ccsdkapps
componentWorkflowExecutionService
.executeBluePrintWorkflow(bluePrintRuntimeService, executionServiceInput, properties)
}
- derivedFrom.startsWith(BluePrintConstants.MODEL_TYPE_NODE_DG, true) -> {
+ derivedFrom.startsWith(BluePrintConstants.MODEL_TYPE_NODE_WORKFLOW, true) -> {
dgWorkflowExecutionService
.executeBluePrintWorkflow(bluePrintRuntimeService, executionServiceInput, properties)
}
}
},
- "derived_from": "tosca.nodes.DG"
+ "derived_from": "tosca.nodes.Workflow"
}
\ No newline at end of file
}
}
},
- "derived_from": "tosca.nodes.DG"
+ "derived_from": "tosca.nodes.Workflow"
}
\ No newline at end of file
}
}
},
- "derived_from": "tosca.nodes.DG"
+ "derived_from": "tosca.nodes.Workflow"
}
\ No newline at end of file
}
}
},
- "derived_from": "tosca.nodes.DG"
+ "derived_from": "tosca.nodes.Workflow"
}
\ No newline at end of file
const val MODEL_TYPE_RELATIONSHIPS_ATTACH_TO = "tosca.relationships.AttachesTo"
const val MODEL_TYPE_RELATIONSHIPS_ROUTES_TO = "tosca.relationships.RoutesTo"
- const val MODEL_TYPE_NODE_DG = "tosca.nodes.DG"
+ const val MODEL_TYPE_NODE_WORKFLOW = "tosca.nodes.Workflow"
const val MODEL_TYPE_NODE_COMPONENT = "tosca.nodes.Component"
const val MODEL_TYPE_NODE_VNF = "tosca.nodes.Vnf"
const val MODEL_TYPE_NODE_RESOURCE_SOURCE = "tosca.nodes.ResourceSource"
@JvmStatic
val validNodeTypeDerivedFroms: MutableList<String> = arrayListOf(
BluePrintConstants.MODEL_TYPE_NODES_ROOT,
- BluePrintConstants.MODEL_TYPE_NODE_DG,
+ BluePrintConstants.MODEL_TYPE_NODE_WORKFLOW,
BluePrintConstants.MODEL_TYPE_NODE_COMPONENT,
BluePrintConstants.MODEL_TYPE_NODE_VNF,
BluePrintConstants.MODEL_TYPE_NODE_RESOURCE_SOURCE,
val nodeTypeDerivedFrom = bluePrintRuntimeService.bluePrintContext().nodeTemplateNodeType(it).derivedFrom
- check(nodeTypeDerivedFrom == BluePrintConstants.MODEL_TYPE_NODE_DG
+ check(nodeTypeDerivedFrom == BluePrintConstants.MODEL_TYPE_NODE_WORKFLOW
|| nodeTypeDerivedFrom == BluePrintConstants.MODEL_TYPE_NODE_COMPONENT) {
"NodeType(${nodeTemplate.type}) derived from is '$nodeTypeDerivedFrom', Expected " +
- "'${BluePrintConstants.MODEL_TYPE_NODE_DG}' or '${BluePrintConstants.MODEL_TYPE_NODE_COMPONENT}'"
+ "'${BluePrintConstants.MODEL_TYPE_NODE_WORKFLOW}' or '${BluePrintConstants.MODEL_TYPE_NODE_COMPONENT}'"
}
} catch (e: Exception) {
bluePrintRuntimeService.getBluePrintError()
assertEquals(1, bluePrintRuntime.getBluePrintError().errors.size)
assertEquals("Failed to validate Workflow(resource-assignment)'s step(test)'s definition : " +
"resource-assignment/steps/test : NodeType(TestNodeType) derived from is 'tosca.nodes.TEST', " +
- "Expected 'tosca.nodes.DG' or 'tosca.nodes.Component'", bluePrintRuntime.getBluePrintError().errors[0])
+ "Expected 'tosca.nodes.Workflow' or 'tosca.nodes.Component'", bluePrintRuntime.getBluePrintError().errors[0])
}
@Test
derivedFrom.startsWith(BluePrintConstants.MODEL_TYPE_NODE_COMPONENT, true) -> {
// DO Nothing
}
- derivedFrom.startsWith(BluePrintConstants.MODEL_TYPE_NODE_DG, true) -> {
+ derivedFrom.startsWith(BluePrintConstants.MODEL_TYPE_NODE_WORKFLOW, true) -> {
enhanceDGStepTargets(name, workflow, firstNodeTemplateName)
}
else -> {
}\r
}\r
},\r
- "derived_from": "tosca.nodes.DG"\r
+ "derived_from": "tosca.nodes.Workflow"\r
},\r
"dg-activate-netconf": {\r
"description": "This is Download Netconf Directed Graph",\r
}\r
}\r
},\r
- "derived_from": "tosca.nodes.DG"\r
+ "derived_from": "tosca.nodes.Workflow"\r
},\r
"artifact-config-template": {\r
"description": "This is Configuration Velocity Template",\r
testComponentInvokeEnhancementAndValidation(basePath, "base-enhance")
}
- @Test
- @Throws(Exception::class)
- fun testComponentInvokeEnhancementAndValidation() {
- val basePath = "./../../../../components/model-catalog/blueprint-model/test-blueprint/component_invoke"
- testComponentInvokeEnhancementAndValidation(basePath, "component-enhance")
- }
-
@Test
@Throws(Exception::class)
fun testGoldenEnhancementAndValidation() {
<parent>
<groupId>org.onap.ccsdk.parent</groupId>
<artifactId>odlparent-lite</artifactId>
- <version>1.2.1</version>
+ <version>1.2.2-SNAPSHOT</version>
<relativePath/>
</parent>
<description>CCSDK Controller Design Studio</description>
<modules>
- <!--<module>cds-ui</module>-->
+ <module>cds-ui</module>
<module>components</module>
<module>ms</module>
</modules>