diff --git a/.github/workflows/helm-build.yaml b/.github/workflows/helm-build.yaml new file mode 100644 index 0000000..65eb2c6 --- /dev/null +++ b/.github/workflows/helm-build.yaml @@ -0,0 +1,67 @@ +name: Helm Chart Build + +on: + workflow_dispatch: + push: + branches: + - "main" + - "release-*" + +concurrency: + group: helm-${{ github.ref }} + cancel-in-progress: true + +jobs: + prepare: + runs-on: ubuntu-latest + steps: + - name: Extract tag + id: extract_tag + run: | + tag=$(if [[ ${{github.ref_name}} == v* ]];then echo "${{github.ref_name}}"; else echo "latest"; fi) + echo "tag=$tag" >> $GITHUB_OUTPUT + outputs: + tag: ${{ steps.extract_tag.outputs.tag }} + + helm-build: + runs-on: ubuntu-latest + needs: + - prepare + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-java@v4 + with: + distribution: "temurin" + java-version: "21" + cache: "maven" + - name: Create Helm + run: | + ## Set -Dquarkus.container-image.tag as empty to remove the "v" prefix from the container image of Deployment + mvn package -DskipTests -Dquarkus.container-image.tag= + + # YQ + sudo wget https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -O /usr/bin/yq + sudo chmod +x /usr/bin/yq + + APP_IMAGE_TAG=$TAG yq e -i '.appVersion=strenv(APP_IMAGE_TAG)' target/helm/Chart.yaml + env: + TAG: ${{ needs.prepare.outputs.tag }} + - name: Git add Helm + id: git-add-helm + continue-on-error: true + run: | + cp -R target/helm/ ./ + + if [ -z $(git status --porcelain) ]; then + echo "has_changes=false" >> $GITHUB_OUTPUT + else + echo git status + git add helm/* + echo "has_changes=true" >> $GITHUB_OUTPUT + fi + - name: Commit and Push + uses: trustification/release-tools/.github/actions/commit@main + if: steps.git-add-helm.outputs.has_changes == 'true' + with: + commit_message: "🔅 Helm chart update" + branch: ${{github.ref_name}} \ No newline at end of file diff --git a/README.md b/README.md index e991de7..27ae240 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,31 @@ +# Quick Start - Helm Chart + +If you want to give a quick try of the operator without the whole glory of OLM you can deploy our Operator using Helm. + +- Start minikube: + +```shell +minikube start --addons=ingress,dashboard +``` + +- Install the Helm Chart: + +```shell +helm install myhelm helm/ +``` + +- Create an instance of Trustify: + +```shell +cat << EOF | kubectl apply -f - +apiVersion: "org.trustify/v1alpha1" +kind: "Trustify" +metadata: + name: myapp +spec: { } +EOF +``` + # Local development ## Minikube diff --git a/helm/Chart.yaml b/helm/Chart.yaml new file mode 100644 index 0000000..3cb5da1 --- /dev/null +++ b/helm/Chart.yaml @@ -0,0 +1,5 @@ +--- +name: "trustify-operator" +version: "1.0.0-SNAPSHOT" +apiVersion: "v2" +appVersion: "latest" diff --git a/helm/README.md b/helm/README.md new file mode 100644 index 0000000..d48edfe --- /dev/null +++ b/helm/README.md @@ -0,0 +1,10 @@ +## Configuration + +The following values are configurable: + +- `watchNamespaces` - namespaces to be watched, either: + - a list of comma-separated namespace names + - `JOSDK_ALL_NAMESPACES` to watch all namespaces + - `JOSDK_WATCH_CURRENT` to watch only the namespace in which the operator is deployed +- `version` - the current version of the application. + diff --git a/helm/crds/trustifies.org.trustify-v1.yml b/helm/crds/trustifies.org.trustify-v1.yml new file mode 100644 index 0000000..8c37639 --- /dev/null +++ b/helm/crds/trustifies.org.trustify-v1.yml @@ -0,0 +1,203 @@ +# Generated by Fabric8 CRDGenerator, manual edits might get overwritten! +apiVersion: "apiextensions.k8s.io/v1" +kind: "CustomResourceDefinition" +metadata: + name: "trustifies.org.trustify" +spec: + group: "org.trustify" + names: + kind: "Trustify" + plural: "trustifies" + singular: "trustify" + scope: "Namespaced" + versions: + - name: "v1alpha1" + schema: + openAPIV3Schema: + properties: + spec: + properties: + db: + description: "In this section you can find all properties related\ + \ to connect to a database." + properties: + externalDatabase: + description: "Use external database." + type: "boolean" + host: + description: "The host of the database." + type: "string" + name: + description: "The database name." + type: "string" + passwordSecret: + description: "The reference to a secret holding the password of\ + \ the database user." + properties: + key: + type: "string" + name: + type: "string" + optional: + type: "boolean" + type: "object" + port: + description: "The port of the database." + type: "string" + pvcSize: + description: "Size of the PVC to create. Valid only if externalDatabase=false" + type: "string" + resourceLimits: + description: "In this section you can configure resource limits\ + \ settings. Valid only if externalDatabase=false" + properties: + cpuLimit: + description: "Limit CPU." + type: "string" + cpuRequest: + description: "Requested CPU." + type: "string" + memoryLimit: + description: "Limit Memory." + type: "string" + memoryRequest: + description: "Requested memory." + type: "string" + type: "object" + usernameSecret: + description: "The reference to a secret holding the username of\ + \ the database user." + properties: + key: + type: "string" + name: + type: "string" + optional: + type: "boolean" + type: "object" + type: "object" + dbImage: + description: "Custom Trustify DB Server image to be used. For internal\ + \ use only" + type: "string" + hostname: + description: "In this section you can configure hostname and related\ + \ properties." + properties: + hostname: + description: "Hostname for the server." + type: "string" + type: "object" + http: + description: "In this section you can configure features related to\ + \ HTTP and HTTPS" + properties: + tlsSecret: + description: "A secret containing the TLS configuration for HTTPS.\ + \ Reference: https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets." + type: "string" + type: "object" + imagePullPolicy: + description: "Custom Image Pull Policy for images managed by the Operator" + type: "string" + imagePullSecrets: + description: "Secret(s) that might be used when pulling an image from\ + \ a private container image registry or repository." + items: + properties: + name: + type: "string" + type: "object" + type: "array" + oidc: + description: "In this section you can configure Oidc settings." + properties: + enabled: + description: "Enable Oidc Auth." + type: "boolean" + serverClientId: + description: "Oidc client id for the Server." + type: "string" + serverUrl: + description: "Oidc server url." + type: "string" + uiClientId: + description: "Oidc client id for the UI." + type: "string" + type: "object" + serverImage: + description: "Custom Trustify Server image to be used. For internal\ + \ use only" + type: "string" + serverResourceLimits: + description: "In this section you can configure resource limits settings\ + \ for the Server." + properties: + cpuLimit: + description: "Limit CPU." + type: "string" + cpuRequest: + description: "Requested CPU." + type: "string" + memoryLimit: + description: "Limit Memory." + type: "string" + memoryRequest: + description: "Requested memory." + type: "string" + type: "object" + storage: + description: "In this section you can configure Storage settings." + properties: + compression: + description: "Storage compression." + enum: + - "NONE" + - "ZSTD" + type: "string" + filesystem: + properties: + pvcSize: + description: "Size of the PVC to create." + type: "string" + type: "object" + s3: + properties: + accessKey: + description: "Access key." + type: "string" + bucket: + description: "Bucket name." + type: "string" + region: + description: "Region name." + type: "string" + secretKey: + description: "Secret key." + type: "string" + type: "object" + type: + description: "Storage type." + enum: + - "FILESYSTEM" + - "S3" + type: "string" + type: "object" + type: "object" + status: + properties: + conditions: + items: + properties: + status: + type: "string" + type: + type: "string" + type: "object" + type: "array" + type: "object" + type: "object" + served: true + storage: true + subresources: + status: {} diff --git a/helm/templates/additional-crd-role-binding.yaml b/helm/templates/additional-crd-role-binding.yaml new file mode 100644 index 0000000..e69de29 diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml new file mode 100644 index 0000000..9af7f1f --- /dev/null +++ b/helm/templates/deployment.yaml @@ -0,0 +1,90 @@ +--- +apiVersion: "apps/v1" +kind: "Deployment" +metadata: + annotations: + app.quarkus.io/quarkus-version: "3.15.1" + app.quarkus.io/vcs-uri: "https://github.com/trustification/trustify-operator.git" + prometheus.io/scrape: "true" + prometheus.io/path: "/q/metrics" + prometheus.io/port: "8080" + prometheus.io/scheme: "http" + labels: + app.kubernetes.io/name: "trustify-operator" + app.kubernetes.io/managed-by: "quarkus" + name: "trustify-operator" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: "trustify-operator" + template: + metadata: + annotations: + app.quarkus.io/quarkus-version: "3.15.1" + app.quarkus.io/vcs-uri: "https://github.com/trustification/trustify-operator.git" + prometheus.io/scrape: "true" + prometheus.io/path: "/q/metrics" + prometheus.io/port: "8080" + prometheus.io/scheme: "http" + labels: + app.kubernetes.io/managed-by: "quarkus" + app.kubernetes.io/name: "trustify-operator" + spec: + containers: + - env: + - name: "KUBERNETES_NAMESPACE" + valueFrom: + fieldRef: + fieldPath: "metadata.namespace" + - name: "RELATED_IMAGE_TRUSTIFY_SERVER" + value: "ghcr.io/trustification/trustd:latest" + - name: "RELATED_IMAGE_DB" + value: "quay.io/sclorg/postgresql-15-c9s:latest" + - name: "QUARKUS_OPERATOR_SDK_CONTROLLERS_TRUSTIFY_NAMESPACES" + value: {{ .Values.watchNamespaces }} + image: "ghcr.io/runner/trustify-operator:{{ .Chart.AppVersion }}" + imagePullPolicy: "Always" + livenessProbe: + failureThreshold: 3 + httpGet: + path: "/q/health/live" + port: 8080 + scheme: "HTTP" + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 10 + name: "trustify-operator" + ports: + - containerPort: 8080 + name: "http" + protocol: "TCP" + readinessProbe: + failureThreshold: 3 + httpGet: + path: "/q/health/ready" + port: 8080 + scheme: "HTTP" + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 10 + resources: + limits: + cpu: "250m" + memory: "256Mi" + requests: + cpu: "50m" + memory: "64Mi" + startupProbe: + failureThreshold: 3 + httpGet: + path: "/q/health/started" + port: 8080 + scheme: "HTTP" + initialDelaySeconds: 5 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 10 + serviceAccountName: "trustify-operator" diff --git a/helm/templates/generic-crd-cluster-role-binding.yaml b/helm/templates/generic-crd-cluster-role-binding.yaml new file mode 100644 index 0000000..25f17ed --- /dev/null +++ b/helm/templates/generic-crd-cluster-role-binding.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ .Chart.Name }}-crd-validating-role-binding + labels: + app.kubernetes.io/name: {{ .Chart.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/managed-by: quarkus +roleRef: + kind: ClusterRole + apiGroup: rbac.authorization.k8s.io + name: {{ .Chart.Name }}-crd-validating-cluster-role +subjects: + - kind: ServiceAccount + name: {{ .Chart.Name }} + namespace: {{ .Release.Namespace }} diff --git a/helm/templates/generic-crd-cluster-role.yaml b/helm/templates/generic-crd-cluster-role.yaml new file mode 100644 index 0000000..d7d6b0e --- /dev/null +++ b/helm/templates/generic-crd-cluster-role.yaml @@ -0,0 +1,16 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ .Chart.Name }}-crd-validating-cluster-role + labels: + app.kubernetes.io/name: {{ .Chart.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/managed-by: quarkus +rules: + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list diff --git a/helm/templates/service.yaml b/helm/templates/service.yaml new file mode 100644 index 0000000..efedaa9 --- /dev/null +++ b/helm/templates/service.yaml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: {{ .Chart.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/managed-by: quarkus + name: {{ .Chart.Name }} +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 8080 + selector: + app.kubernetes.io/name: {{ .Chart.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + type: ClusterIP diff --git a/helm/templates/serviceaccount.yaml b/helm/templates/serviceaccount.yaml new file mode 100644 index 0000000..d9181f0 --- /dev/null +++ b/helm/templates/serviceaccount.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/managed-by: quarkus + app.kubernetes.io/name: {{ .Chart.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + name: {{ .Chart.Name }} diff --git a/helm/templates/trustify-crd-cluster-role.yaml b/helm/templates/trustify-crd-cluster-role.yaml new file mode 100644 index 0000000..fb89f79 --- /dev/null +++ b/helm/templates/trustify-crd-cluster-role.yaml @@ -0,0 +1,80 @@ +--- +apiVersion: "rbac.authorization.k8s.io/v1" +kind: "ClusterRole" +metadata: + name: "trustify-cluster-role" +rules: +- apiGroups: + - "org.trustify" + resources: + - "trustifies" + - "trustifies/status" + - "trustifies/finalizers" + verbs: + - "get" + - "list" + - "watch" + - "patch" + - "update" + - "create" + - "delete" +- apiGroups: + - "" + resources: + - "persistentvolumeclaims" + verbs: + - "create" + - "delete" + - "get" + - "list" + - "patch" + - "update" + - "watch" +- apiGroups: + - "apps" + resources: + - "deployments" + verbs: + - "create" + - "delete" + - "get" + - "list" + - "patch" + - "update" + - "watch" +- apiGroups: + - "" + resources: + - "secrets" + verbs: + - "create" + - "delete" + - "get" + - "list" + - "patch" + - "update" + - "watch" +- apiGroups: + - "" + resources: + - "services" + verbs: + - "create" + - "delete" + - "get" + - "list" + - "patch" + - "update" + - "watch" +- apiGroups: + - "networking.k8s.io" + resources: + - "ingresses" + verbs: + - "create" + - "delete" + - "get" + - "list" + - "patch" + - "update" + - "watch" diff --git a/helm/templates/trustify-crd-role-binding.yaml b/helm/templates/trustify-crd-role-binding.yaml new file mode 100644 index 0000000..16f71b2 --- /dev/null +++ b/helm/templates/trustify-crd-role-binding.yaml @@ -0,0 +1,57 @@ +{{ if eq $.Values.watchNamespaces "JOSDK_WATCH_CURRENT" }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: trustify-role-binding + namespace: {{ $.Release.Namespace }} + labels: + app.kubernetes.io/name: {{ .Chart.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/managed-by: quarkus +roleRef: + kind: ClusterRole + apiGroup: rbac.authorization.k8s.io + name: trustify-cluster-role +subjects: + - kind: ServiceAccount + name: {{ $.Chart.Name }} + namespace: {{ $.Release.Namespace }} +{{ else if eq $.Values.watchNamespaces "JOSDK_ALL_NAMESPACES" }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: trustify-role-binding + labels: + app.kubernetes.io/name: {{ .Chart.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/managed-by: quarkus +roleRef: + kind: ClusterRole + apiGroup: rbac.authorization.k8s.io + name: trustify-cluster-role +subjects: + - kind: ServiceAccount + name: {{ $.Chart.Name }} + namespace: {{ $.Release.Namespace }} +{{ else }} +{{ range $anamespace := ( split "," $.Values.watchNamespaces ) }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: trustify-role-binding + namespace: {{ $anamespace }} + labels: + app.kubernetes.io/name: {{ .Chart.Name }} + app.kubernetes.io/version: {{ .Chart.AppVersion }} + app.kubernetes.io/managed-by: quarkus +roleRef: + kind: ClusterRole + apiGroup: rbac.authorization.k8s.io + name: trustify-cluster-role +subjects: + - kind: ServiceAccount + name: {{ $.Chart.Name }} + namespace: {{ $.Release.Namespace }} +--- +{{- end }} +{{- end }} diff --git a/helm/values.schema.json b/helm/values.schema.json new file mode 100644 index 0000000..d7b8b83 --- /dev/null +++ b/helm/values.schema.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://json-schema.org/draft-07/schema#", + "title": "Values", + "type": "object", + "properties": { + "watchNamespaces": { + "type": "string" + } + } +} \ No newline at end of file diff --git a/helm/values.yaml b/helm/values.yaml new file mode 100644 index 0000000..7096e08 --- /dev/null +++ b/helm/values.yaml @@ -0,0 +1,2 @@ +--- +watchNamespaces: "JOSDK_ALL_NAMESPACES" diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 2474215..258c305 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -22,14 +22,10 @@ quarkus: helm: enabled: true # https://quarkus.io/guides/deploying-to-kubernetes#environment-variables-from-keyvalue-pairs - openshift: - env: - vars: - related-image-trustify-ui: ${related.image.ui} - related-image-trustify-server: ${related.image.server} - related-image-db: ${related.image.db} - related-image-importer: ${related.image.importer} kubernetes: + idempotent: "true" + prometheus: + generate-service-monitor: "false" env: vars: related-image-trustify-ui: ${related.image.ui}