Feature 11054: Generation of OKA for helm-based apps 55/14755/3
authorgarciadeblas <gerardo.garciadeblas@telefonica.com>
Wed, 20 Nov 2024 15:29:57 +0000 (16:29 +0100)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Tue, 26 Nov 2024 08:42:57 +0000 (09:42 +0100)
Change-Id: I7288ed6b51a53bbdd6659c17e6acc2acbd1460d8
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
MANIFEST.in
osmclient/cli_commands/oka.py
osmclient/scripts/osm.py
osmclient/sol005/oka.py
osmclient/templates/oka/manifest-helmrelease.j2 [new file with mode: 0644]
osmclient/templates/oka/manifest-helmrepo.j2 [new file with mode: 0644]
osmclient/templates/oka/template-kustomization.j2 [new file with mode: 0644]
osmclient/templates/oka/template-namespace.j2 [new file with mode: 0644]

index bff0dde..8354002 100644 (file)
@@ -14,4 +14,5 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-include osmclient/templates/*.yaml.j2 osmclient/requirements.txt
\ No newline at end of file
+recursive-include osmclient/templates
+include osmclient/requirements.txt
index ff7ad83..786cec6 100755 (executable)
@@ -23,6 +23,81 @@ import logging
 logger = logging.getLogger("osmclient")
 
 
+@click.command(
+    name="oka-generate", short_help="Generate OKA folder structure and files"
+)
+@click.argument("name")
+@click.option(
+    "--base-directory",
+    default=".",
+    help=('Set the base location for OKA folder. Default: "."'),
+)
+@click.option(
+    "--profile-type",
+    type=click.Choice(
+        [
+            "infra-controller-profile",
+            "infra-config-profile",
+            "app-profile",
+            "resource-profile",
+        ]
+    ),
+    default="app-profile",
+    help="type of profile",
+)
+@click.option(
+    "--helm-repo-name",
+    required=True,
+    help="Helm repository name",
+)
+@click.option(
+    "--helm-repo-url",
+    required=True,
+    help="Helm repository URL",
+)
+@click.option(
+    "--helm-chart",
+    required=True,
+    help="Helm chart name (as present in the helm repo)",
+)
+@click.option(
+    "--version",
+    default="latest",
+    help="Version of the helm chart",
+)
+@click.option(
+    "--namespace",
+    required=True,
+    help="Default namespace where the OKA will be deployed",
+)
+@click.pass_context
+def oka_generate(
+    ctx,
+    name,
+    base_directory,
+    profile_type,
+    **kwargs,
+    # helm_repo_name,
+    # helm_repo_url,
+    # helm_chart,
+    # version,
+    # namespace,
+):
+    """
+    Creates an OKA folder structure with manifests and templates
+
+    \b
+    NAME: name of the OKA (matches the name of the destination folder)
+    """
+    logger.debug("")
+    ctx.obj.oka.generate(
+        name,
+        base_directory,
+        profile_type,
+        kwargs,
+    )
+
+
 @click.command(name="oka-add", short_help="adds an OSM Kubernetes Application (OKA)")
 @click.argument("name")
 @click.argument("path")
index f0a10ba..6d7a834 100755 (executable)
@@ -175,6 +175,7 @@ def cli():
         cli_osm.add_command(profiles.attach_profile)
         cli_osm.add_command(profiles.detach_profile)
 
+        cli_osm.add_command(oka.oka_generate)
         cli_osm.add_command(oka.oka_add)
         cli_osm.add_command(oka.oka_delete)
         cli_osm.add_command(oka.oka_list)
index 539bc40..832f25a 100644 (file)
@@ -20,6 +20,9 @@ OSM Kubernetes Application (OKA) API handling
 """
 
 from osmclient.sol005.osm_api_object import GenericOSMAPIObject
+from osmclient.common.exceptions import ClientException
+import os
+from jinja2 import Environment, PackageLoader, select_autoescape
 
 
 class OKA(GenericOSMAPIObject):
@@ -32,3 +35,76 @@ class OKA(GenericOSMAPIObject):
         self._apiBase = "{}{}{}".format(
             self._apiName, self._apiVersion, self._apiResource
         )
+
+    def generate(self, name, base_directory, profile_type, oka_params):
+        """Generate a folder structure of an OKA with manifests and templates"""
+        self._logger.debug("")
+        # if oka_params["manifest_dir"] and oka_params["helm-repo-name"]:
+        #     raise ClientException("Options manifest_dir and helm-xxx are mutually exclusive")
+        if not os.path.exists(base_directory):
+            raise ClientException(f"The specified {base_directory} does not exist")
+        try:
+            self._logger.debug(f"oka_params: {oka_params}")
+            self._logger.debug(f"base_dir: {base_directory}")
+            oka_folder = os.path.join(base_directory, name)
+            self._logger.debug(f"destination_folder: {oka_folder}")
+            manifests_folder = os.path.join(oka_folder, "manifests")
+            templates_folder = os.path.join(oka_folder, "templates")
+            os.makedirs(manifests_folder)
+            os.makedirs(templates_folder)
+
+            # Load the Jinja template from file
+            # loader = FileSystemLoader("osm_lcm/odu_libs/templates")
+            loader = PackageLoader("osmclient", "templates/oka")
+            self._logger.debug(f"Loader: {loader}")
+            env = Environment(loader=loader, autoescape=select_autoescape())
+            self._logger.debug(f"Env: {env}")
+
+            template_list = env.list_templates()
+            self._logger.debug(f"Template list: {template_list}")
+
+            # Get required information from OKA to generate files
+            helm_repo_name = oka_params["helm_repo_name"]
+            helm_repo_url = oka_params["helm_repo_url"]
+            if helm_repo_url.startswith("oci://"):
+                oka_params["helm_repo_type"] = "oci"
+            helm_release = name
+            oka_params["helm_release"] = helm_release
+            namespace = oka_params["namespace"]
+            oka_params["kustomization_name"] = name
+            profile_path_mapping = {
+                "infra-controller-profile": "infra-controllers",
+                "infra-config-profile": "infra-configs",
+                "app-profile": "apps",
+                "resource-profile": "cloud-resources",
+            }
+            profile_path = profile_path_mapping[profile_type]
+            oka_params["manifest_folder"] = f"./{profile_path}/{name}/manifests"
+
+            # Helm repo
+            template = env.get_template("manifest-helmrepo.j2")
+            output_file = os.path.join(manifests_folder, f"{helm_repo_name}-repo.yaml")
+            with open(output_file, "w") as c_file:
+                c_file.write(template.render(oka_params))
+
+            # Helm release
+            template = env.get_template("manifest-helmrelease.j2")
+            output_file = os.path.join(manifests_folder, f"{helm_release}-hr.yaml")
+            with open(output_file, "w") as c_file:
+                c_file.write(template.render(oka_params))
+
+            # Namespace
+            template = env.get_template("template-namespace.j2")
+            output_file = os.path.join(templates_folder, f"{namespace}-ns.yaml")
+            with open(output_file, "w") as c_file:
+                c_file.write(template.render(oka_params))
+
+            # Kustomization
+            template = env.get_template("template-kustomization.j2")
+            output_file = os.path.join(templates_folder, f"{name}-ks.yaml")
+            with open(output_file, "w") as c_file:
+                c_file.write(template.render(oka_params))
+
+            print(f"Folder created: {oka_folder}")
+        except Exception as exc:
+            raise ClientException(f"failure during generation of OKA folder: {exc}")
diff --git a/osmclient/templates/oka/manifest-helmrelease.j2 b/osmclient/templates/oka/manifest-helmrelease.j2
new file mode 100644 (file)
index 0000000..075b816
--- /dev/null
@@ -0,0 +1,37 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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.
+#######################################################################################
+---
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+  name: {{ helm_release }}
+  namespace: {{ namespace }}
+spec:
+  chart:
+    spec:
+      chart: {{ helm_chart }}
+      reconcileStrategy: ChartVersion
+      sourceRef:
+        kind: HelmRepository
+        name: {{ helm_repo_name }}
+        namespace: {{ namespace }}
+  install:
+    createNamespace: true
+  interval: 3m0s
+  targetNamespace: {{ namespace }}
+  values: {}
+
diff --git a/osmclient/templates/oka/manifest-helmrepo.j2 b/osmclient/templates/oka/manifest-helmrepo.j2
new file mode 100644 (file)
index 0000000..ce6e3e9
--- /dev/null
@@ -0,0 +1,27 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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.
+#######################################################################################
+---
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: HelmRepository
+metadata:
+  name: {{ helm_repo_name }}
+  namespace: {{ namespace }}
+spec:
+  interval: 10m0s
+  type: {{ helm_repo_type }}
+  url: {{ helm_repo_url }}
+
diff --git a/osmclient/templates/oka/template-kustomization.j2 b/osmclient/templates/oka/template-kustomization.j2
new file mode 100644 (file)
index 0000000..1cca017
--- /dev/null
@@ -0,0 +1,31 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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.
+#######################################################################################
+---
+apiVersion: kustomize.toolkit.fluxcd.io/v1
+kind: Kustomization
+metadata:
+  name: {{ kustomization_name }}
+  namespace: {{ namespace }}
+spec:
+  interval: 1h0m0s
+  path: {{ manifest_folder }}
+  prune: true
+  sourceRef:
+    kind: GitRepository
+    name: sw-catalogs
+    namespace: flux-system
+
diff --git a/osmclient/templates/oka/template-namespace.j2 b/osmclient/templates/oka/template-namespace.j2
new file mode 100644 (file)
index 0000000..7293d5c
--- /dev/null
@@ -0,0 +1,25 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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.
+#######################################################################################
+---
+apiVersion: v1
+kind: Namespace
+metadata:
+  creationTimestamp: null
+  name: {{ namespace }}
+spec: {}
+status: {}
+