[APACHE] Add Apache CNF use case files 41/127941/6
authorLukasz Rajewski <lukasz.rajewski@orange.com>
Mon, 21 Mar 2022 23:52:38 +0000 (00:52 +0100)
committerLukasz Rajewski <lukasz.rajewski@orange.com>
Tue, 22 Mar 2022 09:43:21 +0000 (10:43 +0100)
Issue-ID: INT-2094
Signed-off-by: Lukasz Rajewski <lukasz.rajewski@orange.com>
Signed-off-by: Michal Chabiera <michal.chabiera@orange.com>
Signed-off-by: Michal Grzesik <michal.grzesik@orange.com>
Change-Id: Ie8f72b9804f1055f49e1bc85dd0d712841eb0f5d

86 files changed:
.coafile
tutorials/ApacheCNF/README.txt [new file with mode: 0644]
tutorials/ApacheCNF/automation/Pipfile [new file with mode: 0644]
tutorials/ApacheCNF/automation/README.md [new file with mode: 0644]
tutorials/ApacheCNF/automation/__init__.py [new file with mode: 0644]
tutorials/ApacheCNF/automation/artifacts/cluster_kubeconfig [new file with mode: 0644]
tutorials/ApacheCNF/automation/config.py [new file with mode: 0644]
tutorials/ApacheCNF/automation/create_cloud_regions.py [new file with mode: 0644]
tutorials/ApacheCNF/automation/delete.py [new file with mode: 0644]
tutorials/ApacheCNF/automation/healthcheck.py [new file with mode: 0644]
tutorials/ApacheCNF/automation/instantiate.py [new file with mode: 0644]
tutorials/ApacheCNF/automation/k8s_client.py [new file with mode: 0644]
tutorials/ApacheCNF/automation/onap_settings.py [new file with mode: 0644]
tutorials/ApacheCNF/automation/onboard.py [new file with mode: 0644]
tutorials/ApacheCNF/automation/update_cba.py [new file with mode: 0644]
tutorials/ApacheCNF/automation/update_connectivity_info.py [new file with mode: 0644]
tutorials/ApacheCNF/automation/vsp/.gitkeep [new file with mode: 0644]
tutorials/ApacheCNF/automation/vsp/.keep [new file with mode: 0644]
tutorials/ApacheCNF/service_config.yaml [new file with mode: 0644]
tutorials/ApacheCNF/templates/.gitattributes [new file with mode: 0644]
tutorials/ApacheCNF/templates/.gitignore [new file with mode: 0644]
tutorials/ApacheCNF/templates/Makefile [new file with mode: 0644]
tutorials/ApacheCNF/templates/README.txt [new file with mode: 0644]
tutorials/ApacheCNF/templates/base_native/MANIFEST.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba-dev/bootstrap.sh [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba-dev/build.sh [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba-dev/deploy.sh [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba-dev/enrich.sh [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba-dev/run-vf-base-ra.sh [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba-dev/run-vnf-config.sh [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba-dev/run-vnf-ra.sh [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Definitions/CNF.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Definitions/artifact_types.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Definitions/data_types.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Definitions/node_types.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Definitions/policy_types.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Definitions/relationship_types.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Definitions/resources_definition_types.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Scripts/kotlin/CollectorScript.kt [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Scripts/kotlin/ConfigDeploy.kt [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Scripts/kotlin/ConfigDeploySetup.kt [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Scripts/kotlin/K8sHealthCheck.kt [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Scripts/kotlin/README.md [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Scripts/kotlin/SimpleErrorCheck.kt [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Scripts/kotlin/SimpleStatusCheck.kt [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/TOSCA-Metadata/TOSCA.meta [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/cnf-mapping.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/cnf-template.vtl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/config-setup-mapping.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/config-setup-template.vtl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config.tar.gz [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/Chart.yaml [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/.helmignore [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/Chart.yaml [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/README.md [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_affinities.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_capabilities.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_errors.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_images.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_labels.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_names.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_secrets.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_storage.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_tplvalues.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_utils.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_validations.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_warnings.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/values.yaml [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/templates/_helpers.tpl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/templates/deployment.yaml [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/values.yaml [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/default-values.yaml [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/restore-values.yaml [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/values-mapping.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/values.yaml.vtl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-profiles/cnf-cds-base-profile.tar.gz [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/k8s-profiles/node-port-profile.tar.gz [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/vnf-mapping.json [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/Templates/vnf-template.vtl [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba/pom.xml [new file with mode: 0644]
tutorials/ApacheCNF/templates/cba2dd.py [new file with mode: 0644]
tutorials/ApacheCNF/templates/helm/.gitignore [new file with mode: 0644]
tutorials/ApacheCNF/templates/helm/Makefile [new file with mode: 0644]
tutorials/ApacheCNF/templates/helm/README.txt [new file with mode: 0644]
tutorials/ApacheCNF/templates/tools/tail_all.sh [new file with mode: 0644]
tutorials/ApacheCNF/templates/tools/tail_config [new file with mode: 0644]

index 0d741e6..47cd835 100644 (file)
--- a/.coafile
+++ b/.coafile
@@ -1,10 +1,11 @@
 [yaml]
 bears = YAMLLintBear
 yamllint_config = .yamllint
-#[vFW_CNF_CDS] Helm tests use go template conditionals that are not yaml-compliant
+# [vFW_CNF_CDS][APACHE] Helm uses go template conditionals that are not yaml-compliant
 ignore =
   .tox/**,
-  heat/vFW_CNF_CDS/templates/helm/**/templates/tests/*
+  heat/vFW_CNF_CDS/templates/helm/**/templates/tests/*,
+  tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/templates/*
 
 [json]
 bears = JSONFormatBear
diff --git a/tutorials/ApacheCNF/README.txt b/tutorials/ApacheCNF/README.txt
new file mode 100644 (file)
index 0000000..d113090
--- /dev/null
@@ -0,0 +1,13 @@
+Demo directory structure:
+
+/templates/           #Base directory containing vFW resources
+    |- /base_dummy    #Directory containing base payload of VSP package in OpenStack VSP format, doesn't need further proceeding
+    |- /base_native   #Directory containing base payload of VSP package in Helm VSP, doesn't need further proceeding
+    |- /helm          #Directory containing helm charts that need to be packaged and attached to VSP package
+    \- /cba           #Directory containing CBA content to be included to csar package. It is prepared for 
+/examples/            #Directory with context-specific overrides over general resources
+/automation/          #Directory with automation scripts. For more details read README file inside.
+
+Note: Makefile script generates two VSP packages, one in Frankfurt format with helm associated with dummy heat templates and second
+with native Helm VSP format where helm packages are standalone. CBA folder contains CBA Definition for native VSP format but 
+make is coverting the definition into Frankfurt format for Frankfurt VSP. Frankfurt VSP is still supported in Guilin. 
diff --git a/tutorials/ApacheCNF/automation/Pipfile b/tutorials/ApacheCNF/automation/Pipfile
new file mode 100644 (file)
index 0000000..a8e7926
--- /dev/null
@@ -0,0 +1,14 @@
+[[source]]
+name = "pypi"
+url = "https://pypi.org/simple"
+verify_ssl = true
+
+[dev-packages]
+
+[packages]
+onapsdk = "==9.3.0"
+markupsafe = "==2.0.1"
+kubernetes = "*"
+
+[requires]
+python_version = "3.8"
diff --git a/tutorials/ApacheCNF/automation/README.md b/tutorials/ApacheCNF/automation/README.md
new file mode 100644 (file)
index 0000000..5b2b80b
--- /dev/null
@@ -0,0 +1,32 @@
+# CNF automation
+
+0. Make sure you have python 3.8.x installed and default interpreter, what is required by onap-pythonsdk
+1. Install required packages with pipenv `pipenv install`
+2. Run virtual environment `pipenv shell`. In case of problems you maye try also `--fancy` option
+   
+   **In case of problems with pipenv:** `venv` can be used as well. In that case, please install all required python packages in correct version according the list in `Pipfile`
+3. Add kubeconfig file for k8s cluster that will host your CNF. Apache can be deployed on any standard cluster but with defult values it need LoadBlanacer
+   - `artifacts/kubeconfig`
+4. Prepare onboarding packages `cd ../templates/ && make && cd ../automation/`
+5. Modify `service_config.yaml`. Please note that the configuration file has yaml syntax but also is jinja templated
+   and values defined in the configuration file may be used also in the jinja templaring process. Templating is an iterative process unless all the values are
+   not resolved. Please not that in most cases you don't have to modify this file at all, despite the configuration of your k8s cluster.
+   We recommend to modify only values from the 'UserParams' section:
+   - cnf_name - name of CNF
+   - k8s_namespace - k8s namespace to use for deployment of CNF
+   - k8s_version - version of the k8s cluster (important for proper helm templating)
+   - k8s_region - name of the k8s region that we want to create in ONAP
+   - release_name - name of the rleease of the helm application (user for naming of k8s resources)
+   - profile_source - source of the k8s profile with values - in our case it may be used to change from LoandBalanser to NodePort service type
+   - skip_day_2 - it defined the SKIP_POST_INSTANTIATION flag in SDC models. The value is used in the SDC service model name
+6. Verify service_config.yaml by running `python config.py`
+7. __Important:__ Before running python scripts, some settings for `onapsdk` with information about ONAP endpoints (and socks) have to be exported. 
+   All settings for ONAP instance are located in `automation/onap_settings.py` file. To export that settings please run command inside `pipenv` or `venv` shell
+   ```shell
+   (automation) ubuntu@onap:~/automation$ export ONAP_PYTHON_SDK_SETTINGS="onap_settings"
+   ```
+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
+
diff --git a/tutorials/ApacheCNF/automation/__init__.py b/tutorials/ApacheCNF/automation/__init__.py
new file mode 100644 (file)
index 0000000..9525040
--- /dev/null
@@ -0,0 +1,19 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Orange
+# ================================================================================
+# 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=========================================================
+
+from .config import Config
+from .k8s_client import K8sClient
diff --git a/tutorials/ApacheCNF/automation/artifacts/cluster_kubeconfig b/tutorials/ApacheCNF/automation/artifacts/cluster_kubeconfig
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tutorials/ApacheCNF/automation/config.py b/tutorials/ApacheCNF/automation/config.py
new file mode 100644 (file)
index 0000000..2498367
--- /dev/null
@@ -0,0 +1,142 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Orange
+# ================================================================================
+# 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=========================================================
+from typing import Dict, Union, List
+import oyaml as yaml
+import os
+from jinja2 import Template
+
+
+class VariablesDict:
+    env_variable = dict(os.environ)
+
+
+class Config:
+    def __init__(self, filename: str = "service_config.yaml", env_dict=None, print_final_file=False):
+        if env_dict is None:
+            env_dict = {}
+        self.filepath = os.path.join(os.path.dirname(os.path.dirname(
+            os.path.realpath(__file__))), filename)
+        self.content_env: Dict = env_dict
+        self.service_instance: Union[None, Dict] = None
+        self.service_model: Union[None, Dict] = None
+        self.user_params: Union[None, Dict] = None
+        self.cloud_regions: Union[None, List] = None
+        self.so_input: Union[None, Dict] = None
+        self.render(print_final_file)
+        self.so_input = self.create_so_input()
+
+    def _load_file(self) -> dict:
+        with open(self.filepath) as file:
+            file_content = yaml.safe_load(file)
+        return file_content
+
+    @staticmethod
+    def templating(rend_dict: dict, render_keys: dict):
+        for k, v in rend_dict.items():
+            if isinstance(v, str):
+                t = Template(v)
+                rend_dict[k] = t.render(**render_keys).strip()
+            elif isinstance(v, dict):
+                Config.templating(rend_dict=v, render_keys=render_keys)
+            elif isinstance(v, list):
+                for i in v:
+                    Config.templating(rend_dict=i, render_keys=render_keys)
+            else:
+                pass
+        return rend_dict
+
+    def render(self, print_final_file=False):
+        raw_file = self._load_file()
+        config_dict = self._render(templated_file=raw_file)
+
+        while not self._completed(templated_file=config_dict):
+            config_dict = self._render(templated_file=config_dict)
+
+        self.__dict__.update(**config_dict)
+        if print_final_file:
+            print(yaml.dump(config_dict, sort_keys=False))
+
+    def _render(self, templated_file: dict) -> dict:
+        config_dict = self.templating(
+            rend_dict=templated_file,
+            render_keys={**self.content_env, **templated_file})
+
+        return config_dict
+
+    def _completed(self, templated_file: dict) -> bool:
+        for v in templated_file.values():
+            if isinstance(v, str):
+                if "{{" in v and "}}" in v:
+                    return False
+            elif isinstance(v, dict):
+                return self._completed(templated_file=v)
+            elif isinstance(v, list):
+                for i in v:
+                    return self._completed(templated_file=i)
+            else:
+                pass
+        return True
+
+    def create_so_input(self, other_cluster=False) -> dict:
+        so_input_dict = dict()
+        so_input_dict["subscription_service_type"] = self.service_instance.get("model_name")
+        _vnfs = self.service_instance.get("vnfs")
+        vnfs = list()
+
+        for vnf in _vnfs:
+            _vnf_raw = dict()
+            # filter vnfs with cloud_region, code block not required with ONAP Jakrta+
+            if vnf.get("cloud_region") and vnf.get("tenant_name"):
+                if not other_cluster:
+                    continue
+                _vnf_raw["cloud_region"] = vnf.get("cloud_region")
+                _vnf_raw["tenant_name"] = vnf.get("tenant_name")
+            else:
+                if other_cluster:
+                    continue
+            # end of filter, end of code block
+            _vnf_raw["model_name"] = vnf.get("model_name")
+            if vnf.get("vnf_name_suffix"):
+                _vnf_raw["instance_name"] = "Instance_" + vnf.get("model_name") + "_" + vnf.get("vnf_name_suffix")
+            else:
+                _vnf_raw["instance_name"] = "Instance_" + vnf.get("model_name") + "_" + str(_vnfs.index(vnf))
+            if vnf.get("processing_priority"):
+                _vnf_raw["processing_priority"] = vnf.get("processing_priority")
+            _vnf_raw["parameters"] = vnf.get("parameters")
+            _vnf_raw["vf_modules"] = list()
+            _vf_modules = vnf.get("vf_modules")
+            for vf_module in _vf_modules:
+                _vf_module_raw = dict()
+                _vf_module_raw["model_name"] = vf_module.get("model_name")
+                if vf_module.get("vf_module_name_suffix"):
+                    _vf_module_raw["instance_name"] = \
+                        "Instance_" + vf_module.get("model_name") + "_" + vf_module.get("vf_module_name_suffix")
+                else:
+                    _vf_module_raw["instance_name"] = \
+                        "Instance_" + vf_module.get("model_name") + "_" + str(_vnfs.index(vnf)) + \
+                        "_" + str(_vf_modules.index(vf_module))
+                if vf_module.get("processing_priority"):
+                    _vf_module_raw["processing_priority"] = vf_module["processing_priority"]
+                _vf_module_raw["parameters"] = vf_module.get("parameters")
+                _vnf_raw["vf_modules"].append(_vf_module_raw)
+            vnfs.append(_vnf_raw)
+        so_input_dict["vnfs"] = vnfs
+
+        return so_input_dict
+
+if __name__ == "__main__":
+    config = Config(env_dict=VariablesDict.env_variable, print_final_file=True)
diff --git a/tutorials/ApacheCNF/automation/create_cloud_regions.py b/tutorials/ApacheCNF/automation/create_cloud_regions.py
new file mode 100644 (file)
index 0000000..9cf94f1
--- /dev/null
@@ -0,0 +1,202 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Orange
+# ================================================================================
+# 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
+from uuid import uuid4
+
+from onapsdk.so.so_db_adapter import SoDbAdapter, IdentityService
+
+from config import Config, VariablesDict
+from onapsdk.exceptions import ResourceNotFound, APIError
+from onapsdk.aai.cloud_infrastructure import Complex, CloudRegion
+from onapsdk.msb.k8s import ConnectivityInfo
+
+logger = logging.getLogger()
+logger.setLevel(logging.DEBUG)
+
+
+def create_complex(complex_id):
+    logger.info("******** Complex *******")
+    try:
+        region_complex = next(Complex.get_all(physical_location_id=complex_id))
+        logger.info("Complex exists")
+        return region_complex
+    except ResourceNotFound:
+        logger.info("Complex does not exist")
+        region_complex = Complex.create(physical_location_id=complex_id,
+                                        name=complex_id,
+                                        physical_location_type="office",
+                                        street1="DummyStreet 1",
+                                        city="DummyCity",
+                                        postal_code="00-000",
+                                        country="DummyCountry",
+                                        region="DummyRegion")
+        logger.info("Complex created")
+        return region_complex
+
+
+def create_cloud_region(cloud_region):
+    logger.info("******** Cloud Region *******")
+    region_id = cloud_region["name"]
+    cloud_owner = cloud_region["cloud_owner"]
+    cloud_type = cloud_region["cloud_type"]
+    complex_id = cloud_region["complex_id"]
+    cloud_region_version = "1.0" if cloud_type == "k8s" else "v2.5"
+    try:
+        region = next(CloudRegion.get_all(cloud_owner=cloud_owner, cloud_region_id=region_id))
+        logger.info("Cloud region exists")
+        return region
+    except ResourceNotFound:
+        logger.info("Cloud region does not exist")
+        region = CloudRegion.create(cloud_owner=cloud_owner,
+                                    cloud_region_id=region_id,
+                                    cloud_type=cloud_type,
+                                    owner_defined_type="t1",
+                                    cloud_region_version=cloud_region_version,
+                                    complex_name=complex_id,
+                                    cloud_zone="CloudZone",
+                                    sriov_automation="false",
+                                    orchestration_disabled=False,
+                                    in_maint=False)
+        logger.info("Cloud region created")
+        return region
+
+
+def link_region_to_complex(cloud_region, complx):
+    logger.info("******** Cloud region <-> Complex *******")
+    cloud_region.link_to_complex(complex_object=complx)
+
+
+def add_tenant(cloud_region, tenant_id, tenant_name):
+    logger.info("Tenant does not exist")
+    cloud_region.add_tenant(tenant_id=tenant_id,
+                            tenant_name=tenant_name)
+    logger.info(f"Tenant {tenant_name} added to region")
+
+
+def add_tenants(cloud_region, k8s_region, tenants):
+    logger.info("******** Tenants *******")
+    for tenant in tenants:
+        tenant_name = tenant["name"]
+        if k8s_region:
+            try:
+                next(_tenant for _tenant in cloud_region.tenants if _tenant.name == tenant_name)
+                logger.info("Tenant exists")
+            except (StopIteration, ResourceNotFound):
+                tenant_id = str(uuid4())
+                add_tenant(cloud_region=cloud_region, tenant_id=tenant_id, tenant_name=tenant_name)
+        else:
+            tenant_id = tenant["id"]
+            try:
+                cloud_region.get_tenant(tenant_id)
+                logger.info("Tenant exists")
+            except ResourceNotFound:
+                add_tenant(cloud_region=cloud_region, tenant_id=tenant_id, tenant_name=tenant_name)
+
+
+def update_connectivity_info(region):
+    logger.info("******** Connectivity Info *******")
+    kubeconfig_path = region["kubeconfig_file"]
+    cloud_owner = region["cloud_owner"]
+    region_id = region["name"]
+    try:
+        with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), kubeconfig_path), 'rb') as kubeconfig_file:
+            kubeconfig = kubeconfig_file.read()
+
+        connectivity_info = ConnectivityInfo.get_connectivity_info_by_region_id(cloud_region_id=region_id)
+        logger.info("Connectivity Info exists ")
+        logger.info("Delete Connectivity Info ")
+        connectivity_info.delete()
+        ConnectivityInfo.create(cloud_region_id=region_id,
+                                cloud_owner=cloud_owner,
+                                kubeconfig=kubeconfig)
+        logger.info("Connectivity Info created ")
+    except (APIError, ResourceNotFound):
+        logger.info("Connectivity Info does not exists ")
+        ConnectivityInfo.create(cloud_region_id=region_id,
+                                cloud_owner=cloud_owner,
+                                kubeconfig=kubeconfig)
+        logger.info("Connectivity Info created ")
+    except FileNotFoundError:
+        logger.error("Error - File Not Found")
+        logger.info("Please check if kubeconfig file exists")
+        exit(1)
+
+
+def add_region_to_so_db(region):
+    logger.info("******** SO Database *******")
+    if is_k8s_region(region):
+        identity_service = IdentityService(identity_id="Keystone_K8s",
+                                           url="http://test:5000/v3",
+                                           mso_id="onapsdk_user",
+                                           mso_pass="mso_pass_onapsdk",
+                                           project_domain_name="NULL",
+                                           user_domain_name="NULL",
+                                           identity_server_type="KEYSTONE")
+
+        SoDbAdapter.add_cloud_site(cloud_region_id=region["name"],
+                                   complex_id=region["complex_id"],
+                                   identity_service=identity_service,
+                                   orchestrator="multicloud")
+    else:
+        identity_url = region["identity_url"]
+        mso_id = region["mso_id"]
+        mso_pass = region["mso_pass"]
+        identity_server_type = region["identity_server_type"]
+        identity_service = IdentityService(identity_id=region["name"] + "_KEYSTONE",
+                                           url=identity_url,
+                                           mso_id=mso_id,
+                                           mso_pass=mso_pass,
+                                           project_domain_name="Default",
+                                           user_domain_name="Default",
+                                           identity_server_type=identity_server_type)
+
+        SoDbAdapter.add_cloud_site(cloud_region_id=region["name"],
+                                   complex_id=region["complex_id"],
+                                   identity_service=identity_service,
+                                   orchestrator="NULL")
+
+
+def is_k8s_region(region):
+    is_k8s = False
+    if region["cloud_type"] == "k8s":
+        is_k8s = True
+    return is_k8s
+
+
+########################################################################################################################
+def main():
+    config = Config(env_dict=VariablesDict.env_variable)
+
+    for region in config.cloud_regions:
+        complx = create_complex(region["complex_id"])
+        cloud_region = create_cloud_region(region)
+        link_region_to_complex(cloud_region, complx)
+        add_tenants(cloud_region, is_k8s_region(region), region.get("tenants"))
+        if is_k8s_region(region):
+            update_connectivity_info(region)
+        add_region_to_so_db(region)
+
+
+if __name__ == "__main__":
+    sh = logging.StreamHandler()
+    sh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+    sh.setFormatter(sh_formatter)
+    logger.addHandler(sh)
+
+    main()
diff --git a/tutorials/ApacheCNF/automation/delete.py b/tutorials/ApacheCNF/automation/delete.py
new file mode 100644 (file)
index 0000000..00d0418
--- /dev/null
@@ -0,0 +1,131 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Orange
+# ================================================================================
+# 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
+
+from config import Config, VariablesDict
+from instantiate import get_customer, check_orchestration_status
+
+from onapsdk.exceptions import ResourceNotFound, APIError
+from onapsdk.aai.business import ServiceInstance
+
+logger = logging.getLogger()
+logger.setLevel(logging.DEBUG)
+
+
+def get_service_subscription(customer, service_type):
+    try:
+        service_subscription = customer.get_service_subscription_by_service_type(
+            service_type=service_type)
+        return service_subscription
+    except ResourceNotFound:
+        logger.error("Service Subscription not found")
+        exit(1)
+
+
+def get_service_instance(service_subscription, service_instance_name):
+    try:
+        service_instance = service_subscription.get_service_instance_by_name(
+            service_instance_name=service_instance_name)
+        return service_instance
+    except ResourceNotFound:
+        logger.error("Service Instance not found")
+        exit(1)
+
+
+def delete_service_macro(service_instance: ServiceInstance, service_instance_info):
+    vnf_infos_list = []
+    for index, vnf_info in enumerate(service_instance_info["vnfs"]):
+        if not vnf_info.get("vnf_name_suffix"):
+            vnf_info["vnf_name_suffix"] = str(index)
+        vnf_info["instance_name"] = f"Instance_{vnf_info['model_name']}_{vnf_info['vnf_name_suffix']}"
+        vnf_infos_list.append(vnf_info)
+
+    ordered_vnf_instances = sorted(vnf_infos_list,
+                                   key=lambda _vnf: _vnf.get("processing_priority", 100),
+                                   reverse=True)
+
+    delete_vnfs_instances(service_instance, ordered_vnf_instances)
+
+    return check_orchestration_status(service_instance.delete(a_la_carte=False))
+
+
+def delete_vnfs_instances(service_instance: ServiceInstance, ordered_vnf_instances):
+    for vnf in ordered_vnf_instances:
+        vnf_name = vnf.get("instance_name")
+        vnf_instance = next((vnf_instance
+                             for vnf_instance in service_instance.vnf_instances
+                             if vnf_instance.vnf_name == vnf_name), None)
+        if not vnf_instance:
+            continue
+
+        try:
+            vnf_deletion = vnf_instance.delete(a_la_carte=False)
+        except APIError:
+            logger.error("Operation not supported, whole service instance will be deleted with random order")
+            break
+        check_orchestration_status(vnf_deletion)
+    return
+
+
+def delete_service_alacarte(service_instance):
+    for vnf in service_instance.vnf_instances:
+        for vf_module in vnf.vf_modules:
+            vf_module_deletion = vf_module.delete()
+            check_orchestration_status(vf_module_deletion)
+        vnf_deletion = vnf.delete()
+        check_orchestration_status(vnf_deletion)
+    service_deletion = service_instance.delete(a_la_carte=True)
+    check_orchestration_status(service_deletion)
+
+
+def main():
+    logger.info("*******************************")
+    logger.info("**** SERVICE DELETION ****")
+    logger.info("*******************************")
+
+    config = Config(env_dict=VariablesDict.env_variable)
+    logger.info("******** GET Customer *******")
+    customer = get_customer(config.service_instance["customer_id"])
+
+    logger.info("******** Check Service Subscription *******")
+    service_subscription = get_service_subscription(customer, config.service_instance["model_name"])
+
+    logger.info("******** Get Service Instance details *******")
+    service_instance = get_service_instance(service_subscription, config.service_instance["instance_name"])
+
+    logger.info("******** Delete Service %s *******", service_instance.instance_name)
+    if config.service_model["macro_orchestration"]:
+        # if config.service_instance.get("deletion_policy") in ('InstantiationOrder', 'ReverseInstantiationOrder'):
+        #     delete_service_macro_delete_policy(service_instance, config.service_instance)
+        # else:
+        delete_service_macro(service_instance, config.service_instance)
+    else:
+        logger.error("A_la_carte orchestration method not updated")
+        if config.service_model["pnfs"] is not None:
+            raise NotImplementedError
+        else:
+            delete_service_alacarte(service_instance)
+
+
+if __name__ == "__main__":
+    sh = logging.StreamHandler()
+    sh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+    sh.setFormatter(sh_formatter)
+    logger.addHandler(sh)
+
+    main()
diff --git a/tutorials/ApacheCNF/automation/healthcheck.py b/tutorials/ApacheCNF/automation/healthcheck.py
new file mode 100644 (file)
index 0000000..aee101d
--- /dev/null
@@ -0,0 +1,92 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Samsung
+# ================================================================================
+# 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=========================================================
+#todo update when onapsdk > 9.3.0
+import logging
+import zipfile
+
+from onapsdk.aai.business import Customer
+from onapsdk.cds.blueprint import Workflow, Blueprint
+
+from config import Config
+
+#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_hc_inputs():
+    logger.info("******** Check Customer *******")
+    customer = None
+    for found_customer in list(Customer.get_all()):
+        logger.debug("Customer %s found", found_customer.subscriber_name)
+        if found_customer.subscriber_name == Config.GLOBAL_CUSTOMER_ID:
+            logger.info("Customer %s found", found_customer.subscriber_name)
+            customer = found_customer
+            break
+    if customer is None:
+        raise Exception("Customer %s wasn't found in ONAP" % Config.GLOBAL_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.SERVICENAME:
+            logger.info("Service %s subscribed", Config.SERVICENAME)
+            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_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():
+    blueprint = None
+    with zipfile.ZipFile(Config.VSPFILE, 'r') as package:
+        with package.open("CBA.zip", 'r') as cba:
+            blueprint = Blueprint(cba.read())
+
+    healthcheck = Workflow('health-check', None, blueprint)
+    serv_id, vnf_id = resolve_hc_inputs()
+    cds_input = {"health-check-properties":
+        {
+            "service-instance-id": serv_id,
+            "vnf-id": vnf_id
+        }
+    }
+    logger.info("Requesting Healthcheck 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("Healthcheck process completed with result: %s", result)
+    logger.info("Please check cds-blueprints-processor logs to see exact status")
+
+if __name__ == "__main__":
+    main()
diff --git a/tutorials/ApacheCNF/automation/instantiate.py b/tutorials/ApacheCNF/automation/instantiate.py
new file mode 100644 (file)
index 0000000..0d9dc5e
--- /dev/null
@@ -0,0 +1,474 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Orange
+# ================================================================================
+# 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
+from time import sleep
+
+from config import Config, VariablesDict
+from onapsdk.aai.cloud_infrastructure import (
+    CloudRegion
+)
+from onapsdk.aai.business import (
+    Customer,
+    OwningEntity as AaiOwningEntity
+)
+from onapsdk.exceptions import ResourceNotFound, APIError
+from onapsdk.msb.k8s import Definition
+from onapsdk.so.instantiation import (
+    ServiceInstantiation,
+    InstantiationParameter, SoService, SoServiceVnf)
+from onapsdk.sdc.service import Service
+# from onapsdk.vid import LineOfBusiness, OwningEntity, Platform, Project
+from onapsdk.so.so_element import OrchestrationRequest
+from onapsdk.aai.service_design_and_creation import Service as AaiService
+
+logger = logging.getLogger()
+logger.setLevel(logging.DEBUG)
+
+
+def get_customer(global_customer_id: str = "customer_cnf"):
+    logger.info("******** Customer *******")
+    try:
+        customer = Customer.get_by_global_customer_id(global_customer_id)
+        logger.info("Customer exists")
+    except ResourceNotFound:
+        logger.info("Customer does not exist")
+        customer = Customer.create(global_customer_id, global_customer_id, "INFRA")
+        logger.info("Customer created")
+    return customer
+
+
+def get_service_model(model_name):
+    try:
+        service_model = next(model for model in Service.get_all() if model.name == model_name)
+        logger.info(
+            f"Found Service {service_model.name} in SDC, distribution status: {service_model.distribution_status}")
+        return service_model
+    except StopIteration:
+        logger.error(f"Service model {model_name} not found in SDC")
+        exit(1)
+
+
+def check_service_customer_subscription(customer, service):
+    try:
+        customer.get_service_subscription_by_service_type(
+            service_type=service.name)
+    except ResourceNotFound:
+        return False
+
+    logger.info(f"Customer {customer.subscriber_name} subscribed for {service.name}")
+    return True
+
+
+def subscribe_service_customer(customer, service):
+    if not check_service_customer_subscription(customer, service):
+        logger.info("******** Subscribe Service *******")
+        customer.subscribe_service(service.name)
+
+
+def get_cloud_region(cloud_owner, cloud_region):
+    try:
+        cloud_region_object = next(cr for cr in CloudRegion.get_all() if
+                                   cr.cloud_region_id == cloud_region and cr.cloud_owner == cloud_owner)
+        return cloud_region_object
+    except (StopIteration, ResourceNotFound):
+        logging.error("Cloud region not found!!!")
+        exit(1)
+
+
+def get_tenant(cloud_region, tenant_name):
+    try:
+        tenant = next(tenant for tenant in cloud_region.tenants if tenant.name == tenant_name)
+        return tenant
+    except (StopIteration, ResourceNotFound):
+        logger.error(f"Tenant {tenant_name} not found")
+        exit(1)
+
+
+def add_owning_entity(owning_entity):
+    logger.info("******** Add Owning Entity to AAI *******")
+    try:
+        aai_owning_entity = AaiOwningEntity.get_by_owning_entity_name(owning_entity)
+    except ResourceNotFound:
+        logger.info("******** Owning Entity not existing: create *******")
+        aai_owning_entity = AaiOwningEntity.create(owning_entity)
+
+    return aai_owning_entity
+
+
+def delete_old_profiles(service, service_config):
+    for vnf in service.vnfs:
+        vnf_config_details = next(
+            (_vnf for _vnf in service_config["vnfs"] if _vnf["model_name"] == vnf.model_name), None)
+        if not vnf_config_details:
+            continue
+        for vf_module in vnf.vf_modules:
+            vf_module_label = next(vfm_prop.value for vfm_prop in vf_module.properties if
+                                   vfm_prop.name == "vf_module_label")
+            if vf_module_label == "base_template_dummy_ignore":
+                continue
+            vf_module_config_details = next((_vf_module for _vf_module in vnf_config_details["vf_modules"] if
+                                            _vf_module["model_name"] == vf_module_label), None)
+            if not vf_module_config_details:
+                continue
+            if "k8s-rb-profile-name" not in vf_module_config_details["parameters"]:
+                continue
+            try:
+                definition = Definition.get_definition_by_name_version(
+                    rb_name=vf_module.model_invariant_uuid,
+                    rb_version=vf_module.model_customization_id)
+            except APIError:
+                definition = Definition.get_definition_by_name_version(
+                    rb_name=vf_module.model_invariant_uuid,
+                    rb_version=vf_module.model_version_id)
+            profile_name = vf_module_config_details["parameters"]["k8s-rb-profile-name"]
+            try:
+                profile = definition.get_profile_by_name(profile_name)
+                namespace = None
+                if "k8s-rb-profile-namespace" in vnf_config_details["parameters"]:
+                    namespace = vnf_config_details["parameters"]["k8s-rb-profile-namespace"]
+                if "k8s-rb-profile-namespace" in vf_module_config_details["parameters"]:
+                    namespace = vf_module_config_details["parameters"]["k8s-rb-profile-namespace"]
+                if namespace is not None and profile.namespace != namespace:
+                    profile.delete()
+                    logger.info("Profile: " + profile_name + " for " + vf_module.name + " deleted")
+                else:
+                    logger.info("No need to delete Profile " + profile_name +
+                                " for " + vf_module.name + ". Namespace is fine")
+            except ResourceNotFound:
+                logger.info("Profile: " + profile_name + " for " + vf_module.name + " not found")
+
+
+def check_service_instance_exists(service_subscription, service_instance_name):
+    try:
+        service_instance = next((instance for instance in service_subscription.service_instances
+                                 if instance.instance_name == service_instance_name), None)
+        return service_instance
+    except ResourceNotFound:
+        return None
+
+
+def get_instantiation_parameters(properties, vnf_vf_module_config):
+    instantiation_parameters = []
+    for property_name, property_value in properties:
+        instantiation_parameters.append(InstantiationParameter(name=property_name, value=property_value))
+
+    for instantiation_parameter_key, instantiation_parameter_value in vnf_vf_module_config["parameters"]:
+        instantiation_parameters.append(InstantiationParameter(name=instantiation_parameter_key,
+                                                               value=instantiation_parameter_value))
+
+    return instantiation_parameters
+
+
+def check_orchestration_status(instantiation):
+    status = None
+    while not (status == OrchestrationRequest.StatusEnum.COMPLETED
+               or status == OrchestrationRequest.StatusEnum.FAILED):
+        sleep(10)
+        status = instantiation.status
+        logger.info(f"Orchestration status is: {status.value}")
+
+    if status == OrchestrationRequest.StatusEnum.FAILED:
+        logger.error("Orchestration was failed!")
+        exit(1)
+    else:
+        logger.info("Orchestration was succeed")
+        return
+
+
+def get_aai_service(service_type):
+    logging.info("******** Retrieve product family for service *******")
+    try:
+        aai_service = next(service for service in AaiService.get_all() if service.service_id == service_type)
+    except (ResourceNotFound, StopIteration):
+        logging.info("******** Service design and creation in AAI not existing: create *******")
+        AaiService.create(service_id=service_type, service_description=service_type)
+        aai_service = next(service for service in AaiService.get_all() if service.service_id == service_type)
+
+    return aai_service
+
+
+def instantiate_service_macro(config, service, cloud_region, tenant, customer, owning_entity,
+                              vid_project, vid_line_of_business, vid_platform):
+    service_instance_name = config.service_instance["instance_name"]
+    so_input = config.so_input
+    for vnf in so_input["vnfs"]:
+        _vnf = next(nf for nf in service.vnfs if nf.model_name == vnf["model_name"])
+        sdnc_model_name = next(prop.value for prop in _vnf.properties if prop.name == "sdnc_model_name")
+        sdnc_model_version = next(prop.value for prop in _vnf.properties if prop.name == "sdnc_model_version")
+        sdnc_artifact_name = next(prop.value for prop in _vnf.properties if prop.name == "sdnc_artifact_name")
+
+        vnf["parameters"]["sdnc_model_name"] = sdnc_model_name
+        vnf["parameters"]["sdnc_model_version"] = sdnc_model_version
+        vnf["parameters"]["sdnc_artifact_name"] = sdnc_artifact_name
+        for vf_module in vnf["vf_modules"]:
+            vf_module_label = vf_module["model_name"]
+            vf_module["parameters"]["sdnc_model_name"] = sdnc_model_name
+            vf_module["parameters"]["sdnc_model_version"] = sdnc_model_version
+            vf_module["parameters"]["vf_module_label"] = vf_module_label
+
+    # TODO: PNF support in so_input -> first ONAPSDK
+
+    so_service = SoService.load(so_input)
+
+    aai_service = get_aai_service(service.name)
+    service_instantiation = ServiceInstantiation.instantiate_macro(
+        sdc_service=service,
+        cloud_region=cloud_region,
+        tenant=tenant,
+        customer=customer,
+        owning_entity=owning_entity,
+        project=vid_project,
+        line_of_business=vid_line_of_business,
+        platform=vid_platform,
+        service_instance_name=service_instance_name,
+        aai_service=aai_service,
+        so_service=so_service
+    )
+    check_orchestration_status(service_instantiation)
+
+
+def instantiate_vnfs_macro(config, service_subscription, line_of_business, platform):
+
+    service_instance = check_service_instance_exists(service_subscription, config.service_instance["instance_name"])
+
+    so_input_vnfs_locations = config.create_so_input(other_cluster=True)
+
+    if not so_input_vnfs_locations["vnfs"]:
+        return
+
+    so_input_vnfs_by_priority = sorted(so_input_vnfs_locations["vnfs"],
+                                       key=lambda _vnf: _vnf.get("processing_priority", 100))
+
+    for vnf in so_input_vnfs_by_priority:
+
+        cloud_owner_name = next(
+            region["cloud_owner"] for region in config.cloud_regions if region["name"] == vnf["cloud_region"])
+        cloud_region = get_cloud_region(cloud_owner=cloud_owner_name, cloud_region=vnf["cloud_region"])
+
+        vnf_model = next(nf for nf in service_instance.sdc_service.vnfs
+                         if nf.model_name == vnf["model_name"])
+
+        sdnc_model_name = next(prop.value for prop in vnf_model.properties if prop.name == "sdnc_model_name")
+        sdnc_model_version = next(prop.value for prop in vnf_model.properties if prop.name == "sdnc_model_version")
+        sdnc_artifact_name = next(prop.value for prop in vnf_model.properties if prop.name == "sdnc_artifact_name")
+
+        vnf["parameters"]["sdnc_model_name"] = sdnc_model_name
+        vnf["parameters"]["sdnc_model_version"] = sdnc_model_version
+        vnf["parameters"]["sdnc_artifact_name"] = sdnc_artifact_name
+        for vf_module in vnf["vf_modules"]:
+            vf_module_label = vf_module["model_name"]
+            vf_module["parameters"]["sdnc_model_name"] = sdnc_model_name
+            vf_module["parameters"]["sdnc_model_version"] = sdnc_model_version
+            vf_module["parameters"]["vf_module_label"] = vf_module_label
+
+        so_vnf = SoServiceVnf.load(vnf)
+
+        vnf_instantiation = service_instance.add_vnf(
+            vnf=vnf_model,
+            line_of_business=line_of_business,
+            platform=platform,
+            cloud_region=cloud_region,
+            tenant=get_tenant(cloud_region=cloud_region, tenant_name=vnf["tenant_name"]),
+            vnf_instance_name=vnf["instance_name"],
+            so_vnf=so_vnf,
+            a_la_carte=False
+        )
+
+        check_orchestration_status(vnf_instantiation)
+
+
+def instantiate_vf_module(vf_module, vf_module_param_list, vnf_instance, sdnc_model_name, sdnc_model_version):
+    vf_module_label = next(vfm_prop.value for vfm_prop in vf_module.properties if vfm_prop.name == "vf_module_label")
+    region_id = vf_module_param_list[vf_module_label]["cloud_configuration"]
+    cloud_region = get_cloud_region(
+        Config.CLOUD_REGIONS[region_id]["cloud_owner"],
+        region_id)
+    tenant = get_tenant(cloud_region, Config.CLOUD_REGIONS[region_id]["tenant"]["name"])
+
+    vfmodule_instantiation_parameters = vf_module_param_list[vf_module_label]["instantiation_parameters"].items()
+
+    base_parameters = [
+        InstantiationParameter(name="sdnc_model_name", value=sdnc_model_name),
+        InstantiationParameter(name="sdnc_model_version", value=sdnc_model_version),
+        InstantiationParameter(name="vf_module_label", value=vf_module_label)]
+
+    for instantiation_parameter_key, instantiation_parameter_value in vfmodule_instantiation_parameters:
+        base_parameters.append(InstantiationParameter(name=instantiation_parameter_key,
+                                                      value=instantiation_parameter_value))
+
+    vf_module_instantiation = vnf_instance.add_vf_module(
+        vf_module=vf_module,
+        cloud_region=cloud_region,
+        tenant=tenant,
+        vnf_parameters=base_parameters,
+        use_preload=False
+    )
+    check_orchestration_status(vf_module_instantiation)
+
+
+def check_vf_module_list_correct(vf_modules, vf_modules_config_list):
+    model_labels = set()
+    config_labels = set()
+    for vf_module in vf_modules:
+        _model_label = next(_prop.value for _prop in vf_module.properties if _prop.name == "vf_module_label")
+        model_labels.add(_model_label)
+    for vf_module in vf_modules_config_list:
+        config_labels.add(vf_module.model_name)
+    if model_labels == config_labels:
+        return True
+    else:
+        return False
+
+
+def get_properties(vnf):
+    properties = dict()
+
+    properties["sdnc_model_name"] = next(prop.value for prop in vnf.properties if prop.name == "sdnc_model_name")
+    properties["sdnc_model_version"] = next(prop.value for prop in vnf.properties if prop.name == "sdnc_model_version")
+    properties["sdnc_artifact_name"] = next(prop.value for prop in vnf.properties if prop.name == "sdnc_artifact_name")
+
+    return properties
+
+
+def instantiate_service_alacarte(config, service_subscription, service_model, cloud_region, tenant, customer,
+                                 owning_entity,
+                                 vid_project, vid_line_of_business, vid_platform):
+    raise NotImplementedError("Not supported since 2022")
+
+    service_instance_name = config.service_instance["instance_name"]
+    # Service creation
+    service_instantiation = ServiceInstantiation.instantiate_ala_carte(
+        sdc_service=service_model,
+        cloud_region=cloud_region,
+        tenant=tenant,
+        customer=customer,
+        owning_entity=owning_entity,
+        project=vid_project,
+        service_instance_name=service_instance_name
+    )
+    check_orchestration_status(service_instantiation)
+    # End of service creation
+
+    service_instance = service_subscription.get_service_instance_by_name(service_instance_name)
+    # Add VNFs
+    for vnf in service_model.vnfs:
+        # TODO: priority
+        properties = get_properties(vnf)
+        vnf_config = next(_vnf for _vnf in config.service_instance["vnfs"]
+                          if config.service_instance["vnfs"]["model_name"] == vnf.name)
+        vnf_parameters = get_instantiation_parameters(properties, vnf_config)
+        #  TODO: instance name
+        vnf_instantiation = service_instance.add_vnf(
+            vnf=vnf,
+            line_of_business=vid_line_of_business,
+            platform=vid_platform,
+            vnf_parameters=vnf_parameters
+        )
+        check_orchestration_status(vnf_instantiation)
+
+        # Add vf_modules
+        vnf_type = service_model.name + "/" + vnf.name
+        vnf_instance = next((vnf for vnf in service_instance.vnf_instances if vnf.vnf_type == vnf_type), None)
+
+        if check_vf_module_list_correct(vnf.vf_modules, vnf_config["vf_modules"]):
+            for vf_module in vnf.vf_modules:
+                vf_module_config = next(_vf for _vf in vnf_config["vf_modules"]
+                                        if _vf["model_name"] == vf_module.properties["vf_module_label"])
+                vf_module_parameters = get_instantiation_parameters(properties, vf_module_config)
+                vf_module_instantiation = vnf_instance.add_vf_module(
+                    vf_module=vf_module,
+                    cloud_region=cloud_region,
+                    tenant=tenant,
+                    vnf_parameters=vf_module_parameters,
+                    use_preload=False
+                )
+                check_orchestration_status(vf_module_instantiation)
+        else:
+            logger.error("VF_MODULE_PARAM_LIST error. ")
+        # End of vf_modules
+    # End of VNFs
+
+
+def main():
+    logger.info("*******************************")
+    logger.info("**** SERVICE INSTANTIATION ****")
+    logger.info("*******************************")
+
+    config = Config(env_dict=VariablesDict.env_variable)
+
+    logger.info("******** GET Customer *******")
+    customer = get_customer(config.service_instance["customer_id"])
+
+    logger.info("******** GET Service Model from SDC *******")
+    service = get_service_model(config.service_instance["model_name"])
+
+    logger.info("******** Subscribe Customer for Service *******")
+    subscribe_service_customer(customer, service)
+
+    logger.info("******** Get Tenant *******")
+    region_details = next(
+        region for region in config.cloud_regions if region["name"] == config.service_instance["cloud_region"])
+    cloud_region = get_cloud_region(region_details["cloud_owner"], region_details["name"])
+    tenant = get_tenant(cloud_region,
+                        config.service_instance["tenant_name"])
+
+    ######
+    logger.info("******** Connect Service to Tenant *******")
+    service_subscription = None
+    try:
+        service_subscription = customer.get_service_subscription_by_service_type(
+            service_type=config.service_instance["model_name"])
+    except ResourceNotFound:
+        logger.error("Service subscription %s is not found", config.service_instance["model_name"])
+        exit(1)
+
+    service_subscription.link_to_cloud_region_and_tenant(cloud_region, tenant)
+    ####
+
+    logger.info("******** Business Objects (OE, P, Pl, LoB) *******")
+    project = "Project-Demonstration"
+    platform = "Platform-test"
+    line_of_business = "Orange-LOB"
+    owning_entity = add_owning_entity("Orange")
+
+    logger.info("******** Delete old profiles ********")
+    delete_old_profiles(service, config.service_instance)
+
+    logger.info("******** Instantiate Service *******")
+    service_instance = check_service_instance_exists(service_subscription, config.service_instance["instance_name"])
+    if service_instance:
+        logger.info("******** Service Instance exists, do not instantiate *******")
+    else:
+        logger.info("******** Service Instance not existing: Instantiate *******")
+        if config.service_model["macro_orchestration"]:
+            instantiate_service_macro(config, service, cloud_region, tenant, customer, owning_entity,
+                                      project, line_of_business, platform)
+            instantiate_vnfs_macro(config=config, service_subscription=service_subscription,
+                                   line_of_business=line_of_business, platform=platform)
+        else:
+            instantiate_service_alacarte(config, service_subscription, service, cloud_region, tenant, customer,
+                                         owning_entity, project, line_of_business, platform)
+
+
+if __name__ == "__main__":
+    sh = logging.StreamHandler()
+    sh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+    sh.setFormatter(sh_formatter)
+    logger.addHandler(sh)
+
+    main()
diff --git a/tutorials/ApacheCNF/automation/k8s_client.py b/tutorials/ApacheCNF/automation/k8s_client.py
new file mode 100644 (file)
index 0000000..98b451b
--- /dev/null
@@ -0,0 +1,59 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Orange
+# ================================================================================
+# 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 os
+from pprint import pprint
+
+import oyaml as yaml
+from kubernetes import config, client
+from kubernetes.client import OpenApiException
+
+
+class K8sClient:
+    def __init__(self, kubeconfig_path):
+        self.mypath = os.path.dirname(os.path.realpath(__file__))
+        config.load_kube_config(config_file=os.path.join(self.mypath, kubeconfig_path))
+        self.api_instance = client.CustomObjectsApi()
+
+    def read_custom_object_file(self, file_path):
+        with open(file_path) as crd_file:
+            crd_body = yaml.load(crd_file, Loader=yaml.FullLoader)
+        return crd_body
+
+    def get_custom_object_details(self, crd_body):
+        group = crd_body["apiVersion"].split("/")[0]
+        version = crd_body["apiVersion"].split("/")[1]
+        plural = crd_body["kind"].lower() + "s"
+        #name = crd_body["metadata"]["name"]
+
+        return group, version, plural #, name
+
+    def create_custom_object(self, file_path):
+        crd_body = self.read_custom_object_file(file_path)
+        #group, version, plural, name = self.get_custom_object_details(crd_body)
+        group, version, plural = self.get_custom_object_details(crd_body)
+        api_response = None
+        try:
+            api_response = self.api_instance.create_cluster_custom_object(group=group,
+                                                                          version=version,
+                                                                          plural=plural,
+                                                                          body=crd_body,
+                                                                          pretty="true")
+        except OpenApiException as error:
+            print(str(error.status) + " " + error.reason)
+            pprint(error.body)
+        return api_response
diff --git a/tutorials/ApacheCNF/automation/onap_settings.py b/tutorials/ApacheCNF/automation/onap_settings.py
new file mode 100644 (file)
index 0000000..e0bad35
--- /dev/null
@@ -0,0 +1,73 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Orange
+# ================================================================================
+# 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=========================================================
+
+"""Global settings module."""  # pylint: disable=bad-whitespace
+# uncomment if socks is used
+#from onapsdk.onap_service import OnapService
+
+######################
+#                    #
+# ONAP SERVICES URLS #
+#                    #
+######################
+
+AAI_URL         = "https://aai.api.sparky.simpledemo.onap.org:30233"
+AAI_API_VERSION = "v23"
+AAI_AUTH        = "Basic QUFJOkFBSQ=="
+CDS_URL         = "http://portal.api.simpledemo.onap.org:30449"
+CDS_AUTH        = ("ccsdkapps", "ccsdkapps")
+MSB_URL         = "https://msb.api.simpledemo.onap.org:30283"
+SDC_BE_URL      = "https://sdc.api.be.simpledemo.onap.org:30204"
+SDC_FE_URL      = "https://sdc.api.fe.simpledemo.onap.org:30207"
+SDC_AUTH        = "Basic YWFpOktwOGJKNFNYc3pNMFdYbGhhazNlSGxjc2UyZ0F3ODR2YW9HR21KdlV5MlU="
+SDNC_URL        = "https://sdnc.api.simpledemo.onap.org:30267"
+SDNC_AUTH       = "Basic YWRtaW46S3A4Yko0U1hzek0wV1hsaGFrM2VIbGNzZTJnQXc4NHZhb0dHbUp2VXkyVQ=="
+SO_URL          = "http://so.api.simpledemo.onap.org:30277"
+SO_API_VERSION  = "v7"
+SO_AUTH         = "Basic SW5mcmFQb3J0YWxDbGllbnQ6cGFzc3dvcmQxJA=="
+SO_CAT_DB_AUTH  = "Basic YnBlbDpwYXNzd29yZDEk"
+VID_URL         = "https://vid.api.simpledemo.onap.org:30200"
+VID_API_VERSION = "/vid"
+CLAMP_URL       = "https://clamp.api.simpledemo.onap.org:30258"
+CLAMP_AUTH      = "Basic ZGVtb0BwZW9wbGUub3NhYWYub3JnOmRlbW8xMjM0NTYh"
+VES_URL         = "http://ves.api.simpledemo.onap.org:30417"
+DMAAP_URL       = "http://dmaap.api.simpledemo.onap.org:3904"
+NBI_URL         = "https://nbi.api.simpledemo.onap.org:30274"
+NBI_API_VERSION = "/nbi/api/v4"
+DCAEMOD_URL = ""
+HOLMES_URL = "https://aai.api.sparky.simpledemo.onap.org:30293"
+POLICY_URL = ""
+
+## GUI
+AAI_GUI_URL = "https://aai.api.sparky.simpledemo.onap.org:30220"
+AAI_GUI_SERVICE = f"{AAI_GUI_URL}/services/aai/webapp/index.html#/browse"
+CDS_GUI_SERVICE = f"{CDS_URL}/"
+SO_MONITOR_GUI_SERVICE = f"{SO_URL}/"
+SDC_GUI_SERVICE = f"{SDC_FE_URL}/sdc1/portal"
+SDNC_DG_GUI_SERVICE = f"{SDNC_URL}/nifi/"
+SDNC_ODL_GUI_SERVICE = f"{SDNC_URL}/odlux/index.html"
+
+DCAEMOD_GUI_SERVICE = f"{DCAEMOD_URL}/"
+HOLMES_GUI_SERVICE = f"{HOLMES_URL}/iui/holmes/default.html"
+POLICY_GUI_SERVICE = f"{POLICY_URL}/onap/login.html"
+POLICY_CLAMP_GUI_SERVICE = f"{CLAMP_URL}/"
+
+# uncomment if socks is used
+#OnapService.set_proxy({'http': 'socks5h://127.0.0.1:8081', 'https': 'socks5h://127.0.0.1:8081'})
+
+# execute in the shell to apply these settings
+# export ONAP_PYTHON_SDK_SETTINGS="onap_settings"
diff --git a/tutorials/ApacheCNF/automation/onboard.py b/tutorials/ApacheCNF/automation/onboard.py
new file mode 100644 (file)
index 0000000..7e27419
--- /dev/null
@@ -0,0 +1,213 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Orange
+# ================================================================================
+# 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 time
+import zipfile
+from io import BytesIO
+
+import yaml
+
+from config import Config, VariablesDict
+import onapsdk.constants as const
+
+from onapsdk.sdc.vendor import Vendor
+from onapsdk.sdc.vsp import Vsp
+from onapsdk.sdc.vf import Vf
+from onapsdk.sdc.pnf import Pnf
+from onapsdk.sdc.service import Service, ServiceInstantiationType
+from onapsdk.exceptions import ResourceNotFound
+
+logger = logging.getLogger()
+logger.setLevel(logging.DEBUG)
+
+
+def retrieve_service(service_name: str):
+    logger.info("Retrieve service from SDC before onboarding")
+    services = Service.get_all()
+
+    for found_service in services:
+        if found_service.name == service_name:
+            logging.info(f"Service {found_service.name} found in SDC, onboarding will not be executed")
+            exit(0)
+    return
+
+
+def onboard_vendor(vendor_name: str = "demo_vendor"):
+    logger.info("******** Onboard Vendor *******")
+    try:
+        vendor = next(vendor for vendor in Vendor.get_all() if vendor.name.lower() == vendor_name.lower())
+    except (StopIteration, ResourceNotFound):
+        vendor = Vendor(vendor_name)
+        vendor.onboard()
+    return vendor
+
+
+def onboard_vsp(vsp_name, vsp_file, vendor):
+    logger.info(f"******** Onboard VSP - {vsp_name} *******")
+    mypath = os.path.dirname(os.path.realpath(__file__))
+    vsp_path = os.path.join(mypath, vsp_file)
+    vsp = None
+    try:
+        vsp = Vsp(name=vsp_name, vendor=vendor, package=open(vsp_path, 'rb'))
+    except FileNotFoundError:
+        logger.error(f"No vsp file was found for {vsp_name}!")
+        exit(1)
+    vsp.onboard()
+    return vsp
+
+
+def onboard_pnf(pnf_name, vsp_name, vsp_file, vendor_name):
+    logger.info(f"******** Onboard PNF - {pnf_name} *******")
+    vendor = onboard_vendor(vendor_name=vendor_name)
+    try:
+        pnf = next(_pnf for _pnf in Pnf.get_all() if _pnf.name == pnf_name)
+        logger.info("PNF with provided name exists in ONAP SDC, onboarding will not be executed")
+    except (StopIteration, ResourceNotFound):
+        pnf_vsp = onboard_vsp(vsp_name=vsp_name, vsp_file=vsp_file, vendor=vendor)
+        pnf = Pnf(name=pnf_name, vsp=pnf_vsp)
+        pnf.onboard()
+    return pnf
+
+
+def onboard_vnf(vnf_name, vsp_name, vsp_file, vendor_name):
+    logger.info(f"******** Onboard VNF - {vnf_name} *******")
+    vendor = onboard_vendor(vendor_name=vendor_name)
+    try:
+        vnf = next(_vf for _vf in Vf.get_all() if _vf.name == vnf_name)
+        if vnf.status != "Certified":
+            logger.error("Selected VNF is not certified. Try Onboard VF with new name.")
+            exit(1)
+        logger.info("VNF with provided name exists in ONAP SDC, onboarding will not  be executed")
+    except (StopIteration, ResourceNotFound):
+        vnf_vsp = onboard_vsp(vsp_name=vsp_name, vsp_file=vsp_file, vendor=vendor)
+        vnf = Vf(name=vnf_name, vsp=vnf_vsp)
+        vnf.create()
+        vnf.onboard()
+    return vnf
+
+
+def create_service(service_name, is_macro: bool = True):
+    logger.info("******** Create Service *******")
+    if is_macro:
+        service = Service(name=service_name,
+                          instantiation_type=ServiceInstantiationType.MACRO)
+    else:
+        service = Service(name=service_name,
+                          instantiation_type=ServiceInstantiationType.A_LA_CARTE)
+    service.create()
+    return service
+
+
+def read_sdnc_model_details(file):
+    mypath = os.path.dirname(os.path.realpath(__file__))
+    file_path = os.path.join(mypath, file)
+    try:
+        with zipfile.ZipFile(file_path, 'r') as package:
+            try:
+                cba_io = BytesIO(package.read("CBA.zip"))
+                with zipfile.ZipFile(cba_io) as cba:
+                    with cba.open('TOSCA-Metadata/TOSCA.meta') as meta_file:
+                        tosca_meta = yaml.load(meta_file, Loader=yaml.SafeLoader)
+                        sdnc_model_name = tosca_meta.get("Template-Name")
+                        sdnc_model_version = tosca_meta.get("Template-Version")
+                        return sdnc_model_name, sdnc_model_version
+            except KeyError:
+                logger.info("No CBA file was found")
+                return None, None
+    except FileNotFoundError:
+        logger.error("No vsp file was found!")
+        exit(1)
+
+
+def set_properties(service, xnf, vsp_details):
+    sdnc_model_name, sdnc_model_version = read_sdnc_model_details(vsp_details["vsp_file"])
+    if sdnc_model_name and sdnc_model_version:
+        if service.status == const.DRAFT:
+            logger.info("******** Set SDNC properties for VF ********")
+            component = service.get_component(xnf)
+            prop = component.get_property("sdnc_model_name")
+            prop.value = sdnc_model_name
+            prop = component.get_property("sdnc_model_version")
+            prop.value = sdnc_model_version
+            prop = component.get_property("controller_actor")
+            prop.value = "CDS"
+            prop = component.get_property("sdnc_artifact_name")
+            prop.value = vsp_details["sdnc_artifact_name"]
+            prop = component.get_property("skip_post_instantiation_configuration")
+            prop.value = vsp_details["skip_post_instantiation_configuration"]
+
+
+def check_distribution_status(service):
+    logger.info("******** Check Service Distribution *******")
+    distribution_completed = False
+    nb_try = 0
+    nb_try_max = 10
+    while distribution_completed is False and nb_try < nb_try_max:
+        distribution_completed = service.distributed
+        if distribution_completed is True:
+            logger.info(f"Service Distribution for {service.name} is successfully finished")
+            break
+        logger.info(f"Service Distribution for {service.name} ongoing, Wait for 60 s")
+        time.sleep(60)
+        nb_try += 1
+
+    if distribution_completed is False:
+        logger.error(f"Service Distribution for {service.name} failed !!", )
+        exit(1)
+
+
+def main():
+    config = Config(env_dict=VariablesDict.env_variable)
+    retrieve_service(service_name=config.service_model["model_name"])
+
+    logger.info("******** SERVICE DESIGN *******")
+    service = create_service(service_name=config.service_model["model_name"],
+                             is_macro=config.service_model["macro_orchestration"])
+    vnfs = config.service_model.get("vnfs")
+    if vnfs:
+        for vnf in vnfs:
+            new_vnf = onboard_vnf(vnf_name=vnf["model_name"],
+                                  vsp_name="VSP" + "_" + vnf["model_name"],
+                                  vsp_file=vnf["vsp"]["vsp_file"],
+                                  vendor_name=vnf["vsp"]["vendor"])
+            service.add_resource(new_vnf)
+            set_properties(service=service, xnf=new_vnf, vsp_details=vnf["vsp"])
+
+    pnfs = config.service_model.get("pnfs")
+    if pnfs:
+        for pnf in pnfs:
+            new_pnf = onboard_pnf(pnf_name=pnf["model_name"],
+                                  vsp_name="VSP" + "_" + pnf["model_name"],
+                                  vsp_file=pnf["vsp"]["vsp_file"],
+                                  vendor_name=pnf["vsp"]["vendor"])
+            service.add_resource(new_pnf)
+            set_properties(service=service, xnf=new_pnf, vsp_details=pnf["vsp"])
+
+    service.checkin()
+    service.onboard()
+    check_distribution_status(service)
+
+
+if __name__ == "__main__":
+    sh = logging.StreamHandler()
+    sh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+    sh.setFormatter(sh_formatter)
+    logger.addHandler(sh)
+
+    main()
diff --git a/tutorials/ApacheCNF/automation/update_cba.py b/tutorials/ApacheCNF/automation/update_cba.py
new file mode 100644 (file)
index 0000000..226029f
--- /dev/null
@@ -0,0 +1,57 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Orange
+# ================================================================================
+# 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 zipfile
+from io import BytesIO
+
+from onapsdk.cds import Blueprint
+
+from config import Config, VariablesDict
+
+logger = logging.getLogger()
+logger.setLevel(logging.DEBUG)
+
+
+def update_cba(file):
+    mypath = os.path.dirname(os.path.realpath(__file__))
+    file_path = os.path.join(mypath, file)
+    try:
+        with zipfile.ZipFile(file_path, 'r') as package:
+            cba_io = BytesIO(package.read("CBA.zip"))
+
+        blueprint = Blueprint(cba_io)
+        blueprint.deploy()
+    except FileNotFoundError:
+        logger.error("Error - File Not Found")
+        exit(1)
+
+
+def main():
+    config = Config(env_dict=VariablesDict.env_variable)
+    for vnf in config.service_model["vnfs"]:
+        update_cba(vnf["vsp"]["vsp_file"])
+
+
+if __name__ == "__main__":
+    sh = logging.StreamHandler()
+    sh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+    sh.setFormatter(sh_formatter)
+    logger.addHandler(sh)
+
+    main()
diff --git a/tutorials/ApacheCNF/automation/update_connectivity_info.py b/tutorials/ApacheCNF/automation/update_connectivity_info.py
new file mode 100644 (file)
index 0000000..d5138bc
--- /dev/null
@@ -0,0 +1,40 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Orange
+# ================================================================================
+# 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
+
+from config import Config, VariablesDict
+from create_cloud_regions import update_connectivity_info, is_k8s_region
+
+logger = logging.getLogger()
+logger.setLevel(logging.DEBUG)
+
+
+def main():
+    config = Config(env_dict=VariablesDict.env_variable)
+    for region in config.cloud_regions:
+        if is_k8s_region(region):
+            update_connectivity_info(region)
+
+
+if __name__ == "__main__":
+    sh = logging.StreamHandler()
+    sh_formatter = logging.Formatter('%(asctime)s %(levelname)s %(lineno)d:%(filename)s(%(process)d) - %(message)s')
+    sh.setFormatter(sh_formatter)
+    logger.addHandler(sh)
+
+    main()
diff --git a/tutorials/ApacheCNF/automation/vsp/.gitkeep b/tutorials/ApacheCNF/automation/vsp/.gitkeep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tutorials/ApacheCNF/automation/vsp/.keep b/tutorials/ApacheCNF/automation/vsp/.keep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tutorials/ApacheCNF/service_config.yaml b/tutorials/ApacheCNF/service_config.yaml
new file mode 100644 (file)
index 0000000..ef88fd2
--- /dev/null
@@ -0,0 +1,94 @@
+# ============LICENSE_START=======================================================
+# Copyright (C) 2022 Orange
+# ================================================================================
+# 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=========================================================
+user_params:
+  cnf_name: &cnf_name apache
+  k8s_namespace: test-cnf
+  k8s_version: 1.18.9
+  k8s_region: &region cnf-region
+  release_name: rel-1
+#  profile_source: cnf-cds-base-profile
+  profile_source: node-port-profile
+  skip_day_2: &skip_day_2 True
+
+cloud_regions:
+  - name: *region
+    cloud_owner: K8sCloudOwner
+    cloud_type: k8s
+    complex_id: k8s-complex1
+    tenants:
+      - name: &tenant  "{{ user_params.k8s_region }}-tenant"
+        k8s_version: "{{ user_params.k8s_version }}"
+    kubeconfig_file: artifacts/kubeconfig
+# - name: openstack-region-test
+#   cloud_owner: CloudOwner
+#   cloud_type: openstack
+#   complex_id: complex1
+#   tenants:
+#     - name: &my_tenant1 onap-dev
+#       id: 5117085204e84027a8d1a0cf34abb0ba
+#   identity_url: http://test:5000/v4
+#   mso_id: test_user
+#   mso_pass: test_encrypted_password
+#   identity_server_type: KEYSTONE_V3
+
+service_model:
+  macro_orchestration: True
+  model_name: &service_model_name "{{ user_params.cnf_name }}_{{ user_params.skip_day_2 }}_k8s_cnf_demo"
+  vnfs:
+    - model_name: &vnf_1_model_name "{{ user_params.cnf_name }}"
+      vsp:
+        vsp_file: vsp/native_cnf_k8s_demo.zip
+        vendor: cnf_vendor
+        sdnc_artifact_name: vnf
+        skip_post_instantiation_configuration: *skip_day_2
+#  pnfs:
+#    - model_name: pnf_example
+#      vsp:
+#        vsp_file: vsp/pnf_package.csar
+#        vendor: pnf_vendor
+#        skip_post_instantiation_configuration: False
+
+
+service_instance:
+  model_name: *service_model_name
+  instance_name: I_{{ service_model.model_name }}_{{ user_params.release_name }}
+  customer_id: orange
+  cloud_region: *region # "{{ cloud_regions[0].name }}"
+  tenant_name: *tenant  # "{{ cloud_regions[0].tenants[0].name }}"
+  service_type: *cnf_name
+  vnfs:
+    - model_name: *vnf_1_model_name
+      #vnf_name_suffix: "001" #needed when more than one vnf instance
+      parameters:
+        k8s-rb-profile-namespace: "{{ user_params.k8s_namespace }}"
+        k8s-rb-profile-k8s-version: "{{ user_params.k8s_version }}"
+      processing_priority: 1 # may be used to order vnf deployment
+      vf_modules:
+        - model_name: helm_apache
+          vf_module_name_suffix: "001"
+          processing_priority: 1 # may be used to order vf-module deployment
+          parameters:
+            k8s-rb-profile-name: "{{ user_params.profile_source }}-{{ user_params.k8s_namespace }}"
+            k8s-rb-profile-source: "{{ user_params.profile_source }}"
+            k8s-rb-instance-release-name: "{{ user_params.release_name }}"
+            k8s-rb-profile-namespace: "{{ user_params.k8s_namespace }}"
+            k8s-rb-config-template-name: replica-count-template
+            k8s-rb-config-template-source: deployment-config
+            k8s-rb-config-name: replica-count-change
+            k8s-rb-config-value-source: custom-values
+#  pnfs:
+#    - model_name: pnf_example
diff --git a/tutorials/ApacheCNF/templates/.gitattributes b/tutorials/ApacheCNF/templates/.gitattributes
new file mode 100644 (file)
index 0000000..4ad2a52
--- /dev/null
@@ -0,0 +1 @@
+/cba/Templates/k8s-profiles/*.tar.gz binary
diff --git a/tutorials/ApacheCNF/templates/.gitignore b/tutorials/ApacheCNF/templates/.gitignore
new file mode 100644 (file)
index 0000000..f88e099
--- /dev/null
@@ -0,0 +1,2 @@
+package/
+vfw_k8s_demo.zip
diff --git a/tutorials/ApacheCNF/templates/Makefile b/tutorials/ApacheCNF/templates/Makefile
new file mode 100644 (file)
index 0000000..9866d6c
--- /dev/null
@@ -0,0 +1,42 @@
+.PHONY: all clean helm base clean_all package cba jsonlint_cba
+NATIVE_ONBOARDING_PACKAGE_NAME ?= native_cnf_k8s_demo
+CBA_NAME ?= CBA
+_type_files = $(wildcard cba/Definitions/*_types.json)
+
+
+clean_all:
+       $(MAKE) clean
+       $(MAKE) all
+
+#Can't use .csar extension or SDC will panic
+all: package helm base cba
+       cd package_native/ && zip -r $(NATIVE_ONBOARDING_PACKAGE_NAME).zip .
+       mv package_native/$(NATIVE_ONBOARDING_PACKAGE_NAME).zip .
+       cp $(NATIVE_ONBOARDING_PACKAGE_NAME).zip  ../automation/vsp/
+
+helm: package
+       $(MAKE) -C helm
+       mv helm/helm_*.tgz package_native/
+
+base: package
+       cp base_native/* package_native/
+
+cba: package
+       cd cba/ && zip -r $(CBA_NAME).zip . -x pom.xml .idea/\* target/\*
+       mv cba/$(CBA_NAME).zip package_native/
+
+package:
+       mkdir package_native/
+
+clean:
+       rm -rf package_native/
+       rm -f $(NATIVE_ONBOARDING_PACKAGE_NAME).zip
+
+jsonlint_cba: $(_type_files)
+       @:
+
+#This shouldn't be PHONY, but it's easier now to define this way
+.PHONY: $(_type_files)
+$(_type_files):
+       @which jq expand unexpand sponge >/dev/null
+       jq -S . <$@ | unexpand -t 2 | expand -t 4 | sponge $@
diff --git a/tutorials/ApacheCNF/templates/README.txt b/tutorials/ApacheCNF/templates/README.txt
new file mode 100644 (file)
index 0000000..3d7c29c
--- /dev/null
@@ -0,0 +1 @@
+cba-dd.json file is Data Dictionary file used to enrich cba model.
diff --git a/tutorials/ApacheCNF/templates/base_native/MANIFEST.json b/tutorials/ApacheCNF/templates/base_native/MANIFEST.json
new file mode 100644 (file)
index 0000000..cfaba8d
--- /dev/null
@@ -0,0 +1,15 @@
+{
+    "name": "simpleCNF",
+    "description": "",
+    "data": [
+        {
+            "file": "CBA.zip",
+            "type": "CONTROLLER_BLUEPRINT_ARCHIVE"
+        },
+        {
+            "file": "helm_apache.tgz",
+            "type": "HELM",
+            "isBase": "true"
+        }
+    ]
+}
diff --git a/tutorials/ApacheCNF/templates/cba-dev/bootstrap.sh b/tutorials/ApacheCNF/templates/cba-dev/bootstrap.sh
new file mode 100644 (file)
index 0000000..74ec06a
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# 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=========================================================
+
+curl --location --request POST 'http://127.0.0.1:8081/api/v1/blueprint-model/bootstrap' \
+--header 'Authorization: Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==' \
+--header 'Content-Type: application/json' \
+--data '{"loadModelType": true, "loadResourceDictionary": true, "loadCBA": false}' | jq
diff --git a/tutorials/ApacheCNF/templates/cba-dev/build.sh b/tutorials/ApacheCNF/templates/cba-dev/build.sh
new file mode 100644 (file)
index 0000000..a7a3406
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# 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=========================================================
+
+cd ../cba/
+
+mvn clean install
+
+if [ $? -eq 1 ]
+then
+   echo "----------------"
+   echo "CBA BUILD FAILED"
+   echo "----------------"
+   exit 1
+fi
+
+CBA_NAME=`ls target/*.zip`
+cp $CBA_NAME ../cba-dev/cba.zip
+
+echo "-----------------"
+echo "CBA BUILD SUCCESS"
+echo "-----------------"
+
+cd ../cba-dev
diff --git a/tutorials/ApacheCNF/templates/cba-dev/deploy.sh b/tutorials/ApacheCNF/templates/cba-dev/deploy.sh
new file mode 100644 (file)
index 0000000..59c9807
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# 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=========================================================
+
+curl --location --request POST 'http://127.0.0.1:8081/api/v1/blueprint-model' \
+--header 'Authorization: Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==' \
+--form 'file=@cba.zip' | jq
diff --git a/tutorials/ApacheCNF/templates/cba-dev/enrich.sh b/tutorials/ApacheCNF/templates/cba-dev/enrich.sh
new file mode 100644 (file)
index 0000000..632cb89
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# 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=========================================================
+
+curl --location --request POST 'http://127.0.0.1:8081/api/v1/blueprint-model/enrich' \
+--header 'Authorization: Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==' \
+-o 'cba.zip' \
+--form 'file=@../package_native/CBA.zip' | jq
diff --git a/tutorials/ApacheCNF/templates/cba-dev/run-vf-base-ra.sh b/tutorials/ApacheCNF/templates/cba-dev/run-vf-base-ra.sh
new file mode 100644 (file)
index 0000000..6151dc7
--- /dev/null
@@ -0,0 +1,65 @@
+#!/bin/sh
+
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# 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=========================================================
+
+REQ_ID=`shuf -i 1-1000000 -n 1`
+SUB_REQ_ID=$REQ_ID"-"`shuf -i 1-1000 -n 1`
+TEMPLATE_NAME="helm_apache"
+
+curl --location --request POST 'http://localhost:8081/api/v1/execution-service/process' \
+--header 'Authorization: Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+    "commonHeader": {
+        "originatorId": "onap-me-cm-adapter",
+        "requestId": "'$REQ_ID'",
+        "subRequestId": "'$SUB_REQ_ID'"
+    },
+    "actionIdentifiers": {
+        "blueprintName": "APACHE",
+        "blueprintVersion": "1.0.0",
+        "actionName": "resource-assignment",
+        "mode": "sync"
+    },
+    "payload": {
+        "resource-assignment-request": {
+            "template-prefix": [
+                "'$TEMPLATE_NAME'"
+            ],
+            "resolution-key": "ra-test-resolution",
+            "resource-assignment-properties": {
+                "replica-count": 2,
+                "aic-cloud-region": "RegionOne",
+                "vnf-model-customization-uuid": "d73864db-1f6e-4e54-a533-a96773c926a4",
+                "service-instance-id": "2afee7c4-8b16-4f2f-a567-48fb7948abcf",
+                "vnf-id": "21dcbbd2-3ec2-4a9c-bb0d-599cafc16a1f",
+                "vnf_name": "sample-vnf-name",
+                "vf-module-name": "vf-module-name",
+                "vf-module-label": "'$TEMPLATE_NAME'",
+                "vf-module-type": "vf-module-type",
+                "vf-module-model-customization-uuid": "d3ae2df9-95d4-48cc-a466-9f12dee80458",
+                "vf-module-model-invariant-uuid": "564e55dc-3b90-4c9c-9e97-42f2c97d8f11",
+                "vf-module-model-version": "3d55e2a6-7634-4ceb-98e9-2852d621a544",
+                "vf-module-id": "3e6a0375-4b92-4bf5-9910-b0b893448a9c",
+                "vf-naming-policy" : "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP",
+                "k8s-rb-profile-name": "vfw-cnf-cds-base-profile",
+                "management-prefix-id" : 3
+            }
+        }
+    }
+}' | jq '.payload | .["resource-assignment-response"] | .["meshed-template"] | .'$TEMPLATE_NAME' | fromjson | .["resource-accumulator-resolved-data"] '
diff --git a/tutorials/ApacheCNF/templates/cba-dev/run-vnf-config.sh b/tutorials/ApacheCNF/templates/cba-dev/run-vnf-config.sh
new file mode 100644 (file)
index 0000000..a211a6b
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/sh
+
+# ============LICENSE_START=======================================================
+# Copyright (C) 2021 Orange
+# ================================================================================
+# 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=========================================================
+
+REQ_ID=`shuf -i 1-1000000 -n 1`
+SUB_REQ_ID=$REQ_ID"-"`shuf -i 1-1000 -n 1`
+ACTION=$1
+
+curl --location --request POST 'http://localhost:8081/api/v1/execution-service/process' \
+--header 'Authorization: Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+    "commonHeader": {
+        "originatorId": "onap-me-cm-adapter",
+        "requestId": "'$REQ_ID'",
+        "subRequestId": "'$SUB_REQ_ID'"
+    },
+    "actionIdentifiers": {
+        "blueprintName": "APACHE",
+        "blueprintVersion": "1.0.0",
+        "actionName": "'config-$ACTION'",
+        "mode": "sync"
+    },
+    "payload": {
+       "'config-$ACTION-request'": {
+           "resolution-key": "VF_apache_k8s_demo_CNF",
+           "'config-$ACTION-properties'": {
+               "service-instance-id": "2a2de3ec-35a4-4e1d-b313-ac5c4c8813a8",
+               "vnf-id": "6b6ff775-a170-4ce4-bcd0-85645d738390"
+           }
+        }
+    }
+}' | jq '.payload | .["'config-$ACTION-response'"]'
+
diff --git a/tutorials/ApacheCNF/templates/cba-dev/run-vnf-ra.sh b/tutorials/ApacheCNF/templates/cba-dev/run-vnf-ra.sh
new file mode 100644 (file)
index 0000000..9cf4c2a
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+
+# ============LICENSE_START=======================================================
+# Copyright (C) 2020 Orange
+# ================================================================================
+# 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=========================================================
+
+REQ_ID=`shuf -i 1-1000000 -n 1`
+SUB_REQ_ID=$REQ_ID"-"`shuf -i 1-1000 -n 1`
+
+curl --location --request POST 'http://localhost:8081/api/v1/execution-service/process' \
+--header 'Authorization: Basic Y2NzZGthcHBzOmNjc2RrYXBwcw==' \
+--header 'Content-Type: application/json' \
+--data-raw '{
+    "commonHeader": {
+        "originatorId": "onap-me-cm-adapter",
+        "requestId": "'$REQ_ID'",
+        "subRequestId": "'$SUB_REQ_ID'"
+    },
+    "actionIdentifiers": {
+        "blueprintName": "APACHE",
+        "blueprintVersion": "1.0.0",
+        "actionName": "resource-assignment",
+        "mode": "sync"
+    },
+    "payload": {
+        "resource-assignment-request": {
+            "template-prefix": [
+                "vnf"
+            ],
+            "resolution-key": "ra-test-resolution",
+            "resource-assignment-properties": {
+                "replica-count": 2,
+                "aic-cloud-region": "RegionOne",
+                "vnf-model-customization-uuid": "d73864db-1f6e-4e54-a533-a96773c926a4",
+                "service-instance-id": "2afee7c4-8b16-4f2f-a567-48fb7948abcf",
+                "vnf-id": "51274ece-55ca-4cbc-b7c4-0da0dcc65d38",
+                "vnf_name": "sample-vnf-name",
+                "k8s-rb-profile-namespace": "vfw-namespace",
+                "k8s-rb-profile-k8s-version": "1.18.9"
+            }
+        }
+    }
+}' | jq '.payload | .["resource-assignment-response"] | .["meshed-template"] | .vnf | fromjson | .["resource-accumulator-resolved-data"] '
+
diff --git a/tutorials/ApacheCNF/templates/cba/Definitions/CNF.json b/tutorials/ApacheCNF/templates/cba/Definitions/CNF.json
new file mode 100644 (file)
index 0000000..bf1a423
--- /dev/null
@@ -0,0 +1,853 @@
+{
+    "tosca_definitions_version": "controller_blueprint_1_0_0",
+    "metadata": {
+        "template_author": "Lukasz Rajewski <lukasz.rajewski@orange.com>",
+        "author-email": "lukasz.rajewski@orange.com",
+        "user-groups": "ADMIN, OPERATION",
+        "template_name": "APACHE",
+        "template_version": "1.0.0",
+        "template_tags": "Lukasz Rajewski, CNF",
+        "template_type": "DEFAULT"
+    },
+    "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"
+        }
+    ],
+    "dsl_definitions": {
+        "naming-resolution": {
+            "type": "basic-auth",
+            "url": "http://neng-serv:8080/web/service",
+            "username": "ccsdkapps",
+            "password": "ccsdkapps"
+        },
+        "vpkg-rest-api": {
+            "type": "basic-auth",
+            "url": "http://",
+            "username": "admin",
+            "password": "admin"
+        },
+        "config-deploy-properties": {
+            "resolution-key": {
+                "get_input": "resolution-key"
+            }
+        },
+        "simple-status-properties": {
+            "resolution-key": {
+                "get_input": "resolution-key"
+            },
+            "config-deploy-setup": {
+                "get_attribute": [
+                    "config-setup-process",
+                    "",
+                    "assignment-map",
+                    "config-deploy",
+                    "config-deploy-setup"
+                ]
+            }
+        }
+    },
+    "topology_template": {
+        "workflows": {
+            "resource-assignment": {
+                "steps": {
+                    "resource-assignment": {
+                        "description": "Resource Assign Workflow",
+                        "target": "resource-assignment",
+                        "activities": [
+                            {
+                                "call_operation": "ResourceResolutionComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "profile-upload"
+                        ]
+                    },
+                    "profile-upload": {
+                        "description": "Generate and upload K8s Profile",
+                        "target": "k8s-profile-upload",
+                        "activities": [
+                            {
+                                "call_operation": "ComponentScriptExecutor.process"
+                            }
+                        ]
+                    }
+                },
+                "inputs": {
+                    "template-prefix": {
+                        "required": true,
+                        "type": "list",
+                        "entry_schema": {
+                            "type": "string"
+                        }
+                    },
+                    "resolution-key": {
+                        "required": false,
+                        "type": "string",
+                        "entry_schema": {
+                            "type": ""
+                        }
+                    },
+                    "resource-assignment-properties": {
+                        "description": "Dynamic PropertyDefinition for workflow(resource-assignment).",
+                        "required": true,
+                        "type": "dt-resource-assignment-properties"
+                    }
+                },
+                "outputs": {
+                    "meshed-template": {
+                        "type": "json",
+                        "value": {
+                            "get_attribute": [
+                                "resource-assignment",
+                                "assignment-params"
+                            ]
+                        }
+                    }
+                }
+            },
+            "config-assign": {
+                "steps": {
+                    "config-setup": {
+                        "description": "Gather necessary input for config template upload",
+                        "target": "config-setup-process",
+                        "activities": [
+                            {
+                                "call_operation": "ResourceResolutionComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "config-template"
+                        ]
+                    },
+                    "config-template": {
+                        "description": "Generate and upload K8s config template",
+                        "target": "k8s-config-template",
+                        "activities": [
+                            {
+                                "call_operation": "K8sConfigTemplateComponent.process"
+                            }
+                        ]
+                    }
+                },
+                "inputs": {
+                    "resolution-key": {
+                        "required": true,
+                        "type": "string"
+                    },
+                    "store-result": {
+                        "required": true,
+                        "type": "boolean"
+                    },
+                    "config-assign-properties": {
+                        "description": "Dynamic PropertyDefinition for workflow(config-assign).",
+                        "required": true,
+                        "type": "dt-config-assign-properties"
+                    }
+                }
+            },
+            "config-deploy": {
+                "steps": {
+                    "config-setup": {
+                        "description": "Gather necessary input for config init and status verification",
+                        "target": "config-setup-process",
+                        "activities": [
+                            {
+                                "call_operation": "ResourceResolutionComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "status-verification-script"
+                        ]
+                    },
+                    "status-verification-script": {
+                        "description": "Simple status verification script",
+                        "target": "simple-status-check",
+                        "activities": [
+                            {
+                                "call_operation": "ComponentScriptExecutor.process"
+                            }
+                        ],
+                        "on_success": [
+                            "config-apply"
+                        ]
+                    },
+                    "config-apply": {
+                        "description": "Activate K8s config template",
+                        "target": "k8s-config-apply",
+                        "activities": [
+                            {
+                                "call_operation": "K8sConfigValueComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "status-verification-script-after"
+                        ]
+                    },
+                    "status-verification-script-after": {
+                        "description": "Simple status verification script",
+                        "target": "simple-status-check",
+                        "activities": [
+                            {
+                                "call_operation": "ComponentScriptExecutor.process"
+                            }
+                        ],
+                        "on_success": [
+                            "collect-results"
+                        ]
+                    },
+                    "collect-results": {
+                        "description": "Final collection of results",
+                        "target": "collect-results"
+                    }
+                },
+                "inputs": {
+                    "resolution-key": {
+                        "required": true,
+                        "type": "string"
+                    },
+                    "config-deploy-properties": {
+                        "description": "Dynamic PropertyDefinition for workflow(config-deploy).",
+                        "required": true,
+                        "type": "dt-config-deploy-properties"
+                    }
+                }
+            },
+            "scale-out": {
+                "steps": {
+                    "config-setup": {
+                        "description": "Gather necessary input for config init and status verification",
+                        "target": "config-setup-process",
+                        "activities": [
+                            {
+                                "call_operation": "ResourceResolutionComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "config-template"
+                        ]
+                    },
+                    "config-template": {
+                        "description": "Generate and upload K8s config template",
+                        "target": "k8s-config-template",
+                        "activities": [
+                            {
+                                "call_operation": "K8sConfigTemplateComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "config-apply"
+                        ]
+                    },
+                    "config-apply": {
+                        "description": "Activate K8s config apply",
+                        "target": "k8s-config-apply",
+                        "activities": [
+                            {
+                                "call_operation": "K8sConfigValueComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "status-verification-script-after"
+                        ]
+                    },
+                    "status-verification-script-after": {
+                        "description": "Simple status verification script",
+                        "target": "simple-status-check",
+                        "activities": [
+                            {
+                                "call_operation": "ComponentScriptExecutor.process"
+                            }
+                        ],
+                        "on_success": [
+                            "collect-results"
+                        ]
+                    },
+                    "collect-results": {
+                        "description": "Final collection of results",
+                        "target": "collect-results"
+                    }
+                },
+                "inputs": {
+                    "resolution-key": {
+                        "required": true,
+                        "type": "string"
+                    },
+                    "scale-out-properties": {
+                        "description": "Dynamic PropertyDefinition for workflow(scale-out).",
+                        "required": true,
+                        "type": "dt-scale-out-properties"
+                    }
+                }
+            },
+            "scale": {
+                "steps": {
+                    "config-setup": {
+                        "description": "Gather necessary input for config init and status verification",
+                        "target": "config-setup-process",
+                        "activities": [
+                            {
+                                "call_operation": "ResourceResolutionComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "config-template"
+                        ]
+                    },
+                    "config-template": {
+                        "description": "Generate and upload K8s config template",
+                        "target": "k8s-config-template",
+                        "activities": [
+                            {
+                                "call_operation": "K8sConfigTemplateComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "config-update"
+                        ]
+                    },
+                    "config-update": {
+                        "description": "Activate K8s config restore",
+                        "target": "k8s-config-update",
+                        "activities": [
+                            {
+                                "call_operation": "K8sConfigValueComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "status-verification-script-after"
+                        ]
+                    },
+                    "status-verification-script-after": {
+                        "description": "Simple status verification script",
+                        "target": "simple-status-check",
+                        "activities": [
+                            {
+                                "call_operation": "ComponentScriptExecutor.process"
+                            }
+                        ],
+                        "on_success": [
+                            "collect-results"
+                        ]
+                    },
+                    "collect-results": {
+                        "description": "Final collection of results",
+                        "target": "collect-results"
+                    }
+                },
+                "inputs": {
+                    "resolution-key": {
+                        "required": true,
+                        "type": "string"
+                    },
+                    "scale-properties": {
+                        "description": "Dynamic PropertyDefinition for workflow(scale).",
+                        "required": true,
+                        "type": "dt-scale-properties"
+                    }
+                }
+            },
+            "scale-in": {
+                "steps": {
+                    "config-setup": {
+                        "description": "Gather necessary input for config init and status verification",
+                        "target": "config-setup-process",
+                        "activities": [
+                            {
+                                "call_operation": "ResourceResolutionComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "config-template"
+                        ]
+                    },
+                    "config-template": {
+                        "description": "Generate and upload K8s config template",
+                        "target": "k8s-config-template",
+                        "activities": [
+                            {
+                                "call_operation": "K8sConfigTemplateComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "config-restore"
+                        ]
+                    },
+                    "config-restore": {
+                        "description": "Activate K8s config restore",
+                        "target": "k8s-config-restore",
+                        "activities": [
+                            {
+                                "call_operation": "K8sConfigValueComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "status-verification-script-after"
+                        ]
+                    },
+                    "status-verification-script-after": {
+                        "description": "Simple status verification script",
+                        "target": "simple-status-check",
+                        "activities": [
+                            {
+                                "call_operation": "ComponentScriptExecutor.process"
+                            }
+                        ],
+                        "on_success": [
+                            "collect-results"
+                        ]
+                    },
+                    "collect-results": {
+                        "description": "Final collection of results",
+                        "target": "collect-results"
+                    }
+                },
+                "inputs": {
+                    "resolution-key": {
+                        "required": true,
+                        "type": "string"
+                    },
+                    "scale-in-properties": {
+                        "description": "Dynamic PropertyDefinition for workflow(scale-in).",
+                        "required": true,
+                        "type": "dt-scale-in-properties"
+                    }
+                }
+            },
+            "health-check": {
+                "steps": {
+                    "config-setup": {
+                        "description": "Gather necessary input for config init and status verification",
+                        "target": "config-setup-process",
+                        "activities": [
+                            {
+                                "call_operation": "ResourceResolutionComponent.process"
+                            }
+                        ],
+                        "on_success": [
+                            "status-verification-script"
+                        ],
+                        "on_failure": [
+                            "handle_error"
+                        ]
+                    },
+                    "status-verification-script": {
+                        "description": "Simple status verification script",
+                        "target": "simple-status-check",
+                        "activities": [
+                            {
+                                "call_operation": "ComponentScriptExecutor.process"
+                            }
+                        ],
+                        "on_success": [
+                            "health-check-process"
+                        ],
+                        "on_failure": [
+                            "handle_error"
+                        ]
+                    },
+                    "health-check-process": {
+                        "description": "Start health check script",
+                        "target": "health-check-script",
+                        "activities": [
+                            {
+                                "call_operation": "ComponentScriptExecutor.process"
+                            }
+                        ],
+                        "on_success": [
+                            "collect-results"
+                        ],
+                        "on_failure": [
+                            "handle_error"
+                        ]
+                    },
+                    "handle_error": {
+                        "description": "Simple error verification script",
+                        "target": "simple-error-check",
+                        "activities": [
+                            {
+                                "call_operation": "ComponentScriptExecutor.process"
+                            }
+                        ],
+                        "on_success": [
+                            "collect-results"
+                        ]
+                    },
+                    "collect-results": {
+                        "description": "Final collection of results",
+                        "target": "collect-results"
+                    }
+                },
+                "inputs": {
+                    "resolution-key": {
+                        "required": true,
+                        "type": "string"
+                    },
+                    "health-check-properties": {
+                        "description": "Dynamic PropertyDefinition for workflow(health-check).",
+                        "required": true,
+                        "type": "dt-health-check-properties"
+                    }
+                }
+            }
+        },
+        "node_templates": {
+            "resource-assignment": {
+                "type": "component-resource-resolution",
+                "interfaces": {
+                    "ResourceResolutionComponent": {
+                        "operations": {
+                            "process": {
+                                "inputs": {
+                                    "artifact-prefix-names": {
+                                        "get_input": "template-prefix"
+                                    }
+                                }
+                            }
+                        }
+                    }
+                },
+                "artifacts": {
+                    "helm_apache-template": {
+                        "type": "artifact-template-velocity",
+                        "file": "Templates/cnf-template.vtl"
+                    },
+                    "helm_apache-mapping": {
+                        "type": "artifact-mapping-resource",
+                        "file": "Templates/cnf-mapping.json"
+                    },
+                    "vnf-template": {
+                        "type": "artifact-template-velocity",
+                        "file": "Templates/vnf-template.vtl"
+                    },
+                    "vnf-mapping": {
+                        "type": "artifact-mapping-resource",
+                        "file": "Templates/vnf-mapping.json"
+                    }
+                }
+            },
+            "k8s-profile-upload": {
+                "type": "component-k8s-profile-upload",
+                "interfaces": {
+                    "K8sProfileUploadComponent": {
+                        "operations": {
+                            "process": {
+                                "inputs": {
+                                    "artifact-prefix-names": {
+                                        "get_input": "template-prefix"
+                                    },
+                                    "resource-assignment-map": {
+                                        "get_attribute": [
+                                            "resource-assignment",
+                                            "assignment-map"
+                                        ]
+                                    }
+                                }
+                            }
+                        }
+                    }
+                },
+                "artifacts": {
+                    "cnf-cds-base-profile": {
+                        "type": "artifact-k8sprofile-content",
+                        "file": "Templates/k8s-profiles/cnf-cds-base-profile.tar.gz"
+                    },
+                    "node-port-profile": {
+                        "type": "artifact-k8sprofile-content",
+                        "file": "Templates/k8s-profiles/node-port-profile.tar.gz"
+                    }
+                }
+            },
+            "k8s-config-template": {
+                "type": "component-k8s-config-template",
+                "interfaces": {
+                    "K8sConfigTemplateComponent": {
+                        "operations": {
+                            "process": {
+                                "inputs": {
+                                    "artifact-prefix-names": [
+                                        "helm_apache"
+                                    ],
+                                    "resource-assignment-map": {
+                                        "get_attribute": [
+                                            "config-setup-process",
+                                            "",
+                                            "assignment-map",
+                                            "config-deploy",
+                                            "config-deploy-setup"
+                                        ]
+                                    }
+                                }
+                            }
+                        }
+                    }
+                },
+                "artifacts": {
+                    "deployment-config": {
+                        "type": "artifact-k8sconfig-content",
+                        "file": "Templates/k8s-configs/deployment-config.tar.gz"
+                    }
+                }
+            },
+            "k8s-config-apply": {
+                "type": "component-k8s-config-value",
+                "interfaces": {
+                    "K8sConfigValueComponent": {
+                        "operations": {
+                            "process": {
+                                "inputs": {
+                                    "artifact-prefix-names": [
+                                        "helm_apache"
+                                    ],
+                                    "k8s-config-operation-type": "create",
+                                    "resource-assignment-map": {
+                                        "get_attribute": [
+                                            "config-setup-process",
+                                            "",
+                                            "assignment-map",
+                                            "config-deploy",
+                                            "config-deploy-setup"
+                                        ]
+                                    }
+                                }
+                            }
+                        }
+                    }
+                },
+                "artifacts": {
+                    "default-values": {
+                        "type": "artifact-k8sconfig-content",
+                        "file": "Templates/k8s-configs/deployment-values/default-values.yaml"
+                    },
+                    "restore-values": {
+                        "type": "artifact-k8sconfig-content",
+                        "file": "Templates/k8s-configs/deployment-values/restore-values.yaml"
+                    },
+                    "custom-values": {
+                        "type": "artifact-k8sconfig-content",
+                        "file": "Templates/k8s-configs/deployment-values/values.yaml.vtl"
+                    },
+                    "custom-values-mapping": {
+                        "type": "artifact-mapping-resource",
+                        "file": "Templates/k8s-configs/deployment-values/values-mapping.json"
+                    }
+                }
+            },
+            "k8s-config-restore": {
+                "type": "component-k8s-config-value",
+                "interfaces": {
+                    "K8sConfigValueComponent": {
+                        "operations": {
+                            "process": {
+                                "inputs": {
+                                    "artifact-prefix-names": [
+                                        "helm_apache"
+                                    ],
+                                    "k8s-config-operation-type": "update",
+                                    "k8s-rb-config-value-source": "restore-values",
+                                    "resource-assignment-map": {
+                                        "get_attribute": [
+                                            "config-setup-process",
+                                            "",
+                                            "assignment-map",
+                                            "config-deploy",
+                                            "config-deploy-setup"
+                                        ]
+                                    }
+                                }
+                            }
+                        }
+                    }
+                },
+                "artifacts": {
+                    "restore-values": {
+                        "type": "artifact-k8sconfig-content",
+                        "file": "Templates/k8s-configs/deployment-values/restore-values.yaml"
+                    }
+                }
+            },
+            "k8s-config-update": {
+                "type": "component-k8s-config-value",
+                "interfaces": {
+                    "K8sConfigValueComponent": {
+                        "operations": {
+                            "process": {
+                                "inputs": {
+                                    "artifact-prefix-names": [
+                                        "helm_apache"
+                                    ],
+                                    "k8s-config-operation-type": "update",
+                                    "k8s-rb-config-value-source": "custom-values",
+                                    "resource-assignment-map": {
+                                        "get_attribute": [
+                                            "config-setup-process",
+                                            "",
+                                            "assignment-map",
+                                            "config-deploy",
+                                            "config-deploy-setup"
+                                        ]
+                                    }
+                                }
+                            }
+                        }
+                    }
+                },
+                "artifacts": {
+                    "custom-values": {
+                        "type": "artifact-k8sconfig-content",
+                        "file": "Templates/k8s-configs/deployment-values/values.yaml.vtl"
+                    },
+                    "custom-values-mapping": {
+                        "type": "artifact-mapping-resource",
+                        "file": "Templates/k8s-configs/deployment-values/values-mapping.json"
+                    }
+                }
+            },
+            "simple-status-check": {
+                "type": "component-script-executor",
+                "interfaces": {
+                    "ComponentScriptExecutor": {
+                        "operations": {
+                            "process": {
+                                "inputs": {
+                                    "script-type": "kotlin",
+                                    "script-class-reference": "org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.SimpleStatusCheck",
+                                    "instance-dependencies": [
+                                        "bluePrintPropertiesService"
+                                    ],
+                                    "dynamic-properties": "*simple-status-properties"
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+            "simple-error-check": {
+                "type": "component-script-executor",
+                "interfaces": {
+                    "ComponentScriptExecutor": {
+                        "operations": {
+                            "process": {
+                                "inputs": {
+                                    "script-type": "kotlin",
+                                    "script-class-reference": "org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.SimpleErrorCheck",
+                                    "instance-dependencies": [
+                                        "bluePrintPropertiesService"
+                                    ],
+                                    "dynamic-properties": "*simple-status-properties"
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+            "health-check-script": {
+                "type": "component-script-executor",
+                "interfaces": {
+                    "ComponentScriptExecutor": {
+                        "operations": {
+                            "process": {
+                                "inputs": {
+                                    "script-type": "kotlin",
+                                    "script-class-reference": "org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.K8sHealthCheck",
+                                    "instance-dependencies": [
+                                        "bluePrintPropertiesService"
+                                    ],
+                                    "dynamic-properties": "*simple-status-properties"
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+            "config-setup-process": {
+                "type": "component-resource-resolution",
+                "interfaces": {
+                    "ResourceResolutionComponent": {
+                        "operations": {
+                            "process": {
+                                "inputs": {
+                                    "resolution-key": {
+                                        "get_input": "resolution-key"
+                                    },
+                                    "store-result": false,
+                                    "artifact-prefix-names": [
+                                        "config-deploy"
+                                    ]
+                                },
+                                "outputs": {
+                                    "resource-assignment-params": {
+                                        "get_attribute": [
+                                            "SELF",
+                                            "assignment-params"
+                                        ]
+                                    },
+                                    "status": "success"
+                                }
+                            }
+                        }
+                    }
+                },
+                "artifacts": {
+                    "config-deploy-template": {
+                        "type": "artifact-template-velocity",
+                        "file": "Templates/config-setup-template.vtl"
+                    },
+                    "config-deploy-mapping": {
+                        "type": "artifact-mapping-resource",
+                        "file": "Templates/config-setup-mapping.json"
+                    }
+                }
+            },
+            "config-deploy-process": {
+                "type": "component-script-executor",
+                "interfaces": {
+                    "ComponentScriptExecutor": {
+                        "operations": {
+                            "process": {
+                                "inputs": {
+                                    "script-type": "kotlin",
+                                    "script-class-reference": "org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.ConfigDeploy",
+                                    "dynamic-properties": "*config-deploy-properties"
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+            "collect-results": {
+                "type": "component-script-executor",
+                "interfaces": {
+                    "ComponentScriptExecutor": {
+                        "operations": {
+                            "process": {
+                                "implementation": {
+                                    "primary": "component-script",
+                                    "timeout": 180,
+                                    "operation_host": "SELF"
+                                },
+                                "inputs": {
+                                    "script-type": "kotlin",
+                                    "script-class-reference": "org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.CollectorScript"
+                                },
+                                "outputs": {}
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Definitions/artifact_types.json b/tutorials/ApacheCNF/templates/cba/Definitions/artifact_types.json
new file mode 100644 (file)
index 0000000..4211156
--- /dev/null
@@ -0,0 +1,30 @@
+{
+    "artifact_types": {
+        "artifact-mapping-resource": {
+            "description": "Resource Mapping File used along with Configuration template",
+            "version": "1.0.0",
+            "derived_from": "tosca.artifacts.Implementation",
+            "file_ext": [
+                "json"
+            ]
+        },
+        "artifact-template-velocity": {
+            "description": " Velocity Template used for Configuration",
+            "version": "1.0.0",
+            "derived_from": "tosca.artifacts.Implementation",
+            "file_ext": [
+                "vtl"
+            ]
+        },
+        "artifact-k8sprofile-content": {
+            "description": "K8s Profile Folder Artifact",
+            "version": "1.0.0",
+            "derived_from": "tosca.artifacts.Implementation"
+        },
+        "artifact-k8sconfig-content": {
+            "description": "K8s Config Folder Artifact",
+            "version": "1.0.0",
+            "derived_from": "tosca.artifacts.Implementation"
+        }
+    }
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Definitions/data_types.json b/tutorials/ApacheCNF/templates/cba/Definitions/data_types.json
new file mode 100644 (file)
index 0000000..603b0ba
--- /dev/null
@@ -0,0 +1,363 @@
+{
+    "data_types": {
+        "dt-config-assign-properties": {
+            "description": "Dynamic DataType definition for workflow(config-assign).",
+            "version": "1.0.0",
+            "properties": {
+                "service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                }
+            },
+            "derived_from": "tosca.datatypes.Dynamic"
+        },
+        "dt-config-deploy-properties": {
+            "description": "Dynamic DataType definition for workflow(config-deploy).",
+            "version": "1.0.0",
+            "properties": {
+                "service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                }
+            },
+            "derived_from": "tosca.datatypes.Dynamic"
+        },
+        "dt-health-check-properties": {
+            "description": "Dynamic DataType definition for workflow(health-check).",
+            "version": "1.0.0",
+            "properties": {
+                "service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "service-instance.service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "generic-vnf.vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                }
+            },
+            "derived_from": "tosca.datatypes.Dynamic"
+        },
+        "dt-scale-out-properties": {
+            "description": "Dynamic DataType definition for workflow(scale-out).",
+            "version": "1.0.0",
+            "properties": {
+                "service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "service-instance.service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "generic-vnf.vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "replica-count": {
+                    "description": "replica count for apache pods",
+                    "type": "integer",
+                    "default": 2
+                }
+            },
+            "derived_from": "tosca.datatypes.Dynamic"
+        },
+        "dt-scale-in-properties": {
+            "description": "Dynamic DataType definition for workflow(scale-in).",
+            "version": "1.0.0",
+            "properties": {
+                "service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "service-instance.service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "generic-vnf.vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "replica-count": {
+                    "description": "replica count for apache pods",
+                    "type": "integer",
+                    "default": 1
+                }
+            },
+            "derived_from": "tosca.datatypes.Dynamic"
+        },
+        "dt-scale-properties": {
+            "description": "Dynamic DataType definition for workflow(scale).",
+            "version": "1.0.0",
+            "properties": {
+                "service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "service-instance.service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "generic-vnf.vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "replica-count": {
+                    "description": "replica count for apache pods",
+                    "type": "integer",
+                    "required": false
+                },
+                "data": {
+                    "description": "the data content of the policy request parameters",
+                    "required": false,
+                    "type": "json"
+                }
+            },
+            "derived_from": "tosca.datatypes.Dynamic"
+        },
+        "dt-resource-assignment-properties": {
+            "description": "Dynamic DataType definition for workflow(resource-assignment).",
+            "version": "1.0.0",
+            "properties": {
+                "replica-count": {
+                    "description": "replica count for apache pods",
+                    "type": "integer",
+                    "default": 0
+                },
+                "k8s-rb-profile-namespace": {
+                    "description": "K8s namespace to create helm chart for specified profile",
+                    "type": "string"
+                },
+                "k8s-rb-profile-name": {
+                    "description": "Profile name used in multicloud/k8s plugin to identify Helm chart(s) where this mapping is providing override values.",
+                    "type": "string"
+                },
+                "k8s-rb-instance-release-name": {
+                    "description": "Name of the release for the helm package instance in k8s",
+                    "type": "string"
+                },
+                "k8s-rb-profile-source": {
+                    "description": "The source folder or file relative to 'Templates/k8s-profiles' folder",
+                    "type": "string"
+                },
+                "k8s-rb-profile-k8s-version": {
+                    "description": "Profile k8s version used in multicloud/k8s plugin",
+                    "type": "string"
+                },
+                "k8s-rb-config-template-name": {
+                    "description": "The name of configuration template for config-assign operation",
+                    "type": "string"
+                },
+                "k8s-rb-config-template-source": {
+                    "description": "The source of configuration template for config-assign operation",
+                    "type": "string"
+                },
+                "k8s-rb-config-name": {
+                    "description": "The source of configuration values for config-deploy operation",
+                    "type": "string"
+                },
+                "k8s-rb-config-value-source": {
+                    "description": "The source of configuration values for config-deploy operation",
+                    "type": "string"
+                },
+                "private1-prefix-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "private2-prefix-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vnf_name": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "demo_artifacts_version": {
+                    "description": "",
+                    "required": false,
+                    "type": "string",
+                    "default": "1.5.0"
+                },
+                "aic-cloud-region": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vf-module-model-customization-uuid": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "onap_private_net_cidr": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "management-prefix-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "dcae_collector_ip": {
+                    "description": "",
+                    "required": false,
+                    "type": "string",
+                    "default": "10.0.4.1"
+                },
+                "int_private1_net_cidr": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vf-module-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "dcae_collector_port": {
+                    "description": "",
+                    "required": false,
+                    "type": "string",
+                    "default": "30235"
+                },
+                "vf-module-name": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vf-module-label": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vf-module-model-invariant-uuid": {
+                    "type": "string"
+                },
+                "vf-naming-policy": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "int_private2_net_cidr": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vf-module-model-version": {
+                    "type": "string"
+                },
+                "core-instance-name": {
+                    "description": "Name of 5g core instance that requires PNF registration",
+                    "type": "string"
+                }
+            },
+            "derived_from": "tosca.datatypes.Dynamic"
+        },
+        "dt-ue-subscribe-properties": {
+            "description": "Dynamic DataType definition for workflow(ue-subscription).",
+            "version": "1.0.0",
+            "properties": {
+                "service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vf-modules-list": {
+                    "type": "json"
+                },
+                "config-deploy-setup": {
+                    "type": "json"
+                }
+            },
+            "derived_from": "tosca.datatypes.Dynamic"
+        },
+        "dt-ue-reconfiguration-properties": {
+            "description": "Dynamic DataType definition for workflow(ue-reconfiguration).",
+            "version": "1.0.0",
+            "properties": {
+                "service-instance-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vnf-id": {
+                    "description": "",
+                    "required": false,
+                    "type": "string"
+                },
+                "vf-modules-list": {
+                    "type": "json"
+                },
+                "config-deploy-setup": {
+                    "type": "json"
+                }
+            },
+            "derived_from": "tosca.datatypes.Dynamic"
+        }
+    }
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Definitions/node_types.json b/tutorials/ApacheCNF/templates/cba/Definitions/node_types.json
new file mode 100644 (file)
index 0000000..c191f16
--- /dev/null
@@ -0,0 +1,676 @@
+{
+    "node_types": {
+        "component-resource-resolution": {
+            "description": "This is Resource Assignment Component API",
+            "version": "1.0.0",
+            "attributes": {
+                "assignment-params": {
+                    "description": "Holds resolved template, resolution-summary or key-value",
+                    "required": true,
+                    "type": "string"
+                },
+                "assignment-map": {
+                    "description": "Holds resolved values for each artifact prefix eg. { vdns: { vnf-id: 123 } }",
+                    "required": true,
+                    "type": "map"
+                }
+            },
+            "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"
+                                },
+                                "occurrence": {
+                                    "description": "Number of time to perform the resolution.",
+                                    "required": false,
+                                    "default": 1,
+                                    "type": "integer"
+                                },
+                                "store-result": {
+                                    "description": "Whether or not to store the output.",
+                                    "required": false,
+                                    "type": "boolean"
+                                },
+                                "resource-type": {
+                                    "description": "Request type.",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "resolution-summary": {
+                                    "description": "Enable resolution-summary output",
+                                    "required": false,
+                                    "type": "boolean"
+                                },
+                                "artifact-prefix-names": {
+                                    "required": true,
+                                    "description": "Template , Resource Assignment Artifact Prefix names",
+                                    "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"
+                                },
+                                "resource-assignment-map": {
+                                    "required": true,
+                                    "type": "string"
+                                },
+                                "status": {
+                                    "required": true,
+                                    "type": "string"
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+            "derived_from": "tosca.nodes.Component"
+        },
+        "component-script-executor": {
+            "description": "This is CLI Transaction Configuration Component API",
+            "version": "1.0.0",
+            "attributes": {
+                "response-data": {
+                    "required": false,
+                    "type": "json"
+                }
+            },
+            "capabilities": {
+                "component-node": {
+                    "type": "tosca.capabilities.Node"
+                }
+            },
+            "interfaces": {
+                "ComponentScriptExecutor": {
+                    "operations": {
+                        "process": {
+                            "inputs": {
+                                "script-type": {
+                                    "description": "Script type, kotlin type is supported",
+                                    "required": true,
+                                    "type": "string",
+                                    "constraints": [
+                                        {
+                                            "valid_values": [
+                                                "kotlin",
+                                                "jython",
+                                                "internal"
+                                            ]
+                                        }
+                                    ],
+                                    "default": "internal"
+                                },
+                                "script-class-reference": {
+                                    "description": "Kotlin Script class name or jython script name.",
+                                    "required": true,
+                                    "type": "string"
+                                },
+                                "instance-dependencies": {
+                                    "description": "Instance names to inject to Jython or Kotlin Script.",
+                                    "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.",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "status": {
+                                    "description": "Status of the Component Execution ( success or failure )",
+                                    "required": true,
+                                    "type": "string"
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+            "derived_from": "tosca.nodes.Component"
+        },
+        "component-k8s-profile-upload": {
+            "description": "This component is rendering and sending the k8s profile to the multicloud plugin.",
+            "version": "1.0.0",
+            "attributes": {
+                "statuses": {
+                    "required": true,
+                    "type": "json"
+                }
+            },
+            "capabilities": {
+                "component-node": {
+                    "type": "tosca.capabilities.Node"
+                }
+            },
+            "interfaces": {
+                "K8sProfileUploadComponent": {
+                    "operations": {
+                        "process": {
+                            "inputs": {
+                                "k8s-rb-profile-name": {
+                                    "description": "K8s profile name",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-rb-definition-name": {
+                                    "description": "K8s definition name",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-rb-definition-version": {
+                                    "description": "Version of the definition",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-rb-profile-namespace": {
+                                    "description": "a K8s namespace for the profile",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-rb-profile-k8s-version": {
+                                    "description": "a K8s cluster version for the profile",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-rb-profile-source": {
+                                    "description": "Source (tgz/folder) for the template in CBA",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "artifact-prefix-names": {
+                                    "description": "Resource Assignment Artifact Prefix names",
+                                    "required": false,
+                                    "type": "list",
+                                    "entry_schema": {
+                                        "type": "string"
+                                    }
+                                },
+                                "resource-assignment-map": {
+                                    "description": "Holds resolved values for each artifact prefix eg. { vdns: { vnf-id: 123 } }",
+                                    "required": false,
+                                    "type": "json"
+                                }
+                            },
+                            "outputs": {
+                                "statuses": {
+                                    "required": true,
+                                    "type": "string"
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+            "derived_from": "tosca.nodes.Component"
+        },
+        "component-k8s-config-template": {
+            "description": "This component is rendering and sending the k8s template to the multicloud plugin.",
+            "version": "1.0.0",
+            "attributes": {
+                "statuses": {
+                    "required": true,
+                    "type": "json"
+                }
+            },
+            "capabilities": {
+                "component-node": {
+                    "type": "tosca.capabilities.Node"
+                }
+            },
+            "interfaces": {
+                "K8sConfigTemplateComponent": {
+                    "operations": {
+                        "process": {
+                            "inputs": {
+                                "k8s-rb-config-template-name": {
+                                    "description": "K8s template name",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-rb-definition-name": {
+                                    "description": "K8s definition name",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-rb-definition-version": {
+                                    "description": "Version of the definition",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-rb-config-template-source": {
+                                    "description": "Source (tgz/folder) for the template in CBA",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "artifact-prefix-names": {
+                                    "description": "Resource Assignment Artifact Prefix names",
+                                    "required": false,
+                                    "type": "list",
+                                    "entry_schema": {
+                                        "type": "string"
+                                    }
+                                },
+                                "resource-assignment-map": {
+                                    "description": "Holds resolved values for each artifact prefix eg. { vdns: { vnf-id: 123 } }",
+                                    "required": false,
+                                    "type": "json"
+                                }
+                            },
+                            "outputs": {
+                                "statuses": {
+                                    "required": true,
+                                    "type": "string"
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+            "derived_from": "tosca.nodes.Component"
+        },
+        "component-k8s-config-value": {
+            "description": "This component is sending the k8s config value to the multicloud plugin.",
+            "version": "1.0.0",
+            "attributes": {
+                "statuses": {
+                    "required": true,
+                    "type": "json"
+                }
+            },
+            "capabilities": {
+                "component-node": {
+                    "type": "tosca.capabilities.Node"
+                }
+            },
+            "interfaces": {
+                "K8sConfigValueComponent": {
+                    "operations": {
+                        "process": {
+                            "inputs": {
+                                "k8s-rb-config-template-name": {
+                                    "description": "K8s template name",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-rb-config-name": {
+                                    "description": "K8s config name",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-instance-id": {
+                                    "description": "K8s instance id",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-rb-config-value-source": {
+                                    "description": "Location of value source in CBA",
+                                    "required": false,
+                                    "type": "string"
+                                },
+                                "k8s-config-operation-type": {
+                                    "required": false,
+                                    "type": "string",
+                                    "constraints": [
+                                        {
+                                            "valid_values": [
+                                                "create",
+                                                "update",
+                                                "delete"
+                                            ]
+                                        }
+                                    ],
+                                    "default": "create"
+                                },
+                                "artifact-prefix-names": {
+                                    "description": "Resource Assignment Artifact Prefix names",
+                                    "required": false,
+                                    "type": "list",
+                                    "entry_schema": {
+                                        "type": "string"
+                                    }
+                                },
+                                "resource-assignment-map": {
+                                    "description": "Holds resolved values for each artifact prefix eg. { vdns: { vnf-id: 123 } }",
+                                    "required": false,
+                                    "type": "json"
+                                }
+                            },
+                            "outputs": {
+                                "statuses": {
+                                    "required": true,
+                                    "type": "string"
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+            "derived_from": "tosca.nodes.Component"
+        },
+        "source-capability": {
+            "description": "This is Component Resource Source Node Type",
+            "version": "1.0.0",
+            "properties": {
+                "script-type": {
+                    "required": true,
+                    "type": "string",
+                    "constraints": [
+                        {
+                            "valid_values": [
+                                "kotlin",
+                                "internal",
+                                "jython"
+                            ]
+                        }
+                    ],
+                    "default": "kotlin"
+                },
+                "script-class-reference": {
+                    "description": "Capability reference name for internal and kotlin, for jython script file path",
+                    "required": true,
+                    "type": "string"
+                },
+                "instance-dependencies": {
+                    "description": "Instance dependency Names to Inject to Kotlin / Jython Script.",
+                    "required": false,
+                    "type": "list",
+                    "entry_schema": {
+                        "type": "string"
+                    }
+                },
+                "key-dependencies": {
+                    "description": "Resource Resolution dependency dictionary names.",
+                    "required": true,
+                    "type": "list",
+                    "entry_schema": {
+                        "type": "string"
+                    }
+                }
+            },
+            "derived_from": "tosca.nodes.ResourceSource"
+        },
+        "source-db": {
+            "description": "This is Database Resource Source Node Type",
+            "version": "1.0.0",
+            "properties": {
+                "type": {
+                    "required": true,
+                    "type": "string",
+                    "constraints": [
+                        {
+                            "valid_values": [
+                                "SQL",
+                                "PLSQL"
+                            ]
+                        }
+                    ],
+                    "default": "SQL"
+                },
+                "endpoint-selector": {
+                    "required": false,
+                    "type": "string"
+                },
+                "query": {
+                    "required": true,
+                    "type": "string"
+                },
+                "input-key-mapping": {
+                    "required": false,
+                    "type": "map",
+                    "entry_schema": {
+                        "type": "string"
+                    }
+                },
+                "output-key-mapping": {
+                    "required": false,
+                    "type": "map",
+                    "entry_schema": {
+                        "type": "string"
+                    }
+                },
+                "key-dependencies": {
+                    "required": true,
+                    "type": "list",
+                    "entry_schema": {
+                        "type": "string"
+                    }
+                }
+            },
+            "derived_from": "tosca.nodes.ResourceSource"
+        },
+        "source-default": {
+            "description": "This is Default Resource Source Node Type",
+            "version": "1.0.0",
+            "properties": {},
+            "derived_from": "tosca.nodes.ResourceSource"
+        },
+        "source-input": {
+            "description": "This is Input Resource Source Node Type",
+            "version": "1.0.0",
+            "properties": {},
+            "derived_from": "tosca.nodes.ResourceSource"
+        },
+        "source-rest": {
+            "description": "This is Rest Resource Source Node Type",
+            "version": "1.0.0",
+            "properties": {
+                "type": {
+                    "required": true,
+                    "type": "string",
+                    "constraints": [
+                        {
+                            "valid_values": [
+                                "JSON"
+                            ]
+                        }
+                    ],
+                    "default": "JSON"
+                },
+                "headers": {
+                    "required": false,
+                    "type": "map",
+                    "entry_schema": {
+                        "type": "string"
+                    }
+                },
+                "verb": {
+                    "required": true,
+                    "type": "string",
+                    "constraints": [
+                        {
+                            "valid_values": [
+                                "GET",
+                                "POST",
+                                "DELETE",
+                                "PUT"
+                            ]
+                        }
+                    ],
+                    "default": "GET"
+                },
+                "payload": {
+                    "required": false,
+                    "type": "string",
+                    "default": ""
+                },
+                "endpoint-selector": {
+                    "required": false,
+                    "type": "string"
+                },
+                "url-path": {
+                    "required": true,
+                    "type": "string"
+                },
+                "path": {
+                    "required": true,
+                    "type": "string"
+                },
+                "expression-type": {
+                    "required": false,
+                    "type": "string",
+                    "constraints": [
+                        {
+                            "valid_values": [
+                                "JSON_PATH",
+                                "JSON_POINTER"
+                            ]
+                        }
+                    ],
+                    "default": "JSON_PATH"
+                },
+                "input-key-mapping": {
+                    "required": false,
+                    "type": "map",
+                    "entry_schema": {
+                        "type": "string"
+                    }
+                },
+                "output-key-mapping": {
+                    "required": false,
+                    "type": "map",
+                    "entry_schema": {
+                        "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",
+            "derived_from": "tosca.nodes.Root"
+        },
+        "tosca.nodes.ResourceSource": {
+            "description": "TOSCA base type for Resource Sources",
+            "version": "1.0.0",
+            "derived_from": "tosca.nodes.Root"
+        },
+        "tosca.nodes.Vnf": {
+            "description": "This is VNF Node Type",
+            "version": "1.0.0",
+            "derived_from": "tosca.nodes.Root"
+        },
+        "tosca.nodes.Workflow": {
+            "description": "This is Directed Graph Node Type",
+            "version": "1.0.0",
+            "derived_from": "tosca.nodes.Root"
+        },
+        "vnf-netconf-device": {
+            "description": "This is VNF Device with Netconf  Capability",
+            "version": "1.0.0",
+            "capabilities": {
+                "netconf": {
+                    "type": "tosca.capabilities.Netconf",
+                    "properties": {
+                        "login-key": {
+                            "required": true,
+                            "type": "string",
+                            "default": "sdnc"
+                        },
+                        "login-account": {
+                            "required": true,
+                            "type": "string",
+                            "default": "sdnc-tacacs"
+                        },
+                        "source": {
+                            "required": false,
+                            "type": "string",
+                            "default": "npm"
+                        },
+                        "target-ip-address": {
+                            "required": true,
+                            "type": "string"
+                        },
+                        "port-number": {
+                            "required": true,
+                            "type": "integer",
+                            "default": 830
+                        },
+                        "connection-time-out": {
+                            "required": false,
+                            "type": "integer",
+                            "default": 30
+                        }
+                    }
+                },
+                "restconf": {
+                    "type": "tosca.capabilities.Restconf",
+                    "properties": {
+                        "login-key": {
+                            "required": true,
+                            "type": "string"
+                        },
+                        "login-account": {
+                            "required": true,
+                            "type": "string"
+                        },
+                        "target-ip-address": {
+                            "required": true,
+                            "type": "string"
+                        },
+                        "port-number": {
+                            "required": true,
+                            "type": "integer"
+                        },
+                        "connection-time-out": {
+                            "required": false,
+                            "type": "integer",
+                            "default": 30
+                        }
+                    }
+                }
+            },
+            "derived_from": "tosca.nodes.Vnf"
+        }
+    }
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Definitions/policy_types.json b/tutorials/ApacheCNF/templates/cba/Definitions/policy_types.json
new file mode 100644 (file)
index 0000000..335746c
--- /dev/null
@@ -0,0 +1,3 @@
+{
+    "policy_types": {}
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Definitions/relationship_types.json b/tutorials/ApacheCNF/templates/cba/Definitions/relationship_types.json
new file mode 100644 (file)
index 0000000..8a38851
--- /dev/null
@@ -0,0 +1,3 @@
+{
+    "relationship_types": {}
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Definitions/resources_definition_types.json b/tutorials/ApacheCNF/templates/cba/Definitions/resources_definition_types.json
new file mode 100644 (file)
index 0000000..38b5fee
--- /dev/null
@@ -0,0 +1,1516 @@
+{
+    "active-streams": {
+        "tags": "active-streams",
+        "name": "active-streams",
+        "property": {
+            "description": "active-streams",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            }
+        }
+    },
+    "aic-cloud-region": {
+        "tags": "aic-cloud-region",
+        "name": "aic-cloud-region",
+        "property": {
+            "description": "aic-cloud-region",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Singal, Kapil <ks220y@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input",
+                "properties": {}
+            }
+        }
+    },
+    "dcae_collector_ip": {
+        "tags": "dcae_collector_ip",
+        "name": "dcae_collector_ip",
+        "property": {
+            "description": "dcae_collector_ip",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/dcae_collector_ip",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "dcae_collector_ip": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            }
+        }
+    },
+    "dcae_collector_port": {
+        "tags": "dcae_collector_port",
+        "name": "dcae_collector_port",
+        "property": {
+            "description": "dcae_collector_port",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/dcae_collector_port",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "dcae_collector_port": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            }
+        }
+    },
+    "demo_artifacts_version": {
+        "tags": "demo_artifacts_version",
+        "name": "demo_artifacts_version",
+        "property": {
+            "description": "demo_artifacts_version",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/demo_artifacts_version",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "demo_artifacts_version": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            }
+        }
+    },
+    "int_private1_net_cidr": {
+        "tags": "int_private1_net_cidr",
+        "name": "int_private1_net_cidr",
+        "property": {
+            "description": "int_private1_net_cidr",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/int_private1_net_cidr",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "int_private1_net_cidr": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "type": "SQL",
+                    "query": "select sdnctl.IPAM_IP_POOL.prefix as prefix from sdnctl.IPAM_IP_POOL where description = \"private1\"",
+                    "input-key-mapping": {},
+                    "output-key-mapping": {
+                        "int_private1_net_cidr": "prefix"
+                    }
+                }
+            }
+        }
+    },
+    "int_private2_net_cidr": {
+        "tags": "int_private2_net_cidr",
+        "name": "int_private2_net_cidr",
+        "property": {
+            "description": "int_private2_net_cidr",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "type": "SQL",
+                    "query": "select sdnctl.IPAM_IP_POOL.prefix as prefix from sdnctl.IPAM_IP_POOL where description = \"private2\"",
+                    "output-key-mapping": {
+                        "int_private2_net_cidr": "prefix"
+                    },
+                    "input-key-mapping": {}
+                }
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/int_private2_net_cidr",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "int_private2_net_cidr": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            }
+        }
+    },
+    "k8s-rb-profile-name": {
+        "tags": "k8s, cnf, profile, k8s-rb-profile-name",
+        "name": "k8s-rb-profile-name",
+        "property": {
+            "description": "Profile name used in multicloud/k8s plugin to identify Helm chart(s) where this mapping is providing override values.",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Samuli, Silvius <s.silvius@partner.samsung.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            }
+        }
+    },
+    "k8s-rb-instance-release-name": {
+        "tags": "k8s, cnf, profile, k8s-rb-instance-release-name",
+        "name": "k8s-rb-instance-release-name",
+        "property": {
+            "description": "Name of the release for the helm package instance in k8s",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Rajewski, Lukasz <lukasz.rajewski@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            }
+        }
+    },
+    "k8s-rb-profile-namespace": {
+        "tags": "k8s, cnf, profile, namespace, k8s-rb-profile-namespace",
+        "name": "k8s-rb-profile-namespace",
+        "property": {
+            "description": "Profile name used in multicloud/k8s plugin",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Samuli, Silvius <s.silvius@partner.samsung.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/k8s-rb-profile-namespace",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "k8s-rb-profile-namespace": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            }
+        }
+    },
+    "k8s-rb-profile-k8s-version": {
+        "tags": "k8s, cnf, profile, k8s version, k8s-rb-profile-k8s-version",
+        "name": "k8s-rb-profile-k8s-version",
+        "property": {
+            "description": "Profile k8s version used in multicloud/k8s plugin",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Rajewski, Lukasz <lukasz.rajewski@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/k8s-rb-profile-k8s-version",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "k8s-rb-profile-k8s-version": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            }
+        }
+    },
+    "k8s-rb-profile-source": {
+        "tags": "k8s, cnf, profile, k8s-rb-profile-source",
+        "name": "k8s-rb-profile-source",
+        "property": {
+            "description": "The source folder or file relative to 'Templates/k8s-profiles' folder",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Rajewski, Lukasz <lukasz.rajewski@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            }
+        }
+    },
+    "k8s-rb-config-template-name": {
+        "tags": "k8s, cnf, config, k8s-rb-config-template-name",
+        "name": "k8s-rb-config-template-name",
+        "property": {
+            "description": "The name of configuration template for config-assign operation",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Rajewski, Lukasz <lukasz.rajewski@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            }
+        }
+    },
+    "k8s-rb-config-template-source": {
+        "tags": "k8s, cnf, config, k8s-rb-config-template-source",
+        "name": "k8s-rb-config-template-source",
+        "property": {
+            "description": "The source of configuration template for config-assign operation",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Rajewski, Lukasz <lukasz.rajewski@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            }
+        }
+    },
+    "k8s-rb-config-value-source": {
+        "tags": "k8s, cnf, config, k8s-rb-config-value-source",
+        "name": "k8s-rb-config-value-source",
+        "property": {
+            "description": "The source of configuration values for config-deploy operation",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Rajewski, Lukasz <lukasz.rajewski@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            }
+        }
+    },
+    "k8s-rb-config-name": {
+        "tags": "k8s, cnf, config, k8s-rb-config-name",
+        "name": "k8s-rb-config-name",
+        "property": {
+            "description": "The source of configuration values for config-deploy operation",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Rajewski, Lukasz <lukasz.rajewski@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            }
+        }
+    },
+    "management-prefix-id": {
+        "tags": "management-prefix-id",
+        "name": "management-prefix-id",
+        "property": {
+            "description": "management-prefix-id",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/management-prefix-id",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "management-prefix-id": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "type": "SQL",
+                    "query": "select sdnctl.IPAM_IP_POOL.prefix_id as prefix_id from sdnctl.IPAM_IP_POOL where description = \"management\"",
+                    "input-key-mapping": {},
+                    "output-key-mapping": {
+                        "management-prefix-id": "prefix_id"
+                    }
+                }
+            }
+        }
+    },
+    "onap_private_net_cidr": {
+        "tags": "onap_private_net_cidr",
+        "name": "onap_private_net_cidr",
+        "property": {
+            "description": "onap_private_net_cidr",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "type": "SQL",
+                    "query": "select sdnctl.IPAM_IP_POOL.prefix as prefix from sdnctl.IPAM_IP_POOL where description = \"management\"",
+                    "input-key-mapping": {},
+                    "output-key-mapping": {
+                        "onap_private_net_cidr": "prefix"
+                    }
+                }
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/onap_private_net_cidr",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "onap_private_net_cidr": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            }
+        }
+    },
+    "private1-prefix-id": {
+        "tags": "private1-prefix-id",
+        "name": "private1-prefix-id",
+        "property": {
+            "description": "private1-prefix-id",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/private1-prefix-id",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "private1-prefix-id": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "type": "SQL",
+                    "query": "select sdnctl.IPAM_IP_POOL.prefix_id as prefix_id from sdnctl.IPAM_IP_POOL where description = \"private1\"",
+                    "input-key-mapping": {},
+                    "output-key-mapping": {
+                        "private1-prefix-id": "prefix_id"
+                    }
+                }
+            }
+        }
+    },
+    "private2-prefix-id": {
+        "tags": "private2-prefix-id",
+        "name": "private2-prefix-id",
+        "property": {
+            "description": "private2-prefix-id",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/private2-prefix-id",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "private2-prefix-id": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "type": "SQL",
+                    "query": "select sdnctl.IPAM_IP_POOL.prefix_id as prefix_id from sdnctl.IPAM_IP_POOL where description = \"private2\"",
+                    "input-key-mapping": {},
+                    "output-key-mapping": {
+                        "private2-prefix-id": "prefix_id"
+                    }
+                }
+            }
+        }
+    },
+    "put-active-streams": {
+        "tags": "put-active-streams",
+        "name": "put-active-streams",
+        "property": {
+            "description": "put-active-streams",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "PUT",
+                    "type": "JSON",
+                    "url-path": "$vpg_onap_private_ip_0:8183/restconf/config/stream-count:stream-count/streams",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "vpg_onap_private_ip_0": "vpg_onap_private_ip_0",
+                        "active-streams": "active-streams"
+                    },
+                    "output-key-mapping": {},
+                    "key-dependencies": [
+                        "vpg_onap_private_ip_0",
+                        "active-streams"
+                    ],
+                    "endpoint-selector": "vpkg-rest-api",
+                    "payload": "{\"streams\": {\"active-streams\": $active-streams}}"
+                }
+            }
+        }
+    },
+    "service-instance-id": {
+        "tags": "service-instance-id, tosca.datatypes.Root, data_type",
+        "name": "service-instance-id",
+        "property": {
+            "description": "To be provided",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Singal, Kapil <ks220y@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input",
+                "properties": {}
+            },
+            "any-db": {
+                "type": "source-db",
+                "properties": {
+                    "query": "SELECT artifact_name FROM BLUEPRINT_RUNTIME where artifact_version=\"1.0.0\"",
+                    "input-key-mapping": {},
+                    "output-key-mapping": {
+                        "service-instance-id": "artifact_name"
+                    }
+                }
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "query": "SELECT artifact_name FROM BLUEPRINT_RUNTIME where artifact_version=\"1.0.0\"",
+                    "input-key-mapping": {},
+                    "output-key-mapping": {
+                        "service-instance-id": "artifact_name"
+                    }
+                }
+            },
+            "capability": {
+                "type": "source-capability",
+                "properties": {
+                    "script-type": "kotlin",
+                    "script-class-reference": "org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.ConfigDeploySetup",
+                    "instance-dependencies": []
+                }
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id",
+                    "path": "/service/0/service-instance-id",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance.service-instance-id"
+                    },
+                    "output-key-mapping": {
+                        "service-instance-id": "service-instance-id"
+                    },
+                    "key-dependencies": [
+                        "service-instance.service-instance-id"
+                    ]
+                }
+            }
+        }
+    },
+    "vf-module-id": {
+        "tags": "vf-module-id",
+        "name": "vf-module-id",
+        "property": {
+            "description": "vf-module-id",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Singal, Kapil <ks220y@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vf-modules/vf-module/$vf-module-id",
+                    "path": "/vf-module/0/vf-module-id",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id",
+                        "vf-module-id": "vf-module.vf-module-id"
+                    },
+                    "output-key-mapping": {
+                        "vf-module-id": "vf-module-id"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id",
+                        "vf-module.vf-module-id"
+                    ]
+                }
+            }
+        }
+    },
+    "vf-module-name": {
+        "tags": "vf-module-name",
+        "name": "vf-module-name",
+        "property": {
+            "description": "vf-module-name",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Singal, Kapil <ks220y@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vf-modules/vf-module/$vf_module_id/vf-module-data/vf-module-topology/vf-module-parameters/param/vf-module-name",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "vf-module-name": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id",
+                        "vf_module_id"
+                    ]
+                }
+            },
+            "rest": {
+                "type": "source-rest",
+                "properties": {
+                    "endpoint-selector": "naming-resolution",
+                    "verb": "POST",
+                    "type": "JSON",
+                    "headers": {
+                        "Accept": "application/json",
+                        "Content-Type": "application/json"
+                    },
+                    "url-path": "/v1/genNetworkElementName",
+                    "payload": "{\r\n  \"elements\": [\r\n    {\r\n      \"resource-name\": \"vf-module-name\",\r\n      \"resource-value\": \"${vf-module-name}\",\r\n      \"external-key\": \"${vf-module-id}\",\r\n      \"policy-instance-name\": \"${vf-naming-policy}\",\r\n      \"naming-type\": \"VF-MODULE\",\r\n      \"VNF_NAME\": \"${vnf_name}\",\r\n      \"VF_MODULE_LABEL\":\"${vf-module-label}\",\r\n      \"VF_MODULE_TYPE\":\"vfmt\"\r\n    }\r\n  ]\r\n}",
+                    "path": "/elements/0/resource-value",
+                    "input-key-mapping": {
+                        "vf-naming-policy": "vf-naming-policy",
+                        "vnf_name": "vnf_name",
+                        "vf-module-label": "vf-module-label",
+                        "vf-module-id": "vf-module-id"
+                    },
+                    "output-key-mapping": {
+                        "vf-module-name": "resource-value"
+                    },
+                    "key-dependencies": [
+                        "vf-naming-policy",
+                        "vnf_name",
+                        "vf-module-label",
+                        "vf-module-id"
+                    ]
+                }
+            }
+        }
+    },
+    "vf-module-type": {
+        "tags": "vf-module-type",
+        "name": "vf-module-type",
+        "property": {
+            "description": "vf-module-type",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "type": "SQL",
+                    "query": "select vf_module_type as vf_module_type from sdnctl.VF_MODULE_MODEL where customization_uuid=:customizationid",
+                    "output-key-mapping": {
+                        "vf-module-type": "vf_module_type"
+                    },
+                    "input-key-mapping": {
+                        "customizationid": "vf-module-model-customization-uuid"
+                    },
+                    "key-dependencies": [
+                        "vf-module-model-customization-uuid"
+                    ]
+                }
+            }
+        }
+    },
+    "vf-module-label": {
+        "tags": "vf-module-label",
+        "name": "vf-module-label",
+        "property": {
+            "description": "vf-module-label",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "type": "SQL",
+                    "query": "select sdnctl.VF_MODULE_MODEL.vf_module_label as vf_module_label from sdnctl.VF_MODULE_MODEL where sdnctl.VF_MODULE_MODEL.customization_uuid=:customizationid",
+                    "input-key-mapping": {
+                        "customizationid": "vf-module-model-customization-uuid"
+                    },
+                    "output-key-mapping": {
+                        "vf-module-label": "vf_module_label"
+                    },
+                    "key-dependencies": [
+                        "vf-module-model-customization-uuid"
+                    ]
+                }
+            }
+        }
+    },
+    "vf-module-model-customization-uuid": {
+        "tags": "vf-module-model-customization-uuid",
+        "name": "vf-module-model-customization-uuid",
+        "property": {
+            "description": "vf-module-model-customization-uuid",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            }
+        }
+    },
+    "vf-module-model-invariant-uuid": {
+        "tags": "vnf, vf-module",
+        "name": "vf-module-model-invariant-uuid",
+        "property": {
+            "description": "vf module model invariant uuid",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Samuli, Silvius <s.silvius@partner.samsung.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "type": "SQL",
+                    "query": "select sdnctl.VF_MODULE_MODEL.invariant_uuid as vf_module_model_invariant_uuid from sdnctl.VF_MODULE_MODEL where sdnctl.VF_MODULE_MODEL.customization_uuid=:customizationid",
+                    "input-key-mapping": {
+                        "customizationid": "vf-module-model-customization-uuid"
+                    },
+                    "output-key-mapping": {
+                        "vf-module-model-invariant-uuid": "vf_module_model_invariant_uuid"
+                    },
+                    "key-dependencies": [
+                        "vf-module-model-customization-uuid"
+                    ]
+                }
+            }
+        }
+    },
+    "vf-module-model-version": {
+        "tags": "vnf, vf-module",
+        "name": "vf-module-model-version",
+        "property": {
+            "description": "vf module model model version",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Samuli, Silvius <s.silvius@partner.samsung.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "type": "SQL",
+                    "query": "select sdnctl.VF_MODULE_MODEL.uuid as vf_module_model_version from sdnctl.VF_MODULE_MODEL where sdnctl.VF_MODULE_MODEL.customization_uuid=:customizationid",
+                    "input-key-mapping": {
+                        "customizationid": "vf-module-model-customization-uuid"
+                    },
+                    "output-key-mapping": {
+                        "vf-module-model-version": "vf_module_model_version"
+                    },
+                    "key-dependencies": [
+                        "vf-module-model-customization-uuid"
+                    ]
+                }
+            }
+        }
+    },
+    "vf-naming-policy": {
+        "tags": "vf-naming-policy",
+        "name": "vf-naming-policy",
+        "property": {
+            "description": "vf-naming-policy",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/vf-naming-policy",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "vf-naming-policy": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            },
+            "processor-db": {
+                "type": "source-db",
+                "properties": {
+                    "type": "SQL",
+                    "query": "select sdnctl.VF_MODEL.naming_policy as vf_naming_policy from sdnctl.VF_MODEL where sdnctl.VF_MODEL.customization_uuid=:vnf_model_customization_uuid",
+                    "input-key-mapping": {
+                        "vnf_model_customization_uuid": "vnf-model-customization-uuid"
+                    },
+                    "output-key-mapping": {
+                        "vf-naming-policy": "vf_naming_policy"
+                    },
+                    "key-dependencies": [
+                        "vnf-model-customization-uuid"
+                    ]
+                }
+            }
+        }
+    },
+    "vnf-id": {
+        "tags": "vnf-id",
+        "name": "vnf-id",
+        "property": {
+            "description": "vnf-id",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "capability": {
+                "type": "source-capability",
+                "properties": {
+                    "script-type": "kotlin",
+                    "script-class-reference": "org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.ConfigDeploySetup",
+                    "instance-dependencies": []
+                }
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/",
+                    "path": "/vnf/0/vnf-id",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "generic-vnf.vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "vnf-id": "vnf-id"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "generic-vnf.vnf-id"
+                    ]
+                }
+            }
+        }
+    },
+    "vnf_name": {
+        "tags": "vnf_name",
+        "name": "vnf_name",
+        "property": {
+            "description": "vnf_name",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "MALAKOV, YURIY <yuriy.malakov@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/vnf_name",
+                    "path": "/param/0/value",
+                    "headers": {
+                        "Accept": "application/json",
+                        "Content-Type": "application/json"
+                    },
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "vnf_name": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            },
+            "rest": {
+                "type": "source-rest",
+                "properties": {
+                    "endpoint-selector": "naming-resolution",
+                    "verb": "POST",
+                    "type": "JSON",
+                    "headers": {
+                        "Accept": "application/json",
+                        "Content-Type": "application/json"
+                    },
+                    "url-path": "/v1/genNetworkElementName",
+                    "payload": "{\r\n  \"elements\": [\r\n    {\r\n      \"resource-name\": \"vnf_name\",\r\n      \"resource-value\": \"${vnf_name}\",\r\n      \"external-key\": \"${vnf-id}\",\r\n      \"policy-instance-name\": \"${vf-naming-policy}\",\r\n      \"naming-type\": \"VNF\",\r\n      \"AIC_CLOUD_REGION\": \"${aic-cloud-region}\"\r\n    }\r\n  ]\r\n}",
+                    "path": "/elements/0/resource-value",
+                    "input-key-mapping": {
+                        "vnf-id": "vnf-id",
+                        "aic-cloud-region": "aic-cloud-region",
+                        "vf-naming-policy": "vf-naming-policy"
+                    },
+                    "output-key-mapping": {
+                        "vnf_name": "resource-value"
+                    },
+                    "key-dependencies": [
+                        "vnf-id",
+                        "aic-cloud-region",
+                        "vf-naming-policy"
+                    ]
+                }
+            }
+        }
+    },
+    "replica-count": {
+        "tags": "replica-count",
+        "name": "replica-count",
+        "property": {
+            "description": "replica-count",
+            "type": "integer"
+        },
+        "group": "default",
+        "updated-by": "Rajewski, Lukasz <lukasz.rajewski@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "capability": {
+                "type": "source-capability",
+                "properties": {
+                    "script-type": "kotlin",
+                    "script-class-reference": "org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.ConfigDeploySetup",
+                    "instance-dependencies": []
+                }
+            }
+        }
+    },
+    "vpg_onap_private_ip_0": {
+        "tags": "vpg_onap_private_ip_0",
+        "name": "vpg_onap_private_ip_0",
+        "property": {
+            "description": "vpg_onap_private_ip_0",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Singal, Kapil <ks220y@att.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vnf-topology/vnf-parameters-data/param/vpg_onap_private_ip_0",
+                    "path": "/param/0/value",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "vpg_onap_private_ip_0": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            }
+        }
+    },
+    "vnf-relationship-list": {
+        "tags": "vnf-relationship-list",
+        "name": "vnf-relationship-list",
+        "property": {
+            "description": "Details about VNF relationships from AAI",
+            "type": "json"
+        },
+        "group": "default",
+        "updated-by": "Lukasz Rajewski <lukasz.rajewski@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "aai-data": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/aai/v19/network/generic-vnfs/generic-vnf/${vnf-id}?depth=1",
+                    "path": "/relationship-list",
+                    "input-key-mapping": {
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "relationship-list": "relationship"
+                    },
+                    "key-dependencies": [
+                        "vnf-id"
+                    ]
+                }
+            }
+        }
+    },
+    "vf-modules-list": {
+        "tags": "vf-modules-list",
+        "name": "vf-modules-list",
+        "property": {
+            "description": "List of vf-modules associated with vnf",
+            "type": "json"
+        },
+        "group": "default",
+        "updated-by": "Lukasz Rajewski <lukasz.rajewski@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "aai-data": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/aai/v19/network/generic-vnfs/generic-vnf/${vnf-id}?depth=1",
+                    "path": "/vf-modules",
+                    "input-key-mapping": {
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "vf-modules": "vf-module"
+                    },
+                    "key-dependencies": [
+                        "vnf-id"
+                    ]
+                }
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id/service-data/vnfs/vnf/$vnf-id/vnf-data/vf-modules",
+                    "path": "/vf-modules",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id",
+                        "vnf-id": "vnf-id"
+                    },
+                    "output-key-mapping": {
+                        "vf-modules": "vf-module"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id",
+                        "vnf-id"
+                    ]
+                }
+            }
+        }
+    },
+    "config-deploy-setup": {
+        "tags": "config-deploy-setup",
+        "name": "config-deploy-setup",
+        "property": {
+            "description": "Configuration Input setup for config-deploy operation",
+            "type": "json"
+        },
+        "group": "default",
+        "updated-by": "Lukasz Rajewski <lukasz.rajewski@orange.com>",
+        "sources": {
+            "capability": {
+                "type": "source-capability",
+                "properties": {
+                    "script-type": "kotlin",
+                    "script-class-reference": "org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.ConfigDeploySetup",
+                    "instance-dependencies": []
+                }
+            }
+        }
+    },
+    "registration-reconfiguration-parameters": {
+        "tags": "registration-reconfiguration-parameters",
+        "name": "registration-reconfiguration-parameters",
+        "property": {
+            "description": "Configuration Input setup for config-deploy operation",
+            "type": "json"
+        },
+        "group": "default",
+        "updated-by": "Chabiera, Michal <michal.chabiera@orange.com>",
+        "sources": {
+            "capability": {
+                "type": "source-capability",
+                "properties": {
+                    "script-type": "kotlin",
+                    "script-class-reference": "org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.ConfigDeploySetup",
+                    "instance-dependencies": []
+                }
+            }
+        }
+    },
+    "pnf-instance-name": {
+        "tags": "pnf-instance-name",
+        "name": "pnf-instance-name",
+        "property": {
+            "description": "Configuration Input setup for config-deploy operation",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Chabiera, Michal <michal.chabiera@orange.com>",
+        "sources": {
+            "capability": {
+                "type": "source-capability",
+                "properties": {
+                    "script-type": "kotlin",
+                    "script-class-reference": "org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts.ConfigDeploySetup",
+                    "instance-dependencies": []
+                }
+            }
+        }
+    },
+    "core-instance-name": {
+        "tags": "PNF, ueransim, core, core-instance-namee",
+        "name": "core-instance-name",
+        "property": {
+            "description": "Name of 5g core instance that requires PNF registration",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Chabiera, Michal <michal.chabiera@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            }
+        }
+    },
+    "service-instance-name": {
+        "tags": "service-instance-name",
+        "name": "service-instance-name",
+        "property": {
+            "description": "service-instance-name",
+            "type": "string"
+        },
+        "group": "default",
+        "updated-by": "Chabiera, Michal <michal.chabiera@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "sdnc": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/restconf/config/GENERIC-RESOURCE-API:services/service/$service-instance-id",
+                    "path": "/service/0/service-data/service-topology/service-topology-identifier/service-instance-name",
+                    "input-key-mapping": {
+                        "service-instance-id": "service-instance-id"
+                    },
+                    "output-key-mapping": {
+                        "service-instance-name": "value"
+                    },
+                    "key-dependencies": [
+                        "service-instance-id"
+                    ]
+                }
+            }
+        }
+    },
+    "pnf-details-aai": {
+        "tags": "pnf-details-aai",
+        "name": "pnf-details-aai",
+        "property": {
+            "description": "PNF details stored in AAI",
+            "type": "json"
+        },
+        "group": "default",
+        "updated-by": "Chabiera, Michal <michal.chabiera@orange.com>",
+        "sources": {
+            "input": {
+                "type": "source-input"
+            },
+            "default": {
+                "type": "source-default",
+                "properties": {}
+            },
+            "aai-data": {
+                "type": "source-rest",
+                "properties": {
+                    "verb": "GET",
+                    "type": "JSON",
+                    "url-path": "/aai/v19/network/pnfs?pnf-name=$pnf-instance-name",
+                    "path": "",
+                    "input-key-mapping": {
+                        "pnf-instance-name": "pnf-instance-name"
+                    },
+                    "output-key-mapping": {
+                        "pnf": "pnf"
+                    },
+                    "key-dependencies": [
+                        "pnf-instance-name"
+                    ]
+                }
+            }
+        }
+    }
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/CollectorScript.kt b/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/CollectorScript.kt
new file mode 100644 (file)
index 0000000..589b934
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  Copyright © 2021 Bell Canada.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts
+
+import com.fasterxml.jackson.databind.JsonNode
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.ComponentScriptExecutor
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
+import org.onap.ccsdk.cds.controllerblueprints.core.asJsonNode
+import org.onap.ccsdk.cds.controllerblueprints.core.logger
+
+open class CollectorScript : AbstractScriptComponentFunction() {
+
+    private val log = logger(CollectorScript::class)
+
+    override suspend fun processNB(executionRequest: ExecutionServiceInput) {
+        bluePrintRuntimeService.bluePrintContext()
+            .serviceTemplate.topologyTemplate!!.nodeTemplates!!
+            .keys.filter { it.startsWith("execute-script") }
+            .associateWith { responseData(it) }
+            .let { it.asJsonNode() }
+            .also { log.info("Collected results: $it") }
+            .let { setAttribute(ComponentScriptExecutor.ATTRIBUTE_RESPONSE_DATA, it) }
+    }
+
+    private fun responseData(nodeTemplateName: String): JsonNode? {
+        return try {
+            bluePrintRuntimeService.getNodeTemplateAttributeValue(
+                nodeTemplateName,
+                ComponentScriptExecutor.ATTRIBUTE_RESPONSE_DATA
+            )
+        } catch (exception: BluePrintProcessorException) { null }
+    }
+
+    override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
+        addError(runtimeException.message ?: "Failed without error message")
+    }
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/ConfigDeploy.kt b/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/ConfigDeploy.kt
new file mode 100644 (file)
index 0000000..96b3c51
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2021 Orange
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts
+
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.storedContentFromResolvedArtifactNB
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction
+import org.slf4j.LoggerFactory
+
+open class ConfigDeploy : AbstractScriptComponentFunction() {
+
+    private val log = LoggerFactory.getLogger(ConfigDeploy::class.java)!!
+
+    override fun getName(): String {
+        return "ConfigDeploy"
+    }
+
+    override suspend fun processNB(executionRequest: ExecutionServiceInput) {
+        val resolutionKey = getDynamicProperties("resolution-key").asText()
+        log.info("Got the resolution_key: $resolutionKey from config-deploy going to retrieve the data from DB")
+        val prefix = "config-deploy" // used in the config-assign resolution
+
+        val payload = storedContentFromResolvedArtifactNB(resolutionKey, prefix)
+        log.info("cnf configuration data from DB : \n$payload\n")
+
+        println("Run config-deploy")
+        println("$payload")
+    }
+
+    override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
+        log.info("Executing Recovery")
+        this.addError("${runtimeException.message}")
+    }
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/ConfigDeploySetup.kt b/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/ConfigDeploySetup.kt
new file mode 100644 (file)
index 0000000..77d86d0
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright © 2021 Orange
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts
+
+import com.fasterxml.jackson.databind.JsonNode
+import com.fasterxml.jackson.databind.node.ObjectNode
+import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.definition.template.K8sConfigTemplateComponent
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.definition.template.K8sConfigValueComponent
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.processor.ResourceAssignmentProcessor
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.resource.resolution.utils.ResourceAssignmentUtils
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintProcessorException
+import org.onap.ccsdk.cds.controllerblueprints.core.isNullOrMissing
+import org.onap.ccsdk.cds.controllerblueprints.resource.dict.ResourceAssignment
+import org.slf4j.LoggerFactory
+
+open class ConfigDeploySetup() : ResourceAssignmentProcessor() {
+
+    private val log = LoggerFactory.getLogger(ConfigDeploySetup::class.java)!!
+
+    override fun getName(): String {
+        return "ConfigDeploySetup"
+    }
+
+    override suspend fun processNB(executionRequest: ResourceAssignment) {
+
+        var retValue: Any? = null
+
+        try {
+            if (executionRequest.name == "service-instance-id") {
+                var value = raRuntimeService.getInputValue(executionRequest.name)
+                if (!value.isNullOrMissing()) {
+                    retValue = value.asText()
+                } else {
+                    val vnfRelationshipList = raRuntimeService.getResolutionStore("vnf-relationship-list")
+                    if (!vnfRelationshipList.isNullOrMissing()) {
+                        vnfRelationshipList["relationship-list"].forEach { relation ->
+                            if (relation["related-to"].asText() == "service-instance") {
+                                relation["relationship-data"].forEach { data ->
+                                    if (data["relationship-key"].asText() == "service-instance.service-instance-id") {
+                                        retValue = data["relationship-value"].asText()
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            } else if (executionRequest.name == "vnf-id") {
+                var value = raRuntimeService.getInputValue(executionRequest.name)
+                if (!value.isNullOrMissing()) {
+                    retValue = value.asText()
+                } else {
+                    value = raRuntimeService.getInputValue("generic-vnf.vnf-id")
+                    if (!value.isNullOrMissing()) {
+                        retValue = value.asText()
+                    }
+                }
+            } 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")
+                    if (!value.isNullOrMissing()) {
+                        if (value["replicaCount"] != null) {
+                            retValue = value["replicaCount"].asText()
+                        }
+                    }
+                }
+            } else if (executionRequest.name == "config-deploy-setup") {
+                val modulesSdnc = raRuntimeService.getResolutionStore("vf-modules-list-sdnc")["vf-modules"]
+                val modulesAai = raRuntimeService.getResolutionStore("vf-modules-list-aai")["vf-modules"]
+                val objectMapper = jacksonObjectMapper()
+                val result: ObjectNode = objectMapper.createObjectNode()
+                for (module in modulesSdnc) {
+                    val modelTopology = module.at("/vf-module-data/vf-module-topology")
+                    val moduleParameters = modelTopology.at("/vf-module-parameters/param")
+                    val label: String? = getParamValueByName(moduleParameters, "vf_module_label")
+                    if (label != null) {
+                        val modelInfo = modelTopology["onap-model-information"]
+                        val moduleData: ObjectNode = objectMapper.createObjectNode()
+                        result.put(label, moduleData)
+                        moduleData.put(K8sConfigTemplateComponent.INPUT_K8S_DEFINITION_NAME, modelInfo["model-invariant-uuid"].asText())
+                        moduleData.put(K8sConfigTemplateComponent.INPUT_K8S_DEFINITION_VERSION, modelInfo["model-customization-uuid"].asText())
+                        val templateName: String? = getParamValueByName(moduleParameters, K8sConfigTemplateComponent.INPUT_K8S_TEMPLATE_NAME)
+                        val templateSource: String? = getParamValueByName(moduleParameters, K8sConfigTemplateComponent.INPUT_K8S_TEMPLATE_SOURCE)
+                        val configValueSource: String? = getParamValueByName(moduleParameters, K8sConfigValueComponent.INPUT_K8S_CONFIG_VALUE_SOURCE)
+                        val configName: String? = getParamValueByName(moduleParameters, K8sConfigValueComponent.INPUT_K8S_RB_CONFIG_NAME)
+
+                        if (templateName != null)
+                            moduleData.put(K8sConfigTemplateComponent.INPUT_K8S_TEMPLATE_NAME, templateName)
+                        if (templateSource != null)
+                            moduleData.put(K8sConfigTemplateComponent.INPUT_K8S_TEMPLATE_SOURCE, templateSource)
+                        if (configValueSource != null)
+                            moduleData.put(K8sConfigValueComponent.INPUT_K8S_CONFIG_VALUE_SOURCE, configValueSource)
+                        if (configName != null)
+                            moduleData.put(K8sConfigValueComponent.INPUT_K8S_RB_CONFIG_NAME, configName)
+
+                        for (aaiModule in modulesAai) {
+                            if (aaiModule["vf-module-id"].asText() == module["vf-module-id"].asText() && aaiModule["heat-stack-id"] != null) {
+                                moduleData.put(K8sConfigValueComponent.INPUT_K8S_INSTANCE_ID, aaiModule["heat-stack-id"].asText())
+                                break
+                            }
+                        }
+                    }
+                }
+                retValue = result
+            }
+            ResourceAssignmentUtils.setResourceDataValue(executionRequest, raRuntimeService, retValue)
+        } catch (e: Exception) {
+            log.error(e.message, e)
+            ResourceAssignmentUtils.setResourceDataValue(executionRequest, raRuntimeService, "ERROR")
+
+            throw BluePrintProcessorException("Failed in template key ($executionRequest) assignments, cause: ${e.message}", e)
+        }
+    }
+
+    private fun getParamValueByName(params: JsonNode, paramName: String): String? {
+        for (param in params) {
+            if (param["name"].asText() == paramName && param["value"].asText() != "null") {
+                return param["value"].asText()
+            }
+        }
+        return null
+    }
+
+    override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ResourceAssignment) {
+        this.addError("${runtimeException.message}")
+    }
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/K8sHealthCheck.kt b/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/K8sHealthCheck.kt
new file mode 100644 (file)
index 0000000..dd87c6f
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 Samsung Electronics
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts
+
+import com.fasterxml.jackson.databind.node.ObjectNode
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.joinAll
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.runBlocking
+import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintPropertiesService
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.K8sConnectionPluginConfiguration
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance.K8sPluginInstanceApi
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance.healthcheck.K8sRbInstanceHealthCheck
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance.healthcheck.K8sRbInstanceHealthCheckSimple
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction
+import org.slf4j.LoggerFactory
+
+open class K8sHealthCheck : AbstractScriptComponentFunction() {
+
+    private val log = LoggerFactory.getLogger(K8sHealthCheck::class.java)!!
+
+    override fun getName(): String {
+        return "K8sHealthCheck"
+    }
+
+    private fun initPluginApi(): K8sPluginInstanceApi {
+        val bluePrintPropertiesService: BluePrintPropertiesService = this.functionDependencyInstanceAsType("bluePrintPropertiesService")!!
+        val k8sConfiguration = K8sConnectionPluginConfiguration(bluePrintPropertiesService)
+
+        return K8sPluginInstanceApi(k8sConfiguration)
+    }
+
+    override suspend fun processNB(executionRequest: ExecutionServiceInput) {
+        val instanceApi = initPluginApi()
+
+        log.info("Health check script execution - START")
+        val configValueSetup: ObjectNode = getDynamicProperties("config-deploy-setup") as ObjectNode
+        log.info("Config Value Setup: $configValueSetup")
+
+        val instanceHealthCheckList = startInstanceHealthCheck(configValueSetup, instanceApi)
+        val statuses = getStatuses(instanceHealthCheckList, instanceApi)
+        log.info("Health check script execution - END")
+    }
+
+    private fun startInstanceHealthCheck(configValueSetup: ObjectNode, instanceApi: K8sPluginInstanceApi): List<HealthCheckInstance> {
+        val healthCheckInstanceList = arrayListOf<HealthCheckInstance>()
+
+        configValueSetup.fields().forEach {
+            val instanceName = it.value.get("k8s-instance-id").asText()
+            val response: K8sRbInstanceHealthCheckSimple? = instanceApi.startInstanceHealthCheck(instanceName)
+            log.debug("K8sRbInstanceHealthCheckSimple response: $$response")
+            healthCheckInstanceList.add(HealthCheckInstance(instanceName, response?.id))
+        }
+        log.info("healthCheckInstanceList: $healthCheckInstanceList")
+
+        return healthCheckInstanceList
+    }
+
+    private fun getStatuses(instanceHealthCheckList: List<HealthCheckInstance>, instanceApi: K8sPluginInstanceApi): Map<String, String> {
+        val statuses = hashMapOf<String, String>()
+        runBlocking {
+            val jobs: List<Job> = instanceHealthCheckList.map {
+                launch {
+                    log.info("Thread started: ${Thread.currentThread().name} for $it")
+                    // WAIT APPROX 5 MINUTES
+                    repeat(30) { _ ->
+                        val response: K8sRbInstanceHealthCheck = instanceApi.getInstanceHealthCheck(it.heatStackId, it.healthCheckInstance!!)!!
+                        log.debug("Response for $it: $response")
+                        val status = response.status!!
+                        if (!"RUNNING".equals(status, true)) {
+                            statuses[it.heatStackId] = status
+                            log.info("Poll status: $status for $it")
+                            instanceApi.deleteInstanceHealthCheck(it.heatStackId, it.healthCheckInstance)
+                            cancel()
+                        }
+                        delay(10_000L)
+                    }
+                    statuses[it.heatStackId] = "Timeout"
+                    log.warn("Send delete hc request")
+                    instanceApi.deleteInstanceHealthCheck(it.heatStackId, it.healthCheckInstance!!)
+                }
+            }
+            jobs.joinAll()
+        }
+        var success = true
+        statuses?.forEach { it ->
+            if (it.value != "Succeeded") {
+                success = false
+            }
+        }
+        log.info("---")
+        if (success) {
+            log.info("Healthcheck finished successfully")
+        } else {
+            log.info("Healthcheck finished with failure")
+        }
+        log.info("Detailed results: $statuses")
+        log.info("---")
+        return statuses
+    }
+
+    data class HealthCheckInstance(val heatStackId: String, val healthCheckInstance: String?) {
+        override fun toString(): String {
+            return "HealthCheckInstance(heatStackId='$heatStackId', healthCheckInstance='$healthCheckInstance')"
+        }
+    }
+
+    override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
+        log.info("Executing Recovery")
+        bluePrintRuntimeService.getBluePrintError().addError("${runtimeException.message}", getName())
+    }
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/README.md b/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/README.md
new file mode 100644 (file)
index 0000000..29b7978
--- /dev/null
@@ -0,0 +1 @@
+kotlin Folder
\ No newline at end of file
diff --git a/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/SimpleErrorCheck.kt b/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/SimpleErrorCheck.kt
new file mode 100644 (file)
index 0000000..8e4a58a
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2021 Orange
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts
+
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction
+import org.slf4j.LoggerFactory
+
+open class SimpleErrorCheck : AbstractScriptComponentFunction() {
+
+    private val log = LoggerFactory.getLogger(SimpleErrorCheck::class.java)!!
+
+    override fun getName(): String {
+        return "SimpleErrorCheck"
+    }
+
+    override suspend fun processNB(executionRequest: ExecutionServiceInput) {
+        log.info("SIMPLE ERROR CHECK - START")
+
+        log.info("SIMPLE ERROR CHECK - END")
+    }
+
+    override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
+        log.info("Executing Recovery")
+        this.addError("${runtimeException.message}")
+    }
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/SimpleStatusCheck.kt b/tutorials/ApacheCNF/templates/cba/Scripts/kotlin/SimpleStatusCheck.kt
new file mode 100644 (file)
index 0000000..c99dcd4
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2021 Orange
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.ccsdk.cds.blueprintsprocessor.services.execution.scripts
+
+import com.fasterxml.jackson.databind.node.ObjectNode
+import org.onap.ccsdk.cds.blueprintsprocessor.core.BluePrintPropertiesService
+import org.onap.ccsdk.cds.blueprintsprocessor.core.api.data.ExecutionServiceInput
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.K8sConnectionPluginConfiguration
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance.K8sPluginInstanceApi
+import org.onap.ccsdk.cds.blueprintsprocessor.functions.k8s.instance.K8sRbInstanceStatus
+import org.onap.ccsdk.cds.blueprintsprocessor.services.execution.AbstractScriptComponentFunction
+import org.onap.ccsdk.cds.controllerblueprints.core.BluePrintException
+import org.slf4j.LoggerFactory
+
+open class SimpleStatusCheck : AbstractScriptComponentFunction() {
+
+    private val log = LoggerFactory.getLogger(SimpleStatusCheck::class.java)!!
+
+    override fun getName(): String {
+        return "SimpleStatusCheck"
+    }
+
+    override suspend fun processNB(executionRequest: ExecutionServiceInput) {
+        log.info("SIMPLE STATUS CHECK - START")
+
+        val configValueSetup: ObjectNode = getDynamicProperties("config-deploy-setup") as ObjectNode
+
+        val bluePrintPropertiesService: BluePrintPropertiesService =
+            this.functionDependencyInstanceAsType("bluePrintPropertiesService")
+
+        val k8sConfiguration = K8sConnectionPluginConfiguration(bluePrintPropertiesService)
+
+        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 ->
+                val vfModuleName = it.key
+                val instanceName = it.value.get("k8s-instance-id").asText()
+
+                val instanceStatus: K8sRbInstanceStatus? = instanceApi.getInstanceStatus(instanceName)
+                log.debug("Get status for $vfModuleName ($instanceName)")
+                if (!instanceStatus?.ready!!) {
+                    continueCheck = true
+                    log.info("VfModule $vfModuleName ($instanceName) is not ready. Please wait...")
+                } else {
+                    log.info("VfModule $vfModuleName ($instanceName) is ready.")
+                }
+            }
+            if (continueCheck) {
+                checkCount--
+                if (checkCount == 0)
+                    throw BluePrintException("Instance State verification failed")
+                Thread.sleep(10000L)
+            } else
+                checkCount = 0
+        }
+
+        log.info("SIMPLE STATUS CHECK - END")
+    }
+
+    override suspend fun recoverNB(runtimeException: RuntimeException, executionRequest: ExecutionServiceInput) {
+        log.info("Executing Recovery")
+        this.addError("${runtimeException.message}")
+    }
+}
diff --git a/tutorials/ApacheCNF/templates/cba/TOSCA-Metadata/TOSCA.meta b/tutorials/ApacheCNF/templates/cba/TOSCA-Metadata/TOSCA.meta
new file mode 100644 (file)
index 0000000..a828207
--- /dev/null
@@ -0,0 +1,8 @@
+TOSCA-Meta-File-Version: 1.0.0
+CSAR-Version: 1.0
+Created-By: Lukasz Rajewski <lukasz.rajewski@orange.com>
+Entry-Definitions: Definitions/CNF.json
+Template-Name: APACHE
+Template-Version: 1.0.0
+Template-Type: DEFAULT
+Template-Tags: Lukasz Rajewski, CNF
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/cnf-mapping.json b/tutorials/ApacheCNF/templates/cba/Templates/cnf-mapping.json
new file mode 100644 (file)
index 0000000..63f5431
--- /dev/null
@@ -0,0 +1,314 @@
+[
+    {
+        "name": "vf-module-model-invariant-uuid",
+        "property": {
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "vf-module-model-invariant-uuid",
+        "dictionary-source": "processor-db",
+        "dependencies": [
+            "vf-module-model-customization-uuid"
+        ]
+    },
+    {
+        "name": "vf-module-model-version",
+        "property": {
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "vf-module-model-version",
+        "dictionary-source": "processor-db",
+        "dependencies": [
+            "vf-module-model-customization-uuid"
+        ]
+    },
+    {
+        "name": "vf-module-name",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string",
+            "status": "",
+            "constraints": [
+                {}
+            ],
+            "entry_schema": {
+                "type": ""
+            }
+        },
+        "input-param": false,
+        "dictionary-name": "vf-module-name",
+        "dictionary-source": "rest",
+        "dependencies": [
+            "vnf_name",
+            "vf-module-label",
+            "vf-naming-policy",
+            "vf-module-id"
+        ],
+        "version": 0
+    },
+    {
+        "name": "vnf_name",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "vnf_name",
+        "dictionary-source": "sdnc",
+        "dependencies": [
+            "service-instance-id",
+            "vnf-id"
+        ],
+        "version": 0
+    },
+    {
+        "name": "service-instance-id",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "service-instance-id",
+        "dictionary-source": "input",
+        "dependencies": [],
+        "version": 0
+    },
+    {
+        "name": "vf-module-label",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "vf-module-label",
+        "dictionary-source": "processor-db",
+        "dependencies": [
+            "vf-module-model-customization-uuid"
+        ],
+        "version": 0
+    },
+    {
+        "name": "vf-naming-policy",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "vf-naming-policy",
+        "dictionary-source": "sdnc",
+        "dependencies": [
+            "service-instance-id",
+            "vnf-id"
+        ],
+        "version": 0
+    },
+    {
+        "name": "vf-module-model-customization-uuid",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "vf-module-model-customization-uuid",
+        "dictionary-source": "input",
+        "dependencies": [],
+        "version": 0
+    },
+    {
+        "name": "vnf-id",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "vnf-id",
+        "dictionary-source": "input",
+        "dependencies": [],
+        "version": 0
+    },
+    {
+        "name": "vf-module-id",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "vf-module-id",
+        "dictionary-source": "input",
+        "dependencies": [],
+        "version": 0
+    },
+    {
+        "name": "k8s-rb-profile-namespace",
+        "property": {
+            "description": "K8s namespace to create helm chart for specified RB profile",
+            "type": "string",
+            "required": false,
+            "default": "default"
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-profile-namespace",
+        "dictionary-source": "sdnc",
+        "dependencies": [
+            "service-instance-id",
+            "vnf-id"
+        ]
+    },
+    {
+        "name": "k8s-rb-profile-k8s-version",
+        "property": {
+            "description": "K8s cluster version to create helm chart for specified RB profile",
+            "type": "string",
+            "required": false,
+            "default": "1.18.9"
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-profile-k8s-version",
+        "dictionary-source": "sdnc",
+        "dependencies": [
+            "service-instance-id",
+            "vnf-id"
+        ]
+    },
+    {
+        "name": "k8s-rb-profile-name",
+        "property": {
+            "description": "RB Profile name used in k8s plugin to identify Helm chart(s) where this mapping is providing override values.",
+            "type": "string",
+            "required": false,
+            "default": "default"
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-profile-name",
+        "dictionary-source": "default",
+        "dependencies": []
+    },
+    {
+        "name": "k8s-rb-instance-release-name",
+        "property": {
+            "description": "Name of the release for the helm package instance in k8s",
+            "type": "string",
+            "required": false,
+            "default": "base"
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-instance-release-name",
+        "dictionary-source": "default",
+        "dependencies": []
+    },
+    {
+        "name": "k8s-rb-definition-name",
+        "property": {
+            "description": "RB Name identifier of Helm chart(s) in k8s plugin",
+            "type": "string",
+            "required": false,
+            "metadata": {
+                "transform-template": "${vf-module-model-invariant-uuid}"
+            }
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-definition-name",
+        "dictionary-source": "default",
+        "dependencies": [
+            "vf-module-model-invariant-uuid"
+        ]
+    },
+    {
+        "name": "k8s-rb-definition-version",
+        "property": {
+            "description": "RB Version identifier of Helm chart(s) in k8s plugin",
+            "type": "string",
+            "required": false,
+            "metadata": {
+                "transform-template": "${vf-module-model-customization-uuid}"
+            }
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-definition-version",
+        "dictionary-source": "default",
+        "dependencies": [
+            "vf-module-model-customization-uuid"
+        ]
+    },
+    {
+        "name": "k8s-rb-profile-source",
+        "property": {
+            "description": "The source folder or file relative to 'Templates/k8s-profiles' folder",
+            "type": "string",
+            "required": false
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-profile-source",
+        "dictionary-source": "default",
+        "dependencies": []
+    },
+    {
+        "name": "k8s-rb-config-template-name",
+        "property": {
+            "description": "The source of configuration template for ue-reconfiuration operation",
+            "type": "string",
+            "required": false
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-config-template-name",
+        "dictionary-source": "default",
+        "dependencies": []
+    },
+    {
+        "name": "k8s-rb-config-template-source",
+        "property": {
+            "description": "The source of configuration template for ue-reconfiuration operation",
+            "type": "string",
+            "required": false
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-config-template-source",
+        "dictionary-source": "default",
+        "dependencies": []
+    },
+    {
+        "name": "k8s-rb-config-name",
+        "property": {
+            "description": "The source of configuration values for ue-reconfiguration operation",
+            "type": "string",
+            "required": false
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-config-name",
+        "dictionary-source": "default",
+        "dependencies": []
+    },
+    {
+        "name": "k8s-rb-config-value-source",
+        "property": {
+            "description": "The source of configuration values for ue-reconfiguration operation",
+            "type": "string",
+            "required": false
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-config-value-source",
+        "dictionary-source": "default",
+        "dependencies": []
+    },
+    {
+        "name": "core-instance-name",
+        "property": {
+            "description": "Name of 5g core instance that requires PNF registration",
+            "type": "string",
+            "required": false
+        },
+        "input-param": false,
+        "dictionary-name": "core-instance-name",
+        "dictionary-source": "default",
+        "dependencies": []
+    }
+]
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/cnf-template.vtl b/tutorials/ApacheCNF/templates/cba/Templates/cnf-template.vtl
new file mode 100644 (file)
index 0000000..1bebcaa
--- /dev/null
@@ -0,0 +1,67 @@
+{
+    "capability-data": [
+        {
+            "capability-name": "aai-vf-module-put",
+            "key-mapping": [
+                {
+                    "output-key-mapping": [
+                        {
+                            "resource-name": "aai-vf-module-put",
+                            "resource-value": ""
+                        }
+                    ]
+                }
+            ]
+        }
+    ],
+    "resource-accumulator-resolved-data": [
+        {
+            "param-name": "vnf_name",
+            "param-value": "${vnf_name}"
+        },
+        {
+            "param-name": "vf-module-name",
+            "param-value": "${vf-module-name}"
+        },
+##RB name
+        {
+            "param-name": "vf-module-model-invariant-uuid",
+            "param-value": "${vf-module-model-invariant-uuid}"
+        },
+##RB version
+        {
+            "param-name": "vf-module-model-version",
+            "param-value": "${vf-module-model-version}"
+        },
+##Release name
+        {
+            "param-name": "k8s-rb-instance-release-name",
+            "param-value": "${k8s-rb-instance-release-name}"
+        },
+##Profile name
+        {
+            "param-name": "k8s-rb-profile-name",
+            "param-value": "${k8s-rb-profile-name}"
+        },
+        {
+            "param-name": "k8s-rb-config-template-name",
+            "param-value": "${k8s-rb-config-template-name}"
+        },
+        {
+            "param-name": "k8s-rb-config-template-source",
+            "param-value": "${k8s-rb-config-template-source}"
+        },
+        {
+            "param-name": "k8s-rb-config-name",
+            "param-value": "${k8s-rb-config-name}"
+        },
+        {
+            "param-name": "k8s-rb-config-value-source",
+            "param-value": "${k8s-rb-config-value-source}"
+        },
+        {
+            "param-name": "core-instance-name",
+            "param-value": "${core-instance-name}"
+        }
+    ]
+}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/config-setup-mapping.json b/tutorials/ApacheCNF/templates/cba/Templates/config-setup-mapping.json
new file mode 100644 (file)
index 0000000..95d2681
--- /dev/null
@@ -0,0 +1,105 @@
+[
+    {
+        "name": "vnf-id",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "vnf-id",
+        "dictionary-source": "capability",
+        "dependencies": [],
+        "version": 0
+    },
+    {
+        "name": "vnf-relationship-list",
+        "property": {
+            "description": "Details about VNF relationships from AAI",
+            "type": "json"
+        },
+        "input-param": false,
+        "dictionary-name": "vnf-relationship-list",
+        "dictionary-source": "aai-data",
+        "dependencies": [
+            "vnf-id"
+        ]
+    },
+    {
+        "name": "service-instance-id",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string",
+            "status": "",
+            "constraints": [
+                {}
+            ],
+            "entry_schema": {
+                "type": ""
+            }
+        },
+        "input-param": false,
+        "dictionary-name": "service-instance-id",
+        "dictionary-source": "capability",
+        "dependencies": [
+            "vnf-relationship-list"
+        ],
+        "version": 0
+    },
+    {
+        "name": "vf-modules-list-sdnc",
+        "property": {
+            "description": "list of modules associated with vnf from MDSAL",
+            "type": "json"
+        },
+        "input-param": false,
+        "dictionary-name": "vf-modules-list",
+        "dictionary-source": "sdnc",
+        "dependencies": [
+            "service-instance-id",
+            "vnf-id"
+        ]
+    },
+    {
+        "name": "vf-modules-list-aai",
+        "property": {
+            "description": "list of modules associated with vnf from AAI",
+            "type": "json"
+        },
+        "input-param": false,
+        "dictionary-name": "vf-modules-list",
+        "dictionary-source": "aai-data",
+        "dependencies": [
+            "service-instance-id",
+            "vnf-id"
+        ]
+    },
+    {
+        "name": "config-deploy-setup",
+        "property": {
+            "description": "configuration for config value setup",
+            "type": "json"
+        },
+        "input-param": false,
+        "dictionary-name": "config-deploy-setup",
+        "dictionary-source": "capability",
+        "dependencies": [
+            "vf-modules-list-aai",
+            "vf-modules-list-sdnc"
+        ]
+    },
+    {
+        "name": "service-instance-name",
+        "property": {
+            "description": "Service instance name retrieved based on service instance id",
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "service-instance-name",
+        "dictionary-source": "sdnc",
+        "dependencies": [
+            "service-instance-id"
+        ]
+    }
+]
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/config-setup-template.vtl b/tutorials/ApacheCNF/templates/cba/Templates/config-setup-template.vtl
new file mode 100644 (file)
index 0000000..88771d6
--- /dev/null
@@ -0,0 +1 @@
+${config-deploy-setup}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config.tar.gz b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config.tar.gz
new file mode 100644 (file)
index 0000000..44fc1dd
Binary files /dev/null and b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config.tar.gz differ
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/Chart.yaml b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/Chart.yaml
new file mode 100644 (file)
index 0000000..82fb790
--- /dev/null
@@ -0,0 +1,6 @@
+apiVersion: v1
+appVersion: 2.4.46
+description: A Helm chart to modify Apache deployment
+engine: gotpl
+name: apache
+version: 7.6.0
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/.helmignore b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/.helmignore
new file mode 100644 (file)
index 0000000..50af031
--- /dev/null
@@ -0,0 +1,22 @@
+# Patterns to ignore when building packages.
+# This supports shell glob matching, relative path matching, and
+# negation (prefixed with !). Only one pattern per line.
+.DS_Store
+# Common VCS dirs
+.git/
+.gitignore
+.bzr/
+.bzrignore
+.hg/
+.hgignore
+.svn/
+# Common backup files
+*.swp
+*.bak
+*.tmp
+*~
+# Various IDEs
+.project
+.idea/
+*.tmproj
+.vscode/
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/Chart.yaml b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/Chart.yaml
new file mode 100644 (file)
index 0000000..85ef7d6
--- /dev/null
@@ -0,0 +1,22 @@
+annotations:
+  category: Infrastructure
+apiVersion: v1
+appVersion: 0.8.2
+description: A Library Helm Chart for grouping common logic between bitnami charts.
+  This chart is not deployable by itself.
+home: https://github.com/bitnami/charts/tree/master/bitnami/common
+icon: https://bitnami.com/downloads/logos/bitnami-mark.png
+keywords:
+- common
+- helper
+- template
+- function
+- bitnami
+maintainers:
+- email: containers@bitnami.com
+  name: Bitnami
+name: common
+sources:
+- https://github.com/bitnami/charts
+- http://www.bitnami.com/
+version: 0.8.2
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/README.md b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/README.md
new file mode 100644 (file)
index 0000000..9bcdfd6
--- /dev/null
@@ -0,0 +1,286 @@
+# Bitnami Common Library Chart
+
+A [Helm Library Chart](https://helm.sh/docs/topics/library_charts/#helm) for grouping common logic between bitnami charts.
+
+## TL;DR
+
+```yaml
+dependencies:
+  - name: common
+    version: 0.x.x
+    repository: https://charts.bitnami.com/bitnami
+```
+
+```bash
+$ helm dependency update
+```
+
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ include "common.names.fullname" . }}
+data:
+  myvalue: "Hello World"
+```
+
+## Introduction
+
+This chart provides a common template helpers which can be used to develop new charts using [Helm](https://helm.sh) package manager.
+
+Bitnami charts can be used with [Kubeapps](https://kubeapps.com/) for deployment and management of Helm Charts in clusters. This Helm chart has been tested on top of [Bitnami Kubernetes Production Runtime](https://kubeprod.io/) (BKPR). Deploy BKPR to get automated TLS certificates, logging and monitoring for your applications.
+
+## Prerequisites
+
+- Kubernetes 1.12+
+- Helm 2.12+ or Helm 3.0-beta3+
+
+## Parameters
+
+The following table lists the helpers available in the library which are scoped in different sections.
+
+### Affinities
+
+| Helper identifier                   | Description                                                     | Expected Input                                                   |
+|-------------------------------------|-----------------------------------------------------------------|------------------------------------------------------------------|
+| `common.affinities.node.soft`       | Return a soft nodeAffinity definition                           | `dict "key" "FOO" "values" (list "BAR" "BAZ")`                   |
+| `common.affinities.node.hard`       | Return a hard nodeAffinity definition                           | `dict "key" "FOO" "values" (list "BAR" "BAZ")`                   |
+| `common.affinities.pod.soft`        | Return a soft podAffinity/podAntiAffinity definition            | `dict "component" "FOO" "context" $`                             |
+| `common.affinities.pod.hard`        | Return a hard podAffinity/podAntiAffinity definition            | `dict "component" "FOO" "context" $`                             |
+
+### Capabilities
+
+| Helper identifier                              | Description                                                     | Expected Input             |
+|------------------------------------------------|-----------------------------------------------------------------|----------------------------|
+| `common.capabilities.deployment.apiVersion`    | Return the appropriate apiVersion for deployment.               | `.` Chart context          |
+| `common.capabilities.statefulset.apiVersion`   | Return the appropriate apiVersion for statefulset.              | `.` Chart context          |
+| `common.capabilities.ingress.apiVersion`       | Return the appropriate apiVersion for ingress.                  | `.` Chart context          |
+
+### Errors
+
+| Helper identifier                        | Description                                                                                                                                                            | Expected Input                                                                      |
+|------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|
+| `common.errors.upgrade.passwords.empty`  | It will ensure required passwords are given when we are upgrading a chart. If `validationErrors` is not empty it will throw an error and will stop the upgrade action. | `dict "validationErrors" (list $validationError00 $validationError01)  "context" $` |
+
+### Images
+
+| Helper identifier              | Description                                                     | Expected Input                                                                                              |
+|--------------------------------|-----------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|
+| `common.images.image`          | Return the proper and full image name                           | `dict "imageRoot" .Values.path.to.the.image "global" $`, see [ImageRoot](#imageroot) for the structure.     |
+| `common.images.pullSecrets`    | Return the proper Docker Image Registry Secret Names            | `dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global`       |
+
+### Labels
+
+| Helper identifier              | Description                                                     | Expected Input              |
+|--------------------------------|-----------------------------------------------------------------|-----------------------------|
+| `common.labels.standard`       | Return Kubernetes standard labels                               | `.` Chart context           |
+| `common.labels.matchLabels`    | Return the proper Docker Image Registry Secret Names            | `.` Chart context           |
+
+### Names
+
+| Helper identifier              | Description                                                     | Expected Inpput             |
+|--------------------------------|-----------------------------------------------------------------|-----------------------------|
+| `common.names.name`            | Expand the name of the chart or use `.Values.nameOverride`      | `.` Chart context           |
+| `common.names.fullname`        | Create a default fully qualified app name.                      | `.` Chart context           |
+| `common.names.chart`           | Chart name plus version                                         | `.` Chart context           |
+
+### Secrets
+
+| Helper identifier              | Description                                                     | Expected Input                                                                                                                                                 |
+|--------------------------------|-----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `common.secrets.name`          | Generate the name of the secret.                                | `dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $` see [ExistingSecret](#existingsecret) for the structure. |
+| `common.secrets.key`           | Generate secret key.                                            | `dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName"` see [ExistingSecret](#existingsecret) for the structure.                            |
+
+### Storage
+
+| Helper identifier              | Description                                                     | Expected Input                                                                                                      |
+|--------------------------------|-----------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------|
+| `common.affinities.node.soft`    | Return a soft nodeAffinity definition                           | `dict "persistence" .Values.path.to.the.persistence "global" $`, see [Persistence](#persistence) for the structure. |
+
+### TplValues
+
+| Helper identifier              | Description                                                     | Expected Input                                                                                                                                           |
+|--------------------------------|-----------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `common.tplvalues.render`      | Renders a value that contains template                          | `dict "value" .Values.path.to.the.Value "context" $`, value is the value should rendered as template, context frecuently is the chart context `$` or `.` |
+
+### Utils
+
+| Helper identifier              | Description                                                     | Expected Input                                                         |
+|--------------------------------|-----------------------------------------------------------------|------------------------------------------------------------------------|
+| `common.utils.fieldToEnvVar`   | Build environment variable name given a field.                  | `dict "field" "my-password"`                                           |
+| `common.utils.secret.getvalue` | Print instructions to get a secret value.                       | `dict "secret" "secret-name" "field" "secret-value-field" "context" $` |
+| `common.utils.getValueFromKey` | Gets a value from `.Values` object given its key path           | `dict "key" "path.to.key" "context" $`                                 |
+
+### Validations
+
+| Helper identifier                                | Description                                                                                                            | Expected Input                                                                                                                                                                                                                           |
+|--------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `common.validations.values.single.empty`         | Validate a value must not be empty.                                                                                    | `dict "valueKey" "path.to.value" "secret" "secret.name" "field" "my-password" "context" $` secret and field are optional. In case they are given, the helper will generate a how to get instruction. See [ValidateValue](#validatevalue) |
+| `common.validations.values.multiple.empty`       | Validate a multiple values must not be empty. It returns a shared error for all the values.                            | `dict "required" (list $validateValueConf00 $validateValueConf01) "context" $`. See [ValidateValue](#validatevalue)                                                                                                                      |
+| `common.validations.values.mariadb.passwords`    | This helper will ensure required password for MariaDB are not empty. It returns a shared error for all the values.     | `dict "secret" "mariadb-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use postgresql chart and the helper.                                                   |
+| `common.validations.values.postgresql.passwords` | This helper will ensure required password for PostgreSQL are not empty. It returns a shared error for all the values.  | `dict "secret" "postgresql-secret" "subchart" "true" "context" $` subchart field is optional and could be true or false it depends on where you will use postgresql chart and the helper.                                                |
+
+### Warnings
+
+| Helper identifier              | Description                                                     | Expected Input                                                   |
+|--------------------------------|-----------------------------------------------------------------|------------------------------------------------------------------|
+| `common.warnings.rollingTag`   | Warning about using rolling tag.                                | `ImageRoot` see [ImageRoot](#imageroot) for the structure.       |
+
+## Special input schemas
+
+### ImageRoot
+
+```yaml
+registry:
+  type: string
+  description: Docker registry where the image is located
+  example: docker.io
+
+repository:
+  type: string
+  description: Repository and image name
+  example: bitnami/nginx
+
+tag:
+  type: string
+  description: image tag
+  example: 1.16.1-debian-10-r63
+
+pullPolicy:
+  type: string
+  description: Specify a imagePullPolicy. Defaults to 'Always' if image tag is 'latest', else set to 'IfNotPresent'
+
+pullSecrets:
+  type: array
+  items:
+    type: string
+  description: Optionally specify an array of imagePullSecrets.
+
+debug:
+  type: boolean
+  description: Set to true if you would like to see extra information on logs
+  example: false
+
+## An instance would be:
+# registry: docker.io
+# repository: bitnami/nginx
+# tag: 1.16.1-debian-10-r63
+# pullPolicy: IfNotPresent
+# debug: false
+```
+
+### Persistence
+
+```yaml
+enabled:
+  type: boolean
+  description: Whether enable persistence.
+  example: true
+
+storageClass:
+  type: string
+  description: Ghost data Persistent Volume Storage Class, If set to "-", storageClassName: "" which disables dynamic provisioning.
+  example: "-"
+
+accessMode:
+  type: string
+  description: Access mode for the Persistent Volume Storage.
+  example: ReadWriteOnce
+
+size:
+  type: string
+  description: Size the Persistent Volume Storage.
+  example: 8Gi
+
+path:
+  type: string
+  description: Path to be persisted.
+  example: /bitnami
+
+## An instance would be:
+# enabled: true
+# storageClass: "-"
+# accessMode: ReadWriteOnce
+# size: 8Gi
+# path: /bitnami
+```
+
+### ExistingSecret
+
+```yaml
+name:
+  type: string
+  description: Name of the existing secret.
+  example: mySecret
+keyMapping:
+  description: Mapping between the expected key name and the name of the key in the existing secret.
+  type: object
+
+## An instance would be:
+# name: mySecret
+# keyMapping:
+#   password: myPasswordKey
+```
+
+#### Example of use
+
+When we store sensitive data for a deployment in a secret, some times we want to give to users the possiblity of using theirs existing secrets.
+
+```yaml
+# templates/secret.yaml
+---
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ include "common.names.fullname" . }}
+  labels:
+    app: {{ include "common.names.fullname" . }}
+type: Opaque
+data:
+  password: {{ .Values.password | b64enc | quote }}
+
+# templates/dpl.yaml
+---
+...
+      env:
+        - name: PASSWORD
+          valueFrom:
+            secretKeyRef:
+              name: {{ include "common.secrets.name" (dict "existingSecret" .Values.existingSecret "context" $) }}
+              key: {{ include "common.secrets.key" (dict "existingSecret" .Values.existingSecret "key" "password") }}
+...
+
+# values.yaml
+---
+name: mySecret
+keyMapping:
+  password: myPasswordKey
+```
+
+### ValidateValue
+
+#### NOTES.txt
+
+```console
+{{- $validateValueConf00 := (dict "valueKey" "path.to.value00" "secret" "secretName" "field" "password-00") -}}
+{{- $validateValueConf01 := (dict "valueKey" "path.to.value01" "secret" "secretName" "field" "password-01") -}}
+
+{{ include "common.validations.values.multiple.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }}
+```
+
+If we force those values to be empty we will see some alerts
+
+```console
+$ helm install test mychart --set path.to.value00="",path.to.value01=""
+    'path.to.value00' must not be empty, please add '--set path.to.value00=$PASSWORD_00' to the command. To get the current value:
+
+        export PASSWORD_00=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-00}" | base64 --decode)
+
+    'path.to.value01' must not be empty, please add '--set path.to.value01=$PASSWORD_01' to the command. To get the current value:
+
+        export PASSWORD_01=$(kubectl get secret --namespace default secretName -o jsonpath="{.data.password-01}" | base64 --decode)
+```
+
+## Notable changes
+
+N/A
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_affinities.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_affinities.tpl
new file mode 100644 (file)
index 0000000..40f575c
--- /dev/null
@@ -0,0 +1,94 @@
+{{/* vim: set filetype=mustache: */}}
+
+{{/*
+Return a soft nodeAffinity definition 
+{{ include "common.affinities.nodes.soft" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}}
+*/}}
+{{- define "common.affinities.nodes.soft" -}}
+preferredDuringSchedulingIgnoredDuringExecution:
+  - preference:
+      matchExpressions:
+        key: {{ .key }}
+        operator: In
+        values:
+          {{- range .values }}
+          - {{ . }}
+          {{- end }}
+    weight: 1
+{{- end -}}
+
+{{/*
+Return a hard nodeAffinity definition
+{{ include "common.affinities.nodes.hard" (dict "key" "FOO" "values" (list "BAR" "BAZ")) -}}
+*/}}
+{{- define "common.affinities.nodes.hard" -}}
+requiredDuringSchedulingIgnoredDuringExecution:
+  nodeSelectorTerms:
+    - matchExpressions:
+        key: {{ .key }}
+        operator: In
+        values:
+          {{- range .values }}
+          - {{ . }}
+          {{- end }}
+{{- end -}}
+
+{{/*
+Return a nodeAffinity definition
+{{ include "common.affinities.nodes" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}}
+*/}}
+{{- define "common.affinities.nodes" -}}
+  {{- if eq .type "soft" }}
+    {{- include "common.affinities.nodes.soft" . -}}
+  {{- else if eq .type "hard" }}
+    {{- include "common.affinities.nodes.hard" . -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Return a soft podAffinity/podAntiAffinity definition
+{{ include "common.affinities.pods.soft" (dict "component" "FOO" "context" $) -}}
+*/}}
+{{- define "common.affinities.pods.soft" -}}
+{{- $component := default "" .component -}}
+preferredDuringSchedulingIgnoredDuringExecution:
+  - podAffinityTerm:
+      labelSelector:
+        matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 10 }}
+          {{- if not (empty $component) }}
+          {{ printf "app.kubernetes.io/component: %s" $component }}
+          {{- end }}
+      namespaces:
+        - {{ .context.Release.Namespace }}
+      topologyKey: kubernetes.io/hostname
+    weight: 1
+{{- end -}}
+
+{{/*
+Return a hard podAffinity/podAntiAffinity definition
+{{ include "common.affinities.pods.hard" (dict "component" "FOO" "context" $) -}}
+*/}}
+{{- define "common.affinities.pods.hard" -}}
+{{- $component := default "" .component -}}
+requiredDuringSchedulingIgnoredDuringExecution:
+  - labelSelector:
+      matchLabels: {{- (include "common.labels.matchLabels" .context) | nindent 8 }}
+        {{- if not (empty $component) }}
+        {{ printf "app.kubernetes.io/component: %s" $component }}
+        {{- end }}
+    namespaces:
+      - {{ .context.Release.Namespace }}
+    topologyKey: kubernetes.io/hostname
+{{- end -}}
+
+{{/*
+Return a podAffinity/podAntiAffinity definition
+{{ include "common.affinities.pods" (dict "type" "soft" "key" "FOO" "values" (list "BAR" "BAZ")) -}}
+*/}}
+{{- define "common.affinities.pods" -}}
+  {{- if eq .type "soft" }}
+    {{- include "common.affinities.pods.soft" . -}}
+  {{- else if eq .type "hard" }}
+    {{- include "common.affinities.pods.hard" . -}}
+  {{- end -}}
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_capabilities.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_capabilities.tpl
new file mode 100644 (file)
index 0000000..143bef2
--- /dev/null
@@ -0,0 +1,33 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Return the appropriate apiVersion for deployment.
+*/}}
+{{- define "common.capabilities.deployment.apiVersion" -}}
+{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+{{- print "extensions/v1beta1" -}}
+{{- else -}}
+{{- print "apps/v1" -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Return the appropriate apiVersion for statefulset.
+*/}}
+{{- define "common.capabilities.statefulset.apiVersion" -}}
+{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+{{- print "apps/v1beta1" -}}
+{{- else -}}
+{{- print "apps/v1" -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Return the appropriate apiVersion for ingress.
+*/}}
+{{- define "common.capabilities.ingress.apiVersion" -}}
+{{- if semverCompare "<1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+{{- print "extensions/v1beta1" -}}
+{{- else -}}
+{{- print "networking.k8s.io/v1beta1" -}}
+{{- end -}}
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_errors.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_errors.tpl
new file mode 100644 (file)
index 0000000..d6d3ec6
--- /dev/null
@@ -0,0 +1,20 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Through error when upgrading using empty passwords values that must not be empty.
+
+Usage:
+{{- $validationError00 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password00" "secret" "secretName" "field" "password-00") -}}
+{{- $validationError01 := include "common.validations.values.single.empty" (dict "valueKey" "path.to.password01" "secret" "secretName" "field" "password-01") -}}
+{{ include "common.errors.upgrade.passwords.empty" (dict "validationErrors" (list $validationError00 $validationError01) "context" $) }}
+
+Required password params:
+  - validationErrors - String - Required. List of validation strings to be return, if it is empty it won't throw error.
+  - context - Context - Required. Parent context.
+*/}}
+{{- define "common.errors.upgrade.passwords.empty" -}}
+  {{- $validationErrors := join "" .validationErrors -}}
+  {{- if and $validationErrors .context.Release.IsUpgrade -}}
+    {{- $errorString := "\nPASSWORDS ERROR: you must provide your current passwords when upgrade the release%s" -}}
+    {{- printf $errorString $validationErrors | fail -}}
+  {{- end -}}
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_images.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_images.tpl
new file mode 100644 (file)
index 0000000..aafde9f
--- /dev/null
@@ -0,0 +1,43 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Return the proper image name
+{{ include "common.images.image" ( dict "imageRoot" .Values.path.to.the.image "global" $) }}
+*/}}
+{{- define "common.images.image" -}}
+{{- $registryName := .imageRoot.registry -}}
+{{- $repositoryName := .imageRoot.repository -}}
+{{- $tag := .imageRoot.tag | toString -}}
+{{- if .global }}
+    {{- if .global.imageRegistry }}
+     {{- $registryName = .global.imageRegistry -}}
+    {{- end -}}
+{{- end -}}
+{{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
+{{- end -}}
+
+{{/*
+Return the proper Docker Image Registry Secret Names
+{{ include "common.images.pullSecrets" ( dict "images" (list .Values.path.to.the.image1, .Values.path.to.the.image2) "global" .Values.global) }}
+*/}}
+{{- define "common.images.pullSecrets" -}}
+  {{- $pullSecrets := list }}
+
+  {{- if .global }}
+    {{- range .global.imagePullSecrets -}}
+      {{- $pullSecrets = append $pullSecrets . -}}
+    {{- end -}}
+  {{- end -}}
+
+  {{- range .images -}}
+    {{- range .pullSecrets -}}
+      {{- $pullSecrets = append $pullSecrets . -}}
+    {{- end -}}
+  {{- end -}}
+
+  {{- if (not (empty $pullSecrets)) }}
+imagePullSecrets:
+    {{- range $pullSecrets }}
+  - name: {{ . }}
+    {{- end }}
+  {{- end }}
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_labels.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_labels.tpl
new file mode 100644 (file)
index 0000000..252066c
--- /dev/null
@@ -0,0 +1,18 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Kubernetes standard labels
+*/}}
+{{- define "common.labels.standard" -}}
+app.kubernetes.io/name: {{ include "common.names.name" . }}
+helm.sh/chart: {{ include "common.names.chart" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Labels to use on deploy.spec.selector.matchLabels and svc.spec.selector
+*/}}
+{{- define "common.labels.matchLabels" -}}
+app.kubernetes.io/name: {{ include "common.names.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_names.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_names.tpl
new file mode 100644 (file)
index 0000000..adf2a74
--- /dev/null
@@ -0,0 +1,32 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "common.names.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "common.names.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "common.names.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_secrets.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_secrets.tpl
new file mode 100644 (file)
index 0000000..ebfb5d4
--- /dev/null
@@ -0,0 +1,57 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Generate secret name.
+
+Usage:
+{{ include "common.secrets.name" (dict "existingSecret" .Values.path.to.the.existingSecret "defaultNameSuffix" "mySuffix" "context" $) }}
+
+Params:
+  - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user
+    to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility.
+    +info: https://github.com/bitnami/charts/tree/master/bitnami/common#existingsecret
+  - defaultNameSuffix - String - Optional. It is used only if we have several secrets in the same deployment.
+  - context - Dict - Required. The context for the template evaluation.
+*/}}
+{{- define "common.secrets.name" -}}
+{{- $name := (include "common.names.fullname" .context) -}}
+
+{{- if .defaultNameSuffix -}}
+{{- $name = printf "%s-%s" $name .defaultNameSuffix | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{- with .existingSecret -}}
+{{- if not (typeIs "string" .) -}}
+{{- $name = .name -}}
+{{- else -}}
+{{- $name = . -}}
+{{- end -}}
+{{- end -}}
+
+{{- printf "%s" $name -}}
+{{- end -}}
+
+{{/*
+Generate secret key.
+
+Usage:
+{{ include "common.secrets.key" (dict "existingSecret" .Values.path.to.the.existingSecret "key" "keyName") }}
+
+Params:
+  - existingSecret - ExistingSecret/String - Optional. The path to the existing secrets in the values.yaml given by the user
+    to be used instead of the default one. Allows for it to be of type String (just the secret name) for backwards compatibility.
+    +info: https://github.com/bitnami/charts/tree/master/bitnami/common#existingsecret
+  - key - String - Required. Name of the key in the secret.
+*/}}
+{{- define "common.secrets.key" -}}
+{{- $key := .key -}}
+
+{{- if .existingSecret -}}
+  {{- if not (typeIs "string" .existingSecret) -}}
+    {{- if .existingSecret.keyMapping -}}
+      {{- $key = index .existingSecret.keyMapping $.key -}}
+    {{- end -}}
+  {{- end }}
+{{- end -}}
+
+{{- printf "%s" $key -}}
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_storage.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_storage.tpl
new file mode 100644 (file)
index 0000000..60e2a84
--- /dev/null
@@ -0,0 +1,23 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Return  the proper Storage Class
+{{ include "common.storage.class" ( dict "persistence" .Values.path.to.the.persistence "global" $) }}
+*/}}
+{{- define "common.storage.class" -}}
+
+{{- $storageClass := .persistence.storageClass -}}
+{{- if .global -}}
+    {{- if .global.storageClass -}}
+        {{- $storageClass = .global.storageClass -}}
+    {{- end -}}
+{{- end -}}
+
+{{- if $storageClass -}}
+  {{- if (eq "-" $storageClass) -}}
+      {{- printf "storageClassName: \"\"" -}}
+  {{- else }}
+      {{- printf "storageClassName: %s" $storageClass -}}
+  {{- end -}}
+{{- end -}}
+
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_tplvalues.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_tplvalues.tpl
new file mode 100644 (file)
index 0000000..2db1668
--- /dev/null
@@ -0,0 +1,13 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Renders a value that contains template.
+Usage:
+{{ include "common.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $) }}
+*/}}
+{{- define "common.tplvalues.render" -}}
+    {{- if typeIs "string" .value }}
+        {{- tpl .value .context }}
+    {{- else }}
+        {{- tpl (.value | toYaml) .context }}
+    {{- end }}
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_utils.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_utils.tpl
new file mode 100644 (file)
index 0000000..74774a3
--- /dev/null
@@ -0,0 +1,45 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Print instructions to get a secret value.
+Usage:
+{{ include "common.utils.secret.getvalue" (dict "secret" "secret-name" "field" "secret-value-field" "context" $) }}
+*/}}
+{{- define "common.utils.secret.getvalue" -}}
+{{- $varname := include "common.utils.fieldToEnvVar" . -}}
+export {{ $varname }}=$(kubectl get secret --namespace {{ .context.Release.Namespace }} {{ .secret }} -o jsonpath="{.data.{{ .field }}}" | base64 --decode)
+{{- end -}}
+
+{{/*
+Build env var name given a field
+Usage:
+{{ include "common.utils.fieldToEnvVar" dict "field" "my-password" }}
+*/}}
+{{- define "common.utils.fieldToEnvVar" -}}
+  {{- $fieldNameSplit := splitList "-" .field -}}
+  {{- $upperCaseFieldNameSplit := list -}}
+
+  {{- range $fieldNameSplit -}}
+    {{- $upperCaseFieldNameSplit = append $upperCaseFieldNameSplit ( upper . ) -}}
+  {{- end -}}
+
+  {{ join "_" $upperCaseFieldNameSplit }}
+{{- end -}}
+
+{{/*
+Gets a value from .Values given
+Usage:
+{{ include "common.utils.getValueFromKey" (dict "key" "path.to.key" "context" $) }}
+*/}}
+{{- define "common.utils.getValueFromKey" -}}
+{{- $splitKey := splitList "." .key -}}
+{{- $value := "" -}}
+{{- $latestObj := $.context.Values -}}
+{{- range $splitKey -}}
+  {{- if not $latestObj -}}
+    {{- printf "please review the entire path of '%s' exists in values" $.key | fail -}}
+  {{- end -}}
+  {{- $value = ( index $latestObj . ) -}}
+  {{- $latestObj = $value -}}
+{{- end -}}
+{{- printf "%v" (default "" $value) -}} 
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_validations.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_validations.tpl
new file mode 100644 (file)
index 0000000..05d1edb
--- /dev/null
@@ -0,0 +1,278 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Validate values must not be empty.
+
+Usage:
+{{- $validateValueConf00 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-00") -}}
+{{- $validateValueConf01 := (dict "valueKey" "path.to.value" "secret" "secretName" "field" "password-01") -}}
+{{ include "common.validations.values.empty" (dict "required" (list $validateValueConf00 $validateValueConf01) "context" $) }}
+
+Validate value params:
+  - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password"
+  - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret"
+  - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password"
+*/}}
+{{- define "common.validations.values.multiple.empty" -}}
+  {{- range .required -}}
+    {{- include "common.validations.values.single.empty" (dict "valueKey" .valueKey "secret" .secret "field" .field "context" $.context) -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Validate a value must not be empty.
+
+Usage:
+{{ include "common.validations.value.empty" (dict "valueKey" "mariadb.password" "secret" "secretName" "field" "my-password" "context" $) }}
+
+Validate value params:
+  - valueKey - String - Required. The path to the validating value in the values.yaml, e.g: "mysql.password"
+  - secret - String - Optional. Name of the secret where the validating value is generated/stored, e.g: "mysql-passwords-secret"
+  - field - String - Optional. Name of the field in the secret data, e.g: "mysql-password"
+*/}}
+{{- define "common.validations.values.single.empty" -}}
+  {{- $value := include "common.utils.getValueFromKey" (dict "key" .valueKey "context" .context) }}
+
+  {{- if not $value -}}
+    {{- $varname := "my-value" -}}
+    {{- $getCurrentValue := "" -}}
+    {{- if and .secret .field -}}
+      {{- $varname = include "common.utils.fieldToEnvVar" . -}}
+      {{- $getCurrentValue = printf " To get the current value:\n\n        %s\n" (include "common.utils.secret.getvalue" .) -}}
+    {{- end -}}
+    {{- printf "\n    '%s' must not be empty, please add '--set %s=$%s' to the command.%s" .valueKey .valueKey $varname $getCurrentValue -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Validate MariaDB required passwords are not empty.
+
+Usage:
+{{ include "common.validations.values.mariadb.passwords" (dict "secret" "secretName" "subchart" false "context" $) }}
+Params:
+  - secret - String - Required. Name of the secret where MariaDB values are stored, e.g: "mysql-passwords-secret"
+  - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false
+*/}}
+{{- define "common.validations.values.mariadb.passwords" -}}
+  {{- $existingSecret := include "common.mariadb.values.existingSecret" . -}}
+  {{- $enabled := include "common.mariadb.values.enabled" . -}}
+  {{- $architecture := include "common.mariadb.values.architecture" . -}}
+  {{- $authPrefix := include "common.mariadb.values.key.auth" . -}}
+  {{- $valueKeyRootPassword := printf "%s.rootPassword" $authPrefix -}}
+  {{- $valueKeyUsername := printf "%s.username" $authPrefix -}}
+  {{- $valueKeyPassword := printf "%s.password" $authPrefix -}}
+  {{- $valueKeyReplicationPassword := printf "%s.replicationPassword" $authPrefix -}}
+
+  {{- if and (not $existingSecret) (eq $enabled "true") -}}
+    {{- $requiredPasswords := list -}}
+
+    {{- $requiredRootPassword := dict "valueKey" $valueKeyRootPassword "secret" .secret "field" "mariadb-root-password" -}}
+    {{- $requiredPasswords = append $requiredPasswords $requiredRootPassword -}}
+
+    {{- $valueUsername := include "common.utils.getValueFromKey" (dict "key" $valueKeyUsername "context" .context) }}
+    {{- if not (empty $valueUsername) -}}
+        {{- $requiredPassword := dict "valueKey" $valueKeyPassword "secret" .secret "field" "mariadb-password" -}}
+        {{- $requiredPasswords = append $requiredPasswords $requiredPassword -}}
+    {{- end -}}
+
+    {{- if (eq $architecture "replication") -}}
+        {{- $requiredReplicationPassword := dict "valueKey" $valueKeyReplicationPassword "secret" .secret "field" "mariadb-replication-password" -}}
+        {{- $requiredPasswords = append $requiredPasswords $requiredReplicationPassword -}}
+    {{- end -}}
+
+    {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}}
+
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Auxiliar function to get the right value for existingSecret.
+
+Usage:
+{{ include "common.mariadb.values.existingSecret" (dict "context" $) }}
+Params:
+  - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false
+*/}}
+{{- define "common.mariadb.values.existingSecret" -}}
+  {{- if .subchart -}}
+    {{- .context.Values.mariadb.existingSecret | quote -}}
+  {{- else -}}
+    {{- .context.Values.existingSecret | quote -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Auxiliar function to get the right value for enabled mariadb.
+
+Usage:
+{{ include "common.mariadb.values.enabled" (dict "context" $) }}
+*/}}
+{{- define "common.mariadb.values.enabled" -}}
+  {{- if .subchart -}}
+    {{- printf "%v" .context.Values.mariadb.enabled -}}
+  {{- else -}}
+    {{- printf "%v" (not .context.Values.enabled) -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Auxiliar function to get the right value for architecture
+
+Usage:
+{{ include "common.mariadb.values.architecture" (dict "subchart" "true" "context" $) }}
+Params:
+  - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false
+*/}}
+{{- define "common.mariadb.values.architecture" -}}
+  {{- if .subchart -}}
+    {{- .context.Values.mariadb.architecture -}}
+  {{- else -}}
+    {{- .context.Values.architecture -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Auxiliar function to get the right value for the key auth
+
+Usage:
+{{ include "common.mariadb.values.key.auth" (dict "subchart" "true" "context" $) }}
+Params:
+  - subchart - Boolean - Optional. Whether MariaDB is used as subchart or not. Default: false
+*/}}
+{{- define "common.mariadb.values.key.auth" -}}
+  {{- if .subchart -}}
+    mariadb.auth
+  {{- else -}}
+    auth
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Validate PostgreSQL required passwords are not empty.
+
+Usage:
+{{ include "common.validations.values.postgresql.passwords" (dict "secret" "secretName" "subchart" false "context" $) }}
+Params:
+  - secret - String - Required. Name of the secret where postgresql values are stored, e.g: "mysql-passwords-secret"
+  - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false
+*/}}
+{{- define "common.validations.values.postgresql.passwords" -}}
+  {{- $existingSecret := include "common.postgresql.values.existingSecret" . -}}
+  {{- $enabled := include "common.postgresql.values.enabled" . -}}
+  {{- $valueKeyPostgresqlPassword := include "common.postgresql.values.key.postgressPassword" . -}}
+  {{- $enabledReplication := include "common.postgresql.values.enabled.replication" . -}}
+  {{- $valueKeyPostgresqlReplicationEnabled := include "common.postgresql.values.key.replicationPassword" . -}}
+
+  {{- if and (not $existingSecret) (eq $enabled "true") -}}
+    {{- $requiredPasswords := list -}}
+
+    {{- $requiredPostgresqlPassword := dict "valueKey" $valueKeyPostgresqlPassword "secret" .secret "field" "postgresql-password" -}}
+    {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlPassword -}}
+
+    {{- if (eq $enabledReplication "true") -}}
+        {{- $requiredPostgresqlReplicationPassword := dict "valueKey" $valueKeyPostgresqlReplicationEnabled "secret" .secret "field" "postgresql-replication-password" -}}
+        {{- $requiredPasswords = append $requiredPasswords $requiredPostgresqlReplicationPassword -}}
+    {{- end -}}
+
+    {{- include "common.validations.values.multiple.empty" (dict "required" $requiredPasswords "context" .context) -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Auxiliar function to decide whether evaluate global values.
+
+Usage:
+{{ include "common.postgresql.values.use.global" (dict "key" "key-of-global" "context" $) }}
+Params:
+  - key - String - Required. Field to be evaluated within global, e.g: "existingSecret"
+*/}}
+{{- define "common.postgresql.values.use.global" -}}
+  {{- if .context.Values.global -}}
+    {{- if .context.Values.global.postgresql -}}
+      {{- index .context.Values.global.postgresql .key | quote -}}
+    {{- end -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Auxiliar function to get the right value for existingSecret.
+
+Usage:
+{{ include "common.postgresql.values.existingSecret" (dict "context" $) }}
+*/}}
+{{- define "common.postgresql.values.existingSecret" -}}
+  {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "existingSecret" "context" .context) -}}
+
+  {{- if .subchart -}}
+    {{- default (.context.Values.postgresql.existingSecret | quote) $globalValue -}}
+  {{- else -}}
+    {{- default (.context.Values.existingSecret | quote) $globalValue -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Auxiliar function to get the right value for enabled postgresql.
+
+Usage:
+{{ include "common.postgresql.values.enabled" (dict "context" $) }}
+*/}}
+{{- define "common.postgresql.values.enabled" -}}
+  {{- if .subchart -}}
+    {{- printf "%v" .context.Values.postgresql.enabled -}}
+  {{- else -}}
+    {{- printf "%v" (not .context.Values.enabled) -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Auxiliar function to get the right value for the key postgressPassword.
+
+Usage:
+{{ include "common.postgresql.values.key.postgressPassword" (dict "subchart" "true" "context" $) }}
+Params:
+  - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false
+*/}}
+{{- define "common.postgresql.values.key.postgressPassword" -}}
+  {{- $globalValue := include "common.postgresql.values.use.global" (dict "key" "postgresqlUsername" "context" .context) -}}
+
+  {{- if not $globalValue -}}
+    {{- if .subchart -}}
+      postgresql.postgresqlPassword
+    {{- else -}}
+      postgresqlPassword
+    {{- end -}}
+  {{- else -}}
+    global.postgresql.postgresqlPassword
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Auxiliar function to get the right value for enabled.replication.
+
+Usage:
+{{ include "common.postgresql.values.enabled.replication" (dict "subchart" "true" "context" $) }}
+Params:
+  - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false
+*/}}
+{{- define "common.postgresql.values.enabled.replication" -}}
+  {{- if .subchart -}}
+    {{- printf "%v" .context.Values.postgresql.replication.enabled -}}
+  {{- else -}}
+    {{- printf "%v" .context.Values.replication.enabled -}}
+  {{- end -}}
+{{- end -}}
+
+{{/*
+Auxiliar function to get the right value for the key replication.password.
+
+Usage:
+{{ include "common.postgresql.values.key.replicationPassword" (dict "subchart" "true" "context" $) }}
+Params:
+  - subchart - Boolean - Optional. Whether postgresql is used as subchart or not. Default: false
+*/}}
+{{- define "common.postgresql.values.key.replicationPassword" -}}
+  {{- if .subchart -}}
+    postgresql.replication.password
+  {{- else -}}
+    replication.password
+  {{- end -}}
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_warnings.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/templates/_warnings.tpl
new file mode 100644 (file)
index 0000000..ae10fa4
--- /dev/null
@@ -0,0 +1,14 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Warning about using rolling tag.
+Usage:
+{{ include "common.warnings.rollingTag" .Values.path.to.the.imageRoot }}
+*/}}
+{{- define "common.warnings.rollingTag" -}}
+
+{{- if and (contains "bitnami/" .repository) (not (.tag | toString | regexFind "-r\\d+$|sha256:")) }}
+WARNING: Rolling tag detected ({{ .repository }}:{{ .tag }}), please note that it is strongly recommended to avoid using rolling tags in a production environment.
++info https://docs.bitnami.com/containers/how-to/understand-rolling-tags-containers/
+{{- end }}
+
+{{- end -}}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/values.yaml b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/charts/common/values.yaml
new file mode 100644 (file)
index 0000000..9ecdc93
--- /dev/null
@@ -0,0 +1,3 @@
+## bitnami/common
+## It is required by CI/CD tools and processes.
+exampleValue: common-chart
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/templates/_helpers.tpl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/templates/_helpers.tpl
new file mode 100644 (file)
index 0000000..e2e1401
--- /dev/null
@@ -0,0 +1,263 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "apache.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+*/}}
+{{- define "apache.fullname" -}}
+{{- if .Values.fullnameOverride -}}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- if contains $name .Release.Name -}}
+{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
+{{- else -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Common labels
+*/}}
+{{- define "apache.labels" -}}
+app.kubernetes.io/name: {{ include "apache.name" . }}
+helm.sh/chart: {{ include "apache.chart" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end -}}
+
+{{/*
+Labels to use on deploy.spec.selector.matchLabels and svc.spec.selector
+*/}}
+{{- define "apache.matchLabels" -}}
+app.kubernetes.io/name: {{ include "apache.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end -}}
+
+{{/*
+Return the proper Apache image name
+*/}}
+{{- define "apache.image" -}}
+{{- $registryName := .Values.image.registry -}}
+{{- $repositoryName := .Values.image.repository -}}
+{{- $tag := .Values.image.tag | toString -}}
+{{/*
+Helm 2.11 supports the assignment of a value to a variable defined in a different scope,
+but Helm 2.9 and 2.10 doesn't support it, so we need to implement this if-else logic.
+Also, we can't use a single if because lazy evaluation is not an option
+*/}}
+{{- if .Values.global }}
+    {{- if .Values.global.imageRegistry }}
+        {{- printf "%s/%s:%s" .Values.global.imageRegistry $repositoryName $tag -}}
+    {{- else -}}
+        {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
+    {{- end -}}
+{{- else -}}
+    {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Return the proper Apache Docker Image Registry Secret Names
+*/}}
+{{- define "apache.imagePullSecrets" -}}
+{{/*
+Helm 2.11 supports the assignment of a value to a variable defined in a different scope,
+but Helm 2.9 and 2.10 doesn't support it, so we need to implement this if-else logic.
+Also, we can't use a single if because lazy evaluation is not an option
+*/}}
+{{- if .Values.global }}
+{{- if .Values.global.imagePullSecrets }}
+imagePullSecrets:
+{{- range .Values.global.imagePullSecrets }}
+  - name: {{ . }}
+{{- end }}
+{{- else if or .Values.image.pullSecrets .Values.metrics.image.pullSecrets }}
+imagePullSecrets:
+{{- range .Values.image.pullSecrets }}
+  - name: {{ . }}
+{{- end }}
+{{- range .Values.metrics.image.pullSecrets }}
+  - name: {{ . }}
+{{- end }}
+{{- end -}}
+{{- else if or .Values.image.pullSecrets .Values.metrics.image.pullSecrets }}
+imagePullSecrets:
+{{- range .Values.image.pullSecrets }}
+  - name: {{ . }}
+{{- end }}
+{{- range .Values.metrics.image.pullSecrets }}
+  - name: {{ . }}
+{{- end }}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Return the proper image name (for the metrics image)
+*/}}
+{{- define "apache.metrics.image" -}}
+{{- $registryName := .Values.metrics.image.registry -}}
+{{- $repositoryName := .Values.metrics.image.repository -}}
+{{- $tag := .Values.metrics.image.tag | toString -}}
+{{/*
+Helm 2.11 supports the assignment of a value to a variable defined in a different scope,
+but Helm 2.9 and 2.10 doesn't support it, so we need to implement this if-else logic.
+Also, we can't use a single if because lazy evaluation is not an option
+*/}}
+{{- if .Values.global }}
+    {{- if .Values.global.imageRegistry }}
+        {{- printf "%s/%s:%s" .Values.global.imageRegistry $repositoryName $tag -}}
+    {{- else -}}
+        {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
+    {{- end -}}
+{{- else -}}
+    {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Return true if mouting a static web page
+*/}}
+{{- define "apache.useHtdocs" -}}
+{{ default "" (or .Values.cloneHtdocsFromGit.enabled .Values.htdocsConfigMap .Values.htdocsPVC) }}
+{{- end -}}
+
+{{/*
+Return associated volume
+*/}}
+{{- define "apache.htdocsVolume" -}}
+{{- if .Values.cloneHtdocsFromGit.enabled }}
+emptyDir: {}
+{{- else if .Values.htdocsConfigMap }}
+configMap:
+  name: {{ .Values.htdocsConfigMap }}
+{{- else if .Values.htdocsPVC }}
+persistentVolumeClaim:
+  claimName: {{ .Values.htdocsPVC }}
+{{- end }}
+{{- end -}}
+
+{{/*
+Validate data
+*/}}
+{{- define "apache.validateValues" -}}
+{{- $messages := list -}}
+{{- $messages := append $messages (include "apache.validateValues.htdocs" .) -}}
+{{- $messages := append $messages (include "apache.validateValues.htdocsGit" .) -}}
+{{- $messages := without $messages "" -}}
+{{- $message := join "\n" $messages -}}
+ {{- if $message -}}
+{{-   printf "\nVALUES VALIDATION:\n%s" $message | fail -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "apache.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/*
+Validate data (htdocs)
+*/}}
+{{- define "apache.validateValues.htdocs" -}}
+{{- if or (and .Values.cloneHtdocsFromGit.enabled (or .Values.htdocsPVC .htdocsConfigMap )) (and .Values.htdocsPVC (or .Values.htdocsConfigMap .Values.cloneHtdocsFromGit.enabled )) (and .Values.htdocsConfigMap (or .Values.htdocsPVC .Values.cloneHtdocsFromGit.enabled )) }}
+apache: htdocs
+    You have selected more than one way of deploying htdocs. Please select only one of htdocsConfigMap cloneHtdocsFromGit or htdocsVolume
+{{- end }}
+{{- end -}}
+
+{{/*
+Validate data (htdocs git)
+*/}}
+{{- define "apache.validateValues.htdocsGit" -}}
+{{- if .Values.cloneHtdocsFromGit.enabled }}
+  {{- if not .Values.cloneHtdocsFromGit.repository }}
+apache: htdocs-git-repository
+    You did not specify a git repository to clone. Please set cloneHtdocsFromGit.repository
+  {{- end }}
+  {{- if not .Values.cloneHtdocsFromGit.branch }}
+apache: htdocs-git-branch
+    You did not specify a branch to checkout in the git repository. Please set cloneHtdocsFromGit.branch
+  {{- end }}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Validate values of Apache - Incorrect extra volume settings
+*/}}
+{{- define "apache.validateValues.extraVolumes" -}}
+{{- if and (.Values.extraVolumes) (not .Values.extraVolumeMounts) -}}
+apache: missing-extra-volume-mounts
+    You specified extra volumes but not mount points for them. Please set
+    the extraVolumeMounts value
+{{- end -}}
+{{- end -}}
+
+{{/*
+Return the proper git image name
+*/}}
+{{- define "git.image" -}}
+{{- $registryName := .Values.git.registry -}}
+{{- $repositoryName := .Values.git.repository -}}
+{{- $tag := .Values.git.tag | toString -}}
+{{/*
+Helm 2.11 supports the assignment of a value to a variable defined in a different scope,
+but Helm 2.9 and 2.10 doesn't support it, so we need to implement this if-else logic.
+Also, we can't use a single if because lazy evaluation is not an option
+*/}}
+{{- if .Values.global }}
+    {{- if .Values.global.imageRegistry }}
+        {{- printf "%s/%s:%s" .Values.global.imageRegistry $repositoryName $tag -}}
+    {{- else -}}
+        {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
+    {{- end -}}
+{{- else -}}
+    {{- printf "%s/%s:%s" $registryName $repositoryName $tag -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Get the vhosts config map name.
+*/}}
+{{- define "apache.vhostsConfigMap" -}}
+{{- if .Values.vhostsConfigMap -}}
+    {{- printf "%s" (tpl .Values.vhostsConfigMap $) -}}
+{{- else -}}
+    {{- printf "%s-vhosts" (include "apache.fullname" . ) -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Get the httpd.conf config map name.
+*/}}
+{{- define "apache.httpdConfConfigMap" -}}
+{{- if .Values.httpdConfConfigMap -}}
+    {{- printf "%s" (tpl .Values.httpdConfConfigMap $) -}}
+{{- else -}}
+    {{- printf "%s-httpd-conf" (include "apache.fullname" . ) -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Renders a value that contains template.
+Usage:
+{{ include "apache.tplValue" ( dict "value" .Values.path.to.the.Value "context" $) }}
+*/}}
+{{- define "apache.tplValue" -}}
+    {{- if typeIs "string" .value }}
+        {{- tpl .value .context }}
+    {{- else }}
+        {{- tpl (.value | toYaml) .context }}
+    {{- end }}
+{{- end -}}
+
+
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/templates/deployment.yaml b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/templates/deployment.yaml
new file mode 100644 (file)
index 0000000..4507712
--- /dev/null
@@ -0,0 +1,172 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "apache.fullname" . }}
+  labels: {{- include "apache.labels" . | nindent 4 }}
+spec:
+  selector:
+    matchLabels: {{- include "apache.matchLabels" . | nindent 6 }}
+  replicas: {{ .Values.replicaCount }}
+  template:
+    metadata:
+      labels: {{- include "apache.labels" . | nindent 8 }}
+      {{- if or .Values.podAnnotations (and .Values.metrics.enabled .Values.metrics.podAnnotations) }}
+      annotations:
+        {{- if .Values.podAnnotations }}
+        {{- include "apache.tplValue" (dict "value" .Values.podAnnotations "context" $) | nindent 8 }}
+        {{- end }}
+        {{- if and .Values.metrics.enabled .Values.metrics.podAnnotations }}
+        {{- include "apache.tplValue" (dict "value" .Values.metrics.podAnnotations "context" $) | nindent 8 }}
+        {{- end }}
+      {{- end }}
+    spec:
+{{- include "apache.imagePullSecrets" . | nindent 6 }}
+      hostAliases:
+        - ip: "127.0.0.1"
+          hostnames:
+            - "status.localhost"
+      {{- if .Values.affinity }}
+      affinity: {{- include "apache.tplValue" (dict "value" .Values.affinity "context" $) | nindent 8 }}
+      {{- else }}
+      affinity:
+        podAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAffinityPreset "context" $) | nindent 10 }}
+        podAntiAffinity: {{- include "common.affinities.pods" (dict "type" .Values.podAntiAffinityPreset "context" $) | nindent 10 }}
+        nodeAffinity: {{- include "common.affinities.nodes" (dict "type" .Values.nodeAffinityPreset.type "key" .Values.nodeAffinityPreset.key "values" .Values.nodeAffinityPreset.values) | nindent 10 }}
+      {{- end }}
+      {{- if .Values.nodeSelector }}
+      nodeSelector: {{- include "apache.tplValue" (dict "value" .Values.nodeSelector "context" $) | nindent 8 }}
+      {{- end }}
+      {{- if .Values.tolerations }}
+      tolerations: {{- include "apache.tplValue" (dict "value" .Values.tolerations "context" $) | nindent 8 }}
+      {{- end }}
+      {{- if .Values.cloneHtdocsFromGit.enabled }}
+      initContainers:
+        - name: git-clone-repository
+          image: {{ include "git.image" . }}
+          imagePullPolicy: {{ .Values.git.pullPolicy | quote }}
+          command:
+            - /bin/bash
+            - -ec
+            - |
+              git clone {{ .Values.cloneHtdocsFromGit.repository }} --branch {{ .Values.cloneHtdocsFromGit.branch }} /app
+          resources: {{- toYaml .Values.cloneHtdocsFromGit.resources | nindent 12 }}
+          volumeMounts:
+            - name: htdocs
+              mountPath: /app
+      containers:
+        - name: git-repo-syncer
+          image: {{ include "git.image" . }}
+          imagePullPolicy: {{ .Values.git.pullPolicy | quote }}
+          command:
+            - /bin/bash
+            - -ec
+            - |
+              while true; do
+                  cd /app && git pull origin {{ .Values.cloneHtdocsFromGit.branch }}
+                  sleep {{ .Values.cloneHtdocsFromGit.interval }}
+              done
+          resources: {{- toYaml .Values.cloneHtdocsFromGit.resources | nindent 12 }}
+          volumeMounts:
+            - name: htdocs
+              mountPath: /app
+      {{- else }}
+      containers:
+      {{- end }}
+        - name: apache
+          image: {{ include "apache.image" . }}
+          imagePullPolicy: {{ .Values.image.pullPolicy | quote }}
+          env:
+            - name: BITNAMI_DEBUG
+              value: {{ ternary "true" "false" .Values.image.debug | quote }}
+            {{- if .Values.extraEnvVars }}
+              {{- include "apache.tplValue" (dict "value" .Values.extraEnvVars "context" $) | nindent 12 }}
+            {{- end }}
+          ports:
+            - name: http
+              containerPort: 8080
+            - name: https
+              containerPort: 8443
+          {{- if .Values.livenessProbe.enabled }}
+          livenessProbe:
+            httpGet:
+              path: {{ .Values.livenessProbe.path }}
+              port: http
+            initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
+            periodSeconds: {{ .Values.livenessProbe.periodSeconds }}
+            timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
+            successThreshold: {{ .Values.livenessProbe.successThreshold }}
+            failureThreshold: {{ .Values.livenessProbe.failureThreshold }}
+          {{- end }}
+          {{- if .Values.readinessProbe.enabled }}
+          readinessProbe:
+            httpGet:
+              path: {{ .Values.readinessProbe.path }}
+              port: http
+            initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
+            periodSeconds: {{ .Values.readinessProbe.periodSeconds }}
+            timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
+            successThreshold: {{ .Values.readinessProbe.successThreshold }}
+            failureThreshold: {{ .Values.readinessProbe.failureThreshold }}
+          {{- end }}
+          {{- if .Values.resources }}
+          resources: {{- toYaml .Values.resources | nindent 12 }}
+          {{- end }}
+          volumeMounts:
+            {{- if (include "apache.useHtdocs" .) }}
+            - name: htdocs
+              mountPath: /app
+            {{- end }}
+            {{- if or (.Files.Glob "files/vhosts/*.conf") (.Values.vhostsConfigMap) }}
+            - name: vhosts
+              mountPath: /vhosts
+            {{- end }}
+            {{- if or (.Files.Glob "files/httpd.conf") (.Values.httpdConfConfigMap) }}
+            - name: httpd-conf
+              mountPath: /opt/bitnami/apache/conf/httpd.conf
+              subPath: httpd.conf
+            {{- end }}
+            {{- if .Values.extraVolumeMounts }}
+            {{- include "common.tplvalues.render" ( dict "value" .Values.extraVolumeMounts "context" $) | nindent 12 }}
+            {{- end }}
+        {{- if .Values.metrics.enabled }}
+        - name: metrics
+          image: {{ template "apache.metrics.image" . }}
+          imagePullPolicy: {{ .Values.metrics.image.pullPolicy | quote }}
+          command: ['/bin/apache_exporter', '--scrape_uri', 'http://status.localhost:8080/server-status/?auto']
+          ports:
+            - name: metrics
+              containerPort: 9117
+          livenessProbe:
+            httpGet:
+              path: /metrics
+              port: metrics
+            initialDelaySeconds: 15
+            timeoutSeconds: 5
+          readinessProbe:
+            httpGet:
+              path: /metrics
+              port: metrics
+            initialDelaySeconds: 5
+            timeoutSeconds: 1
+          {{- if .Values.metrics.resources }}
+          resources: {{- toYaml .Values.metrics.resources | nindent 12 }}
+          {{- end }}
+        {{- end }}
+      volumes:
+        {{- if (include "apache.useHtdocs" .) }}
+        - name: htdocs
+          {{- include "apache.htdocsVolume" . | nindent 10 }}
+        {{- end }}
+        {{- if or (.Files.Glob "files/vhosts/*.conf") (.Values.vhostsConfigMap) }}
+        - name: vhosts
+          configMap:
+            name: {{ include "apache.vhostsConfigMap" . }}
+        {{- end }}
+        {{- if or (.Files.Glob "files/httpd.conf") (.Values.httpdConfConfigMap) }}
+        - name: httpd-conf
+          configMap:
+            name: {{ include "apache.httpdConfConfigMap" . }}
+        {{- end }}
+        {{- if .Values.extraVolumes }}
+        {{- include "common.tplvalues.render" ( dict "value" .Values.extraVolumes "context" $) | nindent 8 }}
+        {{- end }}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/values.yaml b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-config/values.yaml
new file mode 100644 (file)
index 0000000..3437982
--- /dev/null
@@ -0,0 +1,310 @@
+## Global Docker image parameters
+## Please, note that this will override the image parameters, including dependencies, configured to use the global value
+## Current available global Docker image parameters: imageRegistry and imagepullSecrets
+##
+# global:
+#   imageRegistry: myRegistryName
+#   imagePullSecrets:
+#     - myRegistryKeySecretName
+
+## Bitnami Apache image version
+## ref: https://hub.docker.com/r/bitnami/apache/tags/
+##
+image:
+  registry: docker.io
+  repository: bitnami/apache
+  tag: 2.4.46-debian-10-r62
+  ## Specify a imagePullPolicy
+  ## ref: http://kubernetes.io/docs/user-guide/images/#pre-pulling-images
+  ##
+  pullPolicy: IfNotPresent
+  ## Optionally specify an array of imagePullSecrets.
+  ## Secrets must be manually created in the namespace.
+  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
+  ##
+  # pullSecrets:
+  #   - myRegistryKeySecretName
+
+  ## Set to true if you would like to see extra information on logs
+  ## ref:  https://github.com/bitnami/minideb-extras/#turn-on-bash-debugging
+  ##
+  debug: false
+
+## Bitnami Git image version
+## ref: https://hub.docker.com/r/bitnami/git/tags/
+##
+git:
+  registry: docker.io
+  repository: bitnami/git
+  tag: 2.29.0-debian-10-r0
+  pullPolicy: IfNotPresent
+  ## Optionally specify an array of imagePullSecrets.
+  ## Secrets must be manually created in the namespace.
+  ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
+  ##
+  # pullSecrets:
+  #   - myRegistryKeySecretName
+
+## String to partially override apache.fullname template (will maintain the release name)
+##
+# nameOverride:
+
+## String to fully override apache.fullname template
+##
+# fullnameOverride:
+
+## Number of Apache replicas to deploy
+##
+replicaCount: 1
+
+## Pod affinity preset
+## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity
+## Allowed values: soft, hard
+##
+podAffinityPreset: ""
+
+## Pod anti-affinity preset
+## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity
+## Allowed values: soft, hard
+##
+podAntiAffinityPreset: soft
+
+## Node affinity preset
+## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity
+## Allowed values: soft, hard
+##
+nodeAffinityPreset:
+  ## Node affinity type
+  ## Allowed values: soft, hard
+  type: ""
+  ## Node label key to match
+  ## E.g.
+  ## key: "kubernetes.io/e2e-az-name"
+  ##
+  key: ""
+  ## Node label values to match
+  ## E.g.
+  ## values:
+  ##   - e2e-az1
+  ##   - e2e-az2
+  ##
+  values: []
+
+## Affinity for pod assignment
+## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
+## Note: podAffinityPreset, podAntiAffinityPreset, and  nodeAffinityPreset will be ignored when it's set
+##
+affinity: {}
+
+## Node labels for pod assignment
+## Ref: https://kubernetes.io/docs/user-guide/node-selection/
+##
+nodeSelector: {}
+
+## Tolerations for pod assignment
+## Ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
+##
+tolerations: []
+
+## Get the server static content from a git repository
+##
+cloneHtdocsFromGit:
+  enabled: false
+  # repository:
+  # branch:
+  interval: 60
+  resources: {}
+
+## Name of a config map with the server static content
+##
+# htdocsConfigMap:
+
+## Name of a PVC with the server static content
+##
+# htdocsPVC:
+
+## Name of a config map with the virtual hosts content
+##
+# vhostsConfigMap:
+
+## Name of a config map with the httpd.conf file contents
+##
+# httpdConfConfigMap:
+
+## Pod annotations
+## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
+##
+podAnnotations: {}
+
+## Apache pods' resource requests and limits
+## ref: http://kubernetes.io/docs/user-guide/compute-resources/
+##
+resources:
+  # We usually recommend not to specify default resources and to leave this as a conscious
+  # choice for the user. This also increases chances charts run on environments with little
+  # resources, such as Minikube. If you do want to specify resources, uncomment the following
+  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+  limits: {}
+  #   cpu: 100m
+  #   memory: 128Mi
+  requests: {}
+  #   cpu: 100m
+  #   memory: 128Mi
+
+## Apache container's liveness and readiness probes
+## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#container-probes
+##
+livenessProbe:
+  enabled: true
+  path: "/"
+  port: http
+  initialDelaySeconds: 180
+  periodSeconds: 20
+  timeoutSeconds: 5
+  failureThreshold: 6
+  successThreshold: 1
+readinessProbe:
+  enabled: true
+  path: "/"
+  port: http
+  initialDelaySeconds: 30
+  periodSeconds: 10
+  timeoutSeconds: 5
+  failureThreshold: 6
+  successThreshold: 1
+
+## Ingress paramaters
+##
+ingress:
+  ## Set to true to enable ingress record generation
+  ##
+  enabled: false
+
+  ## Set this to true in order to add the corresponding annotations for cert-manager
+  ##
+  certManager: false
+
+  ## When the ingress is enabled, a host pointing to this will be created
+  ##
+  hostname: example.local
+
+  ## Ingress annotations done as key:value pairs
+  ## For a full list of possible ingress annotations, please see
+  ## ref: https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md
+  ##
+  ## If tls is set to true, annotation ingress.kubernetes.io/secure-backends: "true" will automatically be set
+  ## If certManager is set to true, annotation kubernetes.io/tls-acme: "true" will automatically be set
+  annotations: {}
+  #  kubernetes.io/ingress.class: nginx
+
+  ## The list of additional hostnames to be covered with this ingress record.
+  ## Most likely the hostname above will be enough, but in the event more hosts are needed, this is an array
+  ## hosts:
+  ## - name: example.local
+  ##   path: /
+
+  ## The tls configuration for the ingress
+  ## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls
+  ##
+  tls:
+    - hosts:
+        - example.local
+      secretName: example.local-tls
+
+  secrets:
+  ## If you're providing your own certificates, please use this to add the certificates as secrets
+  ## key and certificate should start with -----BEGIN CERTIFICATE----- or
+  ## -----BEGIN RSA PRIVATE KEY-----
+  ##
+  ## name should line up with a tlsSecret set further up
+  ## If you're using cert-manager, this is unneeded, as it will create the secret for you if it is not set
+  ##
+  ## It is also possible to create and manage the certificates outside of this helm chart
+  ## Please see README.md for more information
+  # - name: apache.local-tls
+  #   key:
+  #   certificate:
+
+## Prometheus Exporter / Metrics
+##
+metrics:
+  enabled: false
+  ## Bitnami Apache Prometheus Exporter image
+  ## ref: https://hub.docker.com/r/bitnami/apache-exporter/tags/
+  ##
+  image:
+    registry: docker.io
+    repository: bitnami/apache-exporter
+    tag: 0.8.0-debian-10-r186
+    pullPolicy: IfNotPresent
+    ## Optionally specify an array of imagePullSecrets.
+    ## Secrets must be manually created in the namespace.
+    ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
+    ##
+    # pullSecrets:
+    #   - myRegistryKeySecretName
+  ## Metrics exporter pod Annotation and Labels
+  ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
+  ##
+  podAnnotations:
+    prometheus.io/scrape: "true"
+    prometheus.io/port: "9117"
+  ## Apache Prometheus exporter resource requests and limits
+  ## ref: http://kubernetes.io/docs/user-guide/compute-resources/
+  ##
+  resources:
+    # We usually recommend not to specify default resources and to leave this as a conscious
+    # choice for the user. This also increases chances charts run on environments with little
+    # resources, such as Minikube. If you do want to specify resources, uncomment the following
+    # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+    limits: {}
+    #   cpu: 100m
+    #   memory: 128Mi
+    requests: {}
+    #   cpu: 100m
+    #   memory: 128Mi
+
+## Array to add extra volumes (evaluated as a template)
+##
+extraVolumes: []
+
+## Array to add extra mounts (normally used with extraVolumes, evaluated as a template)
+##
+extraVolumeMounts: []
+
+## An array to add extra env vars
+##
+extraEnvVars: []
+
+## Service paramaters
+##
+service:
+  ## Service type
+  ##
+  type: LoadBalancer
+  ## HTTP Port
+  ##
+  port: 80
+  ## HTTPS Port
+  ##
+  httpsPort: 443
+  ## Specify the nodePort(s) value(s) for the LoadBalancer and NodePort service types.
+  ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport
+  ##
+  nodePorts:
+    http: ""
+    https: ""
+  ## Set the LoadBalancer service type to internal only.
+  ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer
+  ##
+  # loadBalancerIP:
+  ## Provide any additional annotations which may be required. This can be used to
+  ## set the LoadBalancer service type to internal only.
+  ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer
+  ##
+  annotations: {}
+
+  ## Enable client source IP preservation
+  ## ref http://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip
+  ##
+  externalTrafficPolicy: Cluster
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/default-values.yaml b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/default-values.yaml
new file mode 100644 (file)
index 0000000..ef8deec
--- /dev/null
@@ -0,0 +1,3 @@
+## Number of Apache replicas to deploy
+##
+replicaCount: 2
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/restore-values.yaml b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/restore-values.yaml
new file mode 100644 (file)
index 0000000..69243f8
--- /dev/null
@@ -0,0 +1,3 @@
+## Number of Apache replicas to deploy
+##
+replicaCount: 1
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/values-mapping.json b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/values-mapping.json
new file mode 100644 (file)
index 0000000..043d62e
--- /dev/null
@@ -0,0 +1,14 @@
+[
+    {
+        "name": "replica-count",
+        "property": {
+            "description": "Number of replicas for scaling",
+            "type": "integer",
+            "required": false
+        },
+        "input-param": false,
+        "dictionary-name": "replica-count",
+        "dictionary-source": "capability",
+        "dependencies": []
+    }
+]
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/values.yaml.vtl b/tutorials/ApacheCNF/templates/cba/Templates/k8s-configs/deployment-values/values.yaml.vtl
new file mode 100644 (file)
index 0000000..a76d6ba
--- /dev/null
@@ -0,0 +1,3 @@
+## Number of Apache replicas to deploy
+##
+replicaCount: ${replica-count}
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-profiles/cnf-cds-base-profile.tar.gz b/tutorials/ApacheCNF/templates/cba/Templates/k8s-profiles/cnf-cds-base-profile.tar.gz
new file mode 100644 (file)
index 0000000..ee8465c
Binary files /dev/null and b/tutorials/ApacheCNF/templates/cba/Templates/k8s-profiles/cnf-cds-base-profile.tar.gz differ
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/k8s-profiles/node-port-profile.tar.gz b/tutorials/ApacheCNF/templates/cba/Templates/k8s-profiles/node-port-profile.tar.gz
new file mode 100644 (file)
index 0000000..ef37a9e
Binary files /dev/null and b/tutorials/ApacheCNF/templates/cba/Templates/k8s-profiles/node-port-profile.tar.gz differ
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/vnf-mapping.json b/tutorials/ApacheCNF/templates/cba/Templates/vnf-mapping.json
new file mode 100644 (file)
index 0000000..a049e45
--- /dev/null
@@ -0,0 +1,104 @@
+[
+    {
+        "name": "vnf-id",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "vnf-id",
+        "dictionary-source": "input",
+        "dependencies": [],
+        "version": 0
+    },
+    {
+        "name": "vnf_name",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string",
+            "status": "",
+            "constraints": [
+                {}
+            ],
+            "entry_schema": {
+                "type": ""
+            }
+        },
+        "input-param": false,
+        "dictionary-name": "vnf_name",
+        "dictionary-source": "rest",
+        "dependencies": [
+            "aic-cloud-region",
+            "vf-naming-policy",
+            "vnf-id"
+        ],
+        "version": 0
+    },
+    {
+        "name": "vf-naming-policy",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string",
+            "default": "SDNC_Policy.ONAP_NF_NAMING_TIMESTAMP"
+        },
+        "input-param": false,
+        "dictionary-name": "vf-naming-policy",
+        "dictionary-source": "default",
+        "dependencies": [],
+        "version": 0
+    },
+    {
+        "name": "aic-cloud-region",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "aic-cloud-region",
+        "dictionary-source": "input",
+        "dependencies": [],
+        "version": 0
+    },
+    {
+        "name": "service-instance-id",
+        "property": {
+            "description": "",
+            "required": false,
+            "type": "string"
+        },
+        "input-param": false,
+        "dictionary-name": "service-instance-id",
+        "dictionary-source": "input",
+        "dependencies": [],
+        "version": 0
+    },
+    {
+        "name": "k8s-rb-profile-namespace",
+        "property": {
+            "description": "K8s namespace to create helm chart for specified profile",
+            "type": "string",
+            "default": "default"
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-profile-namespace",
+        "dictionary-source": "default",
+        "dependencies": []
+    },
+    {
+        "name": "k8s-rb-profile-k8s-version",
+        "property": {
+            "description": "K8s cluster version to create helm chart for specified RB profile",
+            "type": "string",
+            "required": false,
+            "default": "1.18.9"
+        },
+        "input-param": false,
+        "dictionary-name": "k8s-rb-profile-k8s-version",
+        "dictionary-source": "default",
+        "dependencies": []
+    }
+]
diff --git a/tutorials/ApacheCNF/templates/cba/Templates/vnf-template.vtl b/tutorials/ApacheCNF/templates/cba/Templates/vnf-template.vtl
new file mode 100644 (file)
index 0000000..3e5ad19
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "capability-data": [
+    ],
+    "resource-accumulator-resolved-data": [
+        {
+            "param-name": "vnf_name",
+            "param-value": "${vnf_name}"
+        },
+        {
+            "param-name": "vf-naming-policy",
+            "param-value": "${vf-naming-policy}"
+        },
+        {
+            "param-name": "k8s-rb-profile-namespace",
+            "param-value": "${k8s-rb-profile-namespace}"
+        },
+        {
+            "param-name": "k8s-rb-profile-k8s-version",
+            "param-value": "${k8s-rb-profile-k8s-version}"
+        }
+    ]
+}
diff --git a/tutorials/ApacheCNF/templates/cba/pom.xml b/tutorials/ApacheCNF/templates/cba/pom.xml
new file mode 100644 (file)
index 0000000..18324c7
--- /dev/null
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright © 2020 Bell Canada
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onap.ccsdk.cds.components.cba</groupId>
+        <artifactId>test-blueprint-kotlin-parent</artifactId>
+        <version>1.2.0</version>
+    </parent>
+
+    <artifactId>apache</artifactId>
+    <version>1.2.0</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <!-- Properties for -Pdeploy-cba -->
+        <cds.username>ccsdkapps</cds.username>
+        <cds.password>ccsdkapps</cds.password>
+        <!-- DEFAULTS
+        <cds.protocol>http</cds.protocol>
+        <cds.host>localhost</cds.host>
+        <cds.port>8081</cds.port>
+        <cds.enrich.endpoint>api/v1/blueprint-model/enrich</cds.enrich.endpoint>
+        <cds.publish.endpoint>api/v1/blueprint-model/publish</cds.publish.endpoint>
+        <ca></ca-->
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onap.ccsdk.cds.blueprintsprocessor.modules</groupId>
+            <artifactId>processor-core</artifactId>
+            <version>1.2.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.ccsdk.cds.blueprintsprocessor.functions</groupId>
+            <artifactId>k8s-connection-plugin</artifactId>
+            <version>1.2.0</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.att.aft</groupId>
+            <artifactId>dme2</artifactId>
+            <version>3.1.200-oss</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.ccsdk.cds.blueprintsprocessor.modules</groupId>
+            <artifactId>selfservice-api</artifactId>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/tutorials/ApacheCNF/templates/cba2dd.py b/tutorials/ApacheCNF/templates/cba2dd.py
new file mode 100644 (file)
index 0000000..02cf608
--- /dev/null
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+#   COPYRIGHT NOTICE STARTS HERE
+
+#   Copyright 2020 . Samsung Electronics Co., Ltd.
+#
+#   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.
+
+#   COPYRIGHT NOTICE ENDS HERE
+
+import os
+import argparse
+import json
+
+#
+# Script to convert given Enriched CDS CBA model to Data Dictionary output
+# Usage:
+#   ./cba2dd.py --cba_dir <path to cba main directory> | python3 -m json.tool
+#
+
+def get_resources_definition_file(cba_dir):
+    definitions_dir = cba_dir + os.sep + "Definitions"
+    resource_definition_file = definitions_dir + os.sep + "resources_definition_types.json"
+    if not os.path.exists(definitions_dir):
+        raise RuntimeError("'%s' directory does not exists or is not CBA directory" % cba_dir)
+    if not os.path.exists(resource_definition_file):
+        raise RuntimeError("'%s' file does not exists in CBA Definitions directory. CBA is not Enriched!" % resource_definition_file)
+    return resource_definition_file
+
+def create_dd(cba_dir):
+    with open(get_resources_definition_file(cba_dir)) as f:
+        output_json = json.load(f)
+    dd = []
+    for _, entry in output_json.items():
+        dd.append(build_dd_entry(entry))
+    print(json.dumps(dd))
+
+def build_dd_entry(definition_entry):
+    """Builds Data Dictionary entry from given dictionary entry. Given entry
+    itself is added as value for "definition" key.
+    {
+        "name": "",
+        "tags": "",
+        "data_type": "",
+        "description": "",
+        "entry_schema": "",
+        "updatedBy": "",
+        "definition": definition_entry
+    }
+    """
+    out_dict = {}
+    out_dict["name"] = definition_entry["name"]
+    out_dict["tags"] = definition_entry["tags"]
+    out_dict["data_type"] = definition_entry["property"]["type"]
+    out_dict["description"] = definition_entry["property"]["description"]
+    out_dict["entry_schema"] = definition_entry["property"]["type"]
+    out_dict["updatedBy"] = definition_entry["updated-by"]
+    out_dict["definition"] = definition_entry
+    return out_dict
+
+def main():
+    description = """Script to convert given Enriched CDS CBA model to Data Dictionary output.
+Example:
+  ./cba2dd.py --cba_dir cba | python3 -m json.tool
+    """
+    parser = argparse.ArgumentParser(description=description,
+        formatter_class=argparse.RawTextHelpFormatter)
+    parser.add_argument('--cba_dir',
+                        help='Path to CDS CBA model main directory',
+                        default='')
+    args = parser.parse_args()
+    try:
+        create_dd(args.cba_dir)
+    except Exception as e:
+        print(e)
+        parser.print_help()
+        exit(1)
+
+if __name__ == '__main__':
+    main()
diff --git a/tutorials/ApacheCNF/templates/helm/.gitignore b/tutorials/ApacheCNF/templates/helm/.gitignore
new file mode 100644 (file)
index 0000000..17d6b36
--- /dev/null
@@ -0,0 +1 @@
+/*.tgz
diff --git a/tutorials/ApacheCNF/templates/helm/Makefile b/tutorials/ApacheCNF/templates/helm/Makefile
new file mode 100644 (file)
index 0000000..5bcea8f
--- /dev/null
@@ -0,0 +1,17 @@
+vf-modules = apache
+.PHONY: build clean $(vf-modules:=-build) $(vf-modules:-clean) $(vf-modules:=-package)
+
+package: $(vf-modules:=-package)
+build: $(vf-modules:=-build)
+clean: $(vf-modules:=-clean)
+
+$(vf-modules:=-package): %-package: %-build
+       mv $(@:package=)*.tgz helm_$(@:-package=).tgz
+
+$(vf-modules:=-build): %-build: %-clean
+       helm repo add bitnami https://charts.bitnami.com/bitnami
+       helm pull bitnami/apache --version 7.6.0
+
+$(vf-modules:=-clean):
+       rm -f $(@:-clean=)-*.tgz
+       rm -f helm_$(@:-clean=).tgz
diff --git a/tutorials/ApacheCNF/templates/helm/README.txt b/tutorials/ApacheCNF/templates/helm/README.txt
new file mode 100644 (file)
index 0000000..63429e9
--- /dev/null
@@ -0,0 +1,7 @@
+Helm content of onboarding package
+
+To create necessary archives, please ensure you have [helm] and [make] installed first.
+
+In case it's your first time you're using helm, please issue `helm init -c` command to initialize your helm client
+
+To create necessary artifacts, issue `make` command
diff --git a/tutorials/ApacheCNF/templates/tools/tail_all.sh b/tutorials/ApacheCNF/templates/tools/tail_all.sh
new file mode 100644 (file)
index 0000000..d18674e
--- /dev/null
@@ -0,0 +1,161 @@
+#!/bin/bash
+#   COPYRIGHT NOTICE STARTS HERE
+
+#   Copyright 2020 . Samsung Electronics Co., Ltd.
+#
+#   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.
+
+#   COPYRIGHT NOTICE ENDS HERE
+
+set -e
+
+get_pod_name() {
+    kubectl -n ${NAMESPACE} get pod -l app="$1" -o jsonpath='{ .items[0].metadata.name }'
+}
+
+exec_in_pod() {
+    local pod="$1"
+    local container="$2"
+    shift 2
+    local cmd="$@"
+    kubectl --namespace ${NAMESPACE} exec ${pod} --container ${container} -- sh -c "${cmd}"
+}
+
+pod_logs() {
+    local pod="$1"
+    local container="$2"
+    local options="$3"
+    shift 3
+    kubectl --namespace ${NAMESPACE} logs ${pod} --container ${container} ${options:+"${options}"}
+}
+
+k8s_tail() {
+    local operation="$1"
+    local file_to_tail="$2"
+    local pod_label="$3"
+    local container="$4"
+    if [ -z ${container} ]; then
+        container=${pod_label}
+    fi
+    mkdir -p ${CACHE_FILE_DIR}
+    local pod=$(get_pod_name ${pod_label})
+    file_path_savable_form="$(sed 's#/#__#g' <<<"$file_to_tail")"
+    LINECOUNT_CACHE_FILE=${CACHE_FILE_DIR}/${pod}-${container}-${file_path_savable_form}
+    local line_count=0
+    if [ "${operation}" == "start" ]; then
+        if [ "${file_to_tail}" == "POD_LOG" ]; then
+            line_count=$(pod_logs ${pod} ${container} "" | wc -l)
+        else
+            if ! line_count=$(exec_in_pod ${pod} ${container} "wc -l ${file_to_tail}"); then
+                echo "Failed to get file ${file_to_tail} line count, maybe it does not exist. Using linecount 0." >&2
+                line_count=0
+            else
+                # parse out linecount from wc -l output
+                line_count=$(echo -e "${line_count}" | tail -1 | cut -d' ' -f1)
+            fi
+        fi
+        echo "${line_count}" > ${LINECOUNT_CACHE_FILE}
+        echo "Saved file ${file_to_tail} of POD ${pod_label} linecount ${line_count} into file ${LINECOUNT_CACHE_FILE}"
+    fi
+    if [ "${operation}" == "collect" ]; then
+        if [ ! -f ${LINECOUNT_CACHE_FILE} ]; then
+            echo "Linecount cache file ${LINECOUNT_CACHE_FILE} not found. Either tailing was not started or POD has restarted. Colected from log beginning." >&2
+            start_line=0
+        else
+            start_line=$(cat ${LINECOUNT_CACHE_FILE})
+        fi
+        echo "Tail pod's ${pod_label} container ${container} file ${file_to_tail} starting from line ${start_line} onwards" >&2
+        if [ "${file_to_tail}" == "POD_LOG" ]; then
+            current_line_count=$(pod_logs ${pod} ${container} "" | wc -l)
+            lines_from_end=$(( ${current_line_count}-${start_line} ))
+            echo "Execute kubectl logs for ${pod} POD's ${container} container. Log ${lines_from_end} lines from end"
+            pod_logs ${pod} ${container} --tail=${lines_from_end}
+        else
+            echo "Execute cmd "tail -n +${start_line} ${file_to_tail}" inside ${pod} POD's ${container} container"
+            exec_in_pod ${pod} ${container} "tail -n +${start_line} ${file_to_tail}"
+        fi
+    fi
+}
+
+tail_it() {
+    local operation=$1
+    for tail in "${TAILS[@]}"
+    do
+        tailarray=(${tail})
+        result=$(k8s_tail ${operation} ${tailarray[@]})
+        if [ "${operation}" == "collect" ]; then
+            mkdir -p ${RESULT_DIR}
+            log_file=$(basename ${tailarray[0]})
+            if [ "${log_file}" == "POD_LOG" ]; then
+               log_file=${log_file}.log
+            fi
+            pod=${tailarray[1]}
+            container="${pod:-tailarray[2]}"
+            out_file=${RESULT_DIR}/${pod}_${container}_${log_file}
+            echo -e "${result}" > ${out_file}
+            echo "Saved tail content to log file ${out_file}"
+        else
+            echo -e "${result}"
+        fi
+    done
+}
+
+
+##### MAIN #####
+if [ -f ./tail_config ]; then
+. ./tail_config
+fi
+NAMESPACE=${NAMESPACE:-onap}
+CACHE_FILE_DIR=${CACHE_FILE_DIR:-.k8s_tail}
+RESULT_DIR=${RESULT_DIR:-./tail_results}
+DEFAULT_TAILS=()
+TAILS=("${TAILS[@]:-${DEFAULT_TAILS[@]}}")
+
+case "$1" in
+    -h|--help|help|?|"")
+        echo "Script usage:"
+        echo "$0 start   - Start pods' log tailing"
+        echo "$0 collect - Collect all logs currently tailed or get all logs as whole"
+        echo ""
+        echo "If start is not called before collect is called, collect gathers all logs completely. "
+        echo "Otherwise logs are collected only from the linecount of the time of start call."
+        echo ""
+        echo "Log files collected is configured with 'tail_config' file in the same directory with the script."
+        echo "Config file needs to fontain bash array variable named TAILS=() and format of each entry in array is"
+        echo "    <file path> <POD's app label name> [<container name>]"
+        echo "where <file path> is actual file path inside the pod or special string 'POD_LOG' that means kubectl logs"
+        echo "where optional <container name> is to specify POD's container if many containers in the pod. By default same name as pod is used."
+        echo ""
+        echo 'Example: TAILS=('
+        echo '  "/app/logs/apih/metrics.log so"'
+        echo '  "/app/logs/bpmn/debug.log so-bpmn-infra"'
+        echo '  "/app/logs/vnfm-adapter/debug.log so-vnfm-adapter"'
+        echo '  "/var/log/onap/sdnc/karaf.log sdnc"'
+        echo '  "/tmp/app.out network-name-gen"'
+        echo '  "POD_LOG cds-blueprints-processor"'
+        echo '  "POD_LOG multicloud multicloud"'
+        echo '  "POD_LOG multicloud-k8s multicloud-k8s"'
+        echo '  "POD_LOG multicloud-k8s framework-artifactbroker"'
+        echo '  "/app/logs/openstack/error.log so-openstack-adapter"'
+        echo '  "/app/logs/openstack/debug.log so-openstack-adapter"'
+        echo ' )'
+        echo ""
+        ;;
+    start|collect)
+        tail_it $1
+        ;;
+    *)
+        echo "Wrong usage, check '$0 -h'" >&2
+        exit 1
+        ;;
+esac
diff --git a/tutorials/ApacheCNF/templates/tools/tail_config b/tutorials/ApacheCNF/templates/tools/tail_config
new file mode 100644 (file)
index 0000000..ca49793
--- /dev/null
@@ -0,0 +1,18 @@
+#!/bin/false
+
+NAMESPACE="onap"
+
+TAILS=(
+  "/app/logs/apih/debug.log so"
+  "/app/logs/apih/error.log so"
+  "/app/logs/bpmn/debug.log so-bpmn-infra"
+  "/app/logs/openstack/error.log so-openstack-adapter"
+  "/app/logs/openstack/debug.log so-openstack-adapter"
+  "/var/log/onap/sdnc/karaf.log sdnc"
+  "POD_LOG network-name-gen"
+  "POD_LOG cds-blueprints-processor"
+  "POD_LOG multicloud multicloud"
+  "POD_LOG multicloud-k8s multicloud-k8s"
+  "POD_LOG multicloud-k8s framework-artifactbroker"
+  "POD_LOG msb-iag msb-iag"
+)