Adding custom headers capability to REST client 15/82315/8
authorottero <rodrigo.ottero@est.tech>
Sun, 17 Mar 2019 19:38:32 +0000 (19:38 +0000)
committerottero <rodrigo.ottero@est.tech>
Sun, 17 Mar 2019 19:38:32 +0000 (19:38 +0000)
For YANG PATCH requests to ODL to work, they need to have a Content-
type header of application/yang.patch+json and should not have Accept
as application/json

Current REST client inserts a default header to the requests with this
content:

  Content-Type: application/json
  Accept: application/json

The solution was to add the possibility of sending custom headers alon-
gside the other parameters.

Change-Id: I2cf0cd2ef7b87f4f5a246d427dffafe266cb33f7
Issue-ID: CCSDK-926
Signed-off-by: ottero <rodrigo.ottero@est.tech>
27 files changed:
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Definitions/activation-blueprint.json
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Definitions/config-assign-pnf-mapping.json [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Definitions/config-deploy-pnf-mapping.json [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Definitions/data_types.json
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Definitions/node_types.json
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Definitions/resources_definition_types.json
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Plans/CONFIG_configDeploy.xml [moved from components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Plans/CONFIG_configure.xml with 91% similarity]
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Scripts/python/RestconfAssignConfig.py [deleted file]
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Scripts/python/RestconfConfigDeploy.py [new file with mode: 0644]
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Scripts/python/RestconfConfigure.py [deleted file]
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/config-assign-pnf-mapping.json [deleted file]
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/config-assign-restconf-configlet-template.vtl
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/config-deploy-restconf-mount-template.vtl [moved from components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/configure-restconf-mount-template.vtl with 85% similarity]
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/configure-pnf-mapping.json [deleted file]
components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/configure-restconf-unmount-template.vtl [deleted file]
components/model-catalog/resource-dictionary/starter-dictionary/entity.json [new file with mode: 0755]
components/model-catalog/resource-dictionary/starter-dictionary/pnf-id.json [new file with mode: 0755]
components/model-catalog/resource-dictionary/starter-dictionary/pnf-name.json [new file with mode: 0755]
ms/blueprintsprocessor/application/src/main/resources/application-dev.properties
ms/blueprintsprocessor/application/src/main/resources/application.properties
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/rest/service/BasicAuthRestClientService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/rest/service/BlueprintWebClientService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/rest/service/DME2ProxyRestClientService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/rest/service/SSLBasicAuthRestClientService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/rest/service/TokenAuthRestClientService.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/main/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/rest/utils/WebClientUtils.kt
ms/blueprintsprocessor/modules/commons/rest-lib/src/test/kotlin/org/onap/ccsdk/apps/blueprintsprocessor/rest/service/RestClientServiceTest.kt

index 90b2e3a..628a7d0 100644 (file)
   }, {
     "file" : "Definitions/policy_types.json"
   } ],
