From dfd92fc05308747b4e9985c45a8951aeff446def Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 8 Aug 2025 14:16:43 +0000 Subject: [PATCH 1/7] Add helm chart including debug features first pass at helm chart for fastcs instances fix service name better port exposure for service.yaml add helm chart publishing remove service account creation from helm switch to using Charts folder with subfolders for charts add schema for fastcs-instance chart values.yaml publish chart values schemas publish chart values schemas add schema generation to pre-commit fixing the fastcs-instance chart schema add debug features to helm chart repair incorrect helm chart debug now working fix non-debug mode fix incorrect terminationGracePeriodSeconds add debug entrypoint move initCommand into values rename charts to remove "instance" --- .github/workflows/_helm.yml | 71 ++++++ .github/workflows/ci.yml | 8 +- .pre-commit-config.yaml | 10 +- Charts/fastcs-ioc/Chart.yaml | 8 + Charts/fastcs-ioc/values.schema.json | 300 +++++++++++++++++++++++ Charts/fastcs-ioc/values.yaml | 9 + Charts/fastcs/.helmignore | 23 ++ Charts/fastcs/Chart.yaml | 24 ++ Charts/fastcs/templates/_helpers.tpl | 51 ++++ Charts/fastcs/templates/clusterIP.tpl | 73 ++++++ Charts/fastcs/templates/pvcs.yaml | 20 ++ Charts/fastcs/templates/service.yaml | 51 ++++ Charts/fastcs/templates/statefulset.yaml | 178 ++++++++++++++ Charts/fastcs/values.schema.json | 285 +++++++++++++++++++++ Charts/fastcs/values.yaml | 248 +++++++++++++++++++ generate-schemas.sh | 15 ++ schemas/fastcs-ioc.schema.json | 1 + schemas/fastcs.schema.json | 1 + 18 files changed, 1374 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/_helm.yml create mode 100644 Charts/fastcs-ioc/Chart.yaml create mode 100644 Charts/fastcs-ioc/values.schema.json create mode 100644 Charts/fastcs-ioc/values.yaml create mode 100644 Charts/fastcs/.helmignore create mode 100644 Charts/fastcs/Chart.yaml create mode 100644 Charts/fastcs/templates/_helpers.tpl create mode 100644 Charts/fastcs/templates/clusterIP.tpl create mode 100644 Charts/fastcs/templates/pvcs.yaml create mode 100644 Charts/fastcs/templates/service.yaml create mode 100644 Charts/fastcs/templates/statefulset.yaml create mode 100644 Charts/fastcs/values.schema.json create mode 100644 Charts/fastcs/values.yaml create mode 100755 generate-schemas.sh create mode 120000 schemas/fastcs-ioc.schema.json create mode 120000 schemas/fastcs.schema.json diff --git a/.github/workflows/_helm.yml b/.github/workflows/_helm.yml new file mode 100644 index 000000000..33055ccc1 --- /dev/null +++ b/.github/workflows/_helm.yml @@ -0,0 +1,71 @@ +name: Package helm charts + +on: + workflow_call: + +env: + HELM_VERSION_TO_INSTALL: 3.14.3 + +jobs: + package-helm-charts: + name: Package and Push Helm Chart + runs-on: ubuntu-latest + environment: release + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install helm + uses: Azure/setup-helm@v3 + with: + version: ${{ env.HELM_VERSION_TO_INSTALL }} + + # Check that alpha/beta versions have the form X.Y.Z-alpha.A requried by Helm. + # An early check saves waiting for the entire build before finding a problem. + - name: Check helm version tag + if: ${{ github.ref_type == 'tag' }} + env: + VERSION: "${{ github.ref_name }}" + run: | + if [[ "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-alpha|-beta|-rc).*?$ ]]; then + echo "Valid version format: ${VERSION}" + else + echo "Invalid version: ${VERSION}. Expected: X.Y.Z or X.Y.Z-beta.1 or X.Y.Z-alpha.1" + exit 1 + fi + + - name: Package helm charts + env: + VERSION: "${{ github.ref_type == 'tag' && github.ref_name || '0.0.0' }}" + run: | + set -xe + + mkdir -p charts + for i in Charts/*; do + if [[ ${i} =~ ^.*-ioc$ ]]; then + echo "Skipping IOC schema chart: ${i}" + continue + fi + echo "Packaging chart: ${i}" + helm package -u --app-version ${VERSION} --version ${VERSION} ${i} + mv $(basename ${i})-*.tgz charts/ + done + + - name: Upload helm chart values schemas + uses: actions/upload-artifact@v4 + with: + name: helm-chart-schemas + path: schemas/ + + - name: Push tagged helm chart to registry + if: ${{ github.ref_type == 'tag' }} + run: | + set -x + + echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io/${{ github.repository_owner }} --username ${{ github.repository_owner }} --password-stdin + REGISTRY=oci://ghcr.io/diamondlightsource/charts + for i in charts/*.tgz; do + helm push "${i}" ${REGISTRY} + done diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9529f09e4..6f661fd49 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,6 +44,12 @@ jobs: if: needs.check.outputs.branch-pr == '' uses: ./.github/workflows/_dist.yml + helm: + uses: ./.github/workflows/_helm.yml + permissions: + contents: read + packages: write + pypi: if: github.ref_type == 'tag' needs: dist @@ -53,7 +59,7 @@ jobs: release: if: github.ref_type == 'tag' - needs: [dist, docs] + needs: [dist, docs, helm] uses: ./.github/workflows/_release.yml permissions: contents: write diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 60fc23f9a..deebb103e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,9 +1,10 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v5.0.0 hooks: - id: check-added-large-files - id: check-yaml + exclude: ^Charts/ - id: check-merge-conflict - id: end-of-file-fixer @@ -22,3 +23,10 @@ repos: entry: ruff format --force-exclude types: [python] require_serial: true + + - id: helm-schema + name: Generate Helm schema + entry: ./generate-schemas.sh + language: system + types: [yaml] + require_serial: true diff --git a/Charts/fastcs-ioc/Chart.yaml b/Charts/fastcs-ioc/Chart.yaml new file mode 100644 index 000000000..80f4400f3 --- /dev/null +++ b/Charts/fastcs-ioc/Chart.yaml @@ -0,0 +1,8 @@ +apiVersion: v2 +name: fastcs-ioc +version: 0.1.0 +# This chart allows generating a schema for the fastcs-ioc values file. +# fastcs-ioc schema is used by IOC instances which have fastcs +# as a dependency. +# +# This chart is never used except by helm-schema. diff --git a/Charts/fastcs-ioc/values.schema.json b/Charts/fastcs-ioc/values.schema.json new file mode 100644 index 000000000..67827a5a4 --- /dev/null +++ b/Charts/fastcs-ioc/values.schema.json @@ -0,0 +1,300 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "fastcs": { + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "affinity": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Affinity", + "description": "Affinity for the pod", + "required": [], + "title": "affinity", + "type": "object" + }, + "args": { + "description": "arguments to pass to the above command", + "items": { + "required": [], + "type": "string" + }, + "required": [], + "title": "args", + "type": "array" + }, + "baseIp": { + "default": "10.96.0.0/12", + "description": "Used by allocateIpFromName to allocate a fixed cluster IP for the service.\nThe default is the same for all DLS clusters.\n", + "pattern": "^(\\d{1,3}\\.){3}\\d{1,3}\\/\\d{1,2}$", + "required": [], + "title": "CIDR for services addresses.", + "type": "string" + }, + "ca_server_port": { + "default": 5064, + "description": "service port for Channel Access", + "required": [], + "title": "ca_server_port", + "type": "integer" + }, + "clusterIP": { + "default": "", + "format": "ipv4", + "required": [], + "title": "Override for the cluster IP - only needed if allocateIpFromName clashes", + "type": [ + "string", + "null" + ] + }, + "command": { + "description": "Command to run in the container (as array of arguments)", + "items": { + "required": [], + "type": "string" + }, + "required": [], + "title": "command", + "type": "array" + }, + "debugCommand": { + "description": "Command to run in the debug version of the container", + "items": { + "required": [], + "type": "string" + }, + "required": [], + "title": "debugCommand", + "type": "array" + }, + "developerMode": { + "default": false, + "description": "If true, the container will run in debug mode meaning:-\n - the entrypoint is sleep\n - a PVC is created and mounted over /venv with /venv copied into it\n - adds '-debug' suffix to the image name\n", + "required": [], + "title": "developerMode", + "type": "boolean" + }, + "extra_containers": { + "description": "adds addtional containers specified by image and command", + "items": { + "additionalProperties": false, + "properties": { + "command": { + "description": "Command to run in the container (as array of arguments)", + "required": [], + "type": "array" + }, + "image": { + "description": "Container image URI", + "format": "image", + "required": [], + "type": "string" + }, + "name": { + "description": "A name for the additional container", + "required": [], + "type": "string" + } + }, + "required": [ + "name", + "image", + "command" + ], + "type": "object" + }, + "required": [], + "title": "extra_containers", + "type": "array" + }, + "global": { + "description": "Global values are values that can be accessed from any chart or subchart by exactly the same name.", + "required": [], + "title": "global", + "type": "object" + }, + "image": { + "additionalProperties": false, + "properties": { + "pullPolicy": { + "default": "IfNotPresent", + "required": [], + "title": "pullPolicy", + "type": "string" + }, + "repository": { + "default": "", + "required": [], + "title": "repository", + "type": "string" + }, + "tag": { + "default": "", + "required": [], + "title": "tag", + "type": "string" + } + }, + "required": [ + "repository", + "pullPolicy", + "tag" + ], + "title": "image", + "type": "object" + }, + "initCommand": { + "description": "Command to run in the init container.\nDefaults to copying workspace and venv.\n", + "items": { + "required": [], + "type": "string" + }, + "required": [], + "title": "initCommand", + "type": "array" + }, + "iocConfig": { + "default": "/epics/ioc/config", + "description": "location of config folder (defaults to be the same as C++ IOCs)", + "required": [], + "title": "iocConfig", + "type": "string" + }, + "livenessProbe": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe", + "required": [], + "title": "livenessProbe", + "type": "object" + }, + "nodeSelector": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.NodeSelector", + "description": "Node selector for the pod", + "required": [], + "title": "nodeSelector", + "type": [ + "object", + "null" + ] + }, + "podAnnotations": { + "additionalProperties": false, + "required": [], + "title": "Pod Annotations", + "type": "object" + }, + "podLabels": { + "additionalProperties": false, + "required": [], + "title": "Pod Labels", + "type": "object" + }, + "podSecurityContext": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext", + "required": [], + "title": "Pod Security Context", + "type": "object" + }, + "pva_server_port": { + "default": 5075, + "description": "service port for PV Access", + "required": [], + "title": "pva_server_port", + "type": "integer" + }, + "readinessProbe": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe", + "required": [], + "title": "readinessProbe", + "type": "object" + }, + "resources": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements", + "required": [], + "title": "Resource limits and requests", + "type": "object" + }, + "securityContext": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext", + "required": [], + "title": "Container Security Context", + "type": "object" + }, + "service": { + "additionalProperties": false, + "description": "The service will be configured for Channel Access and PVA. Here you can override\nthe ports and also make this a LoadBalancer service if required.\n", + "properties": { + "ca_port": { + "default": 5064, + "required": [], + "title": "ca_port", + "type": "integer" + }, + "pva_port": { + "default": 5075, + "required": [], + "title": "pva_port", + "type": "integer" + }, + "type": { + "default": "ClusterIP", + "required": [], + "title": "type", + "type": "string" + } + }, + "required": [ + "type", + "ca_port", + "pva_port" + ], + "title": "service", + "type": "object" + }, + "tolerations": { + "description": "Tolerations for the pod", + "items": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Toleration", + "required": [], + "type": "object" + }, + "required": [], + "title": "tolerations", + "type": "array" + }, + "volumeMounts": { + "items": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.VolumeMount", + "required": [], + "type": "object" + }, + "required": [], + "title": "volumeMounts", + "type": "array" + }, + "volumes": { + "description": "Additional volumes to mount in the output Deployment definition.", + "items": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Volume", + "required": [], + "type": "object" + }, + "required": [], + "title": "volumes", + "type": "array" + } + }, + "required": [], + "title": "fastcs", + "type": "object" + }, + "global": { + "description": "Global values are values that can be accessed from any chart or subchart by exactly the same name.", + "required": [], + "title": "global", + "type": "object" + } + }, + "required": [], + "type": "object" +} diff --git a/Charts/fastcs-ioc/values.yaml b/Charts/fastcs-ioc/values.yaml new file mode 100644 index 000000000..5a346bb65 --- /dev/null +++ b/Charts/fastcs-ioc/values.yaml @@ -0,0 +1,9 @@ +# yaml-language-server: $schema=values.schema.json + +# @schema +# title: FastCS IOC Values +# description: Values for the FastCS IOC instance +# type: object +# $ref: ../fastcs/values.schema.json +# @schema +fastcs: {} diff --git a/Charts/fastcs/.helmignore b/Charts/fastcs/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/Charts/fastcs/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/Charts/fastcs/Chart.yaml b/Charts/fastcs/Chart.yaml new file mode 100644 index 000000000..a88bdc1d4 --- /dev/null +++ b/Charts/fastcs/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: fastcs +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/Charts/fastcs/templates/_helpers.tpl b/Charts/fastcs/templates/_helpers.tpl new file mode 100644 index 000000000..3a598e647 --- /dev/null +++ b/Charts/fastcs/templates/_helpers.tpl @@ -0,0 +1,51 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "fastcs.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "fastcs.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "fastcs.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "fastcs.labels" -}} +helm.sh/chart: {{ include "fastcs.chart" . }} +{{ include "fastcs.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "fastcs.selectorLabels" -}} +app.kubernetes.io/name: {{ include "fastcs.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} diff --git a/Charts/fastcs/templates/clusterIP.tpl b/Charts/fastcs/templates/clusterIP.tpl new file mode 100644 index 000000000..e1b43bec9 --- /dev/null +++ b/Charts/fastcs/templates/clusterIP.tpl @@ -0,0 +1,73 @@ + +{{- define "allocateIpFromName" -}} + {{- $name := printf "%s.%s" .name .namespace -}} + {{- $baseIpWithCIDR := .baseIp -}} + + {{- $startIp := .startIp | int -}} + {{- $conversion := atoi (adler32sum $name) -}} + + {{- $baseIpParts := split "/" $baseIpWithCIDR -}} + {{- $baseIp := index $baseIpParts "_0" -}} + {{- $cidrRange := index $baseIpParts "_1" | int -}} + + {{- $octets := split "." $baseIp -}} + {{- $firstOctet := index $octets "_0" | int -}} + {{- $secondOctet := index $octets "_1" | int -}} + {{- $thirdOctet := index $octets "_2" | int -}} + {{- $fourthOctet := index $octets "_3" | int -}} + + + {{- $totalIps := 1 }} + {{- $loopcnt:= sub 32 $cidrRange -}} + {{- range $i,$k := until ($loopcnt | int) }} + {{- $totalIps = mul $totalIps 2 }} + {{- end }} + + {{- $ipSuffix := add $startIp (mod $conversion $totalIps) -}} + + {{- $secondOctet := add $secondOctet (div $ipSuffix 65536) -}} + {{- $ipSuffix = mod $ipSuffix 65536 -}} + {{- $thirdOctet := add $thirdOctet (div $ipSuffix 256) -}} + {{- $fourthOctet := mod $ipSuffix 256 -}} + + {{- if gt $fourthOctet 255 }} + {{- $fourthOctet = mod $fourthOctet 256 -}} + {{- end }} + {{- if gt $thirdOctet 255 }} + {{- $thirdOctet = mod $thirdOctet 256 -}} + {{- $secondOctet = add $secondOctet 1 -}} + {{- end }} + {{- if gt $secondOctet 255 }} + {{- $secondOctet = mod $secondOctet 256 -}} + {{- end }} + + {{- printf "%d.%d.%d.%d" $firstOctet $secondOctet $thirdOctet $fourthOctet -}} +{{- end -}} + + +{{- define "allocateIpFromNames" -}} + {{- $name := printf "%s.%s" .name .namespace -}} + {{- $baseIpWithCIDR := .baseIp -}} + + {{- $startIp := .startIp | int -}} + {{- $conversion := atoi (adler32sum $name) -}} + + {{- $baseIpParts := split "/" $baseIpWithCIDR -}} + {{- $baseIp := index $baseIpParts "_0" -}} + {{- $cidrRange := index $baseIpParts "_1" | int -}} + + {{- $octets := split "." $baseIp -}} + {{- $firstOctet := index $octets "_0" | int -}} + {{- $secondOctet := index $octets "_1" | int -}} + {{- $thirdOctet := index $octets "_2" | int -}} + {{- $fourthOctet := index $octets "_3" | int -}} + + {{- $totalIps := 1 }} + {{- $loopcnt:= sub 32 $cidrRange -}} + {{- range $i,$k := until ($loopcnt | int) }} + {{- $totalIps = mul $totalIps 2 }} + {{- end }} + {{- printf "CIDR %d IPs %d" $cidrRange $totalIps -}} + + +{{- end -}} diff --git a/Charts/fastcs/templates/pvcs.yaml b/Charts/fastcs/templates/pvcs.yaml new file mode 100644 index 000000000..4e1e05358 --- /dev/null +++ b/Charts/fastcs/templates/pvcs.yaml @@ -0,0 +1,20 @@ +# PVC for debugging volume +{{ if .Values.developerMode }} +{{- $location := default .Values.global.location .Values.location | required "ERROR - You must supply location or global.location" -}} +{{- $ioc_group := default .Values.global.ioc_group .Values.ioc_group | required "ERROR - You must supply ioc_group or global.ioc_group" -}} + +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ .Release.Name }}-develop + labels: + app: {{ .Release.Name }} + location: {{ $location }} + ioc_group: {{ $ioc_group }} +spec: + accessModes: + - ReadWriteMany + resources: + requests: + storage: "1Gi" +{{- end }} diff --git a/Charts/fastcs/templates/service.yaml b/Charts/fastcs/templates/service.yaml new file mode 100644 index 000000000..4073818fc --- /dev/null +++ b/Charts/fastcs/templates/service.yaml @@ -0,0 +1,51 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Release.Name }} + labels: + {{- include "fastcs.labels" . | nindent 4 }} + app: {{ .Release.Name }} + location: {{ .Values.global.location }} + ioc_group: {{ .Values.global.ioc_group }} + is_ioc: "true" +spec: + selector: + app: {{ .Release.Name }} + {{- include "fastcs.selectorLabels" . | nindent 4 }} + type: {{ .Values.service.type }} + # allocate a fixed clusterIP for this service based on the service name + {{- $alloc_args := dict "name" .Release.Name "namespace" .Release.Namespace "baseIp" .Values.baseIp "startIp" .Values.startIp }} + clusterIP: {{ .Values.clusterIP | default (include "allocateIpFromName" $alloc_args) }} + ports: + - name: ca-server-tcp + port: {{ .Values.ca_server_port | default 5064 }} + targetPort: {{ .Values.ca_server_port | default 5064 }} + protocol: TCP + - name: ca-server-udp + port: {{ .Values.ca_server_port | default 5064 }} + targetPort: {{ .Values.ca_server_port | default 5064 }} + protocol: UDP + - name: ca-repeater-tcp + port: {{ add1 (.Values.ca_server_port | default 5064) }} + targetPort: {{ add1 (.Values.ca_server_port | default 5064) }} + protocol: TCP + - name: ca-repeater-udp + port: {{ add1 (.Values.ca_server_port | default 5064) }} + targetPort: {{ add1 (.Values.ca_server_port | default 5064) }} + protocol: UDP + - name: pva-server-tcp + port: {{ .Values.pva_server_port | default 5075 }} + targetPort: {{ .Values.pva_server_port | default 5075 }} + protocol: TCP + - name: pva-server-udp + port: {{ .Values.pva_server_port | default 5075 }} + targetPort: {{ .Values.pva_server_port | default 5075 }} + protocol: UDP + - name: pva-broadcast-tcp + port: {{ add1 (.Values.pva_server_port | default 5075) }} + targetPort: {{ add1 (.Values.pva_server_port | default 5075) }} + protocol: TCP + - name: pva-broadcast-udp + port: {{ add1 (.Values.pva_server_port | default 5075) }} + targetPort: {{ add1 (.Values.pva_server_port | default 5075) }} + protocol: UDP diff --git a/Charts/fastcs/templates/statefulset.yaml b/Charts/fastcs/templates/statefulset.yaml new file mode 100644 index 000000000..393a4f8ab --- /dev/null +++ b/Charts/fastcs/templates/statefulset.yaml @@ -0,0 +1,178 @@ +{{- /* +Default the derivable substitution values. + +This keeps the length of the values.txt file for each individual IOC +to a minimum +*/ -}} +{{- $location := default .Values.global.location .Values.location | required "ERROR - You must supply location or global.location" -}} +{{- $ioc_group := default .Values.global.ioc_group .Values.ioc_group | required "ERROR - You must supply ioc_group or global.ioc_group" -}} +{{- $opisClaim := default (print $ioc_group "-opi-claim") .Values.opisClaim -}} +{{- $runtimeClaim := default (print $ioc_group "-runtime-claim") .Values.runtimeClaim -}} +{{- $autosaveClaim := default (print $ioc_group "-autosave-claim") .Values.autosaveClaim -}} +{{- $image := .Values.image | required "ERROR - You must supply image." -}} + +{{- $enabled := eq .Values.global.enabled false | ternary false true -}} + +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ .Release.Name }} + labels: + location: {{ $location }} + ioc_group: {{ $ioc_group }} + enabled: {{ $enabled | quote }} + is_ioc: "true" + {{- include "fastcs.labels" . | nindent 4 }} +spec: + replicas: {{ $enabled | ternary 1 0 }} + selector: + matchLabels: + {{- include "fastcs.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + location: {{ $location }} + ioc_group: {{ $ioc_group }} + enabled: {{ $enabled | quote }} + is_ioc: "true" + {{- include "fastcs.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + # re-deploy in case the configMap has changed - use a random value + # unless the Commit Hash is supplied (by ArgoCD or helm command line) + rollme: {{ .Values.global.commitHash | default (randAlphaNum 5) | quote }} + spec: + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.developerMode }} + # add in an init container to copy out virtual environment and workspaces + initContainers: + - name: {{ .Release.Name }}-init-debug + image: "{{ .Values.image.repository }}-debug:{{ .Values.image.tag }}" + imagePullPolicy: IfNotPresent + resources: + {{- .Values.initResources | default .Values.resources | toYaml | nindent 12 }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.initCommand }} + command: + {{- toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: {{ .Release.Name }}-develop + mountPath: /dest + {{- end }} + containers: + {{- range .Values.extra_containers }} + - name: {{ .name }} + image: {{ .image }} + imagePullPolicy: {{ $.Values.image.pullPolicy }} + {{- with $.Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .command }} + command: + {{- . | toYaml | nindent 12 }} + {{- end }} + volumeMounts: + {{- with $.Values.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + - name: opis-volume + mountPath: /epics/opi + subPath: "{{ $.Release.Name }}" + - name: config-volume + mountPath: {{ $.Values.iocConfig }} + {{- if $.Values.developerMode }} + - name: {{ $.Release.Name }}-develop + mountPath: /dest + {{- end }} + {{- end }} + - name: {{ .Chart.Name }} + image: '{{ .Values.image.repository }}{{ ternary "-debug" "" .Values.developerMode }}:{{ .Values.image.tag }}' + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.developerMode }} + {{- with .Values.debugCommand }} + command: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- else }} + {{- with .Values.command }} + command: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.args }} + args: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- end }} + {{- with .livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + {{- with .Values.volumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + - name: opis-volume + mountPath: /epics/opi + subPath: "{{ .Release.Name }}" + - name: config-volume + mountPath: {{ .Values.iocConfig }} + {{- if .Values.developerMode }} + - name: {{ .Release.Name }}-develop + mountPath: /workspaces + subPath: workspaces + - name: {{ .Release.Name }}-develop + mountPath: /venv + subPath: venv + {{- end }} + volumes: + {{- with .Values.volumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + - name: opis-volume + persistentVolumeClaim: + claimName: {{ $opisClaim }} + - name: config-volume + configMap: + name: {{ .Release.Name }}-config + {{- if .Values.developerMode }} + - name: {{ .Release.Name }}-develop + persistentVolumeClaim: + claimName: {{ .Release.Name }}-develop + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/Charts/fastcs/values.schema.json b/Charts/fastcs/values.schema.json new file mode 100644 index 000000000..96933397a --- /dev/null +++ b/Charts/fastcs/values.schema.json @@ -0,0 +1,285 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "additionalProperties": false, + "properties": { + "affinity": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Affinity", + "description": "Affinity for the pod", + "required": [], + "title": "affinity", + "type": "object" + }, + "args": { + "description": "arguments to pass to the above command", + "items": { + "required": [], + "type": "string" + }, + "required": [], + "title": "args", + "type": "array" + }, + "baseIp": { + "default": "10.96.0.0/12", + "description": "Used by allocateIpFromName to allocate a fixed cluster IP for the service.\nThe default is the same for all DLS clusters.\n", + "pattern": "^(\\d{1,3}\\.){3}\\d{1,3}\\/\\d{1,2}$", + "required": [], + "title": "CIDR for services addresses.", + "type": "string" + }, + "ca_server_port": { + "default": 5064, + "description": "service port for Channel Access", + "required": [], + "title": "ca_server_port", + "type": "integer" + }, + "clusterIP": { + "default": "", + "format": "ipv4", + "required": [], + "title": "Override for the cluster IP - only needed if allocateIpFromName clashes", + "type": [ + "string", + "null" + ] + }, + "command": { + "description": "Command to run in the container (as array of arguments)", + "items": { + "required": [], + "type": "string" + }, + "required": [], + "title": "command", + "type": "array" + }, + "debugCommand": { + "description": "Command to run in the debug version of the container", + "items": { + "required": [], + "type": "string" + }, + "required": [], + "title": "debugCommand", + "type": "array" + }, + "developerMode": { + "default": false, + "description": "If true, the container will run in debug mode meaning:-\n - the entrypoint is sleep\n - a PVC is created and mounted over /venv with /venv copied into it\n - adds '-debug' suffix to the image name\n", + "required": [], + "title": "developerMode", + "type": "boolean" + }, + "extra_containers": { + "description": "adds addtional containers specified by image and command", + "items": { + "additionalProperties": false, + "properties": { + "command": { + "description": "Command to run in the container (as array of arguments)", + "required": [], + "type": "array" + }, + "image": { + "description": "Container image URI", + "format": "image", + "required": [], + "type": "string" + }, + "name": { + "description": "A name for the additional container", + "required": [], + "type": "string" + } + }, + "required": [ + "name", + "image", + "command" + ], + "type": "object" + }, + "required": [], + "title": "extra_containers", + "type": "array" + }, + "global": { + "description": "Global values are values that can be accessed from any chart or subchart by exactly the same name.", + "required": [], + "title": "global", + "type": "object" + }, + "image": { + "additionalProperties": false, + "properties": { + "pullPolicy": { + "default": "IfNotPresent", + "required": [], + "title": "pullPolicy", + "type": "string" + }, + "repository": { + "default": "", + "required": [], + "title": "repository", + "type": "string" + }, + "tag": { + "default": "", + "required": [], + "title": "tag", + "type": "string" + } + }, + "required": [ + "repository", + "pullPolicy", + "tag" + ], + "title": "image", + "type": "object" + }, + "initCommand": { + "description": "Command to run in the init container.\nDefaults to copying workspace and venv.\n", + "items": { + "required": [], + "type": "string" + }, + "required": [], + "title": "initCommand", + "type": "array" + }, + "iocConfig": { + "default": "/epics/ioc/config", + "description": "location of config folder (defaults to be the same as C++ IOCs)", + "required": [], + "title": "iocConfig", + "type": "string" + }, + "livenessProbe": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe", + "required": [], + "title": "livenessProbe", + "type": "object" + }, + "nodeSelector": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.NodeSelector", + "description": "Node selector for the pod", + "required": [], + "title": "nodeSelector", + "type": [ + "object", + "null" + ] + }, + "podAnnotations": { + "additionalProperties": false, + "required": [], + "title": "Pod Annotations", + "type": "object" + }, + "podLabels": { + "additionalProperties": false, + "required": [], + "title": "Pod Labels", + "type": "object" + }, + "podSecurityContext": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext", + "required": [], + "title": "Pod Security Context", + "type": "object" + }, + "pva_server_port": { + "default": 5075, + "description": "service port for PV Access", + "required": [], + "title": "pva_server_port", + "type": "integer" + }, + "readinessProbe": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe", + "required": [], + "title": "readinessProbe", + "type": "object" + }, + "resources": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements", + "required": [], + "title": "Resource limits and requests", + "type": "object" + }, + "securityContext": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext", + "required": [], + "title": "Container Security Context", + "type": "object" + }, + "service": { + "additionalProperties": false, + "description": "The service will be configured for Channel Access and PVA. Here you can override\nthe ports and also make this a LoadBalancer service if required.\n", + "properties": { + "ca_port": { + "default": 5064, + "required": [], + "title": "ca_port", + "type": "integer" + }, + "pva_port": { + "default": 5075, + "required": [], + "title": "pva_port", + "type": "integer" + }, + "type": { + "default": "ClusterIP", + "required": [], + "title": "type", + "type": "string" + } + }, + "required": [ + "type", + "ca_port", + "pva_port" + ], + "title": "service", + "type": "object" + }, + "tolerations": { + "description": "Tolerations for the pod", + "items": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Toleration", + "required": [], + "type": "object" + }, + "required": [], + "title": "tolerations", + "type": "array" + }, + "volumeMounts": { + "items": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.VolumeMount", + "required": [], + "type": "object" + }, + "required": [], + "title": "volumeMounts", + "type": "array" + }, + "volumes": { + "description": "Additional volumes to mount in the output Deployment definition.", + "items": { + "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Volume", + "required": [], + "type": "object" + }, + "required": [], + "title": "volumes", + "type": "array" + } + }, + "required": [], + "type": "object" +} diff --git a/Charts/fastcs/values.yaml b/Charts/fastcs/values.yaml new file mode 100644 index 000000000..b2e46c8cd --- /dev/null +++ b/Charts/fastcs/values.yaml @@ -0,0 +1,248 @@ +# yaml-language-server: $schema=values.schema.json + +# Default values for fastcs-instance chart. +# +# helm-schema annotations describe the schema for values files. +# see https://github.com/dadav/helm-schema +# Generate the values schema with `generate-schema.sh` +# +# This file itself adheres to the schema it describes (to help writing the annotations). + +# @schema +# title: image +# type: object +# @schema +image: + repository: "" + pullPolicy: IfNotPresent + tag: "" + +# @schema +# description: Command to run in the container (as array of arguments) +# type: array +# items: +# type: string +# required: false +# @schema +command: [] + +# @schema +# description: arguments to pass to the above command +# type: array +# items: +# type: string +# required: false +# @schema +args: [] + +# @schema +# description: Command to run in the debug version of the container +# type: array +# items: +# type: string +# required: false +# @schema +debugCommand: + - /bin/bash + - -c + - "sleep infinity" + +# @schema +# description: | +# Command to run in the init container. +# Defaults to copying workspace and venv. +# type: array +# items: +# type: string +# required: false +# @schema +initCommand: + - /bin/bash + - -c + - | + echo "running as account"; id + if [ -d /dest/venv ]; then + echo "Virtual environment already exists, skipping copy" + else + echo "Copying virtual env to the debugging volume" + cp -r /venv /dest/venv + echo "Copying workspaces to the debugging volume" + cp -r /workspaces /dest/workspaces + echo "Setting permissions on the debugging volume" + chmod -R o+rwX /dest/venv /dest/workspaces + fi + echo "Init container completed successfully" + +# @schema +# description: | +# If true, the container will run in debug mode meaning:- +# - the entrypoint is sleep +# - a PVC is created and mounted over /venv with /venv copied into it +# - adds '-debug' suffix to the image name +# type: boolean +# @schema +developerMode: false + +# @schema +# description: location of config folder (defaults to be the same as C++ IOCs) +# type: string +# required: false +# @schema +iocConfig: /epics/ioc/config + +# @schema +# description: service port for Channel Access +# type: integer +# required: false +# @schema +ca_server_port: 5064 +# @schema +# description: service port for PV Access +# type: integer +# required: false +# @schema +pva_server_port: 5075 + +# @schema +# title: CIDR for services addresses. +# description: | +# Used by allocateIpFromName to allocate a fixed cluster IP for the service. +# The default is the same for all DLS clusters. +# type: string +# pattern: ^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$ +# required: false +# @schema +baseIp: 10.96.0.0/12 +# @schema +# title: Override for the cluster IP - only needed if allocateIpFromName clashes +# type: [string, null] +# format: ipv4 +# required: false +# @schema +clusterIP: + +# @schema +# description: | +# The service will be configured for Channel Access and PVA. Here you can override +# the ports and also make this a LoadBalancer service if required. +# type: object +# required: false +# @schema +service: + type: ClusterIP + ca_port: 5064 + pva_port: 5075 + +# @schema +# description: adds addtional containers specified by image and command +# type: array +# items: +# type: object +# properties: +# name: +# type: string +# description: A name for the additional container +# image: +# type: string +# format: image +# description: Container image URI +# command: +# type: array +# description: Command to run in the container (as array of arguments) +# required: [name, image, command] +# additionalProperties: false +# @schema +extra_containers: [] + +# @schema +# title: Pod Annotations +# type: object +# @schema +podAnnotations: {} +# @schema +# title: Pod Labels +# type: object +# @schema +podLabels: {} + +# @schema +# title: Pod Security Context +# type: object +# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext +# @schema +podSecurityContext: {} + +# @schema +# title: Container Security Context +# type: object +# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext +# @schema +securityContext: {} + +# @schema +# title: Resource limits and requests +# type: object +# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements +# @schema +resources: {} + +# @schema +# title: livenessProbe +# type: object +# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe +# @schema +livenessProbe: {} +# @schema +# title: readinessProbe +# type: object +# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe +# @schema +readinessProbe: {} + +# @schema +# title: volumes +# description: Additional volumes to mount in the output Deployment definition. +# type: array +# items: +# type: object +# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Volume +# @schema +volumes: [] + +# @schema +# title: volumeMounts +# type: array +# items: +# type: object +# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.VolumeMount +# @schema +volumeMounts: [] + +# TODO - I had problems with schema checking at helm chart ArgoCD deploy time +# TODO - it seemed that {} for nodeSelector was illegal, so I added null as an option +# TODO - I'm not sure why this was needed but not for other object fields with k8s schemas +# @schema +# title: nodeSelector +# description: Node selector for the pod +# type: [object, null] +# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.NodeSelector +# @schema +nodeSelector: + +# @schema +# title: tolerations +# description: Tolerations for the pod +# type: array +# items: +# type: object +# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Toleration +# @schema +tolerations: [] + +# @schema +# title: affinity +# description: Affinity for the pod +# type: object +# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Affinity +# @schema +affinity: {} diff --git a/generate-schemas.sh b/generate-schemas.sh new file mode 100755 index 000000000..abe52114b --- /dev/null +++ b/generate-schemas.sh @@ -0,0 +1,15 @@ +#!/bin/env bash + +set -euo pipefail + +this_dir=$(dirname "$0") +cd "$this_dir" + +helm schema -v || helm plugin install https://github.com/dadav/helm-schema + +for chart in Charts/*; do + helm schema -c $chart + ln -fs ../$chart/values.schema.json schemas/$(basename $chart).schema.json + # add a newline to the end of the schema file for pre-commit compliance + echo >> schemas/$(basename $chart).schema.json +done diff --git a/schemas/fastcs-ioc.schema.json b/schemas/fastcs-ioc.schema.json new file mode 120000 index 000000000..ada6d0539 --- /dev/null +++ b/schemas/fastcs-ioc.schema.json @@ -0,0 +1 @@ +../Charts/fastcs-ioc/values.schema.json \ No newline at end of file diff --git a/schemas/fastcs.schema.json b/schemas/fastcs.schema.json new file mode 120000 index 000000000..80f78888e --- /dev/null +++ b/schemas/fastcs.schema.json @@ -0,0 +1 @@ +../Charts/fastcs/values.schema.json \ No newline at end of file From 023648e8203c2799f88fbacd23fa8e77dd3e3f6d Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 18 Aug 2025 15:18:52 +0000 Subject: [PATCH 2/7] switch schmema gen to helm-values-schema-json --- .github/workflows/_helm.yml | 10 +- .github/workflows/_tox.yml | 3 + .github/workflows/ci.yml | 2 +- .pre-commit-config.yaml | 11 +- Charts/README_CHARTS.md | 71 +++ Charts/fastcs-ioc/Chart.yaml | 8 - Charts/fastcs-ioc/values.schema.json | 300 ------------- Charts/fastcs-ioc/values.yaml | 9 - Charts/fastcs/.schema.config.yaml | 25 ++ Charts/fastcs/templates/pvcs.yaml | 2 +- Charts/fastcs/templates/statefulset.yaml | 20 +- Charts/fastcs/values.schema.json | 414 ++++++------------ Charts/fastcs/values.yaml | 219 +++------ Dockerfile | 8 + generate-schemas.sh | 15 - schemas/fastcs-ioc.schema.json | 1 - schemas/fastcs-service.schema.json | 12 + ....schema.json => fastcs-values.schema.json} | 0 18 files changed, 341 insertions(+), 789 deletions(-) create mode 100644 Charts/README_CHARTS.md delete mode 100644 Charts/fastcs-ioc/Chart.yaml delete mode 100644 Charts/fastcs-ioc/values.schema.json delete mode 100644 Charts/fastcs-ioc/values.yaml create mode 100644 Charts/fastcs/.schema.config.yaml delete mode 100755 generate-schemas.sh delete mode 120000 schemas/fastcs-ioc.schema.json create mode 100644 schemas/fastcs-service.schema.json rename schemas/{fastcs.schema.json => fastcs-values.schema.json} (100%) diff --git a/.github/workflows/_helm.yml b/.github/workflows/_helm.yml index 33055ccc1..ca1496f5a 100644 --- a/.github/workflows/_helm.yml +++ b/.github/workflows/_helm.yml @@ -10,7 +10,6 @@ jobs: package-helm-charts: name: Package and Push Helm Chart runs-on: ubuntu-latest - environment: release steps: - name: Checkout uses: actions/checkout@v4 @@ -43,7 +42,7 @@ jobs: set -xe mkdir -p charts - for i in Charts/*; do + for i in $(find Charts -type d -maxdepth 1 -mindepth 1); do if [[ ${i} =~ ^.*-ioc$ ]]; then echo "Skipping IOC schema chart: ${i}" continue @@ -57,15 +56,16 @@ jobs: uses: actions/upload-artifact@v4 with: name: helm-chart-schemas - path: schemas/ + path: schemas/* - name: Push tagged helm chart to registry + # TODO - switch to using https://github.com/helm/chart-releaser-action of maybe the docker action? if: ${{ github.ref_type == 'tag' }} run: | set -x echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io/${{ github.repository_owner }} --username ${{ github.repository_owner }} --password-stdin - REGISTRY=oci://ghcr.io/diamondlightsource/charts + REGISTRY=oci://ghcr.io/${{github.repository_owner }}/charts for i in charts/*.tgz; do - helm push "${i}" ${REGISTRY} + helm push "${i}" ${REGISTRY,,} done diff --git a/.github/workflows/_tox.yml b/.github/workflows/_tox.yml index a13536d3a..f01518107 100644 --- a/.github/workflows/_tox.yml +++ b/.github/workflows/_tox.yml @@ -18,5 +18,8 @@ jobs: - name: Install python packages uses: ./.github/actions/install_requirements + - name: Install helm plugins + run: helm plugin install https://github.com/losisin/helm-values-schema-json.git + - name: Run tox run: tox -e ${{ inputs.tox }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6f661fd49..be681822c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,7 +52,7 @@ jobs: pypi: if: github.ref_type == 'tag' - needs: dist + needs: [helm, dist] uses: ./.github/workflows/_pypi.yml permissions: id-token: write diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index deebb103e..80e22ba90 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,9 +24,10 @@ repos: types: [python] require_serial: true + - repo: https://github.com/losisin/helm-values-schema-json + rev: v2.2.1 + hooks: - id: helm-schema - name: Generate Helm schema - entry: ./generate-schemas.sh - language: system - types: [yaml] - require_serial: true + args: + - --config + - Charts/fastcs/.schema.config.yaml diff --git a/Charts/README_CHARTS.md b/Charts/README_CHARTS.md new file mode 100644 index 000000000..e4a14e77c --- /dev/null +++ b/Charts/README_CHARTS.md @@ -0,0 +1,71 @@ +# Charts + +This directory contains Helm charts for deploying FastCS services. + +TODO: The implementation of helm charts in this repo is intended to be general purpose and is a proposed solution for the `python-copier-template`. + +## Github Actions + +This folder works in tandem with [_helm.yml](../.github/workflows/_helm.yml) github actions workflow which: + +- Validates the stricter form of SemVer tag that helm requires. +- Finds all subfolders in the `Charts` directory and packages them as Helm charts. +- Publishes the packaged charts to ghcr.io/${{github.repository_owner }}/charts/CHART_NAME +- Uploads the contents of /schemas to artifacts (meaning they will be published to the release) + +This standalone Helm related workflow is independent of the rest of the workflows except that the _pypi workflow has _helm added to its `needs` in `ci.yml`, making sure we only publish to pypi with valid SemVer tags. + +TODO: for a project that publishes containers referred to by the helm chart, the `_containers.yml` workflow should be added to the `needs` of _helm in `ci.yml`. + +## Schema Generation + +Schema generation for charts' `values.yaml` is handled by [helm-values-schema-json](https://github.com/losisin/helm-values-schema-json). Which is in turn controlled by annotations in the default [values.yaml](fastcs/values.yaml) file. + +The generated schema file will be called `values.schema.json` and will be placed in the same directory as the `values.yaml` file and commited to the repo. This is done automatically by a [pre-commit hook](https://github.com/DiamondLightSource/FastCS/blob/8232393b38cc8e0eee00680e95c2ce06e7983ba6/.pre-commit-config.yaml#L27-L33). Therefore, when developing charts you can update schemas with: + +```bash +git add . ; pre-commit +``` + +Note that this standard name for the schema file means that it is packaged up with the helm chart and available for schema checks in ArgoCD for example. + +## schemas folder + +The schemas folder allows us to declare the schemas you want to publish to the release. + +It should contain: + +- A symlink to each of the `values.schema.json` files in the subfolders of `Charts`. The symlink should have a unique name, e.g. `fastcs-values.schema.json`, thus allowing multiple schemas to be published per repo. +- A service schema file which references the above and can be used to validate `values.yaml` in epics-containers services repos, where the these charts will be used as sub-charts. e.g. [fastcs-service.schema.json](../schemas/fastcs-service.schema.json) + +The service schema files are hand coded as they are extremely simple. The symlinks are also manually created at present. (both of these could potentially be automated). + +## Debuging/Development In-Cluster + +The `fastcs` helm chart has two variables to enable debugging/development in-cluster: + +- `editable`: When true: + - a PVC is created. + - The debug version of the container image is referenced. + - The contents of /workspaces and /venv are copied into the PVC. + - The venv from the debug image is an editable install of the project source code in /workspaces. + - The PVC folders are mounted over the corresponding folders in the container. +- `autostart`: + - When false, the container starts with PID 1 as sleep infinity. + - When true, the container starts with its normal entrypoint. + +In combination these flags can be used to debug or develop in-cluster. + +An initial demonstration script to use these features is provided in [debug.py](https://github.com/epics-containers/p47-services/blob/add-fastcs/debug.py) in the `p47-services` repo. + +This script will: + +- inspect the values of `editable` and `autostart` in the `values.yaml` file of the specified IOC (TODO: at present it uses the p47-services source code to do so but this should be determined from the cluster in future). +- port forward the debugpy port (5678) from the pod to localhost. +- If editable is true, it will mount the PVC locally using pv-mounter and open VSCode to the /workspaces/xxx folder. +- If autostart is false, it will exec into the container and launch debugpy to run the main program. +- If autostart is true, it will exec into the container and attach debugpy to PID 1. + +This then allows you to attach VSCode to debugpy in the cluster container and if 'editable' is true, edit the source code in VSCode and have the changes reflected. + +To attach to debugpy the following launch.json configuration is supplied in the [fastcs-example project](https://github.com/DiamondLightSource/fastcs-example/blob/77daed5f5a2bd01ab4c0e1d8c812e8754b254674/.vscode/launch.json#L7-L22). (this will also go in python-copier-template in future). diff --git a/Charts/fastcs-ioc/Chart.yaml b/Charts/fastcs-ioc/Chart.yaml deleted file mode 100644 index 80f4400f3..000000000 --- a/Charts/fastcs-ioc/Chart.yaml +++ /dev/null @@ -1,8 +0,0 @@ -apiVersion: v2 -name: fastcs-ioc -version: 0.1.0 -# This chart allows generating a schema for the fastcs-ioc values file. -# fastcs-ioc schema is used by IOC instances which have fastcs -# as a dependency. -# -# This chart is never used except by helm-schema. diff --git a/Charts/fastcs-ioc/values.schema.json b/Charts/fastcs-ioc/values.schema.json deleted file mode 100644 index 67827a5a4..000000000 --- a/Charts/fastcs-ioc/values.schema.json +++ /dev/null @@ -1,300 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "fastcs": { - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "affinity": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Affinity", - "description": "Affinity for the pod", - "required": [], - "title": "affinity", - "type": "object" - }, - "args": { - "description": "arguments to pass to the above command", - "items": { - "required": [], - "type": "string" - }, - "required": [], - "title": "args", - "type": "array" - }, - "baseIp": { - "default": "10.96.0.0/12", - "description": "Used by allocateIpFromName to allocate a fixed cluster IP for the service.\nThe default is the same for all DLS clusters.\n", - "pattern": "^(\\d{1,3}\\.){3}\\d{1,3}\\/\\d{1,2}$", - "required": [], - "title": "CIDR for services addresses.", - "type": "string" - }, - "ca_server_port": { - "default": 5064, - "description": "service port for Channel Access", - "required": [], - "title": "ca_server_port", - "type": "integer" - }, - "clusterIP": { - "default": "", - "format": "ipv4", - "required": [], - "title": "Override for the cluster IP - only needed if allocateIpFromName clashes", - "type": [ - "string", - "null" - ] - }, - "command": { - "description": "Command to run in the container (as array of arguments)", - "items": { - "required": [], - "type": "string" - }, - "required": [], - "title": "command", - "type": "array" - }, - "debugCommand": { - "description": "Command to run in the debug version of the container", - "items": { - "required": [], - "type": "string" - }, - "required": [], - "title": "debugCommand", - "type": "array" - }, - "developerMode": { - "default": false, - "description": "If true, the container will run in debug mode meaning:-\n - the entrypoint is sleep\n - a PVC is created and mounted over /venv with /venv copied into it\n - adds '-debug' suffix to the image name\n", - "required": [], - "title": "developerMode", - "type": "boolean" - }, - "extra_containers": { - "description": "adds addtional containers specified by image and command", - "items": { - "additionalProperties": false, - "properties": { - "command": { - "description": "Command to run in the container (as array of arguments)", - "required": [], - "type": "array" - }, - "image": { - "description": "Container image URI", - "format": "image", - "required": [], - "type": "string" - }, - "name": { - "description": "A name for the additional container", - "required": [], - "type": "string" - } - }, - "required": [ - "name", - "image", - "command" - ], - "type": "object" - }, - "required": [], - "title": "extra_containers", - "type": "array" - }, - "global": { - "description": "Global values are values that can be accessed from any chart or subchart by exactly the same name.", - "required": [], - "title": "global", - "type": "object" - }, - "image": { - "additionalProperties": false, - "properties": { - "pullPolicy": { - "default": "IfNotPresent", - "required": [], - "title": "pullPolicy", - "type": "string" - }, - "repository": { - "default": "", - "required": [], - "title": "repository", - "type": "string" - }, - "tag": { - "default": "", - "required": [], - "title": "tag", - "type": "string" - } - }, - "required": [ - "repository", - "pullPolicy", - "tag" - ], - "title": "image", - "type": "object" - }, - "initCommand": { - "description": "Command to run in the init container.\nDefaults to copying workspace and venv.\n", - "items": { - "required": [], - "type": "string" - }, - "required": [], - "title": "initCommand", - "type": "array" - }, - "iocConfig": { - "default": "/epics/ioc/config", - "description": "location of config folder (defaults to be the same as C++ IOCs)", - "required": [], - "title": "iocConfig", - "type": "string" - }, - "livenessProbe": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe", - "required": [], - "title": "livenessProbe", - "type": "object" - }, - "nodeSelector": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.NodeSelector", - "description": "Node selector for the pod", - "required": [], - "title": "nodeSelector", - "type": [ - "object", - "null" - ] - }, - "podAnnotations": { - "additionalProperties": false, - "required": [], - "title": "Pod Annotations", - "type": "object" - }, - "podLabels": { - "additionalProperties": false, - "required": [], - "title": "Pod Labels", - "type": "object" - }, - "podSecurityContext": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext", - "required": [], - "title": "Pod Security Context", - "type": "object" - }, - "pva_server_port": { - "default": 5075, - "description": "service port for PV Access", - "required": [], - "title": "pva_server_port", - "type": "integer" - }, - "readinessProbe": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe", - "required": [], - "title": "readinessProbe", - "type": "object" - }, - "resources": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements", - "required": [], - "title": "Resource limits and requests", - "type": "object" - }, - "securityContext": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext", - "required": [], - "title": "Container Security Context", - "type": "object" - }, - "service": { - "additionalProperties": false, - "description": "The service will be configured for Channel Access and PVA. Here you can override\nthe ports and also make this a LoadBalancer service if required.\n", - "properties": { - "ca_port": { - "default": 5064, - "required": [], - "title": "ca_port", - "type": "integer" - }, - "pva_port": { - "default": 5075, - "required": [], - "title": "pva_port", - "type": "integer" - }, - "type": { - "default": "ClusterIP", - "required": [], - "title": "type", - "type": "string" - } - }, - "required": [ - "type", - "ca_port", - "pva_port" - ], - "title": "service", - "type": "object" - }, - "tolerations": { - "description": "Tolerations for the pod", - "items": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Toleration", - "required": [], - "type": "object" - }, - "required": [], - "title": "tolerations", - "type": "array" - }, - "volumeMounts": { - "items": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.VolumeMount", - "required": [], - "type": "object" - }, - "required": [], - "title": "volumeMounts", - "type": "array" - }, - "volumes": { - "description": "Additional volumes to mount in the output Deployment definition.", - "items": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Volume", - "required": [], - "type": "object" - }, - "required": [], - "title": "volumes", - "type": "array" - } - }, - "required": [], - "title": "fastcs", - "type": "object" - }, - "global": { - "description": "Global values are values that can be accessed from any chart or subchart by exactly the same name.", - "required": [], - "title": "global", - "type": "object" - } - }, - "required": [], - "type": "object" -} diff --git a/Charts/fastcs-ioc/values.yaml b/Charts/fastcs-ioc/values.yaml deleted file mode 100644 index 5a346bb65..000000000 --- a/Charts/fastcs-ioc/values.yaml +++ /dev/null @@ -1,9 +0,0 @@ -# yaml-language-server: $schema=values.schema.json - -# @schema -# title: FastCS IOC Values -# description: Values for the FastCS IOC instance -# type: object -# $ref: ../fastcs/values.schema.json -# @schema -fastcs: {} diff --git a/Charts/fastcs/.schema.config.yaml b/Charts/fastcs/.schema.config.yaml new file mode 100644 index 000000000..ad2b1a94f --- /dev/null +++ b/Charts/fastcs/.schema.config.yaml @@ -0,0 +1,25 @@ +# .schema.yaml + +# Define input, output and source for $refs relative to repository root for pre-commit +values: + - Charts/fastcs/values.yaml + +output: Charts/fastcs/values.schema.json + +# bundle up references (don't do this as K8S refs are 500kb+) +bundleRoot: Charts +bundle: false + +# Include comments for the helm-docs plugin into the schema, to allow e.g. documentation in VSCode +useHelmDocs: false + +# Allow additional properties for eg. initResources, different types of volumes/volumeMounts +noAdditionalProperties: false + +schemaRoot: + title: FastCS Helm chart schema + description: Schema to allow validation of values passed to FastCS Helm chart + # No additional properties in schema root for tighter protection: + additionalProperties: false + +k8sSchemaVersion: v1.33.3 diff --git a/Charts/fastcs/templates/pvcs.yaml b/Charts/fastcs/templates/pvcs.yaml index 4e1e05358..1a2ce3737 100644 --- a/Charts/fastcs/templates/pvcs.yaml +++ b/Charts/fastcs/templates/pvcs.yaml @@ -1,5 +1,5 @@ # PVC for debugging volume -{{ if .Values.developerMode }} +{{ if .Values.editable }} {{- $location := default .Values.global.location .Values.location | required "ERROR - You must supply location or global.location" -}} {{- $ioc_group := default .Values.global.ioc_group .Values.ioc_group | required "ERROR - You must supply ioc_group or global.ioc_group" -}} diff --git a/Charts/fastcs/templates/statefulset.yaml b/Charts/fastcs/templates/statefulset.yaml index 393a4f8ab..4a3170d96 100644 --- a/Charts/fastcs/templates/statefulset.yaml +++ b/Charts/fastcs/templates/statefulset.yaml @@ -47,11 +47,13 @@ spec: # unless the Commit Hash is supplied (by ArgoCD or helm command line) rollme: {{ .Values.global.commitHash | default (randAlphaNum 5) | quote }} spec: + terminationGracePeriodSeconds: 2 + hostNetwork: {{ .Values.hostNetwork }} {{- with .Values.podSecurityContext }} securityContext: {{- toYaml . | nindent 8 }} {{- end }} - {{- if .Values.developerMode }} + {{- if .Values.editable }} # add in an init container to copy out virtual environment and workspaces initContainers: - name: {{ .Release.Name }}-init-debug @@ -72,7 +74,7 @@ spec: mountPath: /dest {{- end }} containers: - {{- range .Values.extra_containers }} + {{- range .Values.extraContainers }} - name: {{ .name }} image: {{ .image }} imagePullPolicy: {{ $.Values.image.pullPolicy }} @@ -93,25 +95,25 @@ spec: subPath: "{{ $.Release.Name }}" - name: config-volume mountPath: {{ $.Values.iocConfig }} - {{- if $.Values.developerMode }} + {{- if $.Values.editable }} - name: {{ $.Release.Name }}-develop mountPath: /dest {{- end }} {{- end }} - name: {{ .Chart.Name }} - image: '{{ .Values.image.repository }}{{ ternary "-debug" "" .Values.developerMode }}:{{ .Values.image.tag }}' + image: '{{ .Values.image.repository }}{{ ternary "-debug" "" .Values.editable }}:{{ .Values.image.tag }}' {{- with .Values.securityContext }} securityContext: {{- toYaml . | nindent 12 }} {{- end }} imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- if .Values.developerMode }} - {{- with .Values.debugCommand }} + {{- if .Values.autostart }} + {{- with .Values.command }} command: {{- toYaml . | nindent 12 }} {{- end }} {{- else }} - {{- with .Values.command }} + {{- with .Values.debugCommand }} command: {{- toYaml . | nindent 12 }} {{- end }} @@ -141,7 +143,7 @@ spec: subPath: "{{ .Release.Name }}" - name: config-volume mountPath: {{ .Values.iocConfig }} - {{- if .Values.developerMode }} + {{- if .Values.editable }} - name: {{ .Release.Name }}-develop mountPath: /workspaces subPath: workspaces @@ -159,7 +161,7 @@ spec: - name: config-volume configMap: name: {{ .Release.Name }}-config - {{- if .Values.developerMode }} + {{- if .Values.editable }} - name: {{ .Release.Name }}-develop persistentVolumeClaim: claimName: {{ .Release.Name }}-develop diff --git a/Charts/fastcs/values.schema.json b/Charts/fastcs/values.schema.json index 96933397a..06df0bd00 100644 --- a/Charts/fastcs/values.schema.json +++ b/Charts/fastcs/values.schema.json @@ -1,285 +1,151 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "additionalProperties": false, - "properties": { - "affinity": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Affinity", - "description": "Affinity for the pod", - "required": [], - "title": "affinity", - "type": "object" - }, - "args": { - "description": "arguments to pass to the above command", - "items": { - "required": [], - "type": "string" - }, - "required": [], - "title": "args", - "type": "array" - }, - "baseIp": { - "default": "10.96.0.0/12", - "description": "Used by allocateIpFromName to allocate a fixed cluster IP for the service.\nThe default is the same for all DLS clusters.\n", - "pattern": "^(\\d{1,3}\\.){3}\\d{1,3}\\/\\d{1,2}$", - "required": [], - "title": "CIDR for services addresses.", - "type": "string" - }, - "ca_server_port": { - "default": 5064, - "description": "service port for Channel Access", - "required": [], - "title": "ca_server_port", - "type": "integer" - }, - "clusterIP": { - "default": "", - "format": "ipv4", - "required": [], - "title": "Override for the cluster IP - only needed if allocateIpFromName clashes", - "type": [ - "string", - "null" - ] - }, - "command": { - "description": "Command to run in the container (as array of arguments)", - "items": { - "required": [], - "type": "string" - }, - "required": [], - "title": "command", - "type": "array" - }, - "debugCommand": { - "description": "Command to run in the debug version of the container", - "items": { - "required": [], - "type": "string" - }, - "required": [], - "title": "debugCommand", - "type": "array" - }, - "developerMode": { - "default": false, - "description": "If true, the container will run in debug mode meaning:-\n - the entrypoint is sleep\n - a PVC is created and mounted over /venv with /venv copied into it\n - adds '-debug' suffix to the image name\n", - "required": [], - "title": "developerMode", - "type": "boolean" - }, - "extra_containers": { - "description": "adds addtional containers specified by image and command", - "items": { - "additionalProperties": false, - "properties": { - "command": { - "description": "Command to run in the container (as array of arguments)", - "required": [], + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "FastCS Helm chart schema", + "description": "Schema to allow validation of values passed to FastCS Helm chart", + "type": "object", + "properties": { + "affinity": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/affinity.json", + "type": "object" + }, + "args": { + "description": "command args to pass to the production container", "type": "array" - }, - "image": { - "description": "Container image URI", - "format": "image", - "required": [], - "type": "string" - }, - "name": { - "description": "A name for the additional container", - "required": [], + }, + "autostart": { + "description": "editable and autostart are used for debugging and development in-cluster", + "type": "boolean" + }, + "baseIp": { + "description": "CIDR for services addresses.", + "type": "string", + "pattern": "^(\\d{1,3}\\.){3}\\d{1,3}\\/\\d{1,2}$" + }, + "ca_server_port": { + "description": "service port for Channel Access", + "type": "integer" + }, + "clusterIP": { + "description": "Override for the cluster IP - only needed if allocateIpFromName clashes", + "type": "null", + "pattern": "^(\\d{1,3}\\.){3}\\d{1,3}$" + }, + "command": { + "description": "command to run for the production container", + "type": "array" + }, + "debugCommand": { + "description": "command to run for the debugging (non- autostart) container", + "type": "array", + "items": { + "type": "string" + } + }, + "editable": { + "description": "editable and autostart are used for debugging and development in-cluster", + "type": "boolean" + }, + "extraContainers": { + "type": "array" + }, + "global": { + "description": "shared values for all services", + "type": "object", + "additionalProperties": true + }, + "hostNetwork": { + "description": "enable host networking for the pod", + "type": "boolean" + }, + "image": { + "description": "container image URI", + "type": "object", + "properties": { + "pullPolicy": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + } + } + }, + "initCommand": { + "description": "command to run in the init container for editable mode", + "type": "array", + "items": { + "type": "string" + } + }, + "iocConfig": { + "description": "path to the location of config folder (defaults to be the same as C++ IOCs)", "type": "string" - } }, - "required": [ - "name", - "image", - "command" - ], - "type": "object" - }, - "required": [], - "title": "extra_containers", - "type": "array" - }, - "global": { - "description": "Global values are values that can be accessed from any chart or subchart by exactly the same name.", - "required": [], - "title": "global", - "type": "object" - }, - "image": { - "additionalProperties": false, - "properties": { - "pullPolicy": { - "default": "IfNotPresent", - "required": [], - "title": "pullPolicy", - "type": "string" + "livenessProbe": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/container.json#/properties/livenessProbe", + "type": "object" }, - "repository": { - "default": "", - "required": [], - "title": "repository", - "type": "string" + "nodeSelector": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/podspec.json#/properties/nodeSelector", + "type": "object" }, - "tag": { - "default": "", - "required": [], - "title": "tag", - "type": "string" - } - }, - "required": [ - "repository", - "pullPolicy", - "tag" - ], - "title": "image", - "type": "object" - }, - "initCommand": { - "description": "Command to run in the init container.\nDefaults to copying workspace and venv.\n", - "items": { - "required": [], - "type": "string" - }, - "required": [], - "title": "initCommand", - "type": "array" - }, - "iocConfig": { - "default": "/epics/ioc/config", - "description": "location of config folder (defaults to be the same as C++ IOCs)", - "required": [], - "title": "iocConfig", - "type": "string" - }, - "livenessProbe": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe", - "required": [], - "title": "livenessProbe", - "type": "object" - }, - "nodeSelector": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.NodeSelector", - "description": "Node selector for the pod", - "required": [], - "title": "nodeSelector", - "type": [ - "object", - "null" - ] - }, - "podAnnotations": { - "additionalProperties": false, - "required": [], - "title": "Pod Annotations", - "type": "object" - }, - "podLabels": { - "additionalProperties": false, - "required": [], - "title": "Pod Labels", - "type": "object" - }, - "podSecurityContext": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext", - "required": [], - "title": "Pod Security Context", - "type": "object" - }, - "pva_server_port": { - "default": 5075, - "description": "service port for PV Access", - "required": [], - "title": "pva_server_port", - "type": "integer" - }, - "readinessProbe": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe", - "required": [], - "title": "readinessProbe", - "type": "object" - }, - "resources": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements", - "required": [], - "title": "Resource limits and requests", - "type": "object" - }, - "securityContext": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext", - "required": [], - "title": "Container Security Context", - "type": "object" - }, - "service": { - "additionalProperties": false, - "description": "The service will be configured for Channel Access and PVA. Here you can override\nthe ports and also make this a LoadBalancer service if required.\n", - "properties": { - "ca_port": { - "default": 5064, - "required": [], - "title": "ca_port", - "type": "integer" + "podAnnotations": { + "description": "Add annotations to the pod", + "type": "object" }, - "pva_port": { - "default": 5075, - "required": [], - "title": "pva_port", - "type": "integer" + "podLabels": { + "description": "Add labels to the pod", + "type": "object" }, - "type": { - "default": "ClusterIP", - "required": [], - "title": "type", - "type": "string" + "podSecurityContext": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/podspec.json#/properties/securityContext", + "type": "object" + }, + "pva_server_port": { + "description": "service port for PV Access", + "type": "integer" + }, + "readinessProbe": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/container.json#/properties/readinessProbe", + "type": "object" + }, + "resources": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/container.json#/properties/resources", + "type": "object" + }, + "securityContext": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/container.json#/properties/securityContext", + "type": "object" + }, + "service": { + "description": "The service will be configured for Channel Access and PVA.", + "type": "object", + "properties": { + "ca_port": { + "type": "integer" + }, + "pva_port": { + "type": "integer" + }, + "type": { + "type": "string" + } + } + }, + "tolerations": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/podspec.json#/properties/tolerations", + "type": "array" + }, + "volumeMounts": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/container.json#/properties/volumeMounts", + "type": "array" + }, + "volumes": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/podspec.json#/properties/volumes", + "type": "array" } - }, - "required": [ - "type", - "ca_port", - "pva_port" - ], - "title": "service", - "type": "object" - }, - "tolerations": { - "description": "Tolerations for the pod", - "items": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Toleration", - "required": [], - "type": "object" - }, - "required": [], - "title": "tolerations", - "type": "array" - }, - "volumeMounts": { - "items": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.VolumeMount", - "required": [], - "type": "object" - }, - "required": [], - "title": "volumeMounts", - "type": "array" }, - "volumes": { - "description": "Additional volumes to mount in the output Deployment definition.", - "items": { - "$ref": "https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Volume", - "required": [], - "type": "object" - }, - "required": [], - "title": "volumes", - "type": "array" - } - }, - "required": [], - "type": "object" + "additionalProperties": false } diff --git a/Charts/fastcs/values.yaml b/Charts/fastcs/values.yaml index b2e46c8cd..96bddcc22 100644 --- a/Charts/fastcs/values.yaml +++ b/Charts/fastcs/values.yaml @@ -1,61 +1,36 @@ # yaml-language-server: $schema=values.schema.json +# NOTE: the $k8s schema references come from +# https://github.com/yannh/kubernetes-json-schema/tree/master/v1.33.1 +# with the version set in .fastcs.schema.config.yaml (k8sSchemaVersion) + # Default values for fastcs-instance chart. -# -# helm-schema annotations describe the schema for values files. -# see https://github.com/dadav/helm-schema -# Generate the values schema with `generate-schema.sh` -# -# This file itself adheres to the schema it describes (to help writing the annotations). +# With annotations for building the schema using: +# https://github.com/losisin/helm-values-schema-json.git -# @schema -# title: image -# type: object -# @schema +# @schema description: shared values for all services +# @schema additionalProperties: true +global: {} + +# @schema description: container image URI image: repository: "" pullPolicy: IfNotPresent tag: "" -# @schema -# description: Command to run in the container (as array of arguments) -# type: array -# items: -# type: string -# required: false -# @schema +# @schema description: command to run for the production container command: [] -# @schema -# description: arguments to pass to the above command -# type: array -# items: -# type: string -# required: false -# @schema +# @schema description: command args to pass to the production container args: [] -# @schema -# description: Command to run in the debug version of the container -# type: array -# items: -# type: string -# required: false -# @schema +# @schema description: command to run for the debugging (non- autostart) container debugCommand: - /bin/bash - -c - "sleep infinity" -# @schema -# description: | -# Command to run in the init container. -# Defaults to copying workspace and venv. -# type: array -# items: -# type: string -# required: false -# @schema +# @schema description: command to run in the init container for editable mode initCommand: - /bin/bash - -c @@ -73,67 +48,46 @@ initCommand: fi echo "Init container completed successfully" -# @schema -# description: | -# If true, the container will run in debug mode meaning:- -# - the entrypoint is sleep -# - a PVC is created and mounted over /venv with /venv copied into it -# - adds '-debug' suffix to the image name -# type: boolean -# @schema -developerMode: false - -# @schema -# description: location of config folder (defaults to be the same as C++ IOCs) -# type: string -# required: false -# @schema +# @schema description: enable host networking for the pod +hostNetwork: true + +# @schema description: editable and autostart are used for debugging and development in-cluster +# editable: +# creates a PVC with /venv and /workspaces mounted into the container +# runs an init container with entrypoint initCommand above +editable: false +# @schema description: editable and autostart are used for debugging and development in-cluster +# autostart: +# false: entrypoint is debugCommand above +# true: entrypoint is command above +autostart: true + +# @schema description: path to the location of config folder (defaults to be the same as C++ IOCs) iocConfig: /epics/ioc/config -# @schema -# description: service port for Channel Access -# type: integer -# required: false -# @schema +# @schema description: service port for Channel Access ca_server_port: 5064 -# @schema -# description: service port for PV Access -# type: integer -# required: false -# @schema +# @schema description: service port for PV Access pva_server_port: 5075 -# @schema -# title: CIDR for services addresses. -# description: | +# @schema description: CIDR for services addresses. # Used by allocateIpFromName to allocate a fixed cluster IP for the service. # The default is the same for all DLS clusters. -# type: string -# pattern: ^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$ -# required: false -# @schema -baseIp: 10.96.0.0/12 -# @schema -# title: Override for the cluster IP - only needed if allocateIpFromName clashes -# type: [string, null] -# format: ipv4 -# required: false -# @schema -clusterIP: +baseIp: 10.96.0.0/12 # @schema pattern:^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$ -# @schema -# description: | -# The service will be configured for Channel Access and PVA. Here you can override -# the ports and also make this a LoadBalancer service if required. -# type: object -# required: false -# @schema +# @schema description: Override for the cluster IP - only needed if allocateIpFromName clashes +clusterIP: # @schema pattern:^(\d{1,3}\.){3}\d{1,3}$ + +# @schema description: The service will be configured for Channel Access and PVA. +# Here you can override the ports or make this a LoadBalancer service if required. service: type: ClusterIP ca_port: 5064 pva_port: 5075 # @schema +# TODO: how do we represent this using +# https://github.com/losisin/helm-values-schema-json.git # description: adds addtional containers specified by image and command # type: array # items: @@ -152,97 +106,40 @@ service: # required: [name, image, command] # additionalProperties: false # @schema -extra_containers: [] +extraContainers: [] -# @schema -# title: Pod Annotations -# type: object -# @schema +# @schema description: Add annotations to the pod podAnnotations: {} -# @schema -# title: Pod Labels -# type: object -# @schema + +# @schema description: Add labels to the pod podLabels: {} -# @schema -# title: Pod Security Context -# type: object -# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext -# @schema +# @schema $ref: $k8s/podspec.json#/properties/securityContext podSecurityContext: {} -# @schema -# title: Container Security Context -# type: object -# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.SecurityContext -# @schema +# @schema $ref:$k8s/container.json#/properties/securityContext securityContext: {} -# @schema -# title: Resource limits and requests -# type: object -# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.ResourceRequirements -# @schema +# @schema $ref: $k8s/container.json#/properties/resources resources: {} -# @schema -# title: livenessProbe -# type: object -# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe -# @schema +# @schema $ref: $k8s/container.json#/properties/livenessProbe livenessProbe: {} -# @schema -# title: readinessProbe -# type: object -# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Probe -# @schema + +# @schema $ref: $k8s/container.json#/properties/readinessProbe readinessProbe: {} -# @schema -# title: volumes -# description: Additional volumes to mount in the output Deployment definition. -# type: array -# items: -# type: object -# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Volume -# @schema +# @schema $ref: $k8s/podspec.json#/properties/volumes volumes: [] -# @schema -# title: volumeMounts -# type: array -# items: -# type: object -# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.VolumeMount -# @schema +# @schema $ref: $k8s/container.json#/properties/volumeMounts volumeMounts: [] -# TODO - I had problems with schema checking at helm chart ArgoCD deploy time -# TODO - it seemed that {} for nodeSelector was illegal, so I added null as an option -# TODO - I'm not sure why this was needed but not for other object fields with k8s schemas -# @schema -# title: nodeSelector -# description: Node selector for the pod -# type: [object, null] -# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.NodeSelector -# @schema -nodeSelector: - -# @schema -# title: tolerations -# description: Tolerations for the pod -# type: array -# items: -# type: object -# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Toleration -# @schema +# @schema $ref: $k8s/podspec.json#/properties/tolerations tolerations: [] -# @schema -# title: affinity -# description: Affinity for the pod -# type: object -# $ref: https://kubernetesjsonschema.dev/v1.18.1/_definitions.json#/definitions/io.k8s.api.core.v1.Affinity -# @schema +# @schema $ref: $k8s/podspec.json#/properties/nodeSelector +nodeSelector: {} + +# @schema $ref: $k8s/affinity.json affinity: {} diff --git a/Dockerfile b/Dockerfile index 35d2abf7a..df0f339a3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ graphviz \ && rm -rf /var/lib/apt/lists/* + # Install helm for the dev container. This is the recommended +# approach per the docs: https://helm.sh/docs/intro/install +RUN curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3; \ + chmod 700 get_helm.sh; \ + ./get_helm.sh; \ + rm get_helm.sh +RUN helm plugin install https://github.com/losisin/helm-values-schema-json.git + # Set up a virtual environment and put it in PATH RUN python -m venv /venv ENV PATH=/venv/bin:$PATH diff --git a/generate-schemas.sh b/generate-schemas.sh deleted file mode 100755 index abe52114b..000000000 --- a/generate-schemas.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/env bash - -set -euo pipefail - -this_dir=$(dirname "$0") -cd "$this_dir" - -helm schema -v || helm plugin install https://github.com/dadav/helm-schema - -for chart in Charts/*; do - helm schema -c $chart - ln -fs ../$chart/values.schema.json schemas/$(basename $chart).schema.json - # add a newline to the end of the schema file for pre-commit compliance - echo >> schemas/$(basename $chart).schema.json -done diff --git a/schemas/fastcs-ioc.schema.json b/schemas/fastcs-ioc.schema.json deleted file mode 120000 index ada6d0539..000000000 --- a/schemas/fastcs-ioc.schema.json +++ /dev/null @@ -1 +0,0 @@ -../Charts/fastcs-ioc/values.schema.json \ No newline at end of file diff --git a/schemas/fastcs-service.schema.json b/schemas/fastcs-service.schema.json new file mode 100644 index 000000000..914325484 --- /dev/null +++ b/schemas/fastcs-service.schema.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "fastcs": { + "$ref": "fastcs-values.schema.json", + "type": "object", + "additionalProperties": false + } + }, + "additionalProperties": false +} diff --git a/schemas/fastcs.schema.json b/schemas/fastcs-values.schema.json similarity index 100% rename from schemas/fastcs.schema.json rename to schemas/fastcs-values.schema.json From 84a329645fe3ec33fbd9a605a3b0e3e208b2b2f9 Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 29 Aug 2025 09:34:03 +0100 Subject: [PATCH 3/7] fixes from Garys PR comments --- Charts/{README_CHARTS.md => README.md} | 0 Charts/fastcs/.schema.config.yaml | 4 ++-- Charts/fastcs/Chart.yaml | 2 +- Charts/fastcs/values.schema.json | 4 ++-- Charts/fastcs/values.yaml | 2 +- Dockerfile | 8 ++++---- 6 files changed, 10 insertions(+), 10 deletions(-) rename Charts/{README_CHARTS.md => README.md} (100%) diff --git a/Charts/README_CHARTS.md b/Charts/README.md similarity index 100% rename from Charts/README_CHARTS.md rename to Charts/README.md diff --git a/Charts/fastcs/.schema.config.yaml b/Charts/fastcs/.schema.config.yaml index ad2b1a94f..5fa33f73e 100644 --- a/Charts/fastcs/.schema.config.yaml +++ b/Charts/fastcs/.schema.config.yaml @@ -17,8 +17,8 @@ useHelmDocs: false noAdditionalProperties: false schemaRoot: - title: FastCS Helm chart schema - description: Schema to allow validation of values passed to FastCS Helm chart + title: FastCS Helm chart + description: Helm chart for deploying a FastCS application # No additional properties in schema root for tighter protection: additionalProperties: false diff --git a/Charts/fastcs/Chart.yaml b/Charts/fastcs/Chart.yaml index a88bdc1d4..eee8b3b42 100644 --- a/Charts/fastcs/Chart.yaml +++ b/Charts/fastcs/Chart.yaml @@ -1,6 +1,6 @@ apiVersion: v2 name: fastcs -description: A Helm chart for Kubernetes +description: A Helm chart for FastCS Applications # A chart can be either an 'application' or a 'library' chart. # diff --git a/Charts/fastcs/values.schema.json b/Charts/fastcs/values.schema.json index 06df0bd00..b11b99b0d 100644 --- a/Charts/fastcs/values.schema.json +++ b/Charts/fastcs/values.schema.json @@ -1,7 +1,7 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "FastCS Helm chart schema", - "description": "Schema to allow validation of values passed to FastCS Helm chart", + "title": "FastCS Helm chart", + "description": "Helm chart for deploying a FastCS application", "type": "object", "properties": { "affinity": { diff --git a/Charts/fastcs/values.yaml b/Charts/fastcs/values.yaml index 96bddcc22..e27a70b35 100644 --- a/Charts/fastcs/values.yaml +++ b/Charts/fastcs/values.yaml @@ -35,7 +35,7 @@ initCommand: - /bin/bash - -c - | - echo "running as account"; id + echo "Running as account"; id if [ -d /dest/venv ]; then echo "Virtual environment already exists, skipping copy" else diff --git a/Dockerfile b/Dockerfile index df0f339a3..e9e61b9a1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,11 +8,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ graphviz \ && rm -rf /var/lib/apt/lists/* - # Install helm for the dev container. This is the recommended +# Install helm for the dev container. This is the recommended # approach per the docs: https://helm.sh/docs/intro/install -RUN curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3; \ - chmod 700 get_helm.sh; \ - ./get_helm.sh; \ +RUN curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 && \ + chmod 700 get_helm.sh && \ + ./get_helm.sh && \ rm get_helm.sh RUN helm plugin install https://github.com/losisin/helm-values-schema-json.git From 2c19f7576c0afbe5d21e4b1c8077892635935a1a Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Fri, 29 Aug 2025 11:06:33 +0100 Subject: [PATCH 4/7] comment the schema for extraContainers --- Charts/fastcs/values.schema.json | 5 ++++- Charts/fastcs/values.yaml | 29 ++++++++--------------------- 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/Charts/fastcs/values.schema.json b/Charts/fastcs/values.schema.json index b11b99b0d..5cab5d81e 100644 --- a/Charts/fastcs/values.schema.json +++ b/Charts/fastcs/values.schema.json @@ -46,7 +46,10 @@ "type": "boolean" }, "extraContainers": { - "type": "array" + "type": "array", + "items": { + "type": "object" + } }, "global": { "description": "shared values for all services", diff --git a/Charts/fastcs/values.yaml b/Charts/fastcs/values.yaml index e27a70b35..2bdbc13d1 100644 --- a/Charts/fastcs/values.yaml +++ b/Charts/fastcs/values.yaml @@ -85,27 +85,14 @@ service: ca_port: 5064 pva_port: 5075 -# @schema -# TODO: how do we represent this using -# https://github.com/losisin/helm-values-schema-json.git -# description: adds addtional containers specified by image and command -# type: array -# items: -# type: object -# properties: -# name: -# type: string -# description: A name for the additional container -# image: -# type: string -# format: image -# description: Container image URI -# command: -# type: array -# description: Command to run in the container (as array of arguments) -# required: [name, image, command] -# additionalProperties: false -# @schema + +# Add addtional containers specified by image and command +# +# should be of the form: +# name: # A name for the additional container +# image: # Container image URI +# command: # Command to run in the container (as array of arguments) +# @schema item: object extraContainers: [] # @schema description: Add annotations to the pod From 9be05b729d460f2ca60982d0f7b305841b3072bd Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 1 Sep 2025 07:09:36 +0000 Subject: [PATCH 5/7] fix values.yaml schema for extraContainers Using https://github.com/losisin/helm-values-schema-json/issues/251#issuecomment-3237674115 --- Charts/fastcs/.schema.config.yaml | 1 + Charts/fastcs/extra.values.yaml | 15 +++++++++++++++ Charts/fastcs/values.schema.json | 19 ++++++++++++++++++- Charts/fastcs/values.yaml | 10 ++-------- 4 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 Charts/fastcs/extra.values.yaml diff --git a/Charts/fastcs/.schema.config.yaml b/Charts/fastcs/.schema.config.yaml index 5fa33f73e..95883aa67 100644 --- a/Charts/fastcs/.schema.config.yaml +++ b/Charts/fastcs/.schema.config.yaml @@ -3,6 +3,7 @@ # Define input, output and source for $refs relative to repository root for pre-commit values: - Charts/fastcs/values.yaml + - Charts/fastcs/extra.values.yaml output: Charts/fastcs/values.schema.json diff --git a/Charts/fastcs/extra.values.yaml b/Charts/fastcs/extra.values.yaml new file mode 100644 index 000000000..49e115d11 --- /dev/null +++ b/Charts/fastcs/extra.values.yaml @@ -0,0 +1,15 @@ +################################################################################ +# values for lists of custom objects from values.yaml for schema generation +################################################################################ + +# @schema description: Add arbitrary containers to the pod +extraContainers: + # @schema: description: A name for the additional container + - name: container_name + # @schema $ref: $k8s/container.json#/properties/image + image: image_uri + # @schema $ref: $k8s/container.json#/properties/command + command: + - command + - arg1 + - arg2 diff --git a/Charts/fastcs/values.schema.json b/Charts/fastcs/values.schema.json index 5cab5d81e..88c13160f 100644 --- a/Charts/fastcs/values.schema.json +++ b/Charts/fastcs/values.schema.json @@ -46,9 +46,26 @@ "type": "boolean" }, "extraContainers": { + "description": "Add arbitrary containers to the pod", "type": "array", "items": { - "type": "object" + "type": "object", + "properties": { + "command": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/container.json#/properties/command", + "type": "array", + "items": { + "type": "string" + } + }, + "image": { + "$ref": "https://raw.githubusercontent.com/yannh/kubernetes-json-schema/master/v1.33.3/container.json#/properties/image", + "type": "string" + }, + "name": { + "type": "string" + } + } } }, "global": { diff --git a/Charts/fastcs/values.yaml b/Charts/fastcs/values.yaml index 2bdbc13d1..9ade52dc4 100644 --- a/Charts/fastcs/values.yaml +++ b/Charts/fastcs/values.yaml @@ -85,14 +85,8 @@ service: ca_port: 5064 pva_port: 5075 - -# Add addtional containers specified by image and command -# -# should be of the form: -# name: # A name for the additional container -# image: # Container image URI -# command: # Command to run in the container (as array of arguments) -# @schema item: object +# Add additional containers specified by image and command +# see extra.values.yaml for the schema of this list of objects extraContainers: [] # @schema description: Add annotations to the pod From b46ee3e1607896ba91bfb7180d5c74d31129671d Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 1 Sep 2025 08:44:47 +0000 Subject: [PATCH 6/7] remove reference to temporary debug.py --- Charts/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Charts/README.md b/Charts/README.md index e4a14e77c..fc9dbd0b2 100644 --- a/Charts/README.md +++ b/Charts/README.md @@ -56,7 +56,7 @@ The `fastcs` helm chart has two variables to enable debugging/development in-clu In combination these flags can be used to debug or develop in-cluster. -An initial demonstration script to use these features is provided in [debug.py](https://github.com/epics-containers/p47-services/blob/add-fastcs/debug.py) in the `p47-services` repo. +These features will be accessed via `ec`. See https://github.com/epics-containers/edge-containers-cli/issues/207 This script will: From 80d25d9ec33ea2f31397323e25113acd274b3e0f Mon Sep 17 00:00:00 2001 From: Giles Knap Date: Mon, 1 Sep 2025 13:03:45 +0000 Subject: [PATCH 7/7] remove README TODOs in favour of https://github.com/DiamondLightSource/python-copier-template/issues/286 --- Charts/README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Charts/README.md b/Charts/README.md index fc9dbd0b2..8d08d850a 100644 --- a/Charts/README.md +++ b/Charts/README.md @@ -2,8 +2,6 @@ This directory contains Helm charts for deploying FastCS services. -TODO: The implementation of helm charts in this repo is intended to be general purpose and is a proposed solution for the `python-copier-template`. - ## Github Actions This folder works in tandem with [_helm.yml](../.github/workflows/_helm.yml) github actions workflow which: @@ -15,8 +13,6 @@ This folder works in tandem with [_helm.yml](../.github/workflows/_helm.yml) git This standalone Helm related workflow is independent of the rest of the workflows except that the _pypi workflow has _helm added to its `needs` in `ci.yml`, making sure we only publish to pypi with valid SemVer tags. -TODO: for a project that publishes containers referred to by the helm chart, the `_containers.yml` workflow should be added to the `needs` of _helm in `ci.yml`. - ## Schema Generation Schema generation for charts' `values.yaml` is handled by [helm-values-schema-json](https://github.com/losisin/helm-values-schema-json). Which is in turn controlled by annotations in the default [values.yaml](fastcs/values.yaml) file. @@ -25,20 +21,23 @@ The generated schema file will be called `values.schema.json` and will be placed ```bash git add . ; pre-commit +# or +pre-commit run --all-files ``` + Note that this standard name for the schema file means that it is packaged up with the helm chart and available for schema checks in ArgoCD for example. -## schemas folder +## `schemas` folder -The schemas folder allows us to declare the schemas you want to publish to the release. +The schemas folder allows us to declare the schemas we want to publish to the release. It should contain: - A symlink to each of the `values.schema.json` files in the subfolders of `Charts`. The symlink should have a unique name, e.g. `fastcs-values.schema.json`, thus allowing multiple schemas to be published per repo. - A service schema file which references the above and can be used to validate `values.yaml` in epics-containers services repos, where the these charts will be used as sub-charts. e.g. [fastcs-service.schema.json](../schemas/fastcs-service.schema.json) -The service schema files are hand coded as they are extremely simple. The symlinks are also manually created at present. (both of these could potentially be automated). +The service schema files are hand coded as they are extremely simple and unlikely to change. ## Debuging/Development In-Cluster @@ -60,8 +59,8 @@ These features will be accessed via `ec`. See https://github.com/epics-container This script will: -- inspect the values of `editable` and `autostart` in the `values.yaml` file of the specified IOC (TODO: at present it uses the p47-services source code to do so but this should be determined from the cluster in future). -- port forward the debugpy port (5678) from the pod to localhost. +- Inspect the values of `editable` and `autostart` in the `values.yaml` file of the specified IOC (TODO: at present it uses the p47-services source code to do so but this should be determined from the cluster in future). +- Port forward the debugpy port (5678) from the pod to localhost. - If editable is true, it will mount the PVC locally using pv-mounter and open VSCode to the /workspaces/xxx folder. - If autostart is false, it will exec into the container and launch debugpy to run the main program. - If autostart is true, it will exec into the container and attach debugpy to PID 1.