diff --git a/datadog/metric/metric b/datadog/metric/metric index 946f3adf..244c7bcb 100755 --- a/datadog/metric/metric +++ b/datadog/metric/metric @@ -263,41 +263,43 @@ transform_response() { echo "$response" | jq ' (.data.attributes.times // []) as $times | (.data.attributes.values // [[]]) as $values | - (.data.attributes.series // []) | map({ - selector: ( - if .group_tags then - if (.group_tags | type) == "array" then - if (.group_tags | length) == 0 then - {} + (.data.attributes.series // []) | to_entries | map( + .key as $idx | + .value | { + selector: ( + if .group_tags then + if (.group_tags | type) == "array" then + if (.group_tags | length) == 0 then + {} + else + # Convert array of "key:value" strings to object + .group_tags | map(split(":") | {(.[0]): .[1]}) | add + end else - # Convert array of "key:value" strings to object - .group_tags | map(split(":") | {(.[0]): .[1]}) | add + .group_tags + end + elif .scope then + if (.scope | type) == "string" then + .scope | split(",") | map(split(":") | {(.[0]): .[1]}) | add + else + .scope end else - .group_tags + {} end - elif .scope then - if (.scope | type) == "string" then - .scope | split(",") | map(split(":") | {(.[0]): .[1]}) | add + ), + data: ( + if ($values | length) > 0 and ($times | length) > 0 then + [range($times | length)] | map({ + timestamp: ($times[.] / 1000 | todate), + value: ($values[$idx][.] // 0) + }) else - .scope + [] end - else - {} - end - ) - } + { - data: ( - if ($values | length) > 0 and ($times | length) > 0 then - [range($times | length)] | map({ - timestamp: ($times[.] / 1000 | todate), - value: $values[0][.] - }) - else - [] - end - ) - })' + ) + } + )' } transformed_results=$(transform_response "$response") diff --git a/k8s/deployment/notify_active_domains b/k8s/deployment/notify_active_domains new file mode 100644 index 00000000..9f32c231 --- /dev/null +++ b/k8s/deployment/notify_active_domains @@ -0,0 +1,17 @@ +#!/bin/bash + +set -euo pipefail + +DOMAINS=$(echo "$CONTEXT" | jq .scope.domains) + +if [[ "$DOMAINS" == "null" || "$DOMAINS" == "[]" ]]; then + return +fi + +echo "$DOMAINS" | jq -r '.[] | "\(.id)|\(.name)"' | while IFS='|' read -r domain_id domain_name; do + echo "Configuring domain: $domain_name" + + np scope domain patch --id "$domain_id" --body '{"status": "active"}' + + echo "Successfully configured domain: $domain_name" +done \ No newline at end of file diff --git a/k8s/deployment/templates/blue-green-ingress.yaml.tpl b/k8s/deployment/templates/blue-green-ingress.yaml.tpl index 314de1fe..f33ca37d 100644 --- a/k8s/deployment/templates/blue-green-ingress.yaml.tpl +++ b/k8s/deployment/templates/blue-green-ingress.yaml.tpl @@ -80,3 +80,117 @@ spec: port: name: use-annotation {{- end }} + +{{ if .scope.capabilities.additional_ports }} +{{ range .scope.capabilities.additional_ports }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: k-8-s-{{ $.scope.slug }}-{{ $.scope.id }}-{{ if eq .type "HTTP" }}http{{ else }}grpc{{ end }}-{{ .port }}-{{ $.ingress_visibility }} + namespace: {{ $.k8s_namespace }} + labels: + nullplatform: "true" + account: {{ $.account.slug }} + account_id: "{{ $.account.id }}" + namespace: {{ $.namespace.slug }} + namespace_id: "{{ $.namespace.id }}" + application: {{ $.application.slug }} + application_id: "{{ $.application.id }}" + scope: {{ $.scope.slug }} + scope_id: "{{ $.scope.id }}" +{{- $global := index $.k8s_modifiers "global" }} +{{- if $global }} + {{- $labels := index $global "labels" }} + {{- if $labels }} +{{ data.ToYAML $labels | indent 4 }} + {{- end }} +{{- end }} +{{- $ingress := index $.k8s_modifiers "ingress" }} +{{- if $ingress }} + {{- $labels := index $ingress "labels" }} + {{- if $labels }} +{{ data.ToYAML $labels | indent 4 }} + {{- end }} +{{- end }} + annotations: + alb.ingress.kubernetes.io/actions.bg-deployment-{{ if eq .type "HTTP" }}http{{ else }}grpc{{ end }}-{{ .port }}: >- + {"type":"forward","forwardConfig":{"targetGroups":[ + {"serviceName":"d-{{ $.scope.id }}-{{ $.blue_deployment_id }}-{{ if eq .type "HTTP" }}http{{ else }}grpc{{ end }}-{{ .port }}","servicePort":{{ .port }},"weight":{{ sub 100 $.deployment.strategy_data.desired_switched_traffic }}}, + {"serviceName":"d-{{ $.scope.id }}-{{ $.deployment.id }}-{{ if eq .type "HTTP" }}http{{ else }}grpc{{ end }}-{{ .port }}","servicePort":{{ .port }},"weight":{{ $.deployment.strategy_data.desired_switched_traffic }}} + ]}} + alb.ingress.kubernetes.io/actions.response-404: '{"type":"fixed-response","fixedResponseConfig":{"contentType":"text/plain","statusCode":"404","messageBody":"404 scope not found or has not been deployed yet"}}' + alb.ingress.kubernetes.io/group.name: {{ $.alb_name }} + alb.ingress.kubernetes.io/load-balancer-name: {{ $.alb_name }} + alb.ingress.kubernetes.io/scheme: {{ $.ingress_visibility }} + alb.ingress.kubernetes.io/target-node-labels: account={{ $.account.slug }},namespace={{ $.namespace.slug }},application={{ $.application.slug }},account_id={{ $.account.id }},namespace_id={{ $.namespace.id }},application_id={{ $.application.id }},scope={{ $.scope.slug }},scope_id={{ $.scope.id }},nullplatform=true + alb.ingress.kubernetes.io/target-type: ip + {{ if eq .type "HTTP" }} + alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80},{"HTTPS":443}]' + alb.ingress.kubernetes.io/ssl-redirect: "443" + {{ else if eq .type "GRPC" }} + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":{{ .port }}}]' + alb.ingress.kubernetes.io/backend-protocol-version: GRPC + alb.ingress.kubernetes.io/load-balancer-attributes: routing.http2.enabled=true +{{- $global := index $.k8s_modifiers "global" }} +{{- if $global }} + {{- $annotations := index $global "annotations" }} + {{- if $annotations }} +{{ data.ToYAML $annotations | indent 4 }} + {{- end }} +{{- end }} +{{- $ingress := index $.k8s_modifiers "ingress" }} +{{- if $ingress }} + {{- $annotations := index $ingress "annotations" }} + {{- if $annotations }} +{{ data.ToYAML $annotations | indent 4 }} + {{- end }} +{{- end }} + {{ end }} +spec: + ingressClassName: alb + rules: + - host: {{ $.scope.domain }} + http: + paths: + {{ if eq .type "HTTP" }} + - path: /{{ .port }} + pathType: Prefix + backend: + service: + name: bg-deployment-{{ if eq .type "HTTP" }}http{{ else }}grpc{{ end }}-{{ .port }} + port: + name: use-annotation + {{ else if eq .type "GRPC" }} + - path: / + pathType: Prefix + backend: + service: + name: bg-deployment-{{ if eq .type "HTTP" }}http{{ else }}grpc{{ end }}-{{ .port }} + port: + name: use-annotation + {{ end }} +{{- range $.scope.domains }} + - host: {{ .name }} + http: + paths: + {{ if eq $.type "HTTP" }} + - path: /{{ $.port }} + pathType: Prefix + backend: + service: + name: bg-deployment-{{ if eq $.type "HTTP" }}http{{ else }}grpc{{ end }}-{{ $.port }} + port: + name: use-annotation + {{ else if eq $.type "GRPC" }} + - path: / + pathType: Prefix + backend: + service: + name: bg-deployment-{{ if eq $.type "HTTP" }}http{{ else }}grpc{{ end }}-{{ $.port }} + port: + name: use-annotation + {{ end }} +{{- end }} +{{ end }} +{{ end }} diff --git a/k8s/deployment/templates/deployment.yaml.tpl b/k8s/deployment/templates/deployment.yaml.tpl index 17b74e67..172e3a30 100644 --- a/k8s/deployment/templates/deployment.yaml.tpl +++ b/k8s/deployment/templates/deployment.yaml.tpl @@ -112,7 +112,7 @@ spec: - name: http securityContext: runAsUser: 0 - image: public.ecr.aws/nullplatform/k8s-traffic-manager:latest + image: {{ .traffic_image }} ports: - containerPort: 80 protocol: TCP @@ -158,6 +158,63 @@ spec: terminationMessagePath: /dev/termination-log terminationMessagePolicy: File imagePullPolicy: Always + + {{ if .scope.capabilities.additional_ports }} + {{ range .scope.capabilities.additional_ports }} + {{ if eq .type "GRPC" }} + - name: grpc-{{ .port }} + securityContext: + runAsUser: 0 + image: {{ $.traffic_image }} + ports: + - containerPort: {{ .port }} + protocol: TCP + env: + - name: HEALTH_CHECK_TYPE + value: grpc + - name: GRACE_PERIOD + value: '15' + - name: LISTENER_PROTOCOL + value: grpc + - name: LISTENER_PORT + value: '{{ .port }}' + resources: + limits: + cpu: 93m + memory: 64Mi + requests: + cpu: 31m + livenessProbe: + grpc: + port: {{ .port }} + timeoutSeconds: 5 + periodSeconds: 10 + initialDelaySeconds: {{ $.scope.capabilities.health_check.initial_delay_seconds }} + successThreshold: 1 + failureThreshold: 9 + readinessProbe: + grpc: + port: {{ .port }} + timeoutSeconds: 5 + periodSeconds: 10 + initialDelaySeconds: {{ $.scope.capabilities.health_check.initial_delay_seconds }} + successThreshold: 1 + failureThreshold: 3 + startupProbe: + grpc: + port: {{ .port }} + timeoutSeconds: 5 + periodSeconds: 10 + initialDelaySeconds: {{ $.scope.capabilities.health_check.initial_delay_seconds }} + successThreshold: 1 + failureThreshold: 90 + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + imagePullPolicy: Always + {{ end }} + {{ end }} + {{ end }} + - name: application envFrom: - secretRef: @@ -169,6 +226,12 @@ spec: ports: - containerPort: 8080 protocol: TCP + {{ if .scope.capabilities.additional_ports }} + {{ range .scope.capabilities.additional_ports }} + - containerPort: {{ .port }} + protocol: TCP + {{ end }} + {{ end }} resources: limits: cpu: {{ .scope.capabilities.cpu_millicores }}m diff --git a/k8s/deployment/templates/initial-ingress.yaml.tpl b/k8s/deployment/templates/initial-ingress.yaml.tpl index dbcdaa12..d2d099ac 100644 --- a/k8s/deployment/templates/initial-ingress.yaml.tpl +++ b/k8s/deployment/templates/initial-ingress.yaml.tpl @@ -74,4 +74,90 @@ spec: name: d-{{ $.scope.id }}-{{ $.deployment.id }} port: number: 8080 -{{- end }} \ No newline at end of file +{{- end }} +{{ if .scope.capabilities.additional_ports }} +{{ range .scope.capabilities.additional_ports }} +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: k-8-s-{{ $.scope.slug }}-{{ $.scope.id }}-{{ if eq .type "HTTP" }}http{{ else }}grpc{{ end }}-{{ .port }}-{{ $.ingress_visibility }} + namespace: {{ $.k8s_namespace }} + labels: + nullplatform: "true" + account: {{ $.account.slug }} + account_id: "{{ $.account.id }}" + namespace: {{ $.namespace.slug }} + namespace_id: "{{ $.namespace.id }}" + application: {{ $.application.slug }} + application_id: "{{ $.application.id }}" + scope: {{ $.scope.slug }} + scope_id: "{{ $.scope.id }}" +{{- $global := index $.k8s_modifiers "global" }} +{{- if $global }} + {{- $labels := index $global "labels" }} + {{- if $labels }} +{{ data.ToYAML $labels | indent 4 }} + {{- end }} +{{- end }} +{{- $ingress := index $.k8s_modifiers "ingress" }} +{{- if $ingress }} + {{- $labels := index $ingress "labels" }} + {{- if $labels }} +{{ data.ToYAML $labels | indent 4 }} + {{- end }} +{{- end }} + annotations: + alb.ingress.kubernetes.io/group.name: {{ $.alb_name }} + {{ if eq .type "HTTP" }} + alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80},{"HTTPS":443}]' + {{ else if eq .type "GRPC" }} + alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":{{ .port }}}]' + alb.ingress.kubernetes.io/backend-protocol-version: GRPC + alb.ingress.kubernetes.io/load-balancer-attributes: routing.http2.enabled=true + {{ end }} + alb.ingress.kubernetes.io/load-balancer-name: {{ $.alb_name }} + alb.ingress.kubernetes.io/scheme: {{ $.ingress_visibility }} + alb.ingress.kubernetes.io/target-node-labels: account={{ $.account.slug }},namespace={{ $.namespace.slug }},application={{ $.application.slug }},account_id={{ $.account.id }},namespace_id={{ $.namespace.id }},application_id={{ $.application.id }},scope={{ $.scope.slug }},scope_id={{ $.scope.id }},nullplatform=true + alb.ingress.kubernetes.io/target-type: ip +{{- $global := index $.k8s_modifiers "global" }} +{{- if $global }} + {{- $annotations := index $global "annotations" }} + {{- if $annotations }} +{{ data.ToYAML $annotations | indent 4 }} + {{- end }} +{{- end }} +{{- $ingress := index $.k8s_modifiers "ingress" }} +{{- if $ingress }} + {{- $annotations := index $ingress "annotations" }} + {{- if $annotations }} +{{ data.ToYAML $annotations | indent 4 }} + {{- end }} +{{- end }} +spec: + ingressClassName: alb + rules: + - host: {{ $.scope.domain }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: d-{{ $.scope.id }}-{{ $.deployment.id }}-{{ if eq .type "HTTP" }}http{{ else }}grpc{{ end }}-{{ .port }} + port: + number: {{ .port }} +{{- range $.scope.domains }} + - host: {{ .name }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: d-{{ $.scope.id }}-{{ $.deployment.id }}-{{ if eq .type "HTTP" }}http{{ else }}grpc{{ end }}-{{ .port }} + port: + number: {{ .port }} +{{- end }} +{{ end }} +{{ end }} diff --git a/k8s/deployment/templates/service.yaml.tpl b/k8s/deployment/templates/service.yaml.tpl index fafe0d81..30a788cc 100644 --- a/k8s/deployment/templates/service.yaml.tpl +++ b/k8s/deployment/templates/service.yaml.tpl @@ -66,4 +66,127 @@ spec: ipFamilies: - IPv4 ipFamilyPolicy: SingleStack - internalTrafficPolicy: Cluster \ No newline at end of file + internalTrafficPolicy: Cluster + +{{ if .scope.capabilities.additional_ports }} +{{ range .scope.capabilities.additional_ports }} +{{ if eq .type "HTTP" }} +--- +apiVersion: v1 +kind: Service +metadata: + name: d-{{ $.scope.id }}-{{ $.deployment.id }}-http-{{ .port }} + namespace: {{ $.k8s_namespace }} + labels: + name: d-{{ $.scope.id }}-{{ $.deployment.id }}-http-{{ .port }} + app.kubernetes.io/part-of: {{ $.namespace.slug }}-{{ $.application.slug }} + app.kubernetes.io/component: application + app.kubernetes.io/instance: {{ $.scope.slug }} + app.kubernetes.io/name: {{ $.scope.slug }} +{{- $global := index .k8s_modifiers "global" }} +{{- if $global }} + {{- $labels := index $global "labels" }} + {{- if $labels }} +{{ data.ToYAML $labels | indent 4 }} + {{- end }} +{{- end }} +{{- $service := index .k8s_modifiers "service" }} +{{- if $service }} + {{- $labels := index $service "labels" }} + {{- if $labels }} +{{ data.ToYAML $labels | indent 4 }} + {{- end }} +{{- end }} + annotations: + service.beta.openshift.io/serving-cert-secret-name: d-{{ $.scope.id }}-http-{{ .port }} + alb.ingress.kubernetes.io/healthcheck-interval-seconds: '{{ $.scope.capabilities.health_check.period_seconds }}' + alb.ingress.kubernetes.io/healthcheck-path: {{ $.scope.capabilities.health_check.path }} + alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '{{ $.scope.capabilities.health_check.timeout_seconds }}' + alb.ingress.kubernetes.io/healthy-threshold-count: '2' + alb.ingress.kubernetes.io/success-codes: 200-299 + alb.ingress.kubernetes.io/unhealthy-threshold-count: '3' + alb.ingress.kubernetes.io/backend-protocol: HTTP +{{- $global := index .k8s_modifiers "global" }} +{{- if $global }} + {{- $annotations := index $global "annotations" }} + {{- if $annotations }} +{{ data.ToYAML $annotations | indent 4 }} + {{- end }} +{{- end }} +{{- $service := index .k8s_modifiers "service" }} +{{- if $service }} + {{- $annotations := index $service "annotations" }} + {{- if $annotations }} +{{ data.ToYAML $annotations | indent 4 }} + {{- end }} +{{- end }} +spec: + ports: + - protocol: TCP + port: {{ .port }} + targetPort: {{ .port }} + selector: + nullplatform: "true" + account: {{ $.account.slug }} + account_id: "{{ $.account.id }}" + namespace: {{ $.namespace.slug }} + namespace_id: "{{ $.namespace.id }}" + application: {{ $.application.slug }} + application_id: "{{ $.application.id }}" + scope: {{ $.scope.slug }} + scope_id: "{{ $.scope.id }}" + deployment_id: "{{ $.deployment.id }}" + type: ClusterIP + sessionAffinity: None + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + internalTrafficPolicy: Cluster +{{ else if eq .type "GRPC" }} +--- +apiVersion: v1 +kind: Service +metadata: + name: d-{{ $.scope.id }}-{{ $.deployment.id }}-grpc-{{ .port }} + namespace: {{ $.k8s_namespace }} + labels: + name: d-{{ $.scope.id }}-{{ $.deployment.id }}-grpc-{{ .port }} + app.kubernetes.io/part-of: {{ $.namespace.slug }}-{{ $.application.slug }} + app.kubernetes.io/component: application + app.kubernetes.io/instance: {{ $.scope.slug }} + app.kubernetes.io/name: {{ $.scope.slug }} + annotations: + service.beta.openshift.io/serving-cert-secret-name: d-{{ $.scope.id }}-grpc-{{ .port }} + alb.ingress.kubernetes.io/healthcheck-interval-seconds: '10' + alb.ingress.kubernetes.io/healthcheck-path: /grpc.health.v1.Health/Check + alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '5' + alb.ingress.kubernetes.io/healthy-threshold-count: '2' + alb.ingress.kubernetes.io/success-codes: '0' + alb.ingress.kubernetes.io/unhealthy-threshold-count: '3' + alb.ingress.kubernetes.io/backend-protocol-version: GRPC + alb.ingress.kubernetes.io/load-balancer-attributes: routing.http2.enabled=true +spec: + ports: + - protocol: TCP + port: {{ .port }} + targetPort: {{ .port }} + selector: + nullplatform: "true" + account: {{ $.account.slug }} + account_id: "{{ $.account.id }}" + namespace: {{ $.namespace.slug }} + namespace_id: "{{ $.namespace.id }}" + application: {{ $.application.slug }} + application_id: "{{ $.application.id }}" + scope: {{ $.scope.slug }} + scope_id: "{{ $.scope.id }}" + deployment_id: "{{ $.deployment.id }}" + type: ClusterIP + sessionAffinity: None + ipFamilies: + - IPv4 + ipFamilyPolicy: SingleStack + internalTrafficPolicy: Cluster +{{ end }} +{{ end }} +{{ end }} diff --git a/k8s/deployment/workflows/initial.yaml b/k8s/deployment/workflows/initial.yaml index 01bbf01b..fc225f4d 100644 --- a/k8s/deployment/workflows/initial.yaml +++ b/k8s/deployment/workflows/initial.yaml @@ -51,8 +51,14 @@ steps: ACTION: apply DRY_RUN: false post: - name: wait deployment active - type: script - file: "$SERVICE_PATH/deployment/wait_deployment_active" - configuration: - TIMEOUT: DEPLOYMENT_MAX_WAIT_IN_SECONDS + name: deployment_checks + type: workflow + steps: + - name: notify_active_domains + type: script + file: "$SERVICE_PATH/deployment/notify_active_domains" + - name: wait deployment active + type: script + file: "$SERVICE_PATH/deployment/wait_deployment_active" + configuration: + TIMEOUT: DEPLOYMENT_MAX_WAIT_IN_SECONDS \ No newline at end of file