diff --git a/apps/tasks.py b/apps/tasks.py index 59aaec07..3a70308c 100644 --- a/apps/tasks.py +++ b/apps/tasks.py @@ -124,15 +124,15 @@ def helm_delete(release_name: str, namespace: str = "default") -> tuple[str | No @shared_task -def helm_template(chart: str, values_file: str, namespace: str) -> tuple[str | None, str | None]: +def helm_template( + chart: str, values_file: str, namespace: str = "default", version: str = None +) -> tuple[str | None, str | None]: """ Executes a Helm template command. """ command = f"helm template tmp-release-name {chart} -f {values_file} --namespace {namespace}" # Append version if deploying via ghcr - # TODO: Make dynamic - version = "1.4.2" if version: command += f" --version {version} --repository-cache /app/charts/.cache/helm/repository" @@ -162,7 +162,7 @@ def helm_lint(chart: str, values_file: str, namespace: str) -> tuple[str | None, def _kubectl_apply_dry(deployment_file: str, target_strategy: str = "client") -> tuple[str | None, str | None]: """ Executes a kubectl apply --dry-run command. - NOTE: This does not appear to be working. + NOTE: This does not appear to be working, but kept for continued testing. """ command = f"kubectl apply --dry-run={target_strategy} -f {deployment_file}" # Execute the command @@ -201,7 +201,7 @@ def deploy_resource(serialized_instance): chart = instance.chart # Use a KubernetesDeploymentManifest to manage the manifest validation and files - from types import KubernetesDeploymentManifest + from apps.types_.kubernetes_deployment_manifest import KubernetesDeploymentManifest kdm = KubernetesDeploymentManifest() @@ -210,21 +210,41 @@ def deploy_resource(serialized_instance): with open(values_file, "w") as f: f.write(yaml.dump(values)) + valid_deployment = True + deployment_file = None + # In development, also generate and validate the k8s deployment manifest if settings.DEBUG: logger.debug(f"Generating and validating k8s deployment yaml for release {release} before deployment.") - output, error = kdm.generate_manifest_yaml_from_template(chart, values_file, values["namespace"]) + output, error = kdm.generate_manifest_yaml_from_template( + chart, values_file, values["namespace"], version, save_to_file=True + ) + + deployment_file = kdm.get_filepaths()["deployment_file"] # Validate the manifest yaml documents is_valid, validation_output = kdm.validate_manifest(output) if is_valid: - logger.debug(f"The deployment manifest file is valid of release {release}") + logger.debug(f"The deployment manifest file is valid for release {release}") + + # Also validate the kubernetes-pod-patches section + kpp_data = kdm.extract_kubernetes_pod_patches_from_manifest(output) + + if kpp_data: + is_valid, message = kdm.validate_kubernetes_pod_patches_yaml(kpp_data) + + if not is_valid: + logger.debug(f"The kubernetes-pod-patches section is invalid for release {release}. {message}") + valid_deployment = False else: - logger.warning(f"The deployment manifest file is INVALID of release {release}. {validation_output}") + valid_deployment = False - # Install the ap using Helm install + if not valid_deployment: + logger.warning(f"The deployment manifest file is INVALID for release {release}. {validation_output}") + + # Install the app using Helm install output, error = helm_install(release, chart, values["namespace"], values_file, version) success = not error @@ -238,21 +258,15 @@ def deploy_resource(serialized_instance): # In development, also generate and validate the k8s deployment manifest if settings.DEBUG: - logger.debug(f"Generating and validating k8s deployment yaml for release {release} after deployment.") - # Get the deployment manifest yaml - output, error = get_manifest_yaml(release) - if error: - logger.warning(f"Unable to get the deployment manifest for release {release}. Error: {error}") - # Save the manifest yaml to this file: - deployment_file = kdm.get_filepaths()["deployment_file"] - with open(deployment_file, "w") as f: - f.write(output) - if not error: - # Validate the manifest yaml if there was no error - logger.debug(f"Validating the deployment manifest yaml for release {release}") - - # TODO: Uncomment - # subprocess.run(["rm", "-f", values_file]) + # Previously, we generated and validated the deployment after creation + # output, error = get_manifest_yaml(release) + pass + + if valid_deployment: + # If valid, then delete both the values and deployment files (if exists) + subprocess.run(["rm", "-f", values_file]) + if deployment_file: + subprocess.run(["rm", "-f", deployment_file]) @shared_task diff --git a/apps/tests/test_kubernetes_deployment_manifest.py b/apps/tests/test_kubernetes_deployment_manifest.py index e1afd5a9..91c19489 100644 --- a/apps/tests/test_kubernetes_deployment_manifest.py +++ b/apps/tests/test_kubernetes_deployment_manifest.py @@ -86,8 +86,11 @@ def test_generate_manifest_yaml_from_template(self): chart = "oci://ghcr.io/scilifelabdatacentre/serve-charts/shinyproxy" values_file = self.kdm.get_filepaths()["values_file"] namespace = "default" + version = "1.4.2" - output, error = self.kdm.generate_manifest_yaml_from_template(chart, values_file, namespace, save_to_file=False) + output, error = self.kdm.generate_manifest_yaml_from_template( + chart, values_file, namespace, version, save_to_file=False + ) self.assertIsNone(error) self.assertIsNotNone(output) @@ -105,8 +108,11 @@ def test_validate_manifest(self): chart = "oci://ghcr.io/scilifelabdatacentre/serve-charts/shinyproxy" values_file = self.kdm.get_filepaths()["values_file"] namespace = "default" + version = "1.4.2" - output, error = self.kdm.generate_manifest_yaml_from_template(chart, values_file, namespace, save_to_file=False) + output, error = self.kdm.generate_manifest_yaml_from_template( + chart, values_file, namespace, version, save_to_file=False + ) self.assertIsNone(error) self.assertIsNotNone(output) @@ -130,8 +136,11 @@ def test_extract_kubernetes_pod_patches_from_manifest(self): chart = "oci://ghcr.io/scilifelabdatacentre/serve-charts/shinyproxy" values_file = self.kdm.get_filepaths()["values_file"] namespace = "default" + version = "1.4.2" - output, error = self.kdm.generate_manifest_yaml_from_template(chart, values_file, namespace, save_to_file=False) + output, error = self.kdm.generate_manifest_yaml_from_template( + chart, values_file, namespace, version, save_to_file=False + ) self.assertIsNone(error) self.assertIsNotNone(output) diff --git a/apps/types_/kubernetes_deployment_manifest.py b/apps/types_/kubernetes_deployment_manifest.py index 25ea748d..ce6bd940 100644 --- a/apps/types_/kubernetes_deployment_manifest.py +++ b/apps/types_/kubernetes_deployment_manifest.py @@ -41,7 +41,7 @@ def save_as_values_file(self, values_data: str) -> None: f.write(values_data) def generate_manifest_yaml_from_template( - self, chart: str, values_file: str, namespace: str, save_to_file: bool = False + self, chart: str, values_file: str, namespace: str, version: str = None, save_to_file: bool = False ) -> tuple[str | None, str | None]: """ Generate the manifest yaml for this deployment. @@ -52,7 +52,7 @@ def generate_manifest_yaml_from_template( from ..tasks import helm_template - output, error = helm_template(chart, values_file, namespace) + output, error = helm_template(chart, values_file, namespace, version) if not error: if save_to_file: @@ -175,7 +175,7 @@ def validate_kubernetes_pod_patches_yaml(self, input: str) -> dict[bool, str]: def _validate_manifest_file(self) -> dict[bool, str, str]: """ Validates the manifest file for this deployment. - Note: This does not appear to be working, but kept for continues testing. + Note: This does not appear to be working, but kept for continued testing. Returns: dict[bool,str,str]: is_valid, output, validation_error