From 86466c8e0188100e6a5ed0fae889d4ac07f7a203 Mon Sep 17 00:00:00 2001 From: rthalho Date: Mon, 5 Aug 2024 15:34:23 +0200 Subject: [PATCH] feat: add helmify --- Makefile | 10 + chart/.helmignore | 23 ++ chart/Chart.yaml | 21 ++ chart/templates/_helpers.tpl | 62 ++++ chart/templates/deployment.yaml | 89 +++++ chart/templates/enterprise-crd.yaml | 186 ++++++++++ chart/templates/image-crd.yaml | 75 ++++ .../templates/kube-state-metrics-config.yaml | 9 + chart/templates/leader-election-rbac.yaml | 59 ++++ chart/templates/manager-rbac.yaml | 184 ++++++++++ chart/templates/organization-crd.yaml | 186 ++++++++++ chart/templates/pool-crd.yaml | 265 ++++++++++++++ chart/templates/repository-crd.yaml | 189 ++++++++++ chart/templates/runner-crd.yaml | 166 +++++++++ chart/templates/selfsigned-issuer.yaml | 8 + chart/templates/serviceaccount.yaml | 11 + chart/templates/serving-cert.yaml | 15 + .../validating-webhook-configuration.yaml | 70 ++++ chart/templates/webhook-service.yaml | 16 + chart/values.yaml | 331 ++++++++++++++++++ config/samples/dev.yaml | 65 ++++ 21 files changed, 2040 insertions(+) create mode 100644 chart/.helmignore create mode 100644 chart/Chart.yaml create mode 100644 chart/templates/_helpers.tpl create mode 100644 chart/templates/deployment.yaml create mode 100644 chart/templates/enterprise-crd.yaml create mode 100644 chart/templates/image-crd.yaml create mode 100644 chart/templates/kube-state-metrics-config.yaml create mode 100644 chart/templates/leader-election-rbac.yaml create mode 100644 chart/templates/manager-rbac.yaml create mode 100644 chart/templates/organization-crd.yaml create mode 100644 chart/templates/pool-crd.yaml create mode 100644 chart/templates/repository-crd.yaml create mode 100644 chart/templates/runner-crd.yaml create mode 100644 chart/templates/selfsigned-issuer.yaml create mode 100644 chart/templates/serviceaccount.yaml create mode 100644 chart/templates/serving-cert.yaml create mode 100644 chart/templates/validating-webhook-configuration.yaml create mode 100644 chart/templates/webhook-service.yaml create mode 100644 chart/values.yaml create mode 100644 config/samples/dev.yaml diff --git a/Makefile b/Makefile index e31152df..fb1d88e5 100644 --- a/Makefile +++ b/Makefile @@ -329,3 +329,13 @@ delete-kind-cluster: .PHONY: tilt-up tilt-up: kind-cluster ## Start tilt and build kind cluster tilt up + +HELMIFY ?= $(LOCALBIN)/helmify + +.PHONY: helmify +helmify: $(HELMIFY) ## Download helmify locally if necessary. +$(HELMIFY): $(LOCALBIN) + test -s $(LOCALBIN)/helmify || GOBIN=$(LOCALBIN) go install github.com/arttor/helmify/cmd/helmify@latest + +helm: manifests kustomize helmify + $(KUSTOMIZE) build config/default | $(HELMIFY) diff --git a/chart/.helmignore b/chart/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/chart/.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/chart/Chart.yaml b/chart/Chart.yaml new file mode 100644 index 00000000..200d9732 --- /dev/null +++ b/chart/Chart.yaml @@ -0,0 +1,21 @@ +apiVersion: v2 +name: chart +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: "0.1.0" diff --git a/chart/templates/_helpers.tpl b/chart/templates/_helpers.tpl new file mode 100644 index 00000000..7ba5edc2 --- /dev/null +++ b/chart/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "chart.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 "chart.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 "chart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "chart.labels" -}} +helm.sh/chart: {{ include "chart.chart" . }} +{{ include "chart.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "chart.selectorLabels" -}} +app.kubernetes.io/name: {{ include "chart.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "chart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "chart.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/chart/templates/deployment.yaml b/chart/templates/deployment.yaml new file mode 100644 index 00000000..85d8addd --- /dev/null +++ b/chart/templates/deployment.yaml @@ -0,0 +1,89 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "chart.fullname" . }}-controller-manager + labels: + app.kubernetes.io/component: manager + app.kubernetes.io/created-by: garm-operator + app.kubernetes.io/part-of: garm-operator + control-plane: controller-manager + {{- include "chart.labels" . | nindent 4 }} + annotations: + prometheus.io/path: /metrics + prometheus.io/port: "8080" + prometheus.io/scrape: "true" +spec: + replicas: {{ .Values.controllerManager.replicas }} + selector: + matchLabels: + control-plane: controller-manager + {{- include "chart.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + control-plane: controller-manager + {{- include "chart.selectorLabels" . | nindent 8 }} + annotations: + kubectl.kubernetes.io/default-container: manager + spec: + containers: + - args: {{- toYaml .Values.controllerManager.manager.args | nindent 8 }} + command: + - /manager + env: + - name: KUBERNETES_CLUSTER_DOMAIN + value: {{ quote .Values.kubernetesClusterDomain }} + image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag + | default .Chart.AppVersion }} + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + ports: + - containerPort: 9443 + name: webhook-server + protocol: TCP + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: {{- toYaml .Values.controllerManager.manager.resources | nindent 10 + }} + securityContext: {{- toYaml .Values.controllerManager.manager.containerSecurityContext + | nindent 10 }} + volumeMounts: + - mountPath: /tmp/k8s-webhook-server/serving-certs + name: cert + readOnly: true + - mountPath: /var/run/secrets/kubernetes.io/serviceaccount + name: serviceaccount-volume + securityContext: + runAsNonRoot: true + serviceAccountName: {{ include "chart.fullname" . }}-controller-manager + volumes: + - name: cert + secret: + defaultMode: 420 + secretName: webhook-server-cert + - name: serviceaccount-volume + projected: + sources: + - serviceAccountToken: + expirationSeconds: 600 + path: token + - configMap: + items: + - key: ca.crt + path: ca.crt + name: kube-root-ca.crt + - downwardAPI: + items: + - fieldRef: + apiVersion: v1 + fieldPath: metadata.namespace + path: namespace \ No newline at end of file diff --git a/chart/templates/enterprise-crd.yaml b/chart/templates/enterprise-crd.yaml new file mode 100644 index 00000000..f3f59acd --- /dev/null +++ b/chart/templates/enterprise-crd.yaml @@ -0,0 +1,186 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: enterprises.garm-operator.mercedes-benz.com + annotations: + cert-manager.io/inject-ca-from: '{{ .Release.Namespace }}/{{ include "chart.fullname" + . }}-serving-cert' + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: '{{ include "chart.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /convert + conversionReviewVersions: + - v1 + group: garm-operator.mercedes-benz.com + names: + categories: + - garm + kind: Enterprise + listKind: EnterpriseList + plural: enterprises + shortNames: + - ent + singular: enterprise + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Enterprise ID + jsonPath: .status.id + name: ID + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Error + priority: 1 + type: string + - jsonPath: .status.conditions[?(@.reason=='PoolManagerFailure')].message + name: Pool_Manager_Failure + priority: 1 + type: string + - description: Time duration since creation of Enterprise + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Enterprise is the Schema for the enterprises API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: EnterpriseSpec defines the desired state of Enterprise + properties: + credentialsName: + type: string + webhookSecretRef: + description: WebhookSecretRef represents a secret that should be used + for the webhook + properties: + key: + description: Key is the key in the secret's data map for this value + type: string + name: + description: Name of the kubernetes secret to use + type: string + required: + - key + - name + type: object + required: + - credentialsName + - webhookSecretRef + type: object + status: + description: EnterpriseStatus defines the observed state of Enterprise + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for direct + use as an array at the field path .status.conditions. For example,\n\n\n\ttype + FooStatus struct{\n\t // Represents the observations of a foo's + current state.\n\t // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\"\n\t // +patchMergeKey=type\n\t + \ // +patchStrategy=merge\n\t // +listType=map\n\t // +listMapKey=type\n\t + \ Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + id: + type: string + required: + - id + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] \ No newline at end of file diff --git a/chart/templates/image-crd.yaml b/chart/templates/image-crd.yaml new file mode 100644 index 00000000..ed0edde4 --- /dev/null +++ b/chart/templates/image-crd.yaml @@ -0,0 +1,75 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: images.garm-operator.mercedes-benz.com + annotations: + cert-manager.io/inject-ca-from: '{{ .Release.Namespace }}/{{ include "chart.fullname" + . }}-serving-cert' + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + group: garm-operator.mercedes-benz.com + names: + categories: + - garm + kind: Image + listKind: ImageList + plural: images + singular: image + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .spec.tag + name: Tag + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Image is the Schema for the images API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ImageSpec defines the desired state of Image + properties: + tag: + description: |- + Tag is the Name of the image in its registry + e.g. + - in openstack it can be the image name or id + - in k8s it can be the docker image name + tag + type: string + type: object + status: + description: ImageStatus defines the observed state of Image + type: object + type: object + served: true + storage: true + subresources: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] \ No newline at end of file diff --git a/chart/templates/kube-state-metrics-config.yaml b/chart/templates/kube-state-metrics-config.yaml new file mode 100644 index 00000000..e8723c19 --- /dev/null +++ b/chart/templates/kube-state-metrics-config.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "chart.fullname" . }}-kube-state-metrics-config + labels: + app.kubernetes.io/component: metrics + {{- include "chart.labels" . | nindent 4 }} +data: + config.yaml: {{ .Values.kubeStateMetricsConfig.configYaml | toYaml | indent 1 }} \ No newline at end of file diff --git a/chart/templates/leader-election-rbac.yaml b/chart/templates/leader-election-rbac.yaml new file mode 100644 index 00000000..4f569af1 --- /dev/null +++ b/chart/templates/leader-election-rbac.yaml @@ -0,0 +1,59 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "chart.fullname" . }}-leader-election-role + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: garm-operator + app.kubernetes.io/part-of: garm-operator + {{- include "chart.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "chart.fullname" . }}-leader-election-rolebinding + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: garm-operator + app.kubernetes.io/part-of: garm-operator + {{- include "chart.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: '{{ include "chart.fullname" . }}-leader-election-role' +subjects: +- kind: ServiceAccount + name: '{{ include "chart.fullname" . }}-controller-manager' + namespace: '{{ .Release.Namespace }}' \ No newline at end of file diff --git a/chart/templates/manager-rbac.yaml b/chart/templates/manager-rbac.yaml new file mode 100644 index 00000000..faf3384a --- /dev/null +++ b/chart/templates/manager-rbac.yaml @@ -0,0 +1,184 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "chart.fullname" . }}-manager-role + labels: + {{- include "chart.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - secrets + verbs: + - get + - list + - watch +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - enterprises + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - enterprises/finalizers + verbs: + - update +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - enterprises/status + verbs: + - get + - patch + - update +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - images + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - organizations + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - organizations/finalizers + verbs: + - update +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - organizations/status + verbs: + - get + - patch + - update +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - pools + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - pools/status + verbs: + - get + - patch + - update +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - repositories + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - repositories/finalizers + verbs: + - update +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - repositories/status + verbs: + - get + - patch + - update +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - runners + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - runners/finalizers + verbs: + - update +- apiGroups: + - garm-operator.mercedes-benz.com + resources: + - runners/status + verbs: + - get + - patch + - update +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "chart.fullname" . }}-manager-role + labels: + {{- include "chart.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "chart.fullname" . }}-manager-rolebinding + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: garm-operator + app.kubernetes.io/part-of: garm-operator + {{- include "chart.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: '{{ include "chart.fullname" . }}-manager-role' +subjects: +- kind: ServiceAccount + name: '{{ include "chart.fullname" . }}-controller-manager' + namespace: '{{ .Release.Namespace }}' \ No newline at end of file diff --git a/chart/templates/organization-crd.yaml b/chart/templates/organization-crd.yaml new file mode 100644 index 00000000..85068341 --- /dev/null +++ b/chart/templates/organization-crd.yaml @@ -0,0 +1,186 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: organizations.garm-operator.mercedes-benz.com + annotations: + cert-manager.io/inject-ca-from: '{{ .Release.Namespace }}/{{ include "chart.fullname" + . }}-serving-cert' + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: '{{ include "chart.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /convert + conversionReviewVersions: + - v1 + group: garm-operator.mercedes-benz.com + names: + categories: + - garm + kind: Organization + listKind: OrganizationList + plural: organizations + shortNames: + - org + singular: organization + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Organization ID + jsonPath: .status.id + name: ID + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Error + priority: 1 + type: string + - jsonPath: .status.conditions[?(@.reason=='PoolManagerFailure')].message + name: Pool_Manager_Failure + priority: 1 + type: string + - description: Time duration since creation of Organization + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Organization is the Schema for the organizations API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: OrganizationSpec defines the desired state of Organization + properties: + credentialsName: + type: string + webhookSecretRef: + description: WebhookSecretRef represents a secret that should be used + for the webhook + properties: + key: + description: Key is the key in the secret's data map for this value + type: string + name: + description: Name of the kubernetes secret to use + type: string + required: + - key + - name + type: object + required: + - credentialsName + - webhookSecretRef + type: object + status: + description: OrganizationStatus defines the observed state of Organization + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for direct + use as an array at the field path .status.conditions. For example,\n\n\n\ttype + FooStatus struct{\n\t // Represents the observations of a foo's + current state.\n\t // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\"\n\t // +patchMergeKey=type\n\t + \ // +patchStrategy=merge\n\t // +listType=map\n\t // +listMapKey=type\n\t + \ Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + id: + type: string + required: + - id + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] \ No newline at end of file diff --git a/chart/templates/pool-crd.yaml b/chart/templates/pool-crd.yaml new file mode 100644 index 00000000..b7dbe3bf --- /dev/null +++ b/chart/templates/pool-crd.yaml @@ -0,0 +1,265 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: pools.garm-operator.mercedes-benz.com + annotations: + cert-manager.io/inject-ca-from: '{{ .Release.Namespace }}/{{ include "chart.fullname" + . }}-serving-cert' + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: '{{ include "chart.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /convert + conversionReviewVersions: + - v1 + group: garm-operator.mercedes-benz.com + names: + categories: + - garm + kind: Pool + listKind: PoolList + plural: pools + singular: pool + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.id + name: ID + type: string + - jsonPath: .spec.minIdleRunners + name: MinIdleRunners + type: string + - jsonPath: .spec.maxRunners + name: MaxRunners + type: string + - jsonPath: .spec.imageName + name: ImageName + priority: 1 + type: string + - jsonPath: .spec.flavor + name: Flavor + priority: 1 + type: string + - jsonPath: .spec.providerName + name: Provider + priority: 1 + type: string + - jsonPath: .spec.githubScopeRef.kind + name: ScopeType + priority: 1 + type: string + - jsonPath: .spec.githubScopeRef.name + name: ScopeName + priority: 1 + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Error + priority: 1 + type: string + - jsonPath: .spec.enabled + name: Enabled + priority: 1 + type: boolean + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Pool is the Schema for the pools API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + properties: + enabled: + type: boolean + extraSpecs: + type: string + flavor: + type: string + githubRunnerGroup: + type: string + githubScopeRef: + description: Defines in which Scope Runners a registered. Has a reference + to either an Enterprise, Org or Repo CRD + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + imageName: + description: The name of the image resource, this image resource must + exists in the same namespace as the pool + type: string + maxRunners: + type: integer + minIdleRunners: + default: 0 + type: integer + osArch: + type: string + osType: + type: string + providerName: + type: string + runnerBootstrapTimeout: + type: integer + runnerPrefix: + type: string + tags: + items: + type: string + type: array + required: + - enabled + - flavor + - githubScopeRef + - imageName + - maxRunners + - minIdleRunners + - osArch + - osType + - providerName + - runnerBootstrapTimeout + - tags + type: object + x-kubernetes-validations: + - message: minIdleRunners must be less than or equal to maxRunners + rule: self.minIdleRunners <= self.maxRunners + status: + description: PoolStatus defines the observed state of Pool + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for direct + use as an array at the field path .status.conditions. For example,\n\n\n\ttype + FooStatus struct{\n\t // Represents the observations of a foo's + current state.\n\t // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\"\n\t // +patchMergeKey=type\n\t + \ // +patchStrategy=merge\n\t // +listType=map\n\t // +listMapKey=type\n\t + \ Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + id: + type: string + longRunningIdleRunners: + type: integer + selector: + type: string + required: + - id + - longRunningIdleRunners + - selector + type: object + type: object + served: true + storage: true + subresources: + scale: + labelSelectorPath: .status.selector + specReplicasPath: .spec.minIdleRunners + statusReplicasPath: .status.longRunningIdleRunners + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] \ No newline at end of file diff --git a/chart/templates/repository-crd.yaml b/chart/templates/repository-crd.yaml new file mode 100644 index 00000000..b9b97097 --- /dev/null +++ b/chart/templates/repository-crd.yaml @@ -0,0 +1,189 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: repositories.garm-operator.mercedes-benz.com + annotations: + cert-manager.io/inject-ca-from: '{{ .Release.Namespace }}/{{ include "chart.fullname" + . }}-serving-cert' + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + conversion: + strategy: Webhook + webhook: + clientConfig: + service: + name: '{{ include "chart.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /convert + conversionReviewVersions: + - v1 + group: garm-operator.mercedes-benz.com + names: + categories: + - garm + kind: Repository + listKind: RepositoryList + plural: repositories + shortNames: + - repo + singular: repository + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Repository ID + jsonPath: .status.id + name: ID + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].status + name: Ready + type: string + - jsonPath: .status.conditions[?(@.type=='Ready')].message + name: Error + priority: 1 + type: string + - jsonPath: .status.conditions[?(@.reason=='PoolManagerFailure')].message + name: Pool_Manager_Failure + priority: 1 + type: string + - description: Time duration since creation of Repository + jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Repository is the Schema for the repositories API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: RepositorySpec defines the desired state of Repository + properties: + credentialsName: + type: string + owner: + type: string + webhookSecretRef: + description: WebhookSecretRef represents a secret that should be used + for the webhook + properties: + key: + description: Key is the key in the secret's data map for this value + type: string + name: + description: Name of the kubernetes secret to use + type: string + required: + - key + - name + type: object + required: + - credentialsName + - owner + - webhookSecretRef + type: object + status: + description: RepositoryStatus defines the observed state of Repository + properties: + conditions: + items: + description: "Condition contains details for one aspect of the current + state of this API Resource.\n---\nThis struct is intended for direct + use as an array at the field path .status.conditions. For example,\n\n\n\ttype + FooStatus struct{\n\t // Represents the observations of a foo's + current state.\n\t // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\"\n\t // +patchMergeKey=type\n\t + \ // +patchStrategy=merge\n\t // +listType=map\n\t // +listMapKey=type\n\t + \ Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + id: + type: string + required: + - id + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] \ No newline at end of file diff --git a/chart/templates/runner-crd.yaml b/chart/templates/runner-crd.yaml new file mode 100644 index 00000000..c2378a27 --- /dev/null +++ b/chart/templates/runner-crd.yaml @@ -0,0 +1,166 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: runners.garm-operator.mercedes-benz.com + annotations: + cert-manager.io/inject-ca-from: '{{ .Release.Namespace }}/{{ include "chart.fullname" + . }}-serving-cert' + controller-gen.kubebuilder.io/version: v0.15.0 + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + group: garm-operator.mercedes-benz.com + names: + categories: + - garm + kind: Runner + listKind: RunnerList + plural: runners + shortNames: + - run + singular: runner + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Runner ID + jsonPath: .status.id + name: ID + type: string + - description: Pool CR Name + jsonPath: .status.poolId + name: Pool + type: string + - description: Garm Runner Status + jsonPath: .status.status + name: Garm Runner Status + type: string + - description: Provider Runner Status + jsonPath: .status.instanceStatus + name: Provider Runner Status + type: string + - description: Provider ID + jsonPath: .status.providerId + name: Provider ID + priority: 1 + type: string + - description: Agent ID + jsonPath: .status.agentId + name: Agent ID + priority: 1 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: Runner is the Schema for the runners API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: RunnerSpec defines the desired state of Runner + type: object + status: + description: RunnerStatus defines the observed state of Runner + properties: + addresses: + description: |- + Addresses is a list of IP addresses the provider reports + for this instance. + items: + properties: + address: + type: string + type: + type: string + required: + - address + - type + type: object + type: array + agentId: + description: AgentID is the github runner agent ID. + format: int64 + type: integer + githubRunnerGroup: + description: |- + GithubRunnerGroup is the github runner group to which the runner belongs. + The runner group must be created by someone with access to the enterprise. + type: string + id: + description: ID is the database ID of this instance. + type: string + instanceStatus: + description: RunnerStatus is the github runner status as it appears + on GitHub. + type: string + name: + description: |- + Name is the name associated with an instance. Depending on + the provider, this may or may not be useful in the context of + the provider, but we can use it internally to identify the + instance. + type: string + osArch: + description: OSArch is the operating system architecture. + type: string + osName: + description: 'OSName is the name of the OS. Eg: ubuntu, centos, etc.' + type: string + osType: + description: |- + OSType is the operating system type. For now, only Linux and + Windows are supported. + type: string + osVersion: + description: OSVersion is the version of the operating system. + type: string + poolId: + description: PoolID is the ID of the garm pool to which a runner belongs. + type: string + providerFault: + description: |- + ProviderFault holds any error messages captured from the IaaS provider that is + responsible for managing the lifecycle of the runner. + type: string + providerId: + description: |- + PeoviderID is the unique ID the provider associated + with the compute instance. We use this to identify the + instance in the provider. + type: string + status: + description: 'Status is the status of the instance inside the provider + (eg: running, stopped, etc)' + type: string + required: + - agentId + - githubRunnerGroup + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] \ No newline at end of file diff --git a/chart/templates/selfsigned-issuer.yaml b/chart/templates/selfsigned-issuer.yaml new file mode 100644 index 00000000..e2a3feaf --- /dev/null +++ b/chart/templates/selfsigned-issuer.yaml @@ -0,0 +1,8 @@ +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: {{ include "chart.fullname" . }}-selfsigned-issuer + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + selfSigned: {} \ No newline at end of file diff --git a/chart/templates/serviceaccount.yaml b/chart/templates/serviceaccount.yaml new file mode 100644 index 00000000..6a738490 --- /dev/null +++ b/chart/templates/serviceaccount.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "chart.fullname" . }}-controller-manager + labels: + app.kubernetes.io/component: rbac + app.kubernetes.io/created-by: garm-operator + app.kubernetes.io/part-of: garm-operator + {{- include "chart.labels" . | nindent 4 }} + annotations: + {{- toYaml .Values.controllerManager.serviceAccount.annotations | nindent 4 }} \ No newline at end of file diff --git a/chart/templates/serving-cert.yaml b/chart/templates/serving-cert.yaml new file mode 100644 index 00000000..5e87f6d1 --- /dev/null +++ b/chart/templates/serving-cert.yaml @@ -0,0 +1,15 @@ +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: {{ include "chart.fullname" . }}-serving-cert + labels: + {{- include "chart.labels" . | nindent 4 }} +spec: + dnsNames: + - '{{ include "chart.fullname" . }}-webhook-service.{{ .Release.Namespace }}.svc' + - '{{ include "chart.fullname" . }}-webhook-service.{{ .Release.Namespace }}.svc.{{ + .Values.kubernetesClusterDomain }}' + issuerRef: + kind: Issuer + name: '{{ include "chart.fullname" . }}-selfsigned-issuer' + secretName: webhook-server-cert \ No newline at end of file diff --git a/chart/templates/validating-webhook-configuration.yaml b/chart/templates/validating-webhook-configuration.yaml new file mode 100644 index 00000000..a2420d52 --- /dev/null +++ b/chart/templates/validating-webhook-configuration.yaml @@ -0,0 +1,70 @@ +apiVersion: admissionregistration.k8s.io/v1 +kind: ValidatingWebhookConfiguration +metadata: + name: {{ include "chart.fullname" . }}-validating-webhook-configuration + annotations: + cert-manager.io/inject-ca-from: {{ .Release.Namespace }}/{{ include "chart.fullname" . }}-serving-cert + labels: + {{- include "chart.labels" . | nindent 4 }} +webhooks: +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: '{{ include "chart.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /validate-garm-operator-mercedes-benz-com-v1alpha1-image + failurePolicy: Fail + name: validate.image.garm-operator.mercedes-benz.com + rules: + - apiGroups: + - garm-operator.mercedes-benz.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + - DELETE + resources: + - images + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: '{{ include "chart.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /validate-garm-operator-mercedes-benz-com-v1alpha1-pool + failurePolicy: Fail + name: validate.pool.garm-operator.mercedes-benz.com + rules: + - apiGroups: + - garm-operator.mercedes-benz.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - pools + sideEffects: None +- admissionReviewVersions: + - v1 + clientConfig: + service: + name: '{{ include "chart.fullname" . }}-webhook-service' + namespace: '{{ .Release.Namespace }}' + path: /validate-garm-operator-mercedes-benz-com-v1alpha1-repository + failurePolicy: Fail + name: validate.repository.garm-operator.mercedes-benz.com + rules: + - apiGroups: + - garm-operator.mercedes-benz.com + apiVersions: + - v1alpha1 + operations: + - CREATE + - UPDATE + resources: + - repositories + sideEffects: None \ No newline at end of file diff --git a/chart/templates/webhook-service.yaml b/chart/templates/webhook-service.yaml new file mode 100644 index 00000000..33306bfb --- /dev/null +++ b/chart/templates/webhook-service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "chart.fullname" . }}-webhook-service + labels: + app.kubernetes.io/component: webhook + app.kubernetes.io/created-by: garm-operator + app.kubernetes.io/part-of: garm-operator + {{- include "chart.labels" . | nindent 4 }} +spec: + type: {{ .Values.webhookService.type }} + selector: + control-plane: controller-manager + {{- include "chart.selectorLabels" . | nindent 4 }} + ports: + {{- .Values.webhookService.ports | toYaml | nindent 2 }} \ No newline at end of file diff --git a/chart/values.yaml b/chart/values.yaml new file mode 100644 index 00000000..303784de --- /dev/null +++ b/chart/values.yaml @@ -0,0 +1,331 @@ +controllerManager: + manager: + args: + - --garm-server=$GARM_SERVER_URL + - --garm-username=$GARM_SERVER_USERNAME + - --garm-password=$GARM_SERVER_PASSWORD + - --operator-watch-namespace=$OPERATOR_WATCH_NAMESPACE + containerSecurityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + image: + repository: controller + tag: latest + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 10m + memory: 64Mi + replicas: 1 + serviceAccount: + annotations: {} +kubeStateMetricsConfig: + configYaml: |- + kind: CustomResourceStateMetrics + spec: + resources: + ################## + # ENTERPRISE # + ################# + - groupVersionKind: + group: garm-operator.mercedes-benz.com + kind: "Enterprise" + version: "v1alpha1" + metricNamePrefix: garm_operator + commonLabels: + crd_type: "enterprise" + labelsFromPath: + name: [ metadata, name ] + namespace: [ metadata, namespace ] + metrics: + - name: enterprise_created + help: Unix creation timestamp. + each: + gauge: + path: + - metadata + - creationTimestamp + type: Gauge + - name: enterprise_info + help: Information about an enterprise. + each: + type: Info + info: + labelsFromPath: + credentialsName: [ spec, credentialsName ] + webhookSecretRefKey: [ spec, webhookSecretRef, key ] + webhookSecretRefName: [ spec, webhookSecretRef, name ] + id: [ status, id ] + - name: enterprise_annotation_paused_info + help: Whether the enterprise reconciliation is paused. + each: + type: Info + info: + path: + - metadata + - annotations + - garm-operator.mercedes-benz.com/paused + labelsFromPath: + paused_value: [] + - name: enterprise_status_conditions + help: Displays whether status of each possible condition is True or False. + each: + type: Gauge + gauge: + path: + - status + - conditions + valueFrom: + - status + labelFromKey: reason + labelsFromPath: + type: [ type ] + ################## + # Org # + ################# + - groupVersionKind: + group: garm-operator.mercedes-benz.com + kind: "Organization" + version: "v1alpha1" + metricNamePrefix: garm_operator + commonLabels: + crd_type: "organization" + labelsFromPath: + name: [ metadata, name ] + namespace: [ metadata, namespace ] + metrics: + - name: org_created + help: Unix creation timestamp. + each: + gauge: + path: + - metadata + - creationTimestamp + type: Gauge + - name: org_info + help: Information about an organization. + each: + type: Info + info: + labelsFromPath: + credentialsName: [ spec, credentialsName ] + webhookSecretRefKey: [ spec, webhookSecretRef, key ] + webhookSecretRefName: [ spec, webhookSecretRef, name ] + id: [ status, id ] + - name: org_annotation_paused_info + help: Whether the org reconciliation is paused. + each: + type: Info + info: + path: + - metadata + - annotations + - garm-operator.mercedes-benz.com/paused + labelsFromPath: + paused_value: [ ] + - name: org_status_conditions + help: Displays whether status of each possible condition is True or False. + each: + type: Gauge + gauge: + path: + - status + - conditions + valueFrom: + - status + labelFromKey: reason + labelsFromPath: + type: [ type ] + ################## + # Repo # + ################# + - groupVersionKind: + group: garm-operator.mercedes-benz.com + kind: "Repository" + version: "v1alpha1" + metricNamePrefix: garm_operator + commonLabels: + crd_type: "repository" + labelsFromPath: + name: [ metadata, name ] + namespace: [ metadata, namespace ] + metrics: + - name: repo_created + help: Unix creation timestamp. + each: + gauge: + path: + - metadata + - creationTimestamp + type: Gauge + - name: repo_info + help: Information about a repository. + each: + type: Info + info: + labelsFromPath: + owner: [ spec, owner ] + credentialsName: [ spec, credentialsName ] + webhookSecretRefKey: [ spec, webhookSecretRef, key ] + webhookSecretRefName: [ spec, webhookSecretRef, name ] + id: [ status, id ] + - name: repo_annotation_paused_info + help: Whether the repo reconciliation is paused. + each: + type: Info + info: + path: + - metadata + - annotations + - garm-operator.mercedes-benz.com/paused + labelsFromPath: + paused_value: [ ] + - name: repo_status_conditions + help: Displays whether status of each possible condition is True or False. + each: + type: Gauge + gauge: + path: + - status + - conditions + valueFrom: + - status + labelFromKey: reason + labelsFromPath: + type: [ type ] + ################## + # Pool # + ################# + - groupVersionKind: + group: garm-operator.mercedes-benz.com + kind: "Pool" + version: "v1alpha1" + metricNamePrefix: garm_operator + commonLabels: + crd_type: "pool" + labelsFromPath: + name: [ metadata, name ] + namespace: [ metadata, namespace ] + metrics: + - name: pool_created + help: Unix creation timestamp. + each: + gauge: + path: + - metadata + - creationTimestamp + type: Gauge + - name: pool_info + help: Information about a pool. + each: + type: Info + info: + labelsFromPath: + githubRunnerGroup: [spec, githubRunnerGroup] + scopeKind: [spec, githubScopeRef, kind] + scopeName: [spec, githubScopeRef, name] + imageName: [spec, imageName] + osArch: [spec, osArch] + osType: [spec, osType] + providerName: [spec, providerName] + runnerBootstrapTimeout: [spec, runnerBootstrapTimeout] + runnerPrefix: [spec, runnerPrefix] + tags: [spec, tags] + id: [status, id] + - name: pool_enabled + help: Whether the pool is enabled. + each: + type: Gauge + gauge: + nilIsZero: true + path: + - spec + - enabled + - name: pool_min_idle_runners + help: Minimum number of idle runners. + each: + type: Gauge + gauge: + path: + - spec + - minIdleRunners + - name: pool_max_runners + help: Maximum number of runners. + each: + type: Gauge + gauge: + path: + - spec + - maxRunners + - name: status_long_running_idle_runners + help: Number of long running idle runners. + each: + type: Gauge + gauge: + path: + - status + - longRunningIdleRunners + - name: pool_annotation_paused_info + help: Whether the pool reconciliation is paused. + each: + type: Info + info: + path: + - metadata + - annotations + - garm-operator.mercedes-benz.com/paused + labelsFromPath: + paused_value: [ ] + - name: pool_status_conditions + help: Displays whether status of each possible condition is True or False. + each: + type: Gauge + gauge: + path: + - status + - conditions + valueFrom: + - status + labelFromKey: reason + labelsFromPath: + type: [ type ] + ################## + # Image # + ################# + - groupVersionKind: + group: garm-operator.mercedes-benz.com + kind: "Image" + version: "v1alpha1" + metricNamePrefix: garm_operator + commonLabels: + crd_type: "image" + labelsFromPath: + name: [ metadata, name ] + namespace: [ metadata, namespace ] + metrics: + - name: image_created + help: Unix creation timestamp. + each: + gauge: + path: + - metadata + - creationTimestamp + type: Gauge + - name: image_info + help: Information about an image. + each: + type: Info + info: + labelsFromPath: + tag: [spec, tag] +kubernetesClusterDomain: cluster.local +webhookService: + ports: + - port: 443 + protocol: TCP + targetPort: 9443 + type: ClusterIP diff --git a/config/samples/dev.yaml b/config/samples/dev.yaml new file mode 100644 index 00000000..343ba350 --- /dev/null +++ b/config/samples/dev.yaml @@ -0,0 +1,65 @@ +apiVersion: garm-operator.mercedes-benz.com/v1alpha1 +kind: Image +metadata: + labels: + app.kubernetes.io/name: image + app.kubernetes.io/instance: image-sample + app.kubernetes.io/part-of: garm-operator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: garm-operator + name: runner-default + namespace: garm-operator-system +spec: + tag: runner:linux-ubuntu-22.04-arm64 +--- +apiVersion: garm-operator.mercedes-benz.com/v1alpha1 +kind: Organization +metadata: + labels: + app.kubernetes.io/name: organization + app.kubernetes.io/instance: organization-sample + app.kubernetes.io/part-of: garm-operator + app.kubernetes.io/managed-by: kustomize + app.kubernetes.io/created-by: garm-operator + name: github-actions + namespace: garm-operator-system +spec: + webhookSecretRef: + key: "webhookSecret" + name: "org-webhook-secret" + credentialsName: "github-pat" +--- +apiVersion: v1 +kind: Secret +metadata: + name: org-webhook-secret + namespace: garm-operator-system +data: + webhookSecret: bXlzZWNyZXQ= +--- +apiVersion: garm-operator.mercedes-benz.com/v1alpha1 +kind: Pool +metadata: + name: kubernetes-pool-medium-org-github-actions + namespace: garm-operator-system +spec: + githubScopeRef: + apiGroup: garm-operator.mercedes-benz.com + kind: Organization + name: github-actions + enabled: true + flavor: medium + extraSpecs: '{}' + githubRunnerGroup: "" + imageName: runner-default + maxRunners: 2 + minIdleRunners: 1 + osArch: arm64 + osType: linux + providerName: kubernetes_external + runnerBootstrapTimeout: 2 + runnerPrefix: "road-runner-k8s-rthalho" + tags: + - medium + - k8s-dev + - garm-operator-dev