Skip to content

Commit

Permalink
Implemented registry reader (#2)
Browse files Browse the repository at this point in the history
* implemented chronicler and tests

* removed default automountServiceAccountToken

* Added limits

* Fixed cpu limit

* Update reusable-verify-chart.yaml to latest version

* Changed initContainer to use kubectl

* removed .debug

* Moved UriOptionsLoader to common

* Improve security by setting container security context

* Add ephemeral-storage limit to deployment and limits templates
  • Loading branch information
MartinSchmidt authored Aug 19, 2024
1 parent 24547b6 commit ad9f462
Show file tree
Hide file tree
Showing 50 changed files with 2,619 additions and 206 deletions.
2 changes: 1 addition & 1 deletion .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [5000, 5001],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "make restore",
"postCreateCommand": "helm plugin install https://github.com/helm-unittest/helm-unittest.git && make restore",
// Configure tool-specific properties.
"customizations": {
"vscode": {
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pullrequest-verify.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
uses: project-origin/.github/.github/workflows/reusable-verify-renovate.yaml@5f308f6499ed423ed1252156296e18be614202de

verify-chart:
uses: project-origin/.github/.github/workflows/reusable-verify-chart.yaml@5f308f6499ed423ed1252156296e18be614202de
uses: project-origin/.github/.github/workflows/reusable-verify-chart.yaml@32ff33baaf1c9960ef1f01ef4ee554225db1972c

verify-container-build:
uses: project-origin/.github/.github/workflows/reusable-build-push-container-ghcr.yaml@5f308f6499ed423ed1252156296e18be614202de
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,5 @@ unit-test:
verify-chart:
@kind version >/dev/null 2>&1 || { echo >&2 "kind not installed! kind is required to use recipe, please install or use devcontainer"; exit 1;}
@helm version >/dev/null 2>&1 || { echo >&2 "helm not installed! helm is required to use recipe, please install or use devcontainer"; exit 1;}
helm unittest chart
chart/run_kind_test.sh
87 changes: 74 additions & 13 deletions chart/run_kind_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,43 +5,104 @@

# Define kind cluster name
cluster_name=chronicler-test
namespace=chronicler

# Ensures script fails if something goes wrong.
set -eo pipefail

# cleanup - delete temp_folder and cluster
trap 'rm -fr $temp_folder; kind delete cluster -n ${cluster_name} >/dev/null 2>&1' 0
# define cleanup function
cleanup() {
rm -fr $temp_folderx
kind delete cluster --name ${cluster_name} >/dev/null 2>&1
}

# define debug function
debug() {
echo -e "\nDebugging information:"
echo -e "\nHelm status:"
helm status chronicler --namespace ${namespace} --show-desc --show-resources

echo -e "\nDeployment description:"
kubectl describe deployment --namespace ${namespace} po-chronicler-deployment

POD_NAMES=$(kubectl get pods --namespace ${namespace} -l app=po-chronicler -o jsonpath="{.items[*].metadata.name}")
# Loop over the pods and print their logs
for POD_NAME in $POD_NAMES
do
echo -e "\nLogs for $POD_NAME:"
kubectl logs --namespace ${namespace} $POD_NAME
done
}

# trap cleanup function on script exit
trap 'cleanup' 0
trap 'debug; cleanup' ERR

# define variables
temp_folder=$(mktemp -d)
values_filename=${temp_folder}/values.yaml
secret_filename=${temp_folder}/secret.yaml

# create kind cluster
kind delete cluster -n ${cluster_name}
kind create cluster -n ${cluster_name}
kind delete cluster --name ${cluster_name}
kind create cluster --name ${cluster_name}

# install rabbitmq-operator
kubectl apply -f "https://github.com/rabbitmq/cluster-operator/releases/download/v2.5.0/cluster-operator.yml"
# create namespace
kubectl create namespace ${namespace}

# install cnpg-operator
helm install cnpg-operator cloudnative-pg --repo https://cloudnative-pg.io/charts --version 0.18.0 --namespace cnpg --create-namespace --wait
# install postgresql chart
helm install postgresql oci://registry-1.docker.io/bitnamicharts/postgresql --namespace ${namespace}

# build docker image
docker build -f src/Chronicler.Dockerfile -t ghcr.io/project-origin/chronicler:test src/

# load docker image into cluster
kind load -n ${cluster_name} docker-image ghcr.io/project-origin/chronicler:test
kind load --name ${cluster_name} docker-image ghcr.io/project-origin/chronicler:test

# generate keys
openssl genpkey -algorithm ED25519 > ${secret_filename}

# generate secret
kubectl create secret generic signing-key --from-file=my-key=${secret_filename} --namespace ${namespace}

# generate values.yaml file
cat << EOF > "${values_filename}"
image:
tag: test
replicaCount: 1
config:
signingKeySecret:
name: signing-key
key: my-key
gridAreas:
- narnia
networkConfigurationFile: |-
{
"RegistryUrls": {
"narniaRegistry": "https://registry.narnia.example.com"
}
}
postgresql:
host: postgresql
database: postgres
username: postgres
password:
secretRef:
name: postgresql
key: postgres-password
messageBroker:
type: rabbitmqOperator
EOF

# install chronicler chart
helm install chronicler ./chart --values ${values_filename} --namespace chronicler --create-namespace --wait
helm install chronicler ./chart --values ${values_filename} --namespace ${namespace} --wait --timeout 1m

# verify deployment is ready
deployments_status=$(kubectl get deployments --namespace ${namespace} --no-headers | awk '$3 != $4 {print "Deployment " $1 " is not ready"}')

echo "Test completed successfully ✅"
# Print the results to stderr if there are any issues
if [ -n "$deployments_status" ]; then
echo "$deployments_status" 1>&2
echo "Test failed ❌"
else
echo "Test completed successfully ✅"
fi
40 changes: 40 additions & 0 deletions chart/templates/_database-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{{- define "checkKey" -}}
{{- $value := index . 0 -}}
{{- $name := index . 1 -}}

{{- if kindIs "string" $value }}
value: {{ required (printf "The value for %s is not provided" $name) $value | quote }}
{{- else if and (hasKey $value "secretRef") (hasKey $value "configMapRef") }}
{{ fail (printf "Both secretRef and configMapRef are defined for %s" $name) }}
{{- else if hasKey $value "secretRef" }}
valueFrom:
secretKeyRef:
name: {{ required (printf "The value for %s.secretRef.name is not provided" $name) $value.secretRef.name | quote }}
key: {{ required (printf "The value for %s.secretRef.key is not provided" $name) $value.secretRef.key | quote }}
{{- else if hasKey $value "configMapRef" }}
valueFrom:
configMapKeyRef:
name: {{ required (printf "The value for %s.configMapRef.name is not provided" $name) $value.configMapRef.name | quote }}
key: {{ required (printf "The value for %s.configMapRef.name is not provided" $name) $value.configMapRef.key | quote }}
{{- else }}
{{ fail (printf "The value for %s is not provided" $name) }}
{{- end }}
{{- end -}}

{{- define "database.config" -}}
# Database Configuration
- name: DB_HOST
{{- include "checkKey" (list .Values.postgresql.host ".postgresql.host") }}
- name: DB_PORT
{{- include "checkKey" (list .Values.postgresql.port ".postgresql.port") }}
- name: DB_DATABASE
{{- include "checkKey" (list .Values.postgresql.database ".postgresql.database") }}
- name: DB_USERNAME
{{- include "checkKey" (list .Values.postgresql.username ".postgresql.username") }}
- name: DB_PASSWORD
{{- include "checkKey" (list .Values.postgresql.password ".postgresql.password") }}
- name: ConnectionStrings__Database
value: Host=$(DB_HOST); Port=$(DB_PORT); Database=$(DB_DATABASE); Username=$(DB_USERNAME); Password=$(DB_PASSWORD);
{{- end }}


18 changes: 18 additions & 0 deletions chart/templates/_limits.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{{- define "limits" -}}
resources:
requests:
{{- if .Values.resources.requests.cpu }}
cpu: {{ .Values.resources.requests.cpu }}
{{- end }}
{{- if .Values.resources.requests.memory }}
memory: {{ .Values.resources.requests.memory }}
{{- end }}
limits:
{{- if .Values.resources.limits.cpu }}
cpu: {{ .Values.resources.limits.cpu }}
{{- end }}
{{- if .Values.resources.limits.memory }}
memory: {{ .Values.resources.limits.memory }}
{{- end }}
ephemeral-storage: "1Mi"
{{- end -}}
18 changes: 0 additions & 18 deletions chart/templates/cnpg-cluster.yaml

This file was deleted.

133 changes: 93 additions & 40 deletions chart/templates/deployment.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
{{- $tag := .Values.image.tag | default .Chart.AppVersion -}}
apiVersion: apps/v1
kind: Deployment
metadata:
Expand All @@ -8,7 +7,7 @@ metadata:
labels:
app: po-chronicler
spec:
replicas: {{ .Values.chronicler.replicaCount }}
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: po-chronicler
Expand All @@ -20,54 +19,108 @@ spec:
app: po-chronicler
spec:
serviceAccountName: chronicler-migration-waiter
automountServiceAccountToken: false
securityContext:
runAsUser: 1654
runAsNonRoot: true
initContainers:
- name: wait-for-migration
image: groundnuty/k8s-wait-for:v2.0 # TODO verify this image
args:
- "job"
- "po-chronicler-migrate-job-{{ .Values.image.tag | default .Chart.AppVersion | replace "." "-" }}"
image: bitnami/kubectl:1.30.4
resources:
requests:
cpu: 0.1
limits:
memory: 50Mi
ephemeral-storage: "1Mi"
command:
- /bin/sh
- -c
- |
kubectl wait --for=condition=complete job/${JOB_NAME} --timeout=300s -n {{ .Release.Namespace }}
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
env:
- name: JOB_NAME
value: po-chronicler-migrate-job-{{ .Values.image.tag | default .Chart.AppVersion | replace "." "-" }}
volumeMounts:
- name: service-account-token
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
containers:
- name: po-chronicler
image: {{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}
{{ include "limits" . | nindent 10 }}
args:
- "--serve"
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
env:
{{- range .Values.registries }}
- name: RegistryUrls__{{ .name }}
value: {{ .address }}
{{- end }}

{{- if eq .Values.persistence.type "CloudNativePG" }}
- name: DB_HOST
value: {{ .Values.persistence.cloudNativePG.name }}-rw
- name: DB_PORT
value: "5432"
- name: DB_DATABASE
value: {{ .Values.persistence.cloudNativePG.database }}
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: {{ .Values.persistence.cloudNativePG.name }}-app
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.persistence.cloudNativePG.name }}-app
key: password
- name: ConnectionStrings__Database
value: "Host=$(DB_HOST);Port=$(DB_PORT);Database=$(DB_DATABASE);Username=$(DB_USERNAME);Password=$(DB_PASSWORD);"
{{- else if eq .Values.persistence.type "BYOD" }}
- name: ConnectionStrings__Database
valueFrom:
secretKeyRef:
name: {{ required "BYOD is selected as the database type, but no secretName is provided in persistence.byod" .Values.persistence.byod.secretName }}
key: {{ required "BYOD is selected as the database type, but no secretKey is provided in persistence.byod" .Values.persistence.byod.secretKey }}
{{- else }}
{{- fail "Unsupported database type specified. Please specify 'persistence.type' as either 'CloudNativePG' or 'BYOD'." }}
{{- end }}
{{- include "database.config" . | nindent 12 }}

# OpenTelemetry Collector Configuration
- name: Otlp__Enabled
value: {{ .Values.otlp.enabled | quote }}
{{- if .Values.otlp.enabled }}
- name: Otlp__Endpoint
value: {{ .Values.otlp.endpoint }}
value: {{ required "otel.endpoint is required when enabled" .Values.otlp.endpoint | quote }}
{{- end }}

# Chronicler Configuration
{{- if .Values.config.networkConfigurationFile }}
- name: network__ConfigurationUri
value: file:///etc/config/networkConfiguration.json
{{- else if .Values.config.networkConfigurationUri }}
- name: network__ConfigurationUri
value: {{ .Values.config.networkConfigurationUri }}
{{- else }}
{{ fail "No network configuration provided" }}
{{- end }}

- name: chronicler__JobInterval
value: {{ .Values.config.jobInterval }}

- name: chronicler__SigningKeyFilename
value: &signingKeyFilename /etc/secret/signing-key

{{- range $i, $area := .Values.config.gridAreas }}
- name: chronicler__GridAreas__{{ $i }}
value: {{ $area }}
{{- end }}
volumeMounts:
- name: service-account-token
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
readOnly: true
- name: &signingKeyVolumeName signing-key-volume
mountPath: *signingKeyFilename
subPath: &signingKeyVolumePath signing-key
{{- if .Values.config.networkConfigurationFile }}
- name: &networkConfigVolumeName config-volume
mountPath: /etc/config/networkConfiguration.json
subPath: &networkConfigSubPath networkConfiguration.json
{{- end }}
volumes:
- name: service-account-token
projected:
sources:
- serviceAccountToken:
path: token
- configMap:
name: kube-root-ca.crt
items:
- key: ca.crt
path: ca.crt
- name: *signingKeyVolumeName
secret:
secretName: {{ .Values.config.signingKeySecret.name }}
items:
- key: {{ .Values.config.signingKeySecret.key }}
path: *signingKeyVolumePath
{{- if .Values.config.networkConfigurationFile }}
- name: *networkConfigVolumeName
configMap:
name: po-chronicler-deployment-config
items:
- key: *networkConfigSubPath
path: *networkConfigSubPath
{{- end }}
Loading

0 comments on commit ad9f462

Please sign in to comment.