[APACHECNF] Update healthcheck and add scale workflow 70/131670/1 jakarta
authorLukasz Rajewski <lukasz.rajewski@t-mobile.pl>
Fri, 21 Oct 2022 15:36:17 +0000 (17:36 +0200)
committerMichal Jagiello <michal.jagiello@t-mobile.pl>
Fri, 21 Oct 2022 16:17:40 +0000 (16:17 +0000)
Issue-ID: INT-2164
Signed-off-by: Lukasz Rajewski <lukasz.rajewski@t-mobile.pl>
Change-Id: I7cf59f58592321ec06d8d812bd081293130ec74d
(cherry picked from commit 5762244a0c6282557169c8183e464f6950438122)

tutorials/ApacheCNF/automation/README.md
tutorials/ApacheCNF/automation/healthcheck.py
tutorials/ApacheCNF/automation/scale.py [new file with mode: 0644]
tutorials/ApacheCNF/service_config.yaml
tutorials/ApacheCNF/templates/cba/Definitions/CNF.json
tutorials/ApacheCNF/templates/cba/Definitions/data_types.json
tutorials/ApacheCNF/templates/cba/Definitions/resources_definition_types.json
tutorials/ApacheCNF/templates/cba/Scripts/kotlin/ConfigDeploySetup.kt
tutorials/ApacheCNF/templates/cba/Scripts/kotlin/K8sHealthCheck.kt
tutorials/ApacheCNF/templates/cba/Scripts/kotlin/SimpleStatusCheck.kt
tutorials/ApacheCNF/templates/cba/Templates/config-setup-mapping.json

index 5b2b80b..66138c9 100644 (file)
@@ -28,5 +28,8 @@
 8. Run script `python create_cloud_regions.py` in order to create **k8s or openstack cloud region**
 9. Onboard CNF `python onboard.py`
 10. Instantiate CNF `python instantiate.py`
-11. Once test is done, CNF service instance can be deleted with `python delete.py` command
-
+11. To run healtcheck operation execute `python healthcheck.py <status_check_max_count>` where <status_check_max_count> [int] (default 1)
+    indicates iteration number to run status check in case of failure
+12. To run scale operation execute `python scale.py <replica_count>` where <replica_count> [int] (default 1)
+    indicates the number of desired replicas of Apache pods
+13. Once test is done, CNF service instance can be deleted with `python delete.py` command
index 9c33375..6fe7239 100644 (file)
@@ -1,5 +1,6 @@
 # ============LICENSE_START=======================================================
 # Copyright (C) 2021 Samsung
+# Modification Copyright (C) 2022 Deutsche Telekom AG
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -16,6 +17,7 @@
 # ============LICENSE_END=========================================================
 import logging
 import os
+import sys
 import zipfile
 from io import BytesIO
 
@@ -61,7 +63,7 @@ def resolve_hc_inputs(config: Config):
     vnf_id = vnfs[0].vnf_id
     return service_id, vnf_id
 
-def main():
+def main(status_count):
     mypath = os.path.dirname(os.path.realpath(__file__))
     config = Config(env_dict=VariablesDict.env_variable)
     for vnf in config.service_model["vnfs"]:
@@ -77,7 +79,8 @@ def main():
             cds_input = {"health-check-properties":
                 {
                     "service-instance-id": serv_id,
-                    "vnf-id": vnf_id
+                    "vnf-id": vnf_id,
+                    "status-check-max-count": int(status_count)
                 }
             }
 
@@ -90,4 +93,8 @@ def main():
             logger.info("Please check cds-blueprints-processor logs to see exact status")
 
 if __name__ == "__main__":