-  "topology_template" : {
-    "inputs" : {
-      "serviceInstanceId" : {
-        "required" : true,
-        "type" : "string"
-      },
-      "identifier" : {
-        "required" : true,
-        "type" : "string"
+  "dsl_definitions" : {
+    "config-assign-properties" : {
+      "resolution-key" : {
+        "get_input" : "resolution-key"
       }
     },
+    "config-deploy-properties" : {
+      "resolution-key" : {
+        "get_input" : "resolution-key"
+      }
+    }
+
+  },
+  "topology_template" : {
     "workflows" : {
       "config-assign" : {
         "steps" : {
           }
         },
         "inputs" : {
+          "resolution-key" : {
+            "required" : true,
+            "type" : "string"
+          },
+          "artifact-name" : {
+            "required" : true,
+            "type" : "list",
+            "entry_schema" : {
+              "type" : "string"
+            }
+          },
+          "store-result" : {
+            "required" : true,
+            "type" : "boolean"
+          },
           "config-assign-properties" : {
             "description" : "Dynamic PropertyDefinition for workflow(config-assign).",
             "required" : true,
           }
         }
       },
-      "configure" : {
+      "config-deploy" : {
         "steps" : {
           "activate-process" : {
             "description" : "Send a configlet to the pnf",
-            "target" : "configure-process",
+            "target" : "config-deploy-process",
             "activities" : [ {
               "call_operation" : ""
             } ]
           }
         },
         "inputs" : {
-          "configure-properties" : {
-            "description" : "Dynamic PropertyDefinition for workflow(configure).",
+          "resolution-key" : {
+            "required" : true,
+            "type" : "string"
+          },
+          "config-deploy-properties" : {
+            "description" : "Dynamic PropertyDefinition for workflow(config-deploy).",
             "required" : true,
-            "type" : "dt-configure-properties"
+            "type" : "dt-config-deploy-properties"
           }
         }
       }
           }
         }
       },
-
-
       "config-assign" : {
-        "type" : "component-restconf-executor",
+        "type" : "component-resource-resolution",
         "interfaces" : {
-          "ComponentRestconfExecutor" : {
+          "ResourceResolutionComponent" : {
             "operations" : {
               "process" : {
-                "implementation" : {
-                  "primary" : "component-script"
-                },
                 "inputs" : {
-                  "script-type" : "jython",
-                  "script-class-reference" : "Scripts/python/RestconfAssignConfig.py",
-                  "instance-dependencies" : [ ]
+                  "resolution-key" : {
+                    "get_input" : "resolution-key"
+                  },
+                  "store-result" : true,
+                  "artifact-prefix-names" : ["config-assign"]
                 },
                 "outputs" : {
-                  "response-data" : "",
-                  "status" : ""
+                  "resource-assignment-params" : {
+                    "get_attribute" : [ "SELF", "assignment-params" ]
+                  },
+                  "status" : "success"
                 }
               }
             }
           },
           "config-assign-mapping" : {
             "type" : "artifact-mapping-resource",
-            "file" : "Templates/config-assign-pnf-mapping.json"
-          },
-          "component-script" : {
-            "type" : "artifact-script-jython",
-            "file" : "Scripts/python/RestconfAssignConfig.py"
+            "file" : "Definitions/config-assign-pnf-mapping.json"
           }
         }
       },
-
-
-
-      "configure-process" : {
+      "config-deploy-process" : {
         "type" : "dg-generic",
         "properties" : {
           "content" : {
-            "get_artifact" : [ "SELF", "dg-configure-process" ]
+            "get_artifact" : [ "SELF", "dg-config-deploy-process" ]
           },
-          "dependency-node-templates" : [ "configure" ]
+          "dependency-node-templates" : [ "config-deploy" ]
         },
         "artifacts" : {
           "dg-config-assign-process" : {
             "type" : "artifact-directed-graph",
-            "file" : "Plans/CONFIG_configure.xml"
+            "file" : "Plans/CONFIG_configDeploy.xml"
           }
         }
       },
-      "configure" : {
+      "config-deploy" : {
         "type" : "component-restconf-executor",
         "interfaces" : {
           "ComponentRestconfExecutor" : {
                 },
                 "inputs" : {
                   "script-type" : "jython",
-                  "script-class-reference" : "Scripts/python/RestconfConfigure.py",
-                  "instance-dependencies" : [ ]
+                  "script-class-reference" : "Scripts/python/RestconfConfigDeploy.py",
+                  "instance-dependencies" : [ ],
+                  "dynamic-properties" : "*config-deploy-properties"
                 },
                 "outputs" : {
                   "response-data" : "",
-                  "status" : ""
+                  "status" : "success"
                 }
               }
             }
           }
         },
         "artifacts" : {
-          "configure-mount-template" : {
-            "type" : "artifact-template-velocity",
-            "file" : "Templates/configure-restconf-mount-template.vtl"
-          },
-          "configure-unmount-template" : {
+          "config-deploy-template" : {
             "type" : "artifact-template-velocity",
-            "file" : "Templates/configure-restconf-unmount-template.vtl"
+            "file" : "Templates/config-deploy-restconf-mount-template.vtl"
           },
-          "configure-mapping" : {
+          "config-deploy-mapping" : {
             "type" : "artifact-mapping-resource",
-            "file" : "Templates/configure-pnf-mapping.json"
+            "file" : "Definitions/config-deploy-pnf-mapping.json"
           },
           "component-script" : {
             "type" : "artifact-script-jython",
-            "file" : "Scripts/python/RestconfConfigure.py"
+            "file" : "Scripts/python/RestconfConfigDeploy.py"
           }
         }
       }
     }
   }
-}
+}
\ No newline at end of file
diff --git a/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Definitions/config-assign-pnf-mapping.json b/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Definitions/config-assign-pnf-mapping.json
new file mode 100644 (file)
index 0000000..fc8e1bf
--- /dev/null
@@ -0,0 +1,13 @@
+[
+  {
+    "name": "entity",
+    "input-param": true,
+    "property": {
+      "type": "json"
+    },
+    "dictionary-name": "entity",
+    "dictionary-source": "input",
+    "dependencies": [
+    ]
+  }
+]
diff --git a/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Definitions/config-deploy-pnf-mapping.json b/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Definitions/config-deploy-pnf-mapping.json
new file mode 100644 (file)
index 0000000..fc8e1bf
--- /dev/null
@@ -0,0 +1,13 @@
+[
+  {
+    "name": "entity",
+    "input-param": true,
+    "property": {
+      "type": "json"
+    },
+    "dictionary-name": "entity",
+    "dictionary-source": "input",
+    "dependencies": [
+    ]
+  }
+]
index 9f35eef..e5aa763 100644 (file)
@@ -3,13 +3,21 @@
     "dt-config-assign-properties" : {
       "description" : "Dynamic DataType definition for workflow(config-assign).",
       "version" : "1.0.0",
-      "properties" : { },
+      "properties" : {
+        "entity" : {
+          "type" : "json"
+        }
+      },
       "derived_from" : "tosca.datatypes.Dynamic"
     },
-    "dt-configure-properties" : {
-      "description" : "Dynamic DataType definition for workflow(configure).",
+    "dt-config-deploy-properties" : {
+      "description" : "Dynamic DataType definition for workflow(config-deploy).",
       "version" : "1.0.0",
-      "properties" : { },
+      "properties" : {
+        "entity" : {
+          "type" : "json"
+        }
+      },
       "derived_from" : "tosca.datatypes.Dynamic"
     }
   }
index be3bd31..ed7c580 100644 (file)
@@ -1,5 +1,84 @@
 {
   "node_types" : {
+    "component-resource-resolution" : {
+      "description" : "This is Resource Assignment Component API",
+      "version" : "1.0.0",
+      "attributes" : {
+        "assignment-params" : {
+          "required" : true,
+          "type" : "string"
+        }
+      },
+      "capabilities" : {
+        "component-node" : {
+          "type" : "tosca.capabilities.Node"
+        }
+      },
+      "interfaces" : {
+        "ResourceResolutionComponent" : {
+          "operations" : {
+            "process" : {
+              "inputs" : {
+                "resolution-key" : {
+                  "description" : "Key for service instance related correlation.",
+                  "required" : false,
+                  "type" : "string"
+                },
+                "store-result" : {
+                  "description" : "Whether or not to store the output.",
+                  "required" : false,
+                  "type" : "boolean"
+                },
+                "resource-type" : {
+                  "description" : "Request type.",
+                  "required" : false,
+                  "type" : "string"
+                },
+                "artifact-prefix-names" : {
+                  "description" : "Template , Resource Assignment Artifact Prefix names",
+                  "required" : true,
+                  "type" : "list",
+                  "entry_schema" : {
+                    "type" : "string"
+                  }
+                },
+                "request-id" : {
+                  "description" : "Request Id, Unique Id for the request.",
+                  "required" : true,
+                  "type" : "string"
+                },
+                "resource-id" : {
+                  "description" : "Resource Id.",
+                  "required" : false,
+                  "type" : "string"
+                },
+                "action-name" : {
+                  "description" : "Action Name of the process",
+                  "required" : false,
+                  "type" : "string"
+                },
+                "dynamic-properties" : {
+                  "description" : "Dynamic Json Content or DSL Json reference.",
+                  "required" : false,
+                  "type" : "json"
+                }
+              },
+              "outputs" : {
+                "resource-assignment-params" : {
+                  "required" : true,
+                  "type" : "string"
+                },
+                "status" : {
+                  "required" : true,
+                  "type" : "string"
+                }
+              }
+            }
+          }
+        }
+      },
+      "derived_from" : "tosca.nodes.Component"
+    },
     "component-restconf-executor" : {
       "description" : "This is Restconf Transaction Configuration Component API",
       "version" : "1.0.0",
                   "entry_schema" : {
                     "type" : "string"
                   }
+                },
+                "dynamic-properties" : {
+                  "description" : "Dynamic Json Content or DSL Json reference.",
+                  "required" : false,
+                  "type" : "json"
                 }
               },
               "outputs" : {
       },
       "derived_from" : "tosca.nodes.DG"
     },
+    "source-input" : {
+      "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"
+          }
+        }
+      },
+      "derived_from" : "tosca.nodes.ResourceSource"
+    },
     "tosca.nodes.Component" : {
       "description" : "This is default Component Node",
       "version" : "1.0.0",
       "description" : "This is Directed Graph Node Type",
       "version" : "1.0.0",
       "derived_from" : "tosca.nodes.Root"
+    },
+    "tosca.nodes.ResourceSource" : {
+      "description" : "TOSCA base type for Resource Sources",
+      "version" : "1.0.0",
+      "derived_from" : "tosca.nodes.Root"
     }
   }
 }
