From f90ad05af54603a16b9ac290801ea7195928f5e4 Mon Sep 17 00:00:00 2001 From: Stanislav German-Evtushenko Date: Wed, 16 Apr 2025 18:54:20 +0900 Subject: [PATCH] cluster, helm: Add new Helm-chart "splice-info" This helm charts runs a simple web-server to provide static deployment and dynamic runtime information as JSON files. - Static deployment configuration is published as JSON under / - Runtime part supports fetching DSO information from Scan and publishes it under /runtime/dso.json Signed-off-by: Stanislav German-Evtushenko --- cluster/helm/local.mk | 3 +- cluster/helm/splice-info/Chart-template.yaml | 6 + .../templates/configmap-config.yaml | 12 ++ .../templates/configmap-content-static.yaml | 40 ++++++ .../splice-info/templates/deployment.yaml | 93 +++++++++++++ .../helm/splice-info/templates/service.yaml | 12 ++ cluster/helm/splice-info/values-template.yaml | 35 +++++ cluster/helm/splice-info/values.schema.json | 128 ++++++++++++++++++ 8 files changed, 328 insertions(+), 1 deletion(-) create mode 100644 cluster/helm/splice-info/Chart-template.yaml create mode 100644 cluster/helm/splice-info/templates/configmap-config.yaml create mode 100644 cluster/helm/splice-info/templates/configmap-content-static.yaml create mode 100644 cluster/helm/splice-info/templates/deployment.yaml create mode 100644 cluster/helm/splice-info/templates/service.yaml create mode 100644 cluster/helm/splice-info/values-template.yaml create mode 100644 cluster/helm/splice-info/values.schema.json diff --git a/cluster/helm/local.mk b/cluster/helm/local.mk index 923f8463a..bb056d0c0 100644 --- a/cluster/helm/local.mk +++ b/cluster/helm/local.mk @@ -16,7 +16,8 @@ app_charts := \ splice-splitwell-app \ splice-splitwell-web-ui \ splice-sv-node \ - splice-validator + splice-validator \ + splice-info HELM_VERSION_TAG := cluster/helm/.version-tag IMAGE_DIGESTS := cluster/helm/.image-digests diff --git a/cluster/helm/splice-info/Chart-template.yaml b/cluster/helm/splice-info/Chart-template.yaml new file mode 100644 index 000000000..77fc82a9d --- /dev/null +++ b/cluster/helm/splice-info/Chart-template.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: splice-info +version: VERSION_NUMBER +appVersion: VERSION_NUMBER + +description: "A simple web server that serves JSON files with deployment and runtime information." diff --git a/cluster/helm/splice-info/templates/configmap-config.yaml b/cluster/helm/splice-info/templates/configmap-config.yaml new file mode 100644 index 000000000..1dbb66516 --- /dev/null +++ b/cluster/helm/splice-info/templates/configmap-config.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-config + namespace: {{ .Release.Namespace }} +data: + staticfile.conf: | + add_header Cache-Control no-cache; + + types { + {{ .Values.contentType }} html; + } diff --git a/cluster/helm/splice-info/templates/configmap-content-static.yaml b/cluster/helm/splice-info/templates/configmap-content-static.yaml new file mode 100644 index 000000000..58282c933 --- /dev/null +++ b/cluster/helm/splice-info/templates/configmap-content-static.yaml @@ -0,0 +1,40 @@ +{{- define "configmap-content-static" }} +deploymentInfo: + network: {{ .Values.deploymentDetails.network | quote }} + sv: + version: {{ .Values.deploymentDetails.sv.version | quote }} + configDigest: + {{- with .Values.deploymentDetails.configDigest }} + allowed-ip-ranges: {{ printf "%s:%s" .allowedIpRanges.type .allowedIpRanges.value | quote }} + approved-sv-id-values: {{ printf "%s:%s" .approvedSvIdentities.type .approvedSvIdentities.value | quote }} + {{- end }} + synchronizer: + {{- with .Values.deploymentDetails.synchronizer }} + active: + version: {{ .active.version | quote }} + migrationId: {{ .active.migrationId }} + chainIdSuffix: {{ .active.chainIdSuffix | quote }} + staging: + {{- if .staging }} + version: {{ .staging.version | quote }} + migrationId: {{ .staging.migrationId }} + chainIdSuffix: {{ .staging.chainIdSuffix | quote }} + {{- end }} + legacy: + {{- if .legacy }} + version: {{ .legacy.version | quote }} + migrationId: {{ .legacy.migrationId }} + chainIdSuffix: {{ .legacy.chainIdSuffix | quote }} + {{- end }} + {{- end }} +{{- end }} + +{{- if .Values.deploymentDetails }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-content-static + namespace: {{ .Release.Namespace }} +data: + index.html: {{ include "configmap-content-static" . | fromYaml | toJson | quote }} +{{- end }} diff --git a/cluster/helm/splice-info/templates/deployment.yaml b/cluster/helm/splice-info/templates/deployment.yaml new file mode 100644 index 000000000..3fd0d5004 --- /dev/null +++ b/cluster/helm/splice-info/templates/deployment.yaml @@ -0,0 +1,93 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} +spec: + replicas: 1 + selector: + matchLabels: + app: {{ .Release.Name }} + template: + metadata: + labels: + app: {{ .Release.Name }} + spec: + containers: + - name: nginx + image: {{ .Values.nginxImage }} + ports: + - containerPort: 80 + volumeMounts: + - name: config + mountPath: /etc/nginx/conf.d/staticfile.conf + subPath: staticfile.conf + {{- if .Values.deploymentDetails }} + - name: content-static + mountPath: /usr/share/nginx/html + {{- end }} + {{- if .Values.runtimeDetails }} + - name: content-runtime + mountPath: /usr/share/nginx/html/runtime + readOnly: true + {{- end }} + resources: + {{ toYaml .Values.resources | nindent 12 }} + {{- if .Values.runtimeDetails }} + - name: content-runtime-updater + image: {{ .Values.nginxImage }} + command: ["/bin/sh", "-c"] + args: + - | + set -eu; + + period=60; + + html_dir=/usr/share/nginx/html; + runtime_index_file="$html_dir/runtime/index.html"; + + dso_json_path=runtime/dso.json; + dso_json_file="$html_dir/$dso_json_path"; + + echo "{\"dso\": \"/$dso_json_path\"}" > "$runtime_index_file"; + + while true; do + start_time=$(date +%s); + exit_code=0; + + if curl -m 10 -fsS "$SCAN_URL/api/scan/v0/dso" > "$dso_json_file.new"; then + mv "$dso_json_file.new" "$dso_json_file"; + else + exit_code=$?; + echo "ERROR: Failed to fetch DSO from $SCAN_URL"; + fi; + + end_time=$(date +%s); + sleep "$((period - (end_time - start_time)))"; + + if [ "$exit_code" -ne 0 ]; then + exit $exit_code; + fi; + done; + env: + - name: SCAN_URL + value: {{ .Values.runtimeDetails.scanUrl | quote }} + volumeMounts: + - name: content-runtime + mountPath: /usr/share/nginx/html/runtime + {{- end }} + volumes: + - name: config + configMap: + name: {{ .Release.Name }}-config + {{- if .Values.deploymentDetails }} + - name: content-static + configMap: + name: {{ .Release.Name }}-content-static + {{- end }} + {{- if .Values.runtimeDetails }} + - name: content-runtime + emptyDir: + sizeLimit: 10Mi + medium: Memory + {{- end }} diff --git a/cluster/helm/splice-info/templates/service.yaml b/cluster/helm/splice-info/templates/service.yaml new file mode 100644 index 000000000..3f878150b --- /dev/null +++ b/cluster/helm/splice-info/templates/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }} + namespace: {{ .Release.Namespace }} +spec: + selector: + app: {{ .Release.Name }} + ports: + - protocol: TCP + port: 80 + targetPort: 80 diff --git a/cluster/helm/splice-info/values-template.yaml b/cluster/helm/splice-info/values-template.yaml new file mode 100644 index 000000000..54e963d8a --- /dev/null +++ b/cluster/helm/splice-info/values-template.yaml @@ -0,0 +1,35 @@ +nginxImage: nginx:latest # Replace `:latest` with `@sha256:digest` of a chosen image for security reasons +contentType: "application/json" + +# runtimeDetails: # optional, exposes the runtime configuration under path /runtime/ +# scanUrl: https://scan.sv.global.canton.network.xxx + +# deploymentDetails: # optional, exposes static configuration under path / +# network: "dev" +# configDigest: +# allowedIpRanges: +# type: "md5" +# value: "AAA" +# approvedSvIdentities: +# type: "sha256" +# value: "BBB" +# sv: +# version: "0.3.3" +# synchronizer: +# active: +# chainIdSuffix: "id0" +# migrationId: 4 +# version: "0.3.3" +# staging: +# chainIdSuffix: "id1" +# migrationId: 5 +# version: "0.3.4" +# legacy: null + +resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 250m + memory: 256Mi diff --git a/cluster/helm/splice-info/values.schema.json b/cluster/helm/splice-info/values.schema.json new file mode 100644 index 000000000..e7cbdadf1 --- /dev/null +++ b/cluster/helm/splice-info/values.schema.json @@ -0,0 +1,128 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$defs": { + "synchronizer": { + "type": "object", + "required": [ "chainIdSuffix", "migrationId", "version" ], + "additionalProperties": false, + "properties": { + "chainIdSuffix": { "type": "string", "minLength": 1 }, + "migrationId": { "type": "integer", "minimum": 0, "maximum": 9 }, + "version": { "type": "string", "minLength": 1 } + } + }, + "digest": { + "type": "object", + "required": [ "type", "value" ], + "additionalProperties": false, + "properties": { + "type": { "type": "string", "enum": ["md5", "sha1", "sha256"] }, + "value": { "type": "string", "minLength": 1 } + } + } + }, + "type": "object", + "required": [ "resources", "nginxImage", "contentType" ], + "properties": { + "nginxImage": { + "type": "string", + "description": "The Docker image to use for Nginx. Defaults to 'nginx:latest' if not present." + }, + "contentType": { + "type": "string", + "description": "The content type for the Nginx server. Defaults to 'application/json' if not present." + }, + "runtimeDetails": { + "type": "object", + "required": [ "scanUrl" ], + "additionalProperties": false, + "properties": { + "scanUrl": { "type": "string", "minLength": 1 } + } + }, + "deploymentDetails": { + "type": "object", + "required": [ "network", "configDigest", "sv", "synchronizer" ], + "additionalProperties": false, + "properties": { + "network": { + "type": "string", + "enum": ["dev", "test", "main"] + }, + "configDigest": { + "type": "object", + "required": [ "allowedIpRanges", "approvedSvIdentities" ], + "additionalProperties": false, + "properties": { + "allowedIpRanges": { "$ref": "#/$defs/digest" }, + "approvedSvIdentities": { "$ref": "#/$defs/digest" } + } + }, + "sv": { + "type": "object", + "required": ["version"], + "additionalProperties": false, + "properties": { + "version": { "type": "string", "minLength": 1 } + } + }, + "synchronizer": { + "type": "object", + "required": ["active"], + "additionalProperties": false, + "properties": { + "active": { + "$ref": "#/$defs/synchronizer" + }, + "legacy": { + "oneOf": [ + { "type": "null" }, + { "$ref": "#/$defs/synchronizer" } + ] + }, + "staging": { + "oneOf": [ + { "type": "null" }, + { "$ref": "#/$defs/synchronizer" } + ] + } + } + } + } + }, + "resources": { + "type": "object", + "required": [ "limits", "requests" ], + "properties": { + "limits": { + "type": "object", + "required": [ "cpu", "memory" ], + "properties": { + "cpu": { + "type": "string", + "description": "CPU limit (e.g., 500m)." + }, + "memory": { + "type": "string", + "description": "Memory limit (e.g., 512Mi)." + } + } + }, + "requests": { + "type": "object", + "required": [ "cpu", "memory" ], + "properties": { + "cpu": { + "type": "string", + "description": "CPU request (e.g., 250m)." + }, + "memory": { + "type": "string", + "description": "Memory request (e.g., 256Mi)." + } + } + } + } + } + } +}