-    main()
+    status_count = 1
+    if len(sys.argv) > 1:
+        status_count = sys.argv[1]
+    print(f"Status Check Max Count: %s" % status_count)
+    main(status_count)
diff --git a/tutorials/ApacheCNF/automation/scale.py b/tutorials/ApacheCNF/automation/scale.py
new file mode 100644 (file)
index 0000000..e4623f4
--- /dev/null
@@ -0,0 +1,100 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2022 Deutsche Telekom AG
+# ================================================================================
+# 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 logging
+import os
+import sys
+import zipfile
+from io import BytesIO
+
+from onapsdk.aai.business import Customer
+from onapsdk.cds.blueprint import Workflow, Blueprint
+from config import Config, VariablesDict
+
+#FIXME remove from global scope
+logger = logging.getLogger("")
+logger.setLevel(logging.INFO)
+fh = logging.StreamHandler()
+fh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+fh.setFormatter(fh_formatter)
+logger.addHandler(fh)
+
+
+def resolve_inputs(config: Config):
+    logger.info("******** Check Customer *******")
+    customer_id = config.service_instance["customer_id"]
+    customer = Customer.get_by_global_customer_id(customer_id)
+    if customer is None:
+        raise Exception("Customer %s wasn't found in ONAP" % customer_id)
+    logger.info("******** Check Service Subscription *******")
+    service_subscription = None
+    for service_sub in customer.service_subscriptions:
+        logger.debug("Service subscription %s is found", service_sub.service_type)
+        if service_sub.service_type == config.service_model["model_name"]:
+            logger.info("Service %s subscribed", config.service_model["model_name"])
+            service_subscription = service_sub
+            break
+    logger.info("******** Retrieve Service Metadata *******")
+    service_instance = None
+    for single_service in service_subscription.service_instances:
+        if single_service.instance_name == config.service_instance["instance_name"]:
+            service_instance = single_service
+            break
+    service_id = service_instance.instance_id
+    vnfs = list(service_instance.vnf_instances)
+    if len(vnfs) > 1:
+        raise NotImplementedError("Service %s is composed of more than one vnf!" % service_id)
+    if not vnfs:
+        raise Exception("Service %s doesn't contain any vnfs" % service_id)
+    vnf_id = vnfs[0].vnf_id
+    return service_id, vnf_id
+
+def main(replica_count):
+    mypath = os.path.dirname(os.path.realpath(__file__))
+    config = Config(env_dict=VariablesDict.env_variable)
+    for vnf in config.service_model["vnfs"]:
+        file = vnf["vsp"]["vsp_file"]
+        file_path = os.path.join(mypath, file)
+        with zipfile.ZipFile(file_path, 'r') as package:
+            cba_io = BytesIO(package.read("CBA.zip"))
+            cba_io.seek(0)
+            blueprint = Blueprint(cba_io.read())
+
+            healthcheck: Workflow = blueprint.get_workflow_by_name('scale')
+            serv_id, vnf_id = resolve_inputs(config)
+            cds_input = {"scale-properties":
+                {
+                    "service-instance-id": serv_id,
+                    "vnf-id": vnf_id,
+                    "status-check-max-count": 20,
+                    "replica-count": int(replica_count)
+                }
+            }
+
+            logger.info("Requesting Scale for CBA %s:%s with inputs:\n%s",
+                    blueprint.metadata.template_name,
+                    blueprint.metadata.template_version,
+                    cds_input)
+            result = healthcheck.execute(cds_input)
+            logger.info("Scale process completed with result: %s", result)
+            logger.info("Please check cds-blueprints-processor logs to see exact status")
+
+if __name__ == "__main__":
+    replica_count = 1
+    if len(sys.argv) > 1:
+        replica_count = sys.argv[1]
+    print(f"Replica Count: %s" % replica_count)
+    main(replica_count)
index 623832a..47bab15 100644 (file)
@@ -90,6 +90,6 @@ service_instance:
             k8s-rb-profile-namespace: "{{ user_params.k8s_namespace }}"
             k8s-rb-config-template-name: replica-count-template
             k8s-rb-config-name: replica-count-change
-            k8s-rb-config-value-source: custom-values
+            k8s-rb-config-value-source: default-values
 #  pnfs:
 #    - model_name: pnf_example
index 2e30ce0..4f44e8a 100644 (file)
                     "config-deploy",
                     "config-deploy-setup"
                 ]
+            },
+            "status-check-max-count": {
+                "get_attribute": [
+                    "config-setup-process",
+                    "",
+                    "assignment-map",
+                    "config-deploy",
+                    "status-check-max-count"
+                ]
             }
         }
     },
                         ],
                         "on_success": [
                             "health-check-process"
-                        ],
-                        "on_failure": [
-                            "handle_error"
                         ]
                     },
                     "health-check-process": {
                         ],
                         "on_success": [
                             "collect-results"
-                        ],
-                        "on_failure": [
-                            "handle_error"
                         ]
                     },
                     "handle_error": {
index 603b0ba..1573c81 100644 (file)
                     "description": "",
                     "required": false,
                     "type": "string"
+                },
+                "replica-count": {
+                    "description": "replica count for apache pods",
+                    "type": "integer",
+                    "required": false
+                },
+                "status-check-max-count": {
+                    "description": "max status check count for pods",
+                    "type": "integer",
+                    "required": false,
+                    "default": 30
                 }
             },
             "derived_from": "tosca.datatypes.Dynamic"
                     "description": "",
                     "required": false,
                     "type": "string"
+                },
+                "status-check-max-count": {
+                    "description": "max status check count for pods",
+                    "type": "integer",
+                    "required": false,
+                    "default": 30
                 }
             },
             "derived_from": "tosca.datatypes.Dynamic"
                     "description": "replica count for apache pods",
                     "type": "integer",
                     "default": 2