\ No newline at end of file
index 6f31cf5..98a73b1 100644 (file)
@@ -1 +1,17 @@
-{ }
\ No newline at end of file
+{
+  "entity" : {
+    "tags" : "entity",
+    "name" : "entity",
+    "property" : {
+      "description" : "entity",
+      "type" : "json"
+    },
+    "updated-by" : "Rodrigo Ottero <rodrigo.ottero@est.tech>",
+    "sources" : {
+      "input" : {
+        "type" : "source-input",
+        "properties" : { }
+      }
+    }
+  }
+}
\ No newline at end of file
@@ -2,7 +2,7 @@
 <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="ResourceAssignAndActivate" mode="sync">
       <block atomic="true">
-         <execute plugin="configure" method="process">
+         <execute plugin="config-deploy" method="process">
             <outcome value="failure">
                <return status="failure" />
             </outcome>
diff --git a/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Scripts/python/RestconfAssignConfig.py b/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Scripts/python/RestconfAssignConfig.py
deleted file mode 100644 (file)
index 36dd32f..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-# ============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 org.onap.ccsdk.apps.blueprintsprocessor.functions.restconf.executor import \
-    RestconfComponentFunction
-
-
-class RestconfAssignConfig(RestconfComponentFunction):
-
-
-    def process(self, execution_request):
-        # create instances of the needed objects
-        # retrieve any needed information not present on the request, like pnf ip
-        # create the configlet
-        # persist the configlet
-        # end
-        print("process", execution_request)
-
-
-    def recover(self, runtime_exception, execution_request):
-        print("recover")
-        return None
\ No newline at end of file
diff --git a/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Scripts/python/RestconfConfigDeploy.py b/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Scripts/python/RestconfConfigDeploy.py
new file mode 100644 (file)
index 0000000..33f9400
--- /dev/null
@@ -0,0 +1,112 @@
+# ============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
+
+from org.onap.ccsdk.apps.blueprintsprocessor.functions.restconf.executor import \
+    RestconfComponentFunction
+from java.lang import Exception as JavaException
+
+
+class RestconfConfigDeploy(RestconfComponentFunction):
+
+    log = globals()["log"]
+    seconds_to_sleep = 5
+    base_mount_url = "restconf/config/network-topology:network-topology/topology/topology-netconf/node/"
+    server_identifier = "sdncodl"
+    configlet_template_name = "config-assign"
+
+    def process(self, execution_request):
+
+        self.log.info("Started execution of process method")
+        try:
+            self.log.info("getting resolution-key")
+            resolution_key = self.getDynamicProperties("resolution-key").asText()
+            self.log.info("resolution_key: {}", resolution_key)
+
+            self.log.info("getting pnf-id")
+            pnf_id = execution_request.payload.get("config-deploy-request").get("config-deploy-properties").get("entity").get("pnf-id")
+            pnf_id = str(pnf_id).strip('\"')
+            self.log.info("pnf-id: {}", pnf_id)
+
+            self.log.info("mounting device {}", pnf_id)
+            self.mount(pnf_id)
+
+            self.log.info("sleeping for {} seconds", self.seconds_to_sleep)
+            sleep(self.seconds_to_sleep)
+
+            try:
+                self.log.info("configuring device {}", 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)
+
+            self.log.info("Ended execution of process method")
+
+        except JavaException, err:
+            self.log.error("Java Exception in the script", err)
+            raise err
+        except Exception, err:
+            self.log.error("Python Exception in the script", err)
+            raise err
+
+    def mount(self, pnf_id):
+        self.log.info("meshing mount payload")
+        mount_payload = self.resolveAndGenerateMessage("config-deploy-mapping", "config-deploy-template")
+        self.log.info("mount payload: \n {}", mount_payload)
+
+        # defining custom header
+        headers = {
+            "Content-Type": "application/xml"
+        }
+
+        url = self.base_mount_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)
+
+    def unmount(self, pnf_id):
+        url = self.base_mount_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 apply_configuration(self, pnf_id, resolution_key, template_name):
+        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)
+
+        # defining custom header
+        headers = {
+            "Content-Type": "application/yang.patch+json"
+        }
+
+        url = "restconf/config/network-topology:network-topology/topology/topology-netconf/node/" + pnf_id \
+              + "/yang-ext:mount/mynetconf:netconflist"
+        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 recover(self, runtime_exception, execution_request):
+        self.log.info("Recover method, no code to execute")
+        return None
diff --git a/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Scripts/python/RestconfConfigure.py b/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Scripts/python/RestconfConfigure.py
deleted file mode 100644 (file)
index c584baa..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-# ============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 org.onap.ccsdk.apps.blueprintsprocessor.functions.restconf.executor import \
-    RestconfComponentFunction
-
-
-class RestconfConfigure(RestconfComponentFunction):
-
-
-    def process(self, execution_request):
-        # create instances of the needed objects
-        # retrieve any needed information not present on the request, like pnf ip
-        # retrieve the configlet
-        # send the configlet
-        # end
-        print("process", execution_request)
-
-
-    def recover(self, runtime_exception, execution_request):
-        print("recover")
-        return None
diff --git a/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/config-assign-pnf-mapping.json b/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/config-assign-pnf-mapping.json
deleted file mode 100644 (file)
index 41b42e6..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-[
-
-]
index e3d7a67..3812380 100644 (file)
@@ -1,19 +1,37 @@
-<yang-patch xmlns="urn:ietf:params:xml:ns:yang:ietf-yang-patch">
-<patch-id>example-patch</patch-id>
-<comment>Example patch</comment>
-<edit>
-  <edit-id>edit1</edit-id>
-  <operation>create</operation>
-  <target>/car-entry</target>
-  <value>
-    <car-entry xmlns="urn:opendaylight:params:xml:ns:yang:controller:config:sal-clustering-it:car">
-      <id>0</id>
-    </car-entry>
-  </value>
-</edit>
-<edit>
-  <edit-id>edit2</edit-id>
-  <operation>delete</operation>
-  <target>/car-entry/0</target>
-</edit>
-</yang-patch>
+{
+   "ietf-restconf:yang-patch":{
+      "patch-id":"patch-1",
+      "edit":[
+         {
+            "edit-id":"edit1",
+            "operation":"merge",
+            "target":"/",
+            "value":{
+               "netconflist":{
+                  "netconf":[
+                     {
+                        "netconf-id":"40",
+                        "netconf-param":"4040"
+                     }
+                  ]
+               }
+            }
+         },
+         {
+            "edit-id":"edit2",
+            "operation":"merge",
+            "target":"/",
+            "value":{
+               "netconflist":{
+                  "netconf":[
+                     {
+                        "netconf-id":"50",
+                        "netconf-param":"98765"
+                     }
+                  ]
+               }
+            }
+         }
+      ]
+   }
+}
\ No newline at end of file
@@ -1,10 +1,10 @@
 <node xmlns="urn:TBD:params:xml:ns:yang:network-topology">
