From 73ac4a546ae0f8e5cfc0967aca807261e55b6b76 Mon Sep 17 00:00:00 2001 From: garciadeblas Date: Wed, 20 Nov 2024 16:29:57 +0100 Subject: [PATCH] Feature 11054: Generation of OKA for helm-based apps Change-Id: I7288ed6b51a53bbdd6659c17e6acc2acbd1460d8 Signed-off-by: garciadeblas --- MANIFEST.in | 3 +- osmclient/cli_commands/oka.py | 75 ++++++++++++++++++ osmclient/scripts/osm.py | 1 + osmclient/sol005/oka.py | 76 +++++++++++++++++++ .../templates/oka/manifest-helmrelease.j2 | 37 +++++++++ osmclient/templates/oka/manifest-helmrepo.j2 | 27 +++++++ .../templates/oka/template-kustomization.j2 | 31 ++++++++ osmclient/templates/oka/template-namespace.j2 | 25 ++++++ 8 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 osmclient/templates/oka/manifest-helmrelease.j2 create mode 100644 osmclient/templates/oka/manifest-helmrepo.j2 create mode 100644 osmclient/templates/oka/template-kustomization.j2 create mode 100644 osmclient/templates/oka/template-namespace.j2 diff --git a/MANIFEST.in b/MANIFEST.in index bff0dde..8354002 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -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 diff --git a/osmclient/cli_commands/oka.py b/osmclient/cli_commands/oka.py index ff7ad83..786cec6 100755 --- a/osmclient/cli_commands/oka.py +++ b/osmclient/cli_commands/oka.py @@ -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") diff --git a/osmclient/scripts/osm.py b/osmclient/scripts/osm.py index f0a10ba..6d7a834 100755 --- a/osmclient/scripts/osm.py +++ b/osmclient/scripts/osm.py @@ -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) diff --git a/osmclient/sol005/oka.py b/osmclient/sol005/oka.py index 539bc40..832f25a 100644 --- a/osmclient/sol005/oka.py +++ b/osmclient/sol005/oka.py @@ -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 index 0000000..075b816 --- /dev/null +++ b/osmclient/templates/oka/manifest-helmrelease.j2 @@ -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 index 0000000..ce6e3e9 --- /dev/null +++ b/osmclient/templates/oka/manifest-helmrepo.j2 @@ -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 index 0000000..1cca017 --- /dev/null +++ b/osmclient/templates/oka/template-kustomization.j2 @@ -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 index 0000000..7293d5c --- /dev/null +++ b/osmclient/templates/oka/template-namespace.j2 @@ -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: {} + -- 2.25.1