+                },
+                "status-check-max-count": {
+                    "description": "max status check count for pods",
+                    "type": "integer",
+                    "required": false,
+                    "default": 30
                 }
             },
             "derived_from": "tosca.datatypes.Dynamic"
                     "description": "replica count for apache pods",
                     "type": "integer",
                     "default": 1
+                },
+                "status-check-max-count": {
+                    "description": "max status check count for pods",
+                    "type": "integer",
+                    "required": false,
+                    "default": 30
                 }
             },
             "derived_from": "tosca.datatypes.Dynamic"
                     "description": "the data content of the policy request parameters",
                     "required": false,
                     "type": "json"
+                },
+                "status-check-max-count": {
+                    "description": "max status check count for pods",
+                    "type": "integer",
+                    "required": false,
+                    "default": 30
                 }
             },
             "derived_from": "tosca.datatypes.Dynamic"
index 38b5fee..31f04c1 100644 (file)
             }
         }
     },
+    "status-check-max-count": {
+        "tags": "max status check count for pods",
+        "name": "status-check-max-count",
+        "property": {
+            "description": "max status check count for pods",
+            "type": "integer"
+        },
+        "group": "default",
+        "updated-by": "Lukasz Rajewski <lukasz.rajewski@t-mobile.pl>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            }
+        }
+    },
     "service-instance-name": {
         "tags": "service-instance-name",
         "name": "service-instance-name",
index 77d86d0..f925be0 100644 (file)
@@ -70,17 +70,22 @@ open class ConfigDeploySetup() : ResourceAssignmentProcessor() {
                     }
                 }
             } else if (executionRequest.name == "replica-count") {
-                var value = raRuntimeService.getInputValue(executionRequest.name)
                 retValue = "1"
-                if (!value.isNullOrMissing()) {
-                    retValue = value.asText()
-                } else {
-                    value = raRuntimeService.getInputValue("data")
+                try {
+                    var value = raRuntimeService.getInputValue(executionRequest.name)
                     if (!value.isNullOrMissing()) {
-                        if (value["replicaCount"] != null) {
-                            retValue = value["replicaCount"].asText()
+                        retValue = value.asText()
+                    } else {
+                        value = raRuntimeService.getInputValue("data")
+                        if (!value.isNullOrMissing()) {
+                            if (value["replicaCount"] != null) {
+                                retValue = value["replicaCount"].asText()
+                            }
                         }
                     }
+                } catch (e: Exception) {
+                    log.error(e.message, e)
+                    log.info("Setting default replica count: 1")
                 }
             } else if (executionRequest.name == "config-deploy-setup") {
                 val modulesSdnc = raRuntimeService.getResolutionStore("vf-modules-list-sdnc")["vf-modules"]
index dd87c6f..30b4d96 100644 (file)
@@ -119,7 +119,6 @@ open class K8sHealthCheck : AbstractScriptComponentFunction() {
     }
 
     override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
-        log.info("Executing Recovery")
-        bluePrintRuntimeService.getBluePrintError().addError("${runtimeException.message}", getName())
+        this.addError("${runtimeException.message}")
     }
 }
index c99dcd4..c1f59d9 100644 (file)
@@ -38,6 +38,7 @@ open class SimpleStatusCheck : AbstractScriptComponentFunction() {
         log.info("SIMPLE STATUS CHECK - START")
 
         val configValueSetup: ObjectNode = getDynamicProperties("config-deploy-setup") as ObjectNode
+        var checkCount: Int = getDynamicProperties("status-check-max-count").asInt()
 
         val bluePrintPropertiesService: BluePrintPropertiesService =
             this.functionDependencyInstanceAsType("bluePrintPropertiesService")
@@ -46,7 +47,6 @@ open class SimpleStatusCheck : AbstractScriptComponentFunction() {
 
         val instanceApi = K8sPluginInstanceApi(k8sConfiguration)
 
-        var checkCount: Int = 30 // in the future to be read in from the input
         while (checkCount > 0) {
             var continueCheck = false
             configValueSetup.fields().forEach { it ->
@@ -75,7 +75,6 @@ open class SimpleStatusCheck : AbstractScriptComponentFunction() {
     }
 
     override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
-        log.info("Executing Recovery")
         this.addError("${runtimeException.message}")
     }
 }
index 95d2681..34189bc 100644 (file)
         "dependencies": [
             "service-instance-id"
         ]
+    },
+    {
+        "name": "status-check-max-count",
+        "property": {
+            "description": "max status check count for pods",
+            "required": false,
+            "type": "integer",
+            "default": 30
+        },
+        "input-param": false,
+        "dictionary-name": "status-check-max-count",
+        "dictionary-source": "default",
+        "dependencies": [],
+        "version": 0
     }
 ]