diff --git a/.gitignore b/.gitignore index ada68ff..a9814ab 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,8 @@ go.work *.swp *.swo *~ + +# Helm lock files & local charts +deploy/charts/*/charts +requirements.lock +Chart.lock \ No newline at end of file diff --git a/.mise.toml b/.mise.toml index 0a95e6e..de33046 100644 --- a/.mise.toml +++ b/.mise.toml @@ -3,9 +3,12 @@ actionlint = '1.7.1' ginkgo = '2.19.0' golang = '1.21' golangci-lint = '1.57.2' +helm = '3.15' +helm-ct = '3.11.0' +helm-docs = '1.13.1' kube-controller-tools = '0.14.0' kubectl = '1.31' kustomize = '5.3.0' -setup-envtest = '0.17.0' -yamllint = '1.35.1' pre-commit = '3.8.0' +setup-envtest = '0.17.0' +yamllint = '1.35.1' \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 89b3b46..d3a04c8 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,21 +6,30 @@ repos: rev: v4.3.0 hooks: - id: check-merge-conflict - - id: check-yaml - args: - - --allow-multiple-documents - id: detect-private-key - id: no-commit-to-branch - id: trailing-whitespace + - repo: https://github.com/rhysd/actionlint + rev: v1.7.1 + hooks: + - id: actionlint + + - repo: https://github.com/norwoodj/helm-docs + rev: v1.11.0 + hooks: + - id: helm-docs + args: + - --template-files=README.md.gotmpl + + - repo: https://github.com/gruntwork-io/pre-commit + rev: v0.1.17 + hooks: + - id: helmlint + - repo: https://github.com/adrienverge/yamllint.git rev: v1.28.0 hooks: - id: yamllint args: - --strict - - - repo: https://github.com/rhysd/actionlint - rev: v1.7.1 - hooks: - - id: actionlint diff --git a/.yamllint b/.yamllint index 20ba0e7..9f62988 100644 --- a/.yamllint +++ b/.yamllint @@ -3,6 +3,7 @@ extends: default ignore: | config/ + deploy/ rules: comments: diff --git a/config/rbac/auth_proxy_client_clusterrole.yaml b/config/rbac/auth_proxy_client_clusterrole.yaml index d8bb099..60f2732 100644 --- a/config/rbac/auth_proxy_client_clusterrole.yaml +++ b/config/rbac/auth_proxy_client_clusterrole.yaml @@ -1,3 +1,4 @@ +# this is the only file that hasn't been converted to a helm template apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: diff --git a/deploy/charts/prefect-operator/.helmignore b/deploy/charts/prefect-operator/.helmignore new file mode 100644 index 0000000..f0c1319 --- /dev/null +++ b/deploy/charts/prefect-operator/.helmignore @@ -0,0 +1,21 @@ +# 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 +*~ +# Various IDEs +.project +.idea/ +*.tmproj diff --git a/deploy/charts/prefect-operator/Chart.yaml b/deploy/charts/prefect-operator/Chart.yaml new file mode 100644 index 0000000..85b4bde --- /dev/null +++ b/deploy/charts/prefect-operator/Chart.yaml @@ -0,0 +1,26 @@ +apiVersion: v2 +dependencies: + - name: common + repository: https://charts.bitnami.com/bitnami + tags: + - bitnami-common + version: 2.20.5 +description: Prefect Operator application bundle +engine: gotpl +home: https://github.com/PrefectHQ +maintainers: + - name: jamiezieziula + email: jamie@prefect.io + - name: jimid27 + email: jimi@prefect.io + - name: parkedwards + email: edward@prefect.io + - name: mitchnielsen + email: mitchell@prefect.io +name: prefect-operator +sources: + - https://github.com/PrefectHQ/prefect-operator +type: application +# The version and appVersion fields are set automatically by the release tool +version: v0.0.0 +appVersion: v0.0.0 diff --git a/deploy/charts/prefect-operator/README.md b/deploy/charts/prefect-operator/README.md new file mode 100644 index 0000000..575fafe --- /dev/null +++ b/deploy/charts/prefect-operator/README.md @@ -0,0 +1,77 @@ +# prefect-operator + +![Version: v0.0.0](https://img.shields.io/badge/Version-v0.0.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v0.0.0](https://img.shields.io/badge/AppVersion-v0.0.0-informational?style=flat-square) + +Prefect Operator application bundle + +**Homepage:** + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| jamiezieziula | | | +| jimid27 | | | +| parkedwards | | | +| mitchnielsen | | | + +## Source Code + +* + +## Requirements + +| Repository | Name | Version | +|------------|------|---------| +| https://charts.bitnami.com/bitnami | common | 2.20.5 | + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| commonAnnotations | object | `{}` | annotations to add to all deployed objects | +| commonLabels | object | `{"app.kubernetes.io/component":"operator"}` | labels to add to all deployed objects | +| fullnameOverride | string | `"prefect-operator"` | fully override common.names.fullname | +| kubeRbacProxy.create | bool | `true` | specifies whether the kube-rbac-proxy should be deployed to the cluster | +| kubeRbacProxy.image | string | `"gcr.io/kubebuilder/kube-rbac-proxy:v0.16.0"` | the image of the kube-rbac-proxy to use | +| kubeRbacProxy.name | string | `"kube-rbac-proxy"` | the name of the kube-rbac-proxy to use | +| metrics.enabled | bool | `false` | enable the export of Prometheus metrics | +| metrics.serviceMonitor.enabled | bool | `false` | creates a Prometheus Operator ServiceMonitor (also requires `metrics.enabled` to be `true`) | +| nameOverride | string | `""` | partially overrides common.names.name | +| namespaceOverride | string | `""` | fully override common.names.namespace | +| operator.affinity | object | `{}` | affinity for operator pods assignment | +| operator.containerSecurityContext.allowPrivilegeEscalation | bool | `false` | set operator containers' security context allowPrivilegeEscalation | +| operator.containerSecurityContext.capabilities | object | `{"drop":["ALL"]}` | set operator container's security context capabilities | +| operator.extraEnvVars | list | `[]` | array with environment variables to add to operator container | +| operator.image.pullPolicy | string | `"IfNotPresent"` | operator image pull policy | +| operator.image.pullSecrets | list | `[]` | operator image pull secrets | +| operator.image.repository | string | `"prefecthq/prefect-operator"` | operator image repository | +| operator.image.tag | string | `"latest"` | operator image tag (immutable tags are recommended) | +| operator.livenessProbe.config.initialDelaySeconds | int | `15` | The number of seconds to wait before starting the first probe. | +| operator.livenessProbe.config.periodSeconds | int | `20` | The number of seconds to wait between consecutive probes. | +| operator.livenessProbe.enabled | bool | `true` | | +| operator.nodeSelector | object | `{}` | node labels for operator pods assignment | +| operator.podAnnotations | object | `{}` | extra annotations for operator pod | +| operator.podLabels | object | `{}` | extra labels for operator pod | +| operator.podSecurityContext.runAsNonRoot | bool | `true` | set operator pod's security context runAsNonRoot | +| operator.priorityClassName | string | `""` | priority class name to use for the operator pods; if the priority class is empty or doesn't exist, the operator pods are scheduled without a priority class | +| operator.readinessProbe.config.initialDelaySeconds | int | `5` | The number of seconds to wait before starting the first probe. | +| operator.readinessProbe.config.periodSeconds | int | `10` | The number of seconds to wait between consecutive probes. | +| operator.readinessProbe.enabled | bool | `true` | | +| operator.replicaCount | int | `1` | number of operator replicas to deploy | +| operator.resources.limits | object | `{"cpu":"500m","memory":"128Mi"}` | the requested limits for the operator container | +| operator.resources.requests | object | `{"cpu":"10m","memory":"64Mi"}` | the requested resources for the operator container | +| operator.terminationGracePeriodSeconds | int | `10` | seconds operator pod needs to terminate gracefully | +| operator.tolerations | list | `[]` | tolerations for operator pods assignment | +| operator.topologySpreadConstraints | list | `[]` | topology spread constraints for operator pod assignment spread across your cluster among failure-domains | +| rbac.operator.create | bool | `true` | specifies whether the operator role & role binding should be created | +| rbac.userRoles.prefectServer.editor.create | bool | `true` | specifies whether the server editor role should be created | +| rbac.userRoles.prefectServer.viewer.create | bool | `true` | specifies whether the server viewer role should be created | +| rbac.userRoles.prefectWorkpool.editor.create | bool | `true` | specifies whether the workpool editor role should be created | +| rbac.userRoles.prefectWorkpool.viewer.create | bool | `true` | specifies whether the workpool viewer role should be created | +| serviceAccount.annotations | object | `{}` | additional service account annotations (evaluated as a template) | +| serviceAccount.create | bool | `true` | specifies whether a ServiceAccount should be created | +| serviceAccount.name | string | `""` | the name of the ServiceAccount to use. if not set and create is true, a name is generated using the common.names.fullname template | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.13.1](https://github.com/norwoodj/helm-docs/releases/v1.13.1) diff --git a/deploy/charts/prefect-operator/crds/prefect.io_prefectservers.yaml b/deploy/charts/prefect-operator/crds/prefect.io_prefectservers.yaml new file mode 100644 index 0000000..8a4b8fd --- /dev/null +++ b/deploy/charts/prefect-operator/crds/prefect.io_prefectservers.yaml @@ -0,0 +1,791 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: prefectservers.prefect.io +spec: + group: prefect.io + names: + kind: PrefectServer + listKind: PrefectServerList + plural: prefectservers + singular: prefectserver + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The version of this Prefect server + jsonPath: .status.version + name: Version + type: string + - description: Whether this Prefect server is ready to receive requests + jsonPath: .status.ready + name: Ready + type: boolean + name: v1 + schema: + openAPIV3Schema: + description: PrefectServer is the Schema for the prefectservers 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: PrefectServerSpec defines the desired state of a PrefectServer + properties: + ephemeral: + description: Ephemeral defines whether the server will be deployed + with an ephemeral storage backend + type: object + image: + description: Image defines the exact image to deploy for the Prefect + Server, overriding Version + type: string + postgres: + description: |- + Postgres defines whether the server will be deployed with a PostgreSQL backend connecting to the + database with the provided connection information + properties: + database: + type: string + databaseFrom: + description: EnvVarSource represents a source for the value of + an EnvVar. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath is written + in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + host: + type: string + hostFrom: + description: EnvVarSource represents a source for the value of + an EnvVar. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath is written + in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + password: + type: string + passwordFrom: + description: EnvVarSource represents a source for the value of + an EnvVar. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath is written + in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + port: + type: integer + portFrom: + description: EnvVarSource represents a source for the value of + an EnvVar. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath is written + in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + user: + type: string + userFrom: + description: EnvVarSource represents a source for the value of + an EnvVar. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath is written + in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, optional + for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + type: object + resources: + description: Resources defines the CPU and memory resources for each + replica of the Prefect Server + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + settings: + description: A list of environment variables to set on the Prefect + Server + items: + description: EnvVar represents an environment variable present in + a Container. + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. Cannot + be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath is + written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + sqlite: + description: SQLite defines whether the server will be deployed with + a SQLite backend with persistent volume storage + properties: + size: + anyOf: + - type: integer + - type: string + description: Size is the requested size of the PersistentVolumeClaim + storing the `prefect.db` + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + storageClassName: + description: StorageClassName is the name of the StorageClass + of the PersistentVolumeClaim storing the SQLite database + type: string + type: object + version: + description: Version defines the version of the Prefect Server to + deploy + type: string + type: object + status: + description: PrefectServerStatus defines the observed state of PrefectServer + properties: + conditions: + description: Conditions store the status conditions of the PrefectServer + instances + 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 + ready: + description: Ready indicates that the PrefectServer is ready to serve + requests + type: boolean + version: + description: Version is the version of the PrefectServer that is currently + running + type: string + required: + - ready + - version + type: object + type: object + served: true + storage: true + subresources: + status: {} \ No newline at end of file diff --git a/deploy/charts/prefect-operator/crds/prefect.io_prefectworkpools.yaml b/deploy/charts/prefect-operator/crds/prefect.io_prefectworkpools.yaml new file mode 100644 index 0000000..3588a57 --- /dev/null +++ b/deploy/charts/prefect-operator/crds/prefect.io_prefectworkpools.yaml @@ -0,0 +1,464 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: prefectworkpools.prefect.io +spec: + group: prefect.io + names: + kind: PrefectWorkPool + listKind: PrefectWorkPoolList + plural: prefectworkpools + singular: prefectworkpool + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The type of this work pool + jsonPath: .spec.type + name: Type + type: string + - description: The version of this work pool + jsonPath: .status.version + name: Version + type: string + - description: Whether the work pool is ready + jsonPath: .status.ready + name: Ready + type: boolean + - description: How many workers are desired + jsonPath: .spec.workers + name: Desired Workers + type: integer + - description: How many workers are ready + jsonPath: .status.readyWorkers + name: Ready Workers + type: integer + name: v1 + schema: + openAPIV3Schema: + description: PrefectWorkPool is the Schema for the prefectworkpools 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: PrefectWorkPoolSpec defines the desired state of PrefectWorkPool + properties: + image: + description: Image defines the exact image to deploy for the Prefect + Server, overriding Version + type: string + resources: + description: Resources defines the CPU and memory resources for each + worker in the Work Pool + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + server: + description: Server defines which Prefect Server to connect to + properties: + accountId: + description: AccountID is the ID of the account to use to connect + to Prefect Cloud + type: string + apiKey: + description: APIKey is the API key to use to connect to a remote + Prefect Server + properties: + value: + description: Value is the literal value of the API key + type: string + valueFrom: + description: ValueFrom is a reference to a secret containing + the API key + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath is + written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + type: object + name: + description: Name is the name of the in-cluster Prefect Server + in the given namespace + type: string + namespace: + description: Namespace is the namespace where the in-cluster Prefect + Server is running + type: string + remoteApiUrl: + description: RemoteAPIURL is the API URL for the remote Prefect + Server. Set if using with an external Prefect Server or Prefect + Cloud + type: string + workspaceId: + description: WorkspaceID is the ID of the workspace to use to + connect to Prefect Cloud + type: string + type: object + settings: + description: A list of environment variables to set on the Prefect + Worker + items: + description: EnvVar represents an environment variable present in + a Container. + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. Cannot + be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath is + written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified + API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed + resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + type: + description: The type of the work pool, such as "kubernetes" or "process" + type: string + version: + description: Version defines the version of the Prefect Server to + deploy + type: string + workers: + description: Workers defines the number of workers to run in the Work + Pool + format: int32 + type: integer + type: object + status: + description: PrefectWorkPoolStatus defines the observed state of PrefectWorkPool + properties: + conditions: + description: Conditions store the status conditions of the PrefectWorkPool + instances + 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 + ready: + description: Ready is true if the work pool is ready to accept work + type: boolean + readyWorkers: + description: ReadyWorkers is the number of workers that are currently + ready + format: int32 + type: integer + version: + description: Version is the version of the Prefect Worker that is + currently running + type: string + required: + - ready + - readyWorkers + - version + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/deploy/charts/prefect-operator/templates/_helpers.tpl b/deploy/charts/prefect-operator/templates/_helpers.tpl new file mode 100644 index 0000000..73c4e22 --- /dev/null +++ b/deploy/charts/prefect-operator/templates/_helpers.tpl @@ -0,0 +1,10 @@ +{{/* +Create the name of the service account to use +*/}} +{{- define "operator.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "common.names.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/deploy/charts/prefect-operator/templates/deployment.yaml b/deploy/charts/prefect-operator/templates/deployment.yaml new file mode 100644 index 0000000..b4f907e --- /dev/null +++ b/deploy/charts/prefect-operator/templates/deployment.yaml @@ -0,0 +1,114 @@ +apiVersion: {{ include "common.capabilities.deployment.apiVersion" . }} +kind: Deployment +metadata: + name: {{ template "common.names.fullname" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} +spec: + replicas: {{ .Values.operator.replicaCount }} + {{- $podLabels := include "common.tplvalues.merge" (dict "values" (list .Values.operator.podLabels .Values.commonLabels) "context" .) }} + selector: + matchLabels: {{- include "common.labels.matchLabels" ( dict "customLabels" $podLabels "context" $ ) | nindent 6 }} + template: + metadata: + {{- if .Values.operator.podAnnotations }} + annotations: {{- include "common.tplvalues.render" (dict "value" .Values.operator.podAnnotations "context" $) | nindent 8 }} + {{- end }} + labels: {{- include "common.labels.standard" ( dict "customLabels" $podLabels "context" $ ) | nindent 8 }} + spec: + {{- if .Values.operator.image.pullSecrets }} + imagePullSecrets: + {{- range .Values.operator.image.pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + serviceAccountName: {{ template "operator.serviceAccountName" . }} + {{- if .Values.operator.affinity }} + affinity: {{- include "common.tplvalues.render" ( dict "value" .Values.operator.affinity "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.operator.nodeSelector }} + nodeSelector: {{- include "common.tplvalues.render" ( dict "value" .Values.operator.nodeSelector "context" $) | nindent 8 }} + {{- end }} + {{- if .Values.operator.tolerations }} + tolerations: {{- include "common.tplvalues.render" (dict "value" .Values.operator.tolerations "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.operator.priorityClassName }} + priorityClassName: {{ .Values.operator.priorityClassName | quote }} + {{- end }} + {{- if .Values.operator.topologySpreadConstraints }} + topologySpreadConstraints: {{- include "common.tplvalues.render" (dict "value" .Values.operator.topologySpreadConstraints "context" .) | nindent 8 }} + {{- end }} + {{- if .Values.operator.podSecurityContext }} + securityContext: {{- .Values.operator.podSecurityContext | toYaml | nindent 8 }} + {{- end }} + {{- if .Values.operator.terminationGracePeriodSeconds }} + terminationGracePeriodSeconds: {{ .Values.operator.terminationGracePeriodSeconds }} + {{- end }} + containers: + - name: operator + image: "{{ .Values.operator.image.repository }}:{{ .Values.operator.image.tag }}" + imagePullPolicy: {{ .Values.operator.image.pullPolicy }} + {{- if .Values.operator.containerSecurityContext.enabled }} + securityContext: {{- include "common.compatibility.renderSecurityContext" (dict "secContext" .Values.operator.containerSecurityContext "context" $) | nindent 12 }} + {{- end }} + command: + - /manager + args: + {{- if .Values.kubeRbacProxy.create }} + - --health-probe-bind-address=:8081 + - --metrics-bind-address=127.0.0.1:8080 + {{- end }} + - --leader-elect + env: + {{- if .Values.operator.extraEnvVars }} + {{- include "common.tplvalues.render" (dict "value" .Values.operator.extraEnvVars "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.operator.resources }} + resources: {{- toYaml .Values.operator.resources | nindent 12 }} + {{- end }} + ports: + - containerPort: 8081 + {{- if .Values.operator.extraContainerPorts }} + {{- include "common.tplvalues.render" (dict "value" .Values.operator.extraContainerPorts "context" $) | nindent 12 }} + {{- end }} + {{- if .Values.operator.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: /healthz + port: 8081 + {{- toYaml .Values.operator.livenessProbe.config | nindent 12 }} + {{- end }} + {{- if .Values.operator.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: /readyz + port: 8081 + {{- toYaml .Values.operator.readinessProbe.config | nindent 12 }} + {{- end }} + {{- if .Values.kubeRbacProxy.create }} + - name: {{ .Values.kubeRbacProxy.name }} + image: {{ .Values.kubeRbacProxy.image }} + imagePullPolicy: IfNotPresent + args: + - "--secure-listen-address=0.0.0.0:8443" + - "--upstream=http://127.0.0.1:8080/" + - "--logtostderr=true" + - "--v=0" + ports: + - containerPort: 8443 + name: https + protocol: TCP + resources: + requests: + cpu: 5m + memory: 64Mi + limits: + cpu: 500m + memory: 128Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + {{- end }} \ No newline at end of file diff --git a/deploy/charts/prefect-operator/templates/kube-rbac-proxy-rbac.yaml b/deploy/charts/prefect-operator/templates/kube-rbac-proxy-rbac.yaml new file mode 100644 index 0000000..2dde9e5 --- /dev/null +++ b/deploy/charts/prefect-operator/templates/kube-rbac-proxy-rbac.yaml @@ -0,0 +1,32 @@ +{{ if .Values.kubeRbacProxy.create -}} +kind: ClusterRole +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ .Values.kubeRbacProxy.name }} + labels: + app.kubernetes.io/component: {{ .Values.kubeRbacProxy.name | quote }} +rules: + - apiGroups: ["authentication.k8s.io"] + resources: ["tokenreviews"] + verbs: + - create + - apiGroups: ["authorization.k8s.io"] + resources: ["subjectaccessreviews"] + verbs: + - create +--- +kind: ClusterRoleBinding +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ .Values.kubeRbacProxy.name | quote }} + labels: + app.kubernetes.io/component: {{ .Values.kubeRbacProxy.name | quote }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ .Values.kubeRbacProxy.name | quote }} +subjects: + - kind: ServiceAccount + name: {{ template "operator.serviceAccountName" . }} + namespace: {{ include "common.names.namespace" . | quote }} +{{- end }} \ No newline at end of file diff --git a/deploy/charts/prefect-operator/templates/kube-rbac-proxy-service.yaml b/deploy/charts/prefect-operator/templates/kube-rbac-proxy-service.yaml new file mode 100644 index 0000000..c84b7de --- /dev/null +++ b/deploy/charts/prefect-operator/templates/kube-rbac-proxy-service.yaml @@ -0,0 +1,17 @@ +{{ if .Values.kubeRbacProxy.create -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.kubeRbacProxy.name }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: + app.kubernetes.io/component: {{ .Values.kubeRbacProxy.name }} +spec: + type: ClusterIP + ports: + - name: https + port: 8443 + protocol: TCP + targetPort: https + selector: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} +{{- end }} \ No newline at end of file diff --git a/deploy/charts/prefect-operator/templates/prefect-server-editor-role.yaml b/deploy/charts/prefect-operator/templates/prefect-server-editor-role.yaml new file mode 100644 index 0000000..6bed8bc --- /dev/null +++ b/deploy/charts/prefect-operator/templates/prefect-server-editor-role.yaml @@ -0,0 +1,22 @@ +{{ if .Values.rbac.userRoles.prefectServer.editor.create -}} +kind: ClusterRole +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: prefect-server:editor + labels: + app.kubernetes.io/component: prefect +rules: + - apiGroups: ["prefect.io"] + resources: ["prefectservers"] + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: ["prefect.io"] + resources: ["prefectservers/status"] + verbs: ["get"] +{{- end }} diff --git a/deploy/charts/prefect-operator/templates/prefect-server-viewer-role.yaml b/deploy/charts/prefect-operator/templates/prefect-server-viewer-role.yaml new file mode 100644 index 0000000..77280c5 --- /dev/null +++ b/deploy/charts/prefect-operator/templates/prefect-server-viewer-role.yaml @@ -0,0 +1,18 @@ +{{ if .Values.rbac.userRoles.prefectServer.viewer.create -}} +kind: ClusterRole +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: prefect-server:viewer + labels: + app.kubernetes.io/component: prefect +rules: + - apiGroups: ["prefect.io"] + resources: ["prefectservers"] + verbs: + - get + - list + - watch + - apiGroups: ["prefect.io"] + resources: ["prefectservers/status"] + verbs: ["get"] +{{- end }} diff --git a/deploy/charts/prefect-operator/templates/prefect-workpool-editor-role.yaml b/deploy/charts/prefect-operator/templates/prefect-workpool-editor-role.yaml new file mode 100644 index 0000000..dfe676b --- /dev/null +++ b/deploy/charts/prefect-operator/templates/prefect-workpool-editor-role.yaml @@ -0,0 +1,22 @@ +{{ if .Values.rbac.userRoles.prefectWorkpool.editor.create -}} +kind: ClusterRole +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: prefect-workpool:editor + labels: + app.kubernetes.io/component: prefect +rules: + - apiGroups: ["prefect.io"] + resources: ["prefectworkpools"] + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: ["prefect.io"] + resources: ["prefectworkpools/status"] + verbs: ["get"] +{{- end }} diff --git a/deploy/charts/prefect-operator/templates/prefect-workpool-viewer-role.yaml b/deploy/charts/prefect-operator/templates/prefect-workpool-viewer-role.yaml new file mode 100644 index 0000000..65136cb --- /dev/null +++ b/deploy/charts/prefect-operator/templates/prefect-workpool-viewer-role.yaml @@ -0,0 +1,18 @@ +{{ if .Values.rbac.userRoles.prefectWorkpool.viewer.create -}} +kind: ClusterRole +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: prefect-workpool:viewer + labels: + app.kubernetes.io/component: prefect +rules: + - apiGroups: ["prefect.io"] + resources: ["prefectworkpools"] + verbs: + - get + - list + - watch + - apiGroups: ["prefect.io"] + resources: ["prefectworkpools/status"] + verbs: ["get"] +{{- end }} diff --git a/deploy/charts/prefect-operator/templates/rbac.yaml b/deploy/charts/prefect-operator/templates/rbac.yaml new file mode 100644 index 0000000..4144c64 --- /dev/null +++ b/deploy/charts/prefect-operator/templates/rbac.yaml @@ -0,0 +1,157 @@ +{{ if .Values.rbac.operator.create -}} +kind: ClusterRole +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ include "common.names.fullname" . }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["events"] + verbs: + - create + - patch + - apiGroups: [""] + resources: ["persistentvolumeclaims"] + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: [""] + resources: ["pods"] + verbs: + - get + - list + - watch + - apiGroups: [""] + resources: ["services"] + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: ["apps"] + resources: ["deployments"] + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: ["prefect.io"] + resources: ["prefectservers"] + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: ["prefect.io"] + resources: ["prefectservers/finalizers"] + verbs: + - update + - apiGroups: ["prefect.io"] + resources: ["prefectservers/status"] + verbs: + - get + - patch + - update + - apiGroups: ["prefect.io"] + resources: ["prefectworkpools"] + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: ["prefect.io"] + resources: ["prefectworkpools/finalizers"] + verbs: + - update + - apiGroups: ["prefect.io"] + resources: ["prefectworkpools/status"] + verbs: + - get + - patch + - update +--- +kind: ClusterRoleBinding +apiVersion: {{ include "common.capabilities.rbac.apiVersion" . }} +metadata: + name: {{ template "common.names.fullname" . }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "common.names.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "operator.serviceAccountName" . }} + namespace: {{ include "common.names.namespace" . | quote }} +--- +# leader election rules +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ template "common.names.fullname" . }}:leaderelection + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} +rules: + - apiGroups: [""] + resources: ["configmaps"] + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: [""] + resources: ["events"] + verbs: + - create + - patch + - apiGroups: ["coordination.k8s.io"] + resources: ["leases"] + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ template "common.names.fullname" . }}:leaderelection + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "common.names.fullname" . }}:leaderelection +subjects: + - kind: ServiceAccount + name: {{ template "operator.serviceAccountName" . }} + namespace: {{ include "common.names.namespace" . | quote }} +{{- end }} + diff --git a/deploy/charts/prefect-operator/templates/service-account.yaml b/deploy/charts/prefect-operator/templates/service-account.yaml new file mode 100644 index 0000000..dbafe63 --- /dev/null +++ b/deploy/charts/prefect-operator/templates/service-account.yaml @@ -0,0 +1,9 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "operator.serviceAccountName" . }} + namespace: {{ include "common.names.namespace" . | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} +{{- end }} diff --git a/deploy/charts/prefect-operator/templates/servicemonitor.yaml b/deploy/charts/prefect-operator/templates/servicemonitor.yaml new file mode 100644 index 0000000..42ced9f --- /dev/null +++ b/deploy/charts/prefect-operator/templates/servicemonitor.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "common.names.fullname" . }} + namespace: {{ default (include "common.names.namespace" .) .Values.metrics.serviceMonitor.namespace | quote }} + labels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + annotations: {{- include "common.tplvalues.render" ( dict "value" .Values.commonAnnotations "context" $ ) | nindent 4 }} +spec: + selector: + matchLabels: {{- include "common.labels.standard" ( dict "customLabels" .Values.commonLabels "context" $ ) | nindent 4 }} + endpoints: + - port: https + path: /metrics + scheme: https + tlsConfig: + insecureSkipVerify: true + bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token +{{- end }} diff --git a/deploy/charts/prefect-operator/values.yaml b/deploy/charts/prefect-operator/values.yaml new file mode 100644 index 0000000..7fe2d2f --- /dev/null +++ b/deploy/charts/prefect-operator/values.yaml @@ -0,0 +1,191 @@ +## Common parameters +# -- partially overrides common.names.name +nameOverride: "" +# -- fully override common.names.fullname +fullnameOverride: prefect-operator +# -- fully override common.names.namespace +namespaceOverride: "" +# -- labels to add to all deployed objects +commonLabels: + app.kubernetes.io/component: operator +# -- annotations to add to all deployed objects +commonAnnotations: {} + + +## Deployment Configuration +operator: + image: + # -- operator image repository + repository: prefecthq/prefect-operator + # -- operator image tag (immutable tags are recommended) + tag: latest + # -- operator image pull policy + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## e.g: + ## pullSecrets: + ## - myRegistryKeySecretName + # -- operator image pull secrets + pullSecrets: [] + + # -- number of operator replicas to deploy + replicaCount: 1 + + # ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ + livenessProbe: + enabled: true + config: + # -- The number of seconds to wait before starting the first probe. + initialDelaySeconds: 15 + # -- The number of seconds to wait between consecutive probes. + periodSeconds: 20 + # -- The number of seconds to wait for a probe response before considering it as failed. + # timeoutSeconds: + # -- The number of consecutive failures allowed before considering the probe as failed. + # failureThreshold: + # -- The minimum consecutive successes required to consider the probe successful. + # successThreshold: + + readinessProbe: + enabled: true + config: + # -- The number of seconds to wait before starting the first probe. + initialDelaySeconds: 5 + # -- The number of seconds to wait between consecutive probes. + periodSeconds: 10 + # -- The number of seconds to wait for a probe response before considering it as failed. + # timeoutSeconds: + # -- The number of consecutive failures allowed before considering the probe as failed. + # failureThreshold: + # -- The minimum consecutive successes required to consider the probe successful. + # successThreshold: + + # requests MUST be specified if using an HPA, otherwise the HPA will not know when to trigger a scale event + + resources: + # -- the requested resources for the operator container + requests: + cpu: 10m + memory: 64Mi + # -- the requested limits for the operator container + limits: + cpu: 500m + memory: 128Mi + + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod + podSecurityContext: + # -- set operator pod's security context runAsUser + # runAsUser: + # -- set operator pod's security context runAsNonRoot + runAsNonRoot: true + # -- set operator pod's security context fsGroup + # fsGroup: + + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-container + containerSecurityContext: + # -- set operator containers' security context runAsUser + # runAsUser: 1001 + # -- set operator containers' security context runAsNonRoot + # runAsNonRoot: true + # -- set operator containers' security context readOnlyRootFilesystem + # readOnlyRootFilesystem: true + # -- set operator containers' security context allowPrivilegeEscalation + allowPrivilegeEscalation: false + # -- set operator container's security context capabilities + capabilities: + drop: ["ALL"] + + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ + # -- extra labels for operator pod + podLabels: {} + + ## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ + # -- extra annotations for operator pod + podAnnotations: {} + + ## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity + # -- affinity for operator pods assignment + affinity: {} + + ## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/ + # -- node labels for operator pods assignment + nodeSelector: {} + + ## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ + # -- tolerations for operator pods assignment + tolerations: [] + + # -- array with environment variables to add to operator container + extraEnvVars: [] + + # ref: https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/#priorityclass + # -- priority class name to use for the operator pods; if the priority class is empty or doesn't exist, the operator pods are scheduled without a priority class + priorityClassName: "" + + ## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods + # -- topology spread constraints for operator pod assignment spread across your cluster among failure-domains + topologySpreadConstraints: [] + + ## ref: https://kubernetes.io/docs/concepts/workloads/pods/pod/#termination-of-pods + # -- seconds operator pod needs to terminate gracefully + terminationGracePeriodSeconds: 10 + +## RBAC configuration +rbac: + operator: + # -- specifies whether the operator role & role binding should be created + create: true + ## For each CRD, "Editor" and "Viewer" roles are created by default, aiding admins in cluster management. + ## Those roles are not used by the operator itself. You can disable those roles by setting + # the following lines to `create: false` or comment them out. + userRoles: + prefectServer: + editor: + # -- specifies whether the server editor role should be created + create: true + viewer: + # -- specifies whether the server viewer role should be created + create: true + prefectWorkpool: + editor: + # -- specifies whether the workpool editor role should be created + create: true + viewer: + # -- specifies whether the workpool viewer role should be created + create: true + + +## ServiceAccount configuration +serviceAccount: + # -- specifies whether a ServiceAccount should be created + create: true + # -- the name of the ServiceAccount to use. if not set and create is true, a name is generated using the common.names.fullname template + name: "" + # -- additional service account annotations (evaluated as a template) + annotations: {} + + +## Kube RBAC Proxy Configuration +## TODO add some more info here +## The kube-rbac-proxy protects your /metrics endpoint. +## ref: https://github.com/brancz/kube-rbac-proxy +kubeRbacProxy: + # -- specifies whether the kube-rbac-proxy should be deployed to the cluster + create: true + # -- the name of the kube-rbac-proxy to use + name: kube-rbac-proxy + # -- the image of the kube-rbac-proxy to use + image: gcr.io/kubebuilder/kube-rbac-proxy:v0.16.0 + + +## Prometheus Metrics Configuration +## This needs to be tested +metrics: + # -- enable the export of Prometheus metrics + enabled: false +# ## Prometheus Operator ServiceMonitor configuration + serviceMonitor: + # -- creates a Prometheus Operator ServiceMonitor (also requires `metrics.enabled` to be `true`) + enabled: false