diff --git a/deployment_manifest.json b/deployment_manifest.json index 6295cfac..ad54b140 100644 --- a/deployment_manifest.json +++ b/deployment_manifest.json @@ -7,7 +7,7 @@ "logCriticality": "AccessLogs", "disasterRecovery": "True" }, - "cluster": "nonprod.np.navi-tech.in", + "cluster": "$CLUSTER", "deployment": { "cluster": "$CLUSTER", "serviceAccount": true, @@ -188,10 +188,6 @@ } ], "prometheusRecordingRule": [] - }, - "efs": { - "enabled": true, - "mountPath": "/test" } }, "extraResources": { diff --git a/src/test/java/com/navi/infra/portal/service/KubernetesManifestServiceTest.java b/src/test/java/com/navi/infra/portal/service/KubernetesManifestServiceTest.java index 0e9a9c28..90a3d8f7 100644 --- a/src/test/java/com/navi/infra/portal/service/KubernetesManifestServiceTest.java +++ b/src/test/java/com/navi/infra/portal/service/KubernetesManifestServiceTest.java @@ -77,6 +77,7 @@ public class KubernetesManifestServiceTest { @ParameterizedTest(name = "{index} => test case=''{0}''") @CsvSource({ "manifest_alb.json,kube_object_alb.json", + "manifest_efs_pvc.json,kube_object_efs_pvc.json", "manifest_alb_redirect.json,kube_object_alb_redirect.json", "manifest_alb_sg.json,kube_object_alb_sg.json", "manifest_custom_alerts.json,kube_object_custom_alerts.json", diff --git a/src/test/resources/fixtures/kube_objects/kube_object_efs_pvc.json b/src/test/resources/fixtures/kube_objects/kube_object_efs_pvc.json new file mode 100644 index 00000000..b76c5931 --- /dev/null +++ b/src/test/resources/fixtures/kube_objects/kube_object_efs_pvc.json @@ -0,0 +1,615 @@ +{ + "namespace": "dev-internal", + "cluster": "nonprod.np.navi-tech.in", + "kubeObject": { + "apiVersion": "v1", + "items": [ + { + "metadata": { + "name": "test-app-navi-service-secret", + "namespace": "dev-internal", + "labels": { + "app": "navi-service", + "Owner": "medici", + "micrometer-prometheus": "enabled", + "release": "test-app", + "Environment": "dev", + "Product": "lending", + "Team": "Infra", + "heritage": "NaviDeploymentManifest", + "chart": "navi-service-0.0.1", + "Name": "test-app", + "repo": "test", + "language": "Java", + "dataSensitivity": "PII_SPI", + "logCriticality": "AccessLogs", + "disasterRecovery":"True" + } + }, + "apiVersion": "v1", + "data": { + "password": "Zm9vYmFy", + "user": "bmFtZQ==" + }, + "kind": "Secret", + "type": "Opaque" + }, + { + "metadata": { + "name": "test-app-navi-service", + "namespace": "dev-internal", + "labels": { + "app": "navi-service", + "Owner": "medici", + "micrometer-prometheus": "enabled", + "release": "test-app", + "Environment": "dev", + "Product": "lending", + "Team": "Infra", + "heritage": "NaviDeploymentManifest", + "chart": "navi-service-0.0.1", + "Name": "test-app", + "repo": "test", + "language": "Java", + "dataSensitivity": "PII_SPI", + "logCriticality": "AccessLogs", + "disasterRecovery":"True" + } + }, + "apiVersion": "autoscaling.k8s.io\/v1", + "kind": "VerticalPodAutoscaler", + "spec": { + "targetRef": { + "apiVersion": "apps\/v1", + "kind": "Deployment", + "name": "test-app-navi-service" + }, + "resourcePolicy": { + "containerPolicies": [ + { + "containerName": "test-app-navi-service", + "minAllowed": { + "memory": "512Mi", + "cpu": "500m" + }, + "controlledResources": [ + "cpu", + "memory" + ] + }, + { + "mode": "Off", + "containerName": "*" + } + ] + } + } + }, + { + "metadata": { + "name": "test-app-navi-service", + "namespace": "dev-internal", + "annotations": { + "alb.ingress.kubernetes.io\/healthcheck-path": "\/actuator\/health", + "alb.ingress.kubernetes.io\/tags": "Environment=dev,Owner=medici,Name=test-app-navi-service,Team=Infra,Namespace=dev-internal", + "alb.ingress.kubernetes.io\/healthcheck-port": "4001" + }, + "labels": { + "app": "navi-service", + "Owner": "medici", + "micrometer-prometheus": "enabled", + "release": "test-app", + "Environment": "dev", + "Product": "lending", + "Team": "Infra", + "heritage": "NaviDeploymentManifest", + "chart": "navi-service-0.0.1", + "Name": "test-app", + "repo": "test", + "language": "Java", + "dataSensitivity": "PII_SPI", + "logCriticality": "AccessLogs", + "disasterRecovery":"True" + } + }, + "apiVersion": "v1", + "kind": "Service", + "spec": { + "selector": { + "app": "navi-service", + "release": "test-app" + }, + "ports": [ + { + "protocol": "TCP", + "port": 4001, + "name": "metrics", + "targetPort": 4001 + }, + { + "protocol": "TCP", + "port": 8080, + "name": "serviceport", + "targetPort": 8080 + } + ], + "type": "ClusterIP" + } + }, + { + "apiVersion": "apps/v1", + "kind": "Deployment", + "metadata": { + "annotations": { }, + "labels": { + "Environment": "dev", + "Name": "test-app", + "Owner": "medici", + "Product": "lending", + "Team": "Infra", + "app": "navi-service", + "chart": "navi-service-0.0.1", + "dataSensitivity": "PII_SPI", + "disasterRecovery": "True", + "heritage": "NaviDeploymentManifest", + "language": "Java", + "logCriticality": "AccessLogs", + "micrometer-prometheus": "enabled", + "release": "test-app", + "repo": "test" + }, + "name": "test-app-navi-service", + "namespace": "dev-internal" + }, + "spec": { + "progressDeadlineSeconds": 720, + "selector": { + "matchLabels": { + "app": "navi-service", + "release": "test-app" + } + }, + "strategy": { + "rollingUpdate": { + "maxSurge": "51%", + "maxUnavailable": 0 + }, + "type": "RollingUpdate" + }, + "template": { + "metadata": { + "annotations": { + "traffic.sidecar.istio.io/excludeInboundPorts": "4001,8080", + "traffic.sidecar.istio.io/includeInboundPorts": "*" + }, + "labels": { + "Environment": "dev", + "Name": "test-app", + "Owner": "medici", + "Product": "lending", + "Team": "Infra", + "app": "navi-service", + "chart": "navi-service-0.0.1", + "dataSensitivity": "PII_SPI", + "disasterRecovery": "True", + "heritage": "NaviDeploymentManifest", + "language": "Java", + "logCriticality": "AccessLogs", + "micrometer-prometheus": "enabled", + "release": "test-app", + "repo": "test" + } + }, + "spec": { + "containers": [ + { + "env": [ + { + "name": "password", + "valueFrom": { + "secretKeyRef": { + "key": "password", + "name": "test-app-navi-service-secret" + } + } + }, + { + "name": "user", + "valueFrom": { + "secretKeyRef": { + "key": "user", + "name": "test-app-navi-service-secret" + } + } + }, + { + "name": "secretMd5", + "value": "ca5855f61008767291e629652da57dc6" + } + ], + "image": "IMAGE", + "imagePullPolicy": "IfNotPresent", + "lifecycle": { + "preStop": { + "exec": { + "command": [ + "sleep", + "30" + ] + } + } + }, + "livenessProbe": { + "failureThreshold": 5, + "httpGet": { + "httpHeaders": [ ], + "path": "/actuator/health", + "port": 4001 + }, + "initialDelaySeconds": 60, + "periodSeconds": 30, + "successThreshold": 1 + }, + "name": "test-app-navi-service", + "ports": [ + { + "containerPort": 4001, + "protocol": "TCP" + }, + { + "containerPort": 8080, + "protocol": "TCP" + } + ], + "readinessProbe": { + "failureThreshold": 5, + "initialDelaySeconds": 60, + "periodSeconds": 30, + "successThreshold": 1, + "tcpSocket": { + "port": 8080 + } + }, + "resources": { + "limits": { + "cpu": 0.375, + "memory": "512Mi" + }, + "requests": { + "cpu": 0.25, + "memory": "512Mi" + } + }, + "volumeMounts": [ + { + "mountPath": "/test", + "name": "efs-persistent-storage" + } + ] + } + ], + "dnsConfig": { + "options": [ + { + "name": "ndots", + "value": "2" + } + ] + }, + "initContainers": null, + "terminationGracePeriodSeconds": 60, + "volumes": [ + { + "name": "efs-persistent-storage", + "persistentVolumeClaim": { + "claimName": "test-app-navi-service-efs" + } + } + ] + } + } + } + }, + { + "metadata": { + "name": "test-app-navi-service-alb", + "namespace": "dev-internal", + "annotations": { + "alb.ingress.kubernetes.io\/scheme": "internal", + "alb.ingress.kubernetes.io\/tags": "Environment=dev,Owner=medici,Name=test-app,Team=Infra,Namespace=dev-internal,Ingress=test-app-navi-service-alb,Product=lending", + "alb.ingress.kubernetes.io\/target-type": "ip", + "alb.ingress.kubernetes.io\/actions.ssl-redirect": "{\"Type\": \"redirect\", \"RedirectConfig\": { \"Protocol\": \"HTTPS\", \"Port\": \"443\", \"StatusCode\": \"HTTP_301\"}}", + "alb.ingress.kubernetes.io\/target-group-attributes": "slow_start.duration_seconds=30", + "alb.ingress.kubernetes.io\/ssl-policy": "ELBSecurityPolicy-TLS-1-2-2017-01", + "alb.ingress.kubernetes.io\/listen-ports": "[{ \"HTTPS\": 443 },{\"HTTP\": 80}]", + "alb.ingress.kubernetes.io\/subnets": "internal-lb-ap-south-1a.nonprod.np.navi-tech.in,internal-lb-ap-south-1b.nonprod.np.navi-tech.in", + "alb.ingress.kubernetes.io\/security-groups": "sg-0bc07e856d000a5f4,sg-01a64c085bfdb2cbb", + "alb.ingress.kubernetes.io\/load-balancer-attributes": "idle_timeout.timeout_seconds=60,access_logs.s3.enabled=true,access_logs.s3.bucket=navi-nonprod-lb-access-logs,access_logs.s3.prefix=test-app", + "alb.ingress.kubernetes.io\/certificate-arn": "arn:aws:acm:ap-south-1:571315076762:certificate\/a19c398a-639b-45ca-b885-4cf6002a16dc", + "kubernetes.io\/ingress.class": "alb", + "alb.ingress.kubernetes.io\/group.order": "100", + "alb.ingress.kubernetes.io\/group.name": "test-app-navi-service-alb-dev-internal" + }, + "labels": { + "app": "navi-service", + "Owner": "medici", + "micrometer-prometheus": "enabled", + "release": "test-app", + "Environment": "dev", + "Product": "lending", + "Team": "Infra", + "heritage": "NaviDeploymentManifest", + "chart": "navi-service-0.0.1", + "Name": "test-app", + "repo": "test", + "language": "Java", + "dataSensitivity": "PII_SPI", + "logCriticality": "AccessLogs", + "disasterRecovery":"True" + } + }, + "apiVersion": "networking.k8s.io\/v1", + "kind": "Ingress", + "spec": { + "rules": [ + { + "host": "dev-test-app.np.navi-tech.in", + "http": { + "paths": [ + { + "path": "\/*", + "backend": { + "service": { + "port": { + "name": "use-annotation" + }, + "name": "ssl-redirect" + } + }, + "pathType": "ImplementationSpecific" + }, + { + "backend": { + "service": { + "port": { + "number": 8080 + }, + "name": "test-app-navi-service" + } + }, + "pathType": "ImplementationSpecific" + } + ] + } + } + ] + } + }, + { + "metadata": { + "name": "test-app-navi-service-pdb", + "namespace": "dev-internal", + "labels": { + "app": "navi-service", + "Owner": "medici", + "micrometer-prometheus": "enabled", + "release": "test-app", + "Environment": "dev", + "Product": "lending", + "Team": "Infra", + "heritage": "NaviDeploymentManifest", + "chart": "navi-service-0.0.1", + "Name": "test-app", + "repo": "test", + "language": "Java", + "dataSensitivity": "PII_SPI", + "logCriticality": "AccessLogs", + "disasterRecovery":"True" + } + }, + "apiVersion": "policy\/v1beta1", + "kind": "PodDisruptionBudget", + "spec": { + "maxUnavailable": "15%", + "selector": { + "matchLabels": { + "app": "navi-service", + "release": "test-app" + } + } + } + }, + { + "metadata": { + "name": "test-app-navi-service", + "namespace": "dev-internal", + "labels": { + "app": "navi-service", + "Owner": "medici", + "micrometer-prometheus": "enabled", + "role": "alert-rules", + "release": "test-app", + "Environment": "dev", + "Product": "lending", + "Team": "Infra", + "heritage": "NaviDeploymentManifest", + "prometheus": "kube-prometheus", + "chart": "navi-service-0.0.1", + "Name": "test-app", + "repo": "test", + "language": "Java", + "dataSensitivity": "PII_SPI", + "logCriticality": "AccessLogs", + "disasterRecovery":"True" + } + }, + "apiVersion": "monitoring.coreos.com\/v1", + "kind": "PrometheusRule", + "spec": { + "groups": [ + { + "name": "test-app-navi-service-basic", + "rules": [ + { + "alert": "HighPodRestarts", + "annotations": { + "summary": "High Pod Restarts", + "description": "Namespace: dev-internal, AppName: test-app-navi-service; Pod restarted multiple times", + "runbook": "https:\/\/navihq.atlassian.net\/wiki\/spaces\/IN\/pages\/279937094\/Act+On+Pod+Alert" + }, + "expr": "sum(increase(kube_pod_container_status_restarts_total{namespace=\"dev-internal\", pod=~\"test-app-navi-service.*\"}[30m])) > 3", + "labels": { + "severity": "critical", + "appName": "test-app-navi-service", + "alertTeam": "Infra" + } + }, + { + "alert": "HighPodFailures", + "annotations": { + "summary": "High Pod Failures", + "description": "Namespace: dev-internal, AppName: test-app-navi-service; Pods were last terminated due to reason {{ $labels.reason }}", + "runbook": "https:\/\/navihq.atlassian.net\/wiki\/spaces\/IN\/pages\/279937094\/Act+On+Pod+Alert" + }, + "expr": "sum(increase(kube_pod_container_status_last_terminated_reason{namespace=\"dev-internal\", container=~\"test-app-navi-service.*\",reason !~ \"Completed|Evicted|OOMKilled\"}[3h])) by (reason,pod) > 2", + "labels": { + "severity": "warning", + "appName": "test-app-navi-service", + "alertTeam": "Infra" + } + }, + { + "alert": "FrequentPodOOMKilled", + "annotations": { + "summary": "High Pod Failures", + "description": "Namespace: dev-internal, AppName: test-app-navi-service; Pod: {{ $labels.pod }} is restarting multiple times because of OOMKilled", + "runbook": "https:\/\/navihq.atlassian.net\/wiki\/spaces\/IN\/pages\/279937094\/Act+On+Pod+Alert" + }, + "expr": "increase(kube_pod_container_status_restarts_total{namespace=\"dev-internal\", container=\"test-app-navi-service\"}[10m]) >= 2 AND ignoring(reason) kube_pod_container_status_last_terminated_reason{namespace=\"dev-internal\", container=\"test-app-navi-service\", reason=\"OOMKilled\"} > 0", + "labels": { + "severity": "critical", + "appName": "test-app-navi-service", + "alertTeam": "Infra" + } + }, + { + "alert": "PodOOMKilled", + "annotations": { + "summary": "Pod OOMKilled", + "description": "Namespace: dev-internal, AppName: test-app-navi-service; Pod: {{ $labels.pod }} killed because of OOMKilled", + "runbook": "https:\/\/navihq.atlassian.net\/wiki\/spaces\/IN\/pages\/279937094\/Act+On+Pod+Alert" + }, + "expr": "kube_pod_container_status_restarts_total{namespace=\"dev-internal\", container=\"test-app-navi-service\"} - kube_pod_container_status_restarts_total{namespace=\"dev-internal\", container=\"test-app-navi-service\"} offset 5m >= 1 AND ignoring(reason) kube_pod_container_status_last_terminated_reason{namespace=\"dev-internal\", container=\"test-app-navi-service\", reason=\"OOMKilled\"} > 0", + "labels": { + "severity": "warning", + "appName": "test-app-navi-service", + "alertTeam": "Infra" + } + }, + { + "alert": "KubeContainerWaiting", + "for": "1h", + "annotations": { + "summary": "container is waiting for too long", + "description": "Namespace: dev-internal, AppName: test-app-navi-service; container in waiting state for one hour", + "runbook": "https:\/\/navihq.atlassian.net\/wiki\/spaces\/IN\/pages\/279937094\/Act+On+Pod+Alert" + }, + "expr": "sum by (namespace, pod, container) (kube_pod_container_status_waiting_reason{container=\"test-app-navi-service\", namespace=\"dev-internal\"}) > 0", + "labels": { + "severity": "critical", + "appName": "test-app-navi-service", + "alertTeam": "Infra" + } + }, + { + "alert": "ReplicaUnavailableAlert", + "for": "15m", + "annotations": { + "summary": "Low desired replica count", + "description": "Namespace: dev-internal, AppName: test-app-navi-service; Not enough instances available since past 15m", + "runbook": "https:\/\/navihq.atlassian.net\/wiki\/spaces\/IN\/pages\/279937094\/Act+On+Pod+Alert" + }, + "expr": "(kube_deployment_status_replicas_available{deployment=\"test-app-navi-service\", namespace=\"dev-internal\"}) - ignoring(poddisruptionbudget, deployment) (kube_poddisruptionbudget_status_desired_healthy{poddisruptionbudget=\"test-app-navi-service-pdb\",namespace=\"dev-internal\"}) < 0", + "labels": { + "severity": "critical", + "appName": "test-app-navi-service", + "alertTeam": "Infra" + } + }, + { + "alert": "VPAUncappedTargetGreaterThanCappedTarget", + "annotations": { + "description": "Uncapped target is more than bounds Namespace:dev-internal; App:test-app-navi-service; ", + "summary": "Uncapped target is more than bounds, this means your service is requires lot more resources than what node may have" + }, + "labels": { + "severity": "warning", + "alertTeam": "Infra", + "appName": "test-app-navi-service" + }, + "for": "1m", + "expr": "kube_verticalpodautoscaler_status_recommendation_containerrecommendations_uncappedtarget{container=\"test-app-navi-service\"} / kube_verticalpodautoscaler_status_recommendation_containerrecommendations_target{container=\"test-app-navi-service\"} > 1" + } + ] + } + ] + } + }, + { + "metadata": { + "name": "test-app-navi-service", + "namespace": "dev-internal", + "annotations": {}, + "labels": { + "app": "navi-service", + "Owner": "medici", + "micrometer-prometheus": "enabled", + "release": "test-app", + "Environment": "dev", + "Product": "lending", + "Team": "Infra", + "heritage": "NaviDeploymentManifest", + "chart": "navi-service-0.0.1", + "Name": "test-app", + "repo": "test", + "language": "Java", + "dataSensitivity": "PII_SPI", + "logCriticality": "AccessLogs", + "disasterRecovery":"True" + } + }, + "apiVersion": "autoscaling\/v2beta2", + "kind": "HorizontalPodAutoscaler", + "spec": { + "maxReplicas": 2, + "minReplicas": 2, + "metrics": [], + "scaleTargetRef": { + "apiVersion": "apps\/v1", + "kind": "Deployment", + "name": "test-app-navi-service" + } + } + }, + { + "apiVersion": "v1", + "kind": "PersistentVolumeClaim", + "metadata": { + "name": "test-app-navi-service-efs" + }, + "spec": { + "accessModes": [ + "ReadWriteOnce" + ], + "resources": { + "requests": { + "storage": "1Mi" + } + }, + "storageClassName": "np-common" + } + } + ], + "kind": "List" + } +} diff --git a/src/test/resources/fixtures/kube_objects/manifest_efs_pvc.json b/src/test/resources/fixtures/kube_objects/manifest_efs_pvc.json new file mode 100644 index 00000000..b3e1af96 --- /dev/null +++ b/src/test/resources/fixtures/kube_objects/manifest_efs_pvc.json @@ -0,0 +1,104 @@ +{ + "version": 14, + "id": 43, + "name": "test-app", + "metadata": { + "repo": "test", + "language": "Java", + "product": "lending", + "dataSensitivity": "PII_SPI", + "logCriticality": "AccessLogs", + "disasterRecovery": "True" + }, + "environment": "dev", + "deployment": { + "efs": { + "enabled": true, + "mountPath": "/test", + "fileSystemName": "np-common" + }, + "isVpaEnabled": true, + "version": 14, + "id": 41, + "loadBalancers": [ + { + "version": 3, + "id": 100, + "endpoint": "dev-test-app.np.navi-tech.in", + "extraSecurityGroups": [], + "accessPolicies": [ + "internal", + "officeIp" + ], + "stickiness": false, + "idleTimeout": 60, + "slowStartDuration": 30, + "name": "", + "type": "alb" + } + ], + "healthChecks": { + "livenessCheck": { + "path": "/actuator/health", + "port": "metrics", + "type": "http", + "periodSeconds": 30, + "failureThreshold": 5, + "successThreshold": 1, + "initialDelaySeconds": 60 + }, + "readinessCheck": { + "port": "serviceport", + "type": "tcp", + "periodSeconds": 30, + "failureThreshold": 5, + "successThreshold": 1, + "initialDelaySeconds": 60 + } + }, + "instance": { + "cpu": 0.25, + "memory": "512Mi" + }, + "exposedPorts": [ + { + "name": "metrics", + "port": 4001 + }, + { + "name": "serviceport", + "port": 8080 + } + ], + "allowEgress": [ + "*.google.com" + ], + "hpa": { + "metrics": [], + "maxReplicas": 2, + "minReplicas": 2, + "custom_metrics": [] + }, + "namespace": "dev-internal", + "securityGroup": [] + }, + "infraVertical": "lending", + "environmentVariables": [ + { + "name": "password", + "value": "foobar", + "type": "SECRET", + "sha256": "c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2" + }, + { + "name": "user", + "value": "name", + "type": "CONFIG", + "sha256": "82a3537ff0dbce7eec35d69edc3a189ee6f17d82f353a553f9aa96cb0be3ce89" + } + ], + "team": { + "name": "Infra" + }, + "cluster": "nonprod.np.navi-tech.in" +} diff --git a/templates/efs_persistent_volume_claim.jsonnet b/templates/efs_persistent_volume_claim.jsonnet index 5505fbfe..c9785242 100644 --- a/templates/efs_persistent_volume_claim.jsonnet +++ b/templates/efs_persistent_volume_claim.jsonnet @@ -10,7 +10,10 @@ if ( deployment_util.isEfsSupported(deployment_manifest) && deployment_util.isEf apiVersion: 'v1', kind: 'PersistentVolumeClaim', metadata: { - name: chart.full_service_name(deployment_manifest.deployment.name) + '-efs', + name: chart.full_service_name(deployment_manifest.deployment.name) + '-efs', + labels: common.labels, + annotations: common.annotations, + namespace: deployment_manifest.deployment.namespace, }, spec: { accessModes: ['ReadWriteOnce'],