-    <node-id>$pnf-id</node-id>
+    <node-id>$entity.pnf-id</node-id>
     <key-based xmlns="urn:opendaylight:netconf-node-topology">
         <key-id xmlns="urn:opendaylight:netconf-node-topology">ODL-private-key</key-id>
         <username xmlns="urn:opendaylight:netconf-node-topology">netconf</username>
      </key-based>
-    <host xmlns="urn:opendaylight:netconf-node-topology">$pnf-ip</host>
+    <host xmlns="urn:opendaylight:netconf-node-topology">$entity.pnf-name</host>
     <port xmlns="urn:opendaylight:netconf-node-topology">6513</port>
     <tcp-only xmlns="urn:opendaylight:netconf-node-topology">false</tcp-only>
        <protocol xmlns="urn:opendaylight:netconf-node-topology">
diff --git a/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/configure-pnf-mapping.json b/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/configure-pnf-mapping.json
deleted file mode 100644 (file)
index 41b42e6..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-[
-
-]
diff --git a/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/configure-restconf-unmount-template.vtl b/components/model-catalog/blueprint-model/test-blueprint/capability_restconf/Templates/configure-restconf-unmount-template.vtl
deleted file mode 100644 (file)
index a099036..0000000
+++ /dev/null
@@ -1 +0,0 @@
-TBD
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/entity.json b/components/model-catalog/resource-dictionary/starter-dictionary/entity.json
new file mode 100755 (executable)
index 0000000..83a32a9
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "name" : "entity",
+  "tags" : "entity",
+  "updated-by" : "Rodrigo Ottero <rodrigo.ottero@est.tech>",
+  "property" : {
+    "description" : "entity",
+    "type" : "json"
+  },
+  "sources" : {
+    "input" : {
+      "type" : "source-input",
+      "properties" : { }
+    }
+  }
+}
\ No newline at end of file
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/pnf-id.json b/components/model-catalog/resource-dictionary/starter-dictionary/pnf-id.json
new file mode 100755 (executable)
index 0000000..3246853
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "name" : "pnf-id",
+  "tags" : "pnf-id",
+  "updated-by" : "Rodrigo Ottero <rodrigo.ottero@est.tech>",
+  "property" : {
+    "description" : "pnf-id",
+    "type" : "string"
+  },
+  "sources" : {
+    "input" : {
+      "type" : "source-input",
+      "properties" : { }
+    }
+  }
+}
\ No newline at end of file
diff --git a/components/model-catalog/resource-dictionary/starter-dictionary/pnf-name.json b/components/model-catalog/resource-dictionary/starter-dictionary/pnf-name.json
new file mode 100755 (executable)
index 0000000..edcc3e9
--- /dev/null
@@ -0,0 +1,15 @@
+{
+  "name" : "pnf-name",
+  "tags" : "pnf-name",
+  "updated-by" : "Rodrigo Ottero <rodrigo.ottero@est.tech>",
+  "property" : {
+    "description" : "pnf-name",
+    "type" : "string"
+  },
+  "sources" : {
+    "input" : {
+      "type" : "source-input",
+      "properties" : { }
+    }
+  }
+}
\ No newline at end of file
index 380eb20..e64dee2 100755 (executable)
@@ -44,5 +44,5 @@ blueprints.processor.functions.python.executor.modulePaths=./../../../components
 blueprintsprocessor.restconfEnabled=true\r
 blueprintsprocessor.restclient.sdncodl.type=basic-auth\r
 blueprintsprocessor.restclient.sdncodl.url=http://localhost:8282/\r
-blueprintsprocessor.restclient.sdncodl.userId=admin\r
-blueprintsprocessor.restclient.sdncodl.token=Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U
\ No newline at end of file
+blueprintsprocessor.restclient.sdncodl.username=admin\r
+blueprintsprocessor.restclient.sdncodl.password=Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U
\ No newline at end of file
index 8cafceb..3b97e67 100755 (executable)
@@ -47,4 +47,5 @@ security.user.name: ccsdkapps
 blueprintsprocessor.restconfEnabled=true
 blueprintsprocessor.restclient.sdncodl.type=basic-auth
 blueprintsprocessor.restclient.sdncodl.url=http://sdnc:8282/
-blueprintsprocessor.restclient.sdncodl.userId=admin
+blueprintsprocessor.restclient.sdncodl.username=admin
+blueprintsprocessor.restclient.sdncodl.password=Kp8bJ4SXszM0WXlhak3eHlcse2gAw84vaoGGmJvUy2U
index 0502f67..98a4fd5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2017-2019 AT&T, Bell Canada
+ * Copyright © 2017-2019 AT&T, Bell Canada, Nordix Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -12,6 +12,8 @@
  * 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
  */
 
 package org.onap.ccsdk.apps.blueprintsprocessor.rest.service
@@ -26,21 +28,31 @@ import java.util.*
 class BasicAuthRestClientService(private val restClientProperties: BasicAuthRestClientProperties) :
     BlueprintWebClientService {
 
-    override fun headers(): Array<BasicHeader> {
+    override fun defaultHeaders(): Map<String, String> {
         val encodedCredentials = setBasicAuth(restClientProperties.username, restClientProperties.password)
-        val params = arrayListOf<BasicHeader>()
-        params.add(BasicHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
-        params.add(BasicHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE))
-        params.add(BasicHeader(HttpHeaders.AUTHORIZATION, "Basic $encodedCredentials"))
-        return params.toTypedArray()
+        return mapOf(
+                HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE,
+                HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE,
+                HttpHeaders.AUTHORIZATION to "Basic $encodedCredentials")
     }
 
     override fun host(uri: String): String {
         return restClientProperties.url + uri
     }
 
+    override fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> {
+        val customHeaders: MutableMap<String, String> = headers.toMutableMap()
+        if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) {
+            val encodedCredentials = setBasicAuth(restClientProperties.username, restClientProperties.password)
+            customHeaders[HttpHeaders.AUTHORIZATION] = "Basic $encodedCredentials"
+        }
+        return super.convertToBasicHeaders(customHeaders)
+    }
+
     private fun setBasicAuth(username: String, password: String): String {
         val credentialsString = "$username:$password"
         return Base64.getEncoder().encodeToString(credentialsString.toByteArray(Charset.defaultCharset()))
     }
+
+
 }
\ No newline at end of file
index 9c2caad..0629909 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2017-2019 AT&T, Bell Canada
+ * Copyright © 2017-2019 AT&T, Bell Canada, Nordix Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * 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
  */
 
 package org.onap.ccsdk.apps.blueprintsprocessor.rest.service
 
 import org.apache.commons.io.IOUtils
-import org.apache.http.client.methods.HttpDelete
-import org.apache.http.client.methods.HttpGet
-import org.apache.http.client.methods.HttpPost
-import org.apache.http.client.methods.HttpPut
+import org.apache.http.client.methods.*
 import org.apache.http.entity.StringEntity
 import org.apache.http.impl.client.CloseableHttpClient
 import org.apache.http.impl.client.HttpClients
@@ -32,7 +31,7 @@ import java.nio.charset.Charset
 
 interface BlueprintWebClientService {
 
-    fun headers(): Array<BasicHeader>
+    fun defaultHeaders(): Map<String, String>
 
     fun host(uri: String): String
 
@@ -44,48 +43,73 @@ interface BlueprintWebClientService {
     }
 
     fun exchangeResource(methodType: String, path: String, request: String): String {
+        return this.exchangeResource(methodType, path, request, defaultHeaders())
+    }
+
+    fun exchangeResource(methodType: String, path: String, request: String, headers: Map<String, String>): String {
+        val convertedHeaders: Array<BasicHeader> = convertToBasicHeaders(headers)
         return when (HttpMethod.resolve(methodType)) {
-            HttpMethod.DELETE -> delete(path)
-            HttpMethod.GET -> get(path)
-            HttpMethod.POST -> post(path, request)
-            HttpMethod.PUT -> put(path, request)
+            HttpMethod.DELETE -> delete(path, convertedHeaders)
+            HttpMethod.GET -> get(path, convertedHeaders)
+            HttpMethod.POST -> post(path, request, convertedHeaders)
+            HttpMethod.PUT -> put(path, request, convertedHeaders)
+            HttpMethod.PATCH -> patch(path, request, convertedHeaders)
             else -> throw BluePrintProcessorException("Unsupported methodType($methodType)")
         }
     }
 
-    fun delete(path: String): String {
+    fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> {
+        val convertedHeaders = Array<BasicHeader>(headers.size){ BasicHeader("","") }
+        var currentElement = 0
+        for ((name, value) in headers) {
+            convertedHeaders[currentElement++] = BasicHeader(name, value)
+        }
+        return convertedHeaders
+    }
+
+    fun delete(path: String, headers: Array<BasicHeader>): String {
         val httpDelete = HttpDelete(host(path))
-        httpDelete.setHeaders(headers())
+        httpDelete.setHeaders(headers)
         httpClient().execute(httpDelete).entity.content.use {
             return IOUtils.toString(it, Charset.defaultCharset())
         }
     }
 
-    fun get(path: String): String {
+    fun get(path: String, headers: Array<BasicHeader>): String {
         val httpGet = HttpGet(host(path))
-        httpGet.setHeaders(headers())
+        httpGet.setHeaders(headers)
         httpClient().execute(httpGet).entity.content.use {
             return IOUtils.toString(it, Charset.defaultCharset())
         }
     }
 
-    fun post(path: String, request: String): String {
+    fun post(path: String, request: String, headers: Array<BasicHeader>): String {
         val httpPost = HttpPost(host(path))
         val entity = StringEntity(request)
         httpPost.entity = entity
-        httpPost.setHeaders(headers())
+        httpPost.setHeaders(headers)
         httpClient().execute(httpPost).entity.content.use {
             return IOUtils.toString(it, Charset.defaultCharset())
         }
     }
 
-    fun put(path: String, request: String): String {
+    fun put(path: String, request: String, headers: Array<BasicHeader>): String {
         val httpPut = HttpPut(host(path))
         val entity = StringEntity(request)
         httpPut.entity = entity
-        httpPut.setHeaders(headers())
+        httpPut.setHeaders(headers)
         httpClient().execute(httpPut).entity.content.use {
             return IOUtils.toString(it, Charset.defaultCharset())
         }
     }
+
+    fun patch(path: String, request: String, headers: Array<BasicHeader>): String {
+        val httpPatch = HttpPatch(host(path))
+        val entity = StringEntity(request)
+        httpPatch.entity = entity
+        httpPatch.setHeaders(headers)
+        httpClient().execute(httpPatch).entity.content.use {
+            return IOUtils.toString(it, Charset.defaultCharset())
+        }
+    }
 }
\ No newline at end of file
index 2b2578a..94e146d 100644 (file)
 
 package org.onap.ccsdk.apps.blueprintsprocessor.rest.service
 
-import org.apache.http.message.BasicHeader
 import org.onap.ccsdk.apps.blueprintsprocessor.rest.RestClientProperties
 
 class DME2ProxyRestClientService(restClientProperties: RestClientProperties) : BlueprintWebClientService {
-    override fun headers(): Array<BasicHeader> {
+    override fun defaultHeaders(): Map<String, String> {
         TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
     }
 
index dc2993d..2bfacf4 100644 (file)
@@ -19,7 +19,6 @@ package org.onap.ccsdk.apps.blueprintsprocessor.rest.service
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory
 import org.apache.http.impl.client.CloseableHttpClient
 import org.apache.http.impl.client.HttpClients
-import org.apache.http.message.BasicHeader
 import org.apache.http.ssl.SSLContextBuilder
 import org.onap.ccsdk.apps.blueprintsprocessor.rest.SSLBasicAuthRestClientProperties
 import org.onap.ccsdk.apps.blueprintsprocessor.rest.utils.WebClientUtils
@@ -33,11 +32,10 @@ import java.security.cert.X509Certificate
 class SSLBasicAuthRestClientService(private val restClientProperties: SSLBasicAuthRestClientProperties) :
     BlueprintWebClientService {
 
-    override fun headers(): Array<BasicHeader> {
-        val params = arrayListOf<BasicHeader>()
-        params.add(BasicHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
-        params.add(BasicHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE))
-        return params.toTypedArray()
+    override fun defaultHeaders(): Map<String, String> {
+        return mapOf(
+                HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE,
+                HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE)
     }
 
     override fun host(uri: String): String {
index 6e90957..d5dec3a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 Bell Canada
+ * Copyright © 2019 Bell Canada, Nordix Foundation
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -12,6 +12,8 @@
  * 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
  */
 
 package org.onap.ccsdk.apps.blueprintsprocessor.rest.service
@@ -24,12 +26,19 @@ import org.springframework.http.MediaType
 class TokenAuthRestClientService(private val restClientProperties: TokenAuthRestClientProperties) :
     BlueprintWebClientService {
 
-    override fun headers(): Array<BasicHeader> {
-        val params = arrayListOf<BasicHeader>()
-        params.add(BasicHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE))
-        params.add(BasicHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE))
-        params.add(BasicHeader(HttpHeaders.AUTHORIZATION, restClientProperties.token))
-        return params.toTypedArray()
+    override fun defaultHeaders(): Map<String, String> {
+        return mapOf(
+                HttpHeaders.CONTENT_TYPE to MediaType.APPLICATION_JSON_VALUE,
+                HttpHeaders.ACCEPT to MediaType.APPLICATION_JSON_VALUE,
+                HttpHeaders.AUTHORIZATION to restClientProperties.token!!)
+    }
+
+    override fun convertToBasicHeaders(headers: Map<String, String>): Array<BasicHeader> {
+        val customHeaders: MutableMap<String, String> = headers.toMutableMap()
+        if (!headers.containsKey(HttpHeaders.AUTHORIZATION)) {
+            customHeaders[HttpHeaders.AUTHORIZATION] = restClientProperties.token!!
+        }
+        return super.convertToBasicHeaders(customHeaders)
     }
 
     override fun host(uri: String): String {
index d6167a8..b9a014e 100644 (file)
@@ -30,6 +30,6 @@ class WebClientUtils {
             HttpRequestInterceptor { request, _ -> log.info("Rest request method(${request?.requestLine?.method}), url(${request?.requestLine?.uri})") }
 
         fun logResponse(): HttpResponseInterceptor =
-            HttpResponseInterceptor { response, _ -> log.info("Response status(${response.statusLine.statusCode})") }
+            HttpResponseInterceptor { response, _ -> log.info("Response status(${response.statusLine.statusCode} - ${response.statusLine.reasonPhrase})") }
     }
 }
\ No newline at end of file
index 4fa82df..0390550 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2017-2018 AT&T Intellectual Property.
+ * 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.
@@ -12,6 +13,8 @@
  * 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
  */
 
 package org.onap.ccsdk.apps.blueprintsprocessor.rest.service
@@ -29,9 +32,11 @@ import org.springframework.test.context.ContextConfiguration
 import org.springframework.test.context.TestPropertySource
 import org.springframework.test.context.junit4.SpringRunner
 import org.springframework.web.bind.annotation.GetMapping
+import org.springframework.web.bind.annotation.PatchMapping
 import org.springframework.web.bind.annotation.RequestMapping
 import org.springframework.web.bind.annotation.RestController
 import kotlin.test.Test
+import kotlin.test.assertEquals
 import kotlin.test.assertNotNull
 
 @RunWith(SpringRunner::class)
@@ -58,6 +63,13 @@ class RestClientServiceTest {
         assertNotNull(response, "failed to get response")
     }
 
+    @Test
+    fun testPatch() {
+        val restClientService = bluePrintRestLibPropertyService.blueprintWebClientService("sample")
+        val response = restClientService.exchangeResource(HttpMethod.PATCH.name, "/sample/name", "")
+        assertEquals("Patch request successful", response, "failed to get patch response")
+    }
+
 }
 
 @RestController
@@ -65,5 +77,7 @@ class RestClientServiceTest {
 open class SampleController {
     @GetMapping("/name")
     fun getName(): String = "Sample Controller"
+    @PatchMapping("/name")
+    fun patchName(): String = "Patch request successful"
 }