From 3375fff29cd8b5ea97dcbe2401e6d8cd84547101 Mon Sep 17 00:00:00 2001 From: Techassi Date: Fri, 23 Jan 2026 11:19:33 +0100 Subject: [PATCH 1/3] feat(crd): Stabilise Entra backend --- deploy/helm/opa-operator/crds/crds.yaml | 1110 ++++++++++++++++- rust/operator-binary/src/crd/mod.rs | 255 ++-- .../mod.rs} | 63 +- .../crd/user_info_fetcher/v1alpha1_impl.rs | 44 + .../crd/user_info_fetcher/v1alpha2_impl.rs | 44 + 5 files changed, 1346 insertions(+), 170 deletions(-) rename rust/operator-binary/src/crd/{user_info_fetcher.rs => user_info_fetcher/mod.rs} (83%) create mode 100644 rust/operator-binary/src/crd/user_info_fetcher/v1alpha1_impl.rs create mode 100644 rust/operator-binary/src/crd/user_info_fetcher/v1alpha2_impl.rs diff --git a/deploy/helm/opa-operator/crds/crds.yaml b/deploy/helm/opa-operator/crds/crds.yaml index ac1b26b0..55846297 100644 --- a/deploy/helm/opa-operator/crds/crds.yaml +++ b/deploy/helm/opa-operator/crds/crds.yaml @@ -16,6 +16,1114 @@ spec: singular: opacluster scope: Namespaced versions: + - additionalPrinterColumns: [] + name: v1alpha2 + schema: + openAPIV3Schema: + description: Auto-generated derived type for OpaClusterSpec via `CustomResource` + properties: + spec: + properties: + clusterConfig: + default: + listenerClass: cluster-internal + tls: null + userInfo: null + description: Global OPA cluster configuration that applies to all roles and role groups. + properties: + listenerClass: + default: cluster-internal + description: |- + This field controls which type of Service the operator creates for this OpaCluster: + + * cluster-internal: Use a ClusterIP service + + * external-unstable: Use a NodePort service + + * external-stable: Use a LoadBalancer service + + This is a temporary solution with the goal to keep yaml manifests forward compatible. + In the future, this setting will control which ListenerClass + will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change. + enum: + - cluster-internal + - external-unstable + - external-stable + type: string + tls: + description: |- + TLS encryption settings for the OPA server. + When configured, OPA will use HTTPS (port 8443) instead of HTTP (port 8081). + Clients must connect using HTTPS and trust the certificates provided by the configured SecretClass. + nullable: true + properties: + serverSecretClass: + description: Name of the SecretClass which will provide TLS certificates for the OPA server. + type: string + required: + - serverSecretClass + type: object + userInfo: + description: |- + Configures how to fetch additional metadata about users (such as group memberships) + from an external directory service. + nullable: true + properties: + backend: + default: + none: {} + description: The backend directory service to use. + oneOf: + - required: + - none + - required: + - keycloak + - required: + - experimentalXfscAas + - required: + - experimentalActiveDirectory + - required: + - entra + - required: + - experimentalOpenLdap + properties: + entra: + description: Backend that fetches user information from Microsoft Entra + properties: + clientCredentialsSecret: + description: |- + Name of a Secret that contains client credentials of an Entra account with + permissions `User.ReadAll` and `GroupMemberShip.ReadAll`. + + Must contain the fields `clientId` and `clientSecret`. + type: string + port: + description: Port of the identity provider. If TLS is used defaults to `443`, otherwise to `80`. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + tenantId: + description: The Microsoft Entra tenant ID. + type: string + tls: + default: + verification: + server: + caCert: + webPki: {} + description: Use a TLS connection. Should usually be set to WebPki. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + tokenHostname: + default: login.microsoft.com + description: Hostname of the token provider, defaults to `login.microsoft.com`. + type: string + userInfoHostname: + default: graph.microsoft.com + description: Hostname of the user info provider, defaults to `graph.microsoft.com`. + type: string + required: + - clientCredentialsSecret + - tenantId + type: object + experimentalActiveDirectory: + description: Backend that fetches user information from Active Directory + properties: + additionalGroupAttributeFilters: + additionalProperties: + type: string + default: {} + description: |- + Attributes that groups must have to be returned. + + These fields will be spliced into an LDAP Search Query, so wildcards can be used, + but characters with a special meaning in LDAP will need to be escaped. + type: object + baseDistinguishedName: + description: The root Distinguished Name (DN) where users and groups are located. + type: string + customAttributeMappings: + additionalProperties: + type: string + default: {} + description: Custom attributes, and their LDAP attribute names. + type: object + kerberosSecretClassName: + description: The name of the Kerberos SecretClass. + type: string + ldapServer: + description: Hostname of the domain controller, e.g. `ad-ds-1.contoso.com`. + type: string + tls: + description: Use a TLS connection. If not specified no TLS will be used. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + required: + - baseDistinguishedName + - kerberosSecretClassName + - ldapServer + type: object + experimentalOpenLdap: + description: Backend that fetches user information from OpenLDAP + properties: + bindCredentials: + description: |- + Credentials for binding to the LDAP server. + + The bind account is used to search for users and groups in the LDAP directory. + properties: + scope: + description: |- + [Scope](https://docs.stackable.tech/home/nightly/secret-operator/scope) of the + [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass). + nullable: true + properties: + listenerVolumes: + default: [] + description: |- + The listener volume scope allows Node and Service scopes to be inferred from the applicable listeners. + This must correspond to Volume names in the Pod that mount Listeners. + items: + type: string + type: array + node: + default: false + description: |- + The node scope is resolved to the name of the Kubernetes Node object that the Pod is running on. + This will typically be the DNS name of the node. + type: boolean + pod: + default: false + description: |- + The pod scope is resolved to the name of the Kubernetes Pod. + This allows the secret to differentiate between StatefulSet replicas. + type: boolean + services: + default: [] + description: |- + The service scope allows Pod objects to specify custom scopes. + This should typically correspond to Service objects that the Pod participates in. + items: + type: string + type: array + type: object + secretClass: + description: '[SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) containing the LDAP bind credentials.' + type: string + required: + - secretClass + type: object + customAttributeMappings: + additionalProperties: + type: string + default: {} + description: Custom attributes, and their LDAP attribute names. + type: object + groupMemberAttribute: + default: member + description: |- + LDAP attribute on group objects that contains member references. + + Common values: + - `member`: For `groupOfNames` objects (uses full DN) + - `memberUid`: For `posixGroup` objects (uses username) + + Defaults to `member`. + type: string + groupsSearchBase: + description: |- + LDAP search base for groups, e.g. `ou=groups,dc=example,dc=org`. + + If not specified, uses the main `searchBase`. + nullable: true + type: string + hostname: + description: Hostname of the LDAP server, e.g. `my.ldap.server`. + type: string + port: + description: Port of the LDAP server. If TLS is used defaults to `636`, otherwise to `389`. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + searchBase: + default: '' + description: LDAP search base, e.g. `ou=users,dc=example,dc=org`. + type: string + tls: + description: Use a TLS connection. If not specified no TLS will be used. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + userIdAttribute: + default: entryUUID + description: LDAP attribute used for the user's unique identifier. Defaults to `entryUUID`. + type: string + userNameAttribute: + default: uid + description: LDAP attribute used for the username. Defaults to `uid`. + type: string + required: + - bindCredentials + - hostname + type: object + experimentalXfscAas: + description: |- + Backend that fetches user information from the Gaia-X + Cross Federation Services Components (XFSC) Authentication & Authorization Service. + properties: + hostname: + description: Hostname of the identity provider, e.g. `my.aas.corp`. + type: string + port: + default: 5000 + description: Port of the identity provider. Defaults to port 5000. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + type: integer + required: + - hostname + type: object + keycloak: + description: Backend that fetches user information from Keycloak. + properties: + adminRealm: + description: |- + The Keycloak realm that OPA's Keycloak account (as specified by `credentialsSecretName` exists in). + + Typically `master`. + type: string + clientCredentialsSecret: + description: |- + Name of a Secret that contains client credentials of a Keycloak account with permission to read user metadata. + + Must contain the fields `clientId` and `clientSecret`. + type: string + hostname: + description: Hostname of the identity provider, e.g. `my.keycloak.corp`. + type: string + port: + description: Port of the identity provider. If TLS is used defaults to `443`, otherwise to `80`. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + rootPath: + default: / + description: Root HTTP path of the identity provider. Defaults to `/`. + type: string + tls: + description: Use a TLS connection. If not specified no TLS will be used. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + userRealm: + description: The Keycloak realm that user metadata should be resolved from. + type: string + required: + - adminRealm + - clientCredentialsSecret + - hostname + - userRealm + type: object + none: + description: Dummy backend that adds no extra user information. + type: object + type: object + cache: + default: + entryTimeToLive: 1m + description: Caching configuration. + properties: + entryTimeToLive: + default: 1m + description: How long metadata about each user should be cached for. + type: string + type: object + type: object + vectorAggregatorConfigMapName: + description: |- + Name of the Vector aggregator discovery ConfigMap. + It must contain the key `ADDRESS` with the address of the Vector aggregator. + nullable: true + type: string + type: object + clusterOperation: + default: + reconciliationPaused: false + stopped: false + description: Cluster operations like pause reconciliation or cluster stop. + properties: + reconciliationPaused: + default: false + description: |- + Flag to stop cluster reconciliation by the operator. This means that all changes in the + custom resource spec are ignored until this flag is set to false or removed. The operator + will however still watch the deployed resources at the time and update the custom resource + status field. + If applied at the same time with `stopped`, `reconciliationPaused` will take precedence over + `stopped` and stop the reconciliation immediately. + type: boolean + stopped: + default: false + description: |- + Flag to stop the cluster. This means all deployed resources (e.g. Services, StatefulSets, + ConfigMaps) are kept but all deployed Pods (e.g. replicas from a StatefulSet) are scaled to 0 + and therefore stopped and removed. + If applied at the same time with `reconciliationPaused`, the latter will pause reconciliation + and `stopped` will take no effect until `reconciliationPaused` is set to false or removed. + type: boolean + type: object + image: + anyOf: + - required: + - custom + - productVersion + - required: + - productVersion + description: The OPA image to use + properties: + custom: + description: |- + Overwrite the docker image. + Specify the full docker image name, e.g. `oci.stackable.tech/sdp/superset:1.4.1-stackable2.1.0` + type: string + productVersion: + description: Version of the product, e.g. `1.4.1`. + type: string + pullPolicy: + default: Always + description: '[Pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) used when pulling the image.' + enum: + - IfNotPresent + - Always + - Never + type: string + pullSecrets: + description: '[Image pull secrets](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) to pull images from a private registry.' + items: + description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + required: + - name + type: object + nullable: true + type: array + repo: + description: Name of the docker repo, e.g. `oci.stackable.tech/sdp` + nullable: true + type: string + stackableVersion: + description: |- + Stackable version of the product, e.g. `23.4`, `23.4.1` or `0.0.0-dev`. + If not specified, the operator will use its own version, e.g. `23.4.1`. + When using a nightly operator or a pr version, it will use the nightly `0.0.0-dev` image. + nullable: true + type: string + type: object + servers: + description: OPA server configuration. + properties: + cliOverrides: + additionalProperties: + type: string + default: {} + type: object + config: + default: {} + properties: + affinity: + default: + nodeAffinity: null + nodeSelector: null + podAffinity: null + podAntiAffinity: null + description: |- + These configuration settings control + [Pod placement](https://docs.stackable.tech/home/nightly/concepts/operations/pod_placement). + properties: + nodeAffinity: + description: Same as the `spec.affinity.nodeAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + nodeSelector: + additionalProperties: + type: string + description: Simple key-value pairs forming a nodeSelector, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + podAffinity: + description: Same as the `spec.affinity.podAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + podAntiAffinity: + description: Same as the `spec.affinity.podAntiAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + gracefulShutdownTimeout: + description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. + nullable: true + type: string + logging: + default: + containers: {} + enableVectorAgent: null + description: Logging configuration, learn more in the [logging concept documentation](https://docs.stackable.tech/home/nightly/concepts/logging). + properties: + containers: + additionalProperties: + anyOf: + - required: + - custom + - {} + description: Log configuration of the container + properties: + console: + description: Configuration for the console appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + - null + nullable: true + type: string + type: object + custom: + description: Custom log configuration provided in a ConfigMap + properties: + configMap: + description: ConfigMap containing the log configuration files + nullable: true + type: string + type: object + file: + description: Configuration for the file appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + - null + nullable: true + type: string + type: object + loggers: + additionalProperties: + description: Configuration of a logger + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + - null + nullable: true + type: string + type: object + default: {} + description: Configuration per logger + type: object + type: object + description: Log configuration per container. + type: object + enableVectorAgent: + description: Wether or not to deploy a container with the Vector log agent. + nullable: true + type: boolean + type: object + resources: + default: + cpu: + max: null + min: null + memory: + limit: null + runtimeLimits: {} + storage: {} + description: |- + Resource usage is configured here, this includes CPU usage, memory usage and disk storage + usage, if this role needs any. + properties: + cpu: + default: + max: null + min: null + properties: + max: + description: |- + The maximum amount of CPU cores that can be requested by Pods. + Equivalent to the `limit` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + min: + description: |- + The minimal amount of CPU cores that Pods need to run. + Equivalent to the `request` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + type: object + memory: + properties: + limit: + description: |- + The maximum amount of memory that should be available to the Pod. + Specified as a byte [Quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/), + which means these suffixes are supported: E, P, T, G, M, k. + You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. + For example, the following represent roughly the same value: + `128974848, 129e6, 129M, 128974848000m, 123Mi` + nullable: true + type: string + runtimeLimits: + description: Additional options that can be specified. + type: object + type: object + storage: + type: object + type: object + type: object + configOverrides: + additionalProperties: + additionalProperties: + type: string + type: object + default: {} + description: |- + The `configOverrides` can be used to configure properties in product config files + that are not exposed in the CRD. Read the + [config overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#config-overrides) + and consult the operator specific usage guide documentation for details on the + available config files and settings for the specific product. + type: object + envOverrides: + additionalProperties: + type: string + default: {} + description: |- + `envOverrides` configure environment variables to be set in the Pods. + It is a map from strings to strings - environment variables and the value to set. + Read the + [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) + for more information and consult the operator specific usage guide to find out about + the product specific environment variables that are available. + type: object + podOverrides: + default: {} + description: |- + In the `podOverrides` property you can define a + [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) + to override any property that can be set on a Kubernetes Pod. + Read the + [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) + for more information. + type: object + x-kubernetes-preserve-unknown-fields: true + roleConfig: + default: {} + description: |- + This is a product-agnostic RoleConfig, with nothing in it. It is used e.g. by products that have + nothing configurable at role level. + type: object + roleGroups: + additionalProperties: + properties: + cliOverrides: + additionalProperties: + type: string + default: {} + type: object + config: + default: {} + properties: + affinity: + default: + nodeAffinity: null + nodeSelector: null + podAffinity: null + podAntiAffinity: null + description: |- + These configuration settings control + [Pod placement](https://docs.stackable.tech/home/nightly/concepts/operations/pod_placement). + properties: + nodeAffinity: + description: Same as the `spec.affinity.nodeAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + nodeSelector: + additionalProperties: + type: string + description: Simple key-value pairs forming a nodeSelector, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + podAffinity: + description: Same as the `spec.affinity.podAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + podAntiAffinity: + description: Same as the `spec.affinity.podAntiAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + gracefulShutdownTimeout: + description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. + nullable: true + type: string + logging: + default: + containers: {} + enableVectorAgent: null + description: Logging configuration, learn more in the [logging concept documentation](https://docs.stackable.tech/home/nightly/concepts/logging). + properties: + containers: + additionalProperties: + anyOf: + - required: + - custom + - {} + description: Log configuration of the container + properties: + console: + description: Configuration for the console appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + - null + nullable: true + type: string + type: object + custom: + description: Custom log configuration provided in a ConfigMap + properties: + configMap: + description: ConfigMap containing the log configuration files + nullable: true + type: string + type: object + file: + description: Configuration for the file appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + - null + nullable: true + type: string + type: object + loggers: + additionalProperties: + description: Configuration of a logger + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + - null + nullable: true + type: string + type: object + default: {} + description: Configuration per logger + type: object + type: object + description: Log configuration per container. + type: object + enableVectorAgent: + description: Wether or not to deploy a container with the Vector log agent. + nullable: true + type: boolean + type: object + resources: + default: + cpu: + max: null + min: null + memory: + limit: null + runtimeLimits: {} + storage: {} + description: |- + Resource usage is configured here, this includes CPU usage, memory usage and disk storage + usage, if this role needs any. + properties: + cpu: + default: + max: null + min: null + properties: + max: + description: |- + The maximum amount of CPU cores that can be requested by Pods. + Equivalent to the `limit` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + min: + description: |- + The minimal amount of CPU cores that Pods need to run. + Equivalent to the `request` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + type: object + memory: + properties: + limit: + description: |- + The maximum amount of memory that should be available to the Pod. + Specified as a byte [Quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/), + which means these suffixes are supported: E, P, T, G, M, k. + You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. + For example, the following represent roughly the same value: + `128974848, 129e6, 129M, 128974848000m, 123Mi` + nullable: true + type: string + runtimeLimits: + description: Additional options that can be specified. + type: object + type: object + storage: + type: object + type: object + type: object + configOverrides: + additionalProperties: + additionalProperties: + type: string + type: object + default: {} + description: |- + The `configOverrides` can be used to configure properties in product config files + that are not exposed in the CRD. Read the + [config overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#config-overrides) + and consult the operator specific usage guide documentation for details on the + available config files and settings for the specific product. + type: object + envOverrides: + additionalProperties: + type: string + default: {} + description: |- + `envOverrides` configure environment variables to be set in the Pods. + It is a map from strings to strings - environment variables and the value to set. + Read the + [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) + for more information and consult the operator specific usage guide to find out about + the product specific environment variables that are available. + type: object + podOverrides: + default: {} + description: |- + In the `podOverrides` property you can define a + [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) + to override any property that can be set on a Kubernetes Pod. + Read the + [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) + for more information. + type: object + x-kubernetes-preserve-unknown-fields: true + replicas: + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + type: object + type: object + required: + - roleGroups + type: object + required: + - image + - servers + type: object + status: + nullable: true + properties: + conditions: + default: [] + items: + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + format: date-time + nullable: true + type: string + message: + description: A human readable message indicating details about the transition. + nullable: true + type: string + reason: + description: The reason for the condition's last transition. + nullable: true + type: string + status: + description: Status of the condition, one of True, False, Unknown. + enum: + - 'True' + - 'False' + - Unknown + type: string + type: + description: Type of deployment condition. + enum: + - Available + - Degraded + - Progressing + - ReconciliationPaused + - Stopped + type: string + required: + - status + - type + type: object + type: array + type: object + required: + - spec + title: OpaCluster + type: object + served: true + storage: true + subresources: + status: {} - additionalPrinterColumns: [] name: v1alpha1 schema: @@ -1121,6 +2229,6 @@ spec: title: OpaCluster type: object served: true - storage: true + storage: false subresources: status: {} diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index 8b782a20..2b1145f3 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -60,33 +60,37 @@ pub enum Error { #[versioned( version(name = "v1alpha1"), + version(name = "v1alpha2"), crates( kube_core = "stackable_operator::kube::core", kube_client = "stackable_operator::kube::client", k8s_openapi = "stackable_operator::k8s_openapi", schemars = "stackable_operator::schemars", versioned = "stackable_operator::versioned" - ), - skip(from) + ) )] pub mod versioned { #[versioned(crd( group = "opa.stackable.tech", status = "OpaClusterStatus", - namespaced, shortname = "opa", + namespaced, ))] #[derive(Clone, Debug, Deserialize, CustomResource, JsonSchema, Serialize)] #[serde(rename_all = "camelCase")] pub struct OpaClusterSpec { /// Global OPA cluster configuration that applies to all roles and role groups. #[serde(default)] - pub cluster_config: v1alpha1::OpaClusterConfig, + pub cluster_config: OpaClusterConfig, + /// Cluster operations like pause reconciliation or cluster stop. #[serde(default)] pub cluster_operation: ClusterOperation, + /// OPA server configuration. + // #[versioned(hint(role))] pub servers: Role, + /// The OPA image to use pub image: ProductImage, } @@ -98,6 +102,7 @@ pub mod versioned { /// It must contain the key `ADDRESS` with the address of the Vector aggregator. #[serde(skip_serializing_if = "Option::is_none")] pub vector_aggregator_config_map_name: Option, + /// This field controls which type of Service the operator creates for this OpaCluster: /// /// * cluster-internal: Use a ClusterIP service @@ -110,16 +115,26 @@ pub mod versioned { /// In the future, this setting will control which ListenerClass /// will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change. #[serde(default)] - pub listener_class: v1alpha1::CurrentlySupportedListenerClasses, + pub listener_class: CurrentlySupportedListenerClasses, + /// Configures how to fetch additional metadata about users (such as group memberships) /// from an external directory service. + #[versioned( + changed( + since = "v1alpha2", + from_type = "Option" + ), + hint(option) + )] #[serde(default)] - pub user_info: Option, + pub user_info: Option, + /// TLS encryption settings for the OPA server. /// When configured, OPA will use HTTPS (port 8443) instead of HTTP (port 8081). /// Clients must connect using HTTPS and trust the certificates provided by the configured SecretClass. #[serde(default)] - pub tls: Option, + #[versioned(hint(option))] + pub tls: Option, } #[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] @@ -141,126 +156,129 @@ pub mod versioned { #[serde(rename = "external-stable")] ExternalStable, } +} - #[allow(clippy::derive_partial_eq_without_eq)] - #[derive(Clone, Debug, Default, Fragment, JsonSchema, PartialEq)] - #[fragment_attrs( - allow(clippy::derive_partial_eq_without_eq), - derive( - Clone, - Debug, - Default, - Deserialize, - Merge, - JsonSchema, - PartialEq, - Serialize - ), - serde(rename_all = "camelCase") - )] - pub struct OpaStorageConfig {} - - #[derive( +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, Debug, Default, Fragment, JsonSchema, PartialEq)] +#[fragment_attrs( + allow(clippy::derive_partial_eq_without_eq), + derive( Clone, Debug, + Default, Deserialize, - Display, - Eq, - EnumIter, + Merge, JsonSchema, - Ord, PartialEq, - PartialOrd, - Serialize, - )] - #[serde(rename_all = "kebab-case")] - #[strum(serialize_all = "kebab-case")] - pub enum Container { - Prepare, - Vector, - BundleBuilder, - Opa, - UserInfoFetcher, - } - - #[derive(Clone, Debug, Default, Fragment, JsonSchema, PartialEq)] - #[fragment_attrs( - derive( - Clone, - Debug, - Default, - Deserialize, - Merge, - JsonSchema, - PartialEq, - Serialize - ), - serde(rename_all = "camelCase") - )] - pub struct OpaConfig { - #[fragment_attrs(serde(default))] - pub resources: Resources, - - #[fragment_attrs(serde(default))] - pub logging: Logging, - - #[fragment_attrs(serde(default))] - pub affinity: StackableAffinity, - - /// Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. - #[fragment_attrs(serde(default))] - pub graceful_shutdown_timeout: Option, - } + Serialize + ), + serde(rename_all = "camelCase") +)] +pub struct OpaStorageConfig {} + +#[derive( + Clone, + Debug, + Deserialize, + Display, + Eq, + EnumIter, + JsonSchema, + Ord, + PartialEq, + PartialOrd, + Serialize, +)] +#[serde(rename_all = "kebab-case")] +#[strum(serialize_all = "kebab-case")] +pub enum Container { + Prepare, + Vector, + BundleBuilder, + Opa, + UserInfoFetcher, +} - #[derive( - EnumIter, +// NOTE (@Techassi): This struct can currently NOT be versioned because it is used via Role which +// makes it incredible hard to implement the From trait for conversions. +#[derive(Clone, Debug, Default, Fragment, JsonSchema, PartialEq)] +#[fragment_attrs( + derive( Clone, Debug, - Hash, + Default, Deserialize, - Eq, + Merge, JsonSchema, PartialEq, - Serialize, - Display, - EnumString, - )] - pub enum OpaRole { - #[serde(rename = "server")] - #[strum(serialize = "server")] - Server, - } + Serialize + ), + serde(rename_all = "camelCase") +)] +pub struct OpaConfig { + #[fragment_attrs(serde(default))] + pub resources: Resources, - #[derive(Clone, Default, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] - #[serde(rename_all = "camelCase")] - pub struct OpaClusterStatus { - #[serde(default)] - pub conditions: Vec, - } + #[fragment_attrs(serde(default))] + pub logging: Logging, + + #[fragment_attrs(serde(default))] + pub affinity: StackableAffinity, + + /// Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. + #[fragment_attrs(serde(default))] + pub graceful_shutdown_timeout: Option, } -impl v1alpha1::CurrentlySupportedListenerClasses { +#[derive( + EnumIter, + Clone, + Debug, + Hash, + Deserialize, + Eq, + JsonSchema, + PartialEq, + Serialize, + Display, + EnumString, +)] +pub enum OpaRole { + #[serde(rename = "server")] + #[strum(serialize = "server")] + Server, +} + +// TODO (@Techassi): Support versioned status +#[derive(Clone, Default, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct OpaClusterStatus { + #[serde(default)] + pub conditions: Vec, +} + +impl v1alpha2::CurrentlySupportedListenerClasses { pub fn k8s_service_type(&self) -> String { match self { - v1alpha1::CurrentlySupportedListenerClasses::ClusterInternal => "ClusterIP".to_string(), - v1alpha1::CurrentlySupportedListenerClasses::ExternalUnstable => "NodePort".to_string(), - v1alpha1::CurrentlySupportedListenerClasses::ExternalStable => { + v1alpha2::CurrentlySupportedListenerClasses::ClusterInternal => "ClusterIP".to_string(), + v1alpha2::CurrentlySupportedListenerClasses::ExternalUnstable => "NodePort".to_string(), + v1alpha2::CurrentlySupportedListenerClasses::ExternalStable => { "LoadBalancer".to_string() } } } } -impl v1alpha1::OpaClusterConfig { +impl v1alpha2::OpaClusterConfig { /// Returns whether TLS encryption is enabled for the OPA server. pub fn tls_enabled(&self) -> bool { self.tls.is_some() } } -impl v1alpha1::OpaConfig { - fn default_config() -> v1alpha1::OpaConfigFragment { - v1alpha1::OpaConfigFragment { +impl OpaConfig { + fn default_config() -> OpaConfigFragment { + OpaConfigFragment { logging: product_logging::spec::default_logging(), resources: ResourcesFragment { cpu: CpuLimitsFragment { @@ -271,7 +289,7 @@ impl v1alpha1::OpaConfig { limit: Some(Quantity("256Mi".to_owned())), runtime_limits: NoRuntimeLimitsFragment {}, }, - storage: v1alpha1::OpaStorageConfigFragment {}, + storage: OpaStorageConfigFragment {}, }, // There is no point in having a default affinity, as exactly one OPA Pods should run on every node. // We only have the affinity configurable to let users limit the nodes the OPA Pods run on. @@ -281,8 +299,8 @@ impl v1alpha1::OpaConfig { } } -impl Configuration for v1alpha1::OpaConfigFragment { - type Configurable = v1alpha1::OpaCluster; +impl Configuration for OpaConfigFragment { + type Configurable = v1alpha2::OpaCluster; fn compute_env( &self, @@ -313,28 +331,23 @@ impl Configuration for v1alpha1::OpaConfigFragment { } } -impl v1alpha1::OpaCluster { +impl v1alpha2::OpaCluster { /// Returns a reference to the role. - pub fn role( - &self, - role_variant: &v1alpha1::OpaRole, - ) -> &Role { + pub fn role(&self, role_variant: &OpaRole) -> &Role { match role_variant { - v1alpha1::OpaRole::Server => &self.spec.servers, + OpaRole::Server => &self.spec.servers, } } /// Returns a reference to the role group. Raises an error if the role or role group are not defined. pub fn rolegroup( &self, - rolegroup_ref: &RoleGroupRef, - ) -> Result<&RoleGroup, Error> - { - let role_variant = v1alpha1::OpaRole::from_str(&rolegroup_ref.role).with_context(|_| { - UnknownOpaRoleSnafu { + rolegroup_ref: &RoleGroupRef, + ) -> Result<&RoleGroup, Error> { + let role_variant = + OpaRole::from_str(&rolegroup_ref.role).with_context(|_| UnknownOpaRoleSnafu { role: rolegroup_ref.role.to_owned(), - } - })?; + })?; let role = self.role(&role_variant); role.role_groups .get(&rolegroup_ref.role_group) @@ -348,7 +361,7 @@ impl v1alpha1::OpaCluster { format!( "{cluster_name}-{role}", cluster_name = self.name_any(), - role = v1alpha1::OpaRole::Server + role = OpaRole::Server ) } @@ -365,14 +378,14 @@ impl v1alpha1::OpaCluster { /// Retrieve and merge resource configs for role and role groups pub fn merged_config( &self, - role: &v1alpha1::OpaRole, - rolegroup_ref: &RoleGroupRef, - ) -> Result { + role: &OpaRole, + rolegroup_ref: &RoleGroupRef, + ) -> Result { // Initialize the result with all default values as baseline - let conf_defaults = v1alpha1::OpaConfig::default_config(); + let conf_defaults = OpaConfig::default_config(); let opa_role = match role { - v1alpha1::OpaRole::Server => &self.spec.servers, + OpaRole::Server => &self.spec.servers, }; let mut conf_role = opa_role.config.config.to_owned(); @@ -401,7 +414,7 @@ impl v1alpha1::OpaCluster { } } -impl HasStatusCondition for v1alpha1::OpaCluster { +impl HasStatusCondition for v1alpha2::OpaCluster { fn conditions(&self) -> Vec { match &self.status { Some(status) => status.conditions.clone(), diff --git a/rust/operator-binary/src/crd/user_info_fetcher.rs b/rust/operator-binary/src/crd/user_info_fetcher/mod.rs similarity index 83% rename from rust/operator-binary/src/crd/user_info_fetcher.rs rename to rust/operator-binary/src/crd/user_info_fetcher/mod.rs index a5dc8eeb..bb65fbe0 100644 --- a/rust/operator-binary/src/crd/user_info_fetcher.rs +++ b/rust/operator-binary/src/crd/user_info_fetcher/mod.rs @@ -7,24 +7,26 @@ use stackable_operator::{ secret_class::SecretClassVolume, tls_verification::{CaCert, Tls, TlsClientDetails, TlsServerVerification, TlsVerification}, }, - crd::authentication::ldap, schemars::{self, JsonSchema}, shared::time::Duration, versioned::versioned, }; -#[versioned(version(name = "v1alpha1"))] +mod v1alpha1_impl; +mod v1alpha2_impl; + +#[versioned(version(name = "v1alpha1"), version(name = "v1alpha2"))] pub mod versioned { #[derive(Clone, Debug, Default, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct Config { /// The backend directory service to use. #[serde(default)] - pub backend: v1alpha1::Backend, + pub backend: Backend, /// Caching configuration. #[serde(default)] - pub cache: v1alpha1::Cache, + pub cache: Cache, } #[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] @@ -34,23 +36,23 @@ pub mod versioned { None {}, /// Backend that fetches user information from Keycloak. - Keycloak(v1alpha1::KeycloakBackend), + Keycloak(KeycloakBackend), /// Backend that fetches user information from the Gaia-X /// Cross Federation Services Components (XFSC) Authentication & Authorization Service. - ExperimentalXfscAas(v1alpha1::AasBackend), + ExperimentalXfscAas(AasBackend), /// Backend that fetches user information from Active Directory #[serde(rename = "experimentalActiveDirectory")] - ActiveDirectory(v1alpha1::ActiveDirectoryBackend), + ActiveDirectory(ActiveDirectoryBackend), /// Backend that fetches user information from Microsoft Entra - #[serde(rename = "experimentalEntra")] - Entra(v1alpha1::EntraBackend), + #[versioned(changed(since = "v1alpha2", from_name = "ExperimentalEntra"))] + Entra(EntraBackend), /// Backend that fetches user information from OpenLDAP #[serde(rename = "experimentalOpenLdap")] - OpenLdap(v1alpha1::OpenLdapBackend), + OpenLdap(OpenLdapBackend), } #[derive(Clone, Debug, Deserialize, Eq, JsonSchema, PartialEq, Serialize)] @@ -210,15 +212,13 @@ pub mod versioned { #[serde(rename_all = "camelCase")] pub struct Cache { /// How long metadata about each user should be cached for. - #[serde(default = "v1alpha1::Cache::default_entry_time_to_live")] + #[serde(default = "default_entry_time_to_live")] pub entry_time_to_live: Duration, } } -impl Default for v1alpha1::Backend { - fn default() -> Self { - Self::None {} - } +const fn default_entry_time_to_live() -> Duration { + Duration::from_minutes_unchecked(1) } fn default_root_path() -> String { @@ -256,36 +256,3 @@ fn openldap_default_user_name_attribute() -> String { fn openldap_default_group_member_attribute() -> String { "member".to_string() } - -impl v1alpha1::Cache { - const fn default_entry_time_to_live() -> Duration { - Duration::from_minutes_unchecked(1) - } -} - -impl Default for v1alpha1::Cache { - fn default() -> Self { - Self { - entry_time_to_live: Self::default_entry_time_to_live(), - } - } -} - -impl v1alpha1::OpenLdapBackend { - /// Returns an LDAP [`AuthenticationProvider`](ldap::v1alpha1::AuthenticationProvider) for - /// connecting to the OpenLDAP server. - /// - /// Converts this OpenLdap backend configuration into a standard LDAP authentication provider - /// that can be used by the user-info-fetcher to establish connections and query user data. - pub fn to_ldap_provider(&self) -> ldap::v1alpha1::AuthenticationProvider { - ldap::v1alpha1::AuthenticationProvider { - hostname: self.hostname.clone(), - port: self.port, - search_base: self.search_base.clone(), - search_filter: String::new(), - ldap_field_names: ldap::v1alpha1::FieldNames::default(), - bind_credentials: Some(self.bind_credentials.clone()), - tls: self.tls.clone(), - } - } -} diff --git a/rust/operator-binary/src/crd/user_info_fetcher/v1alpha1_impl.rs b/rust/operator-binary/src/crd/user_info_fetcher/v1alpha1_impl.rs new file mode 100644 index 00000000..acb8c642 --- /dev/null +++ b/rust/operator-binary/src/crd/user_info_fetcher/v1alpha1_impl.rs @@ -0,0 +1,44 @@ +use stackable_operator::{crd::authentication::ldap, shared::time::Duration}; + +use crate::crd::user_info_fetcher::v1alpha1; + +// TODO (@Techassi): Most of these impls are the exact same across v1alpha1 and v1alpha2. Explore +// and design a more elegant solution for it. +impl Default for v1alpha1::Backend { + fn default() -> Self { + Self::None {} + } +} + +impl Default for v1alpha1::Cache { + fn default() -> Self { + Self { + entry_time_to_live: Self::default_entry_time_to_live(), + } + } +} + +impl v1alpha1::Cache { + pub const fn default_entry_time_to_live() -> Duration { + Duration::from_minutes_unchecked(1) + } +} + +impl v1alpha1::OpenLdapBackend { + /// Returns an LDAP [`AuthenticationProvider`](ldap::v1alpha1::AuthenticationProvider) for + /// connecting to the OpenLDAP server. + /// + /// Converts this OpenLdap backend configuration into a standard LDAP authentication provider + /// that can be used by the user-info-fetcher to establish connections and query user data. + pub fn to_ldap_provider(&self) -> ldap::v1alpha1::AuthenticationProvider { + ldap::v1alpha1::AuthenticationProvider { + hostname: self.hostname.clone(), + port: self.port, + search_base: self.search_base.clone(), + search_filter: String::new(), + ldap_field_names: ldap::v1alpha1::FieldNames::default(), + bind_credentials: Some(self.bind_credentials.clone()), + tls: self.tls.clone(), + } + } +} diff --git a/rust/operator-binary/src/crd/user_info_fetcher/v1alpha2_impl.rs b/rust/operator-binary/src/crd/user_info_fetcher/v1alpha2_impl.rs new file mode 100644 index 00000000..6999bca1 --- /dev/null +++ b/rust/operator-binary/src/crd/user_info_fetcher/v1alpha2_impl.rs @@ -0,0 +1,44 @@ +use stackable_operator::{crd::authentication::ldap, shared::time::Duration}; + +use crate::crd::user_info_fetcher::v1alpha2; + +// TODO (@Techassi): Most of these impls are the exact same across v1alpha1 and v1alpha2. Explore +// and design a more elegant solution for it. +impl Default for v1alpha2::Backend { + fn default() -> Self { + Self::None {} + } +} + +impl Default for v1alpha2::Cache { + fn default() -> Self { + Self { + entry_time_to_live: Self::default_entry_time_to_live(), + } + } +} + +impl v1alpha2::Cache { + pub const fn default_entry_time_to_live() -> Duration { + Duration::from_minutes_unchecked(1) + } +} + +impl v1alpha2::OpenLdapBackend { + /// Returns an LDAP [`AuthenticationProvider`](ldap::v1alpha1::AuthenticationProvider) for + /// connecting to the OpenLDAP server. + /// + /// Converts this OpenLdap backend configuration into a standard LDAP authentication provider + /// that can be used by the user-info-fetcher to establish connections and query user data. + pub fn to_ldap_provider(&self) -> ldap::v1alpha1::AuthenticationProvider { + ldap::v1alpha1::AuthenticationProvider { + hostname: self.hostname.clone(), + port: self.port, + search_base: self.search_base.clone(), + search_filter: String::new(), + ldap_field_names: ldap::v1alpha1::FieldNames::default(), + bind_credentials: Some(self.bind_credentials.clone()), + tls: self.tls.clone(), + } + } +} From 5bc54691ff60234149fe94fa2b5376135eda3bd3 Mon Sep 17 00:00:00 2001 From: Techassi Date: Fri, 23 Jan 2026 11:19:44 +0100 Subject: [PATCH 2/3] chore(crd): Update versions in code --- rust/operator-binary/src/controller.rs | 116 +++++++----------- rust/operator-binary/src/discovery.rs | 10 +- rust/operator-binary/src/main.rs | 11 +- .../src/operations/graceful_shutdown.rs | 5 +- rust/operator-binary/src/product_logging.rs | 9 +- rust/operator-binary/src/service.rs | 22 ++-- rust/user-info-fetcher/src/backend/entra.rs | 8 +- .../user-info-fetcher/src/backend/keycloak.rs | 8 +- .../user-info-fetcher/src/backend/openldap.rs | 9 +- .../user-info-fetcher/src/backend/xfsc_aas.rs | 8 +- rust/user-info-fetcher/src/main.rs | 20 +-- 11 files changed, 105 insertions(+), 121 deletions(-) diff --git a/rust/operator-binary/src/controller.rs b/rust/operator-binary/src/controller.rs index cee53c7f..25900826 100644 --- a/rust/operator-binary/src/controller.rs +++ b/rust/operator-binary/src/controller.rs @@ -10,9 +10,6 @@ use product_config::{ProductConfigManager, types::PropertyNameKind}; use serde::{Deserialize, Serialize}; use serde_json::json; use snafu::{OptionExt, ResultExt, Snafu}; -use stackable_opa_operator::crd::{ - APP_NAME, DEFAULT_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT, OPERATOR_NAME, user_info_fetcher, v1alpha1, -}; use stackable_operator::{ builder::{ self, @@ -75,6 +72,10 @@ use stackable_operator::{ use strum::{EnumDiscriminants, IntoStaticStr}; use crate::{ + crd::{ + APP_NAME, Container, DEFAULT_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT, OPERATOR_NAME, + OpaClusterStatus, OpaConfig, OpaRole, user_info_fetcher, v1alpha2, + }, discovery::{self, build_discovery_configmaps}, operations::graceful_shutdown::add_graceful_shutdown_config, product_logging::{BundleBuilderLogLevel, extend_role_group_config_map}, @@ -172,9 +173,7 @@ pub enum Error { NoName, #[snafu(display("internal operator failure"))] - InternalOperatorFailure { - source: stackable_opa_operator::crd::Error, - }, + InternalOperatorFailure { source: crate::crd::Error }, #[snafu(display("failed to apply role Service"))] ApplyRoleService { @@ -184,31 +183,31 @@ pub enum Error { #[snafu(display("failed to apply Service for [{rolegroup}]"))] ApplyRoleGroupService { source: stackable_operator::cluster_resources::Error, - rolegroup: RoleGroupRef, + rolegroup: RoleGroupRef, }, #[snafu(display("failed to build ConfigMap for [{rolegroup}]"))] BuildRoleGroupConfig { source: stackable_operator::builder::configmap::Error, - rolegroup: RoleGroupRef, + rolegroup: RoleGroupRef, }, #[snafu(display("failed to apply ConfigMap for [{rolegroup}]"))] ApplyRoleGroupConfig { source: stackable_operator::cluster_resources::Error, - rolegroup: RoleGroupRef, + rolegroup: RoleGroupRef, }, #[snafu(display("failed to apply DaemonSet for [{rolegroup}]"))] ApplyRoleGroupDaemonSet { source: stackable_operator::cluster_resources::Error, - rolegroup: RoleGroupRef, + rolegroup: RoleGroupRef, }, #[snafu(display("failed to apply patch for DaemonSet for [{rolegroup}]"))] ApplyPatchRoleGroupDaemonSet { source: stackable_operator::client::Error, - rolegroup: RoleGroupRef, + rolegroup: RoleGroupRef, }, #[snafu(display("failed to patch service account"))] @@ -250,9 +249,7 @@ pub enum Error { }, #[snafu(display("failed to resolve and merge config for role and role group"))] - FailedToResolveConfig { - source: stackable_opa_operator::crd::Error, - }, + FailedToResolveConfig { source: crate::crd::Error }, #[snafu(display("illegal container name"))] IllegalContainerName { @@ -426,7 +423,7 @@ struct OpaClusterConfigStatus { } pub async fn reconcile_opa( - opa: Arc>, + opa: Arc>, ctx: Arc, ) -> Result { tracing::info!("Starting reconcile"); @@ -443,7 +440,7 @@ pub async fn reconcile_opa( .image .resolve(DOCKER_IMAGE_BASE_NAME, crate::built_info::PKG_VERSION) .context(ResolveProductImageSnafu)?; - let opa_role = v1alpha1::OpaRole::Server; + let opa_role = OpaRole::Server; let mut cluster_resources = ClusterResources::new( APP_NAME, @@ -610,7 +607,7 @@ pub async fn reconcile_opa( let cluster_operation_cond_builder = ClusterOperationsConditionBuilder::new(&opa.spec.cluster_operation); - let status = v1alpha1::OpaClusterStatus { + let status = OpaClusterStatus { conditions: compute_conditions(opa, &[&ds_cond_builder, &cluster_operation_cond_builder]), }; @@ -629,10 +626,10 @@ pub async fn reconcile_opa( /// The rolegroup [`ConfigMap`] configures the rolegroup based on the configuration given by the administrator fn build_server_rolegroup_config_map( - opa: &v1alpha1::OpaCluster, + opa: &v1alpha2::OpaCluster, resolved_product_image: &ResolvedProductImage, - rolegroup: &RoleGroupRef, - merged_config: &v1alpha1::OpaConfig, + rolegroup: &RoleGroupRef, + merged_config: &OpaConfig, ) -> Result { let mut cm_builder = ConfigMapBuilder::new(); @@ -681,7 +678,7 @@ fn add_stackable_rust_cli_env_vars( container_builder: &mut ContainerBuilder, cluster_info: &KubernetesClusterInfo, log_level: impl Into, - container: &v1alpha1::Container, + container: &Container, ) { let log_level = log_level.into(); container_builder @@ -721,12 +718,12 @@ fn add_stackable_rust_cli_env_vars( /// policy queries (which are often chained in serial, and block other tasks in the products). #[allow(clippy::too_many_arguments)] fn build_server_rolegroup_daemonset( - opa: &v1alpha1::OpaCluster, + opa: &v1alpha2::OpaCluster, resolved_product_image: &ResolvedProductImage, - opa_role: &v1alpha1::OpaRole, - rolegroup_ref: &RoleGroupRef, + opa_role: &OpaRole, + rolegroup_ref: &RoleGroupRef, server_config: &HashMap>, - merged_config: &v1alpha1::OpaConfig, + merged_config: &OpaConfig, opa_bundle_builder_image: &str, user_info_fetcher_image: &str, service_account: &ServiceAccount, @@ -751,15 +748,15 @@ fn build_server_rolegroup_daemonset( let mut pb = PodBuilder::new(); - let prepare_container_name = v1alpha1::Container::Prepare.to_string(); + let prepare_container_name = Container::Prepare.to_string(); let mut cb_prepare = ContainerBuilder::new(&prepare_container_name).context(IllegalContainerNameSnafu)?; - let bundle_builder_container_name = v1alpha1::Container::BundleBuilder.to_string(); + let bundle_builder_container_name = Container::BundleBuilder.to_string(); let mut cb_bundle_builder = ContainerBuilder::new(&bundle_builder_container_name).context(IllegalContainerNameSnafu)?; - let opa_container_name = v1alpha1::Container::Opa.to_string(); + let opa_container_name = Container::Opa.to_string(); let mut cb_opa = ContainerBuilder::new(&opa_container_name).context(IllegalContainerNameSnafu)?; @@ -832,8 +829,8 @@ fn build_server_rolegroup_daemonset( add_stackable_rust_cli_env_vars( &mut cb_bundle_builder, cluster_info, - sidecar_container_log_level(merged_config, &v1alpha1::Container::BundleBuilder).to_string(), - &v1alpha1::Container::BundleBuilder, + sidecar_container_log_level(merged_config, &Container::BundleBuilder).to_string(), + &Container::BundleBuilder, ); cb_opa @@ -992,15 +989,14 @@ fn build_server_rolegroup_daemonset( add_stackable_rust_cli_env_vars( &mut cb_user_info_fetcher, cluster_info, - sidecar_container_log_level(merged_config, &v1alpha1::Container::UserInfoFetcher) - .to_string(), - &v1alpha1::Container::UserInfoFetcher, + sidecar_container_log_level(merged_config, &Container::UserInfoFetcher).to_string(), + &Container::UserInfoFetcher, ); match &user_info.backend { - user_info_fetcher::v1alpha1::Backend::None {} => {} - user_info_fetcher::v1alpha1::Backend::ExperimentalXfscAas(_) => {} - user_info_fetcher::v1alpha1::Backend::ActiveDirectory(ad) => { + user_info_fetcher::v1alpha2::Backend::None {} => {} + user_info_fetcher::v1alpha2::Backend::ExperimentalXfscAas(_) => {} + user_info_fetcher::v1alpha2::Backend::ActiveDirectory(ad) => { pb.add_volume( SecretClassVolume::new( ad.kerberos_secret_class_name.clone(), @@ -1034,7 +1030,7 @@ fn build_server_rolegroup_daemonset( .add_volumes_and_mounts(&mut pb, vec![&mut cb_user_info_fetcher]) .context(UserInfoFetcherTlsVolumeAndMountsSnafu)?; } - user_info_fetcher::v1alpha1::Backend::Keycloak(keycloak) => { + user_info_fetcher::v1alpha2::Backend::Keycloak(keycloak) => { pb.add_volume( VolumeBuilder::new(USER_INFO_FETCHER_CREDENTIALS_VOLUME_NAME) .secret(SecretVolumeSource { @@ -1055,7 +1051,7 @@ fn build_server_rolegroup_daemonset( .add_volumes_and_mounts(&mut pb, vec![&mut cb_user_info_fetcher]) .context(UserInfoFetcherTlsVolumeAndMountsSnafu)?; } - user_info_fetcher::v1alpha1::Backend::Entra(entra) => { + user_info_fetcher::v1alpha2::Backend::Entra(entra) => { pb.add_volume( VolumeBuilder::new(USER_INFO_FETCHER_CREDENTIALS_VOLUME_NAME) .secret(SecretVolumeSource { @@ -1078,7 +1074,7 @@ fn build_server_rolegroup_daemonset( .add_volumes_and_mounts(&mut pb, vec![&mut cb_user_info_fetcher]) .context(UserInfoFetcherTlsVolumeAndMountsSnafu)?; } - user_info_fetcher::v1alpha1::Backend::OpenLdap(openldap) => { + user_info_fetcher::v1alpha2::Backend::OpenLdap(openldap) => { // Reuse the logic from the LDAP `AuthenticationProvider` which handles // volume mounting of TLS secrets and LDAP bind credentials openldap @@ -1099,10 +1095,7 @@ fn build_server_rolegroup_daemonset( resolved_product_image, CONFIG_VOLUME_NAME, LOG_VOLUME_NAME, - merged_config - .logging - .containers - .get(&v1alpha1::Container::Vector), + merged_config.logging.containers.get(&Container::Vector), ResourceRequirementsBuilder::new() .with_cpu_request("250m") .with_cpu_limit("500m") @@ -1165,7 +1158,7 @@ fn build_server_rolegroup_daemonset( } pub fn error_policy( - _obj: Arc>, + _obj: Arc>, error: &Error, _ctx: Arc, ) -> Action { @@ -1177,15 +1170,12 @@ pub fn error_policy( } } -fn build_config_file(merged_config: &v1alpha1::OpaConfig) -> String { +fn build_config_file(merged_config: &OpaConfig) -> String { let mut decision_logging_enabled = DEFAULT_DECISION_LOGGING_ENABLED; if let Some(ContainerLogConfig { choice: Some(ContainerLogConfigChoice::Automatic(log_config)), - }) = merged_config - .logging - .containers - .get(&v1alpha1::Container::Opa) + }) = merged_config.logging.containers.get(&Container::Opa) { if let Some(config) = log_config.loggers.get("decision") { decision_logging_enabled = config.level != LogLevel::NONE; @@ -1206,7 +1196,7 @@ fn build_config_file(merged_config: &v1alpha1::OpaConfig) -> String { } fn build_opa_start_command( - merged_config: &v1alpha1::OpaConfig, + merged_config: &OpaConfig, container_name: &str, tls_enabled: bool, ) -> String { @@ -1217,10 +1207,7 @@ fn build_opa_start_command( if let Some(ContainerLogConfig { choice: Some(ContainerLogConfigChoice::Automatic(log_config)), - }) = merged_config - .logging - .containers - .get(&v1alpha1::Container::Opa) + }) = merged_config.logging.containers.get(&Container::Opa) { if let Some(AppenderConfig { level: Some(log_level), @@ -1289,10 +1276,7 @@ fn build_opa_start_command( } } -fn build_bundle_builder_start_command( - merged_config: &v1alpha1::OpaConfig, - container_name: &str, -) -> String { +fn build_bundle_builder_start_command(merged_config: &OpaConfig, container_name: &str) -> String { let mut console_logging_off = false; // We need to check if the console logging is deactivated (NONE) @@ -1302,7 +1286,7 @@ fn build_bundle_builder_start_command( }) = merged_config .logging .containers - .get(&v1alpha1::Container::BundleBuilder) + .get(&Container::BundleBuilder) { if let Some(AppenderConfig { level: Some(log_level), @@ -1357,8 +1341,8 @@ fn build_bundle_builder_start_command( /// /// Context: https://docs.stackable.tech/home/stable/concepts/logging/ fn sidecar_container_log_level( - merged_config: &v1alpha1::OpaConfig, - sidecar_container: &v1alpha1::Container, + merged_config: &OpaConfig, + sidecar_container: &Container, ) -> BundleBuilderLogLevel { if let Some(ContainerLogConfig { choice: Some(ContainerLogConfigChoice::Automatic(log_config)), @@ -1375,17 +1359,11 @@ fn sidecar_container_log_level( BundleBuilderLogLevel::Info } -fn build_prepare_start_command( - merged_config: &v1alpha1::OpaConfig, - container_name: &str, -) -> Vec { +fn build_prepare_start_command(merged_config: &OpaConfig, container_name: &str) -> Vec { let mut prepare_container_args = vec![]; if let Some(ContainerLogConfig { choice: Some(ContainerLogConfigChoice::Automatic(log_config)), - }) = merged_config - .logging - .containers - .get(&v1alpha1::Container::Prepare) + }) = merged_config.logging.containers.get(&Container::Prepare) { prepare_container_args.push(product_logging::framework::capture_shell_output( STACKABLE_LOG_DIR, diff --git a/rust/operator-binary/src/discovery.rs b/rust/operator-binary/src/discovery.rs index 3870c03c..77ce45ce 100644 --- a/rust/operator-binary/src/discovery.rs +++ b/rust/operator-binary/src/discovery.rs @@ -1,5 +1,4 @@ use snafu::{OptionExt, ResultExt, Snafu}; -use stackable_opa_operator::crd::v1alpha1; use stackable_operator::{ builder::{configmap::ConfigMapBuilder, meta::ObjectMetaBuilder}, commons::product_image_selection::ResolvedProductImage, @@ -10,6 +9,7 @@ use stackable_operator::{ use crate::{ controller::build_recommended_labels, + crd::{OpaRole, v1alpha2}, service::{APP_PORT, APP_TLS_PORT}, }; @@ -18,7 +18,7 @@ pub enum Error { #[snafu(display("object {} is missing metadata to build owner reference", opa))] ObjectMissingMetadataForOwnerRef { source: stackable_operator::builder::meta::Error, - opa: ObjectRef, + opa: ObjectRef, }, #[snafu(display("object has no name associated"))] @@ -41,7 +41,7 @@ pub enum Error { /// Builds discovery [`ConfigMap`]s for connecting to a [`v1alpha1::OpaCluster`] for all expected scenarios pub fn build_discovery_configmaps( owner: &impl Resource, - opa: &v1alpha1::OpaCluster, + opa: &v1alpha2::OpaCluster, resolved_product_image: &ResolvedProductImage, svc: &Service, cluster_info: &KubernetesClusterInfo, @@ -61,7 +61,7 @@ pub fn build_discovery_configmaps( fn build_discovery_configmap( name: &str, owner: &impl Resource, - opa: &v1alpha1::OpaCluster, + opa: &v1alpha2::OpaCluster, resolved_product_image: &ResolvedProductImage, svc: &Service, cluster_info: &KubernetesClusterInfo, @@ -93,7 +93,7 @@ fn build_discovery_configmap( .with_recommended_labels(build_recommended_labels( opa, &resolved_product_image.app_version_label_value, - &v1alpha1::OpaRole::Server.to_string(), + &OpaRole::Server.to_string(), "discovery", )) .context(ObjectMetaSnafu)? diff --git a/rust/operator-binary/src/main.rs b/rust/operator-binary/src/main.rs index ee4e5bbe..64447bc8 100644 --- a/rust/operator-binary/src/main.rs +++ b/rust/operator-binary/src/main.rs @@ -6,7 +6,6 @@ use std::sync::Arc; use clap::Parser; use futures::StreamExt; use product_config::ProductConfigManager; -use stackable_opa_operator::crd::{OPERATOR_NAME, OpaCluster, OpaClusterVersion, v1alpha1}; use stackable_operator::{ YamlSchema, cli::{Command, RunArguments}, @@ -32,9 +31,13 @@ use stackable_operator::{ utils::cluster_info::KubernetesClusterInfo, }; -use crate::controller::OPA_FULL_CONTROLLER_NAME; +use crate::{ + controller::OPA_FULL_CONTROLLER_NAME, + crd::{OPERATOR_NAME, OpaCluster, OpaClusterVersion, v1alpha2}, +}; mod controller; +mod crd; mod discovery; mod operations; mod product_logging; @@ -66,7 +69,7 @@ async fn main() -> anyhow::Result<()> { let opts = Opts::parse(); match opts.cmd { Command::Crd => { - OpaCluster::merged_crd(OpaClusterVersion::V1Alpha1)? + OpaCluster::merged_crd(OpaClusterVersion::V1Alpha2)? .print_yaml_schema(built_info::PKG_VERSION, SerializeOptions::default())?; } Command::Run(OpaRun { @@ -139,7 +142,7 @@ async fn create_controller( user_info_fetcher_image: String, cluster_info: KubernetesClusterInfo, ) { - let opa_api: Api> = watch_namespace.get_api(&client); + let opa_api: Api> = watch_namespace.get_api(&client); let daemonsets_api: Api> = watch_namespace.get_api(&client); let configmaps_api: Api> = watch_namespace.get_api(&client); let services_api: Api> = watch_namespace.get_api(&client); diff --git a/rust/operator-binary/src/operations/graceful_shutdown.rs b/rust/operator-binary/src/operations/graceful_shutdown.rs index 5862a667..e7d1c188 100644 --- a/rust/operator-binary/src/operations/graceful_shutdown.rs +++ b/rust/operator-binary/src/operations/graceful_shutdown.rs @@ -1,7 +1,8 @@ use snafu::{ResultExt, Snafu}; -use stackable_opa_operator::crd::{SERVER_GRACEFUL_SHUTDOWN_SAFETY_OVERHEAD, v1alpha1}; use stackable_operator::builder::pod::PodBuilder; +use crate::crd::{OpaConfig, SERVER_GRACEFUL_SHUTDOWN_SAFETY_OVERHEAD}; + #[derive(Debug, Snafu)] pub enum Error { #[snafu(display("Failed to set terminationGracePeriod"))] @@ -11,7 +12,7 @@ pub enum Error { } pub fn add_graceful_shutdown_config( - merged_config: &v1alpha1::OpaConfig, + merged_config: &OpaConfig, pod_builder: &mut PodBuilder, ) -> Result<(), Error> { // This must be always set by the merge mechanism, as we provide a default value, diff --git a/rust/operator-binary/src/product_logging.rs b/rust/operator-binary/src/product_logging.rs index a99efcfe..27bc8af6 100644 --- a/rust/operator-binary/src/product_logging.rs +++ b/rust/operator-binary/src/product_logging.rs @@ -1,5 +1,4 @@ use snafu::Snafu; -use stackable_opa_operator::crd::v1alpha1; use stackable_operator::{ builder::configmap::ConfigMapBuilder, product_logging::{ @@ -9,6 +8,8 @@ use stackable_operator::{ role_utils::RoleGroupRef, }; +use crate::crd::{Container, v1alpha2}; + #[derive(Snafu, Debug)] pub enum Error { #[snafu(display("object has no namespace"))] @@ -53,13 +54,13 @@ impl From for BundleBuilderLogLevel { /// Extend the role group ConfigMap with logging and Vector configurations pub fn extend_role_group_config_map( - rolegroup: &RoleGroupRef, - logging: &Logging, + rolegroup: &RoleGroupRef, + logging: &Logging, cm_builder: &mut ConfigMapBuilder, ) -> Result<()> { let vector_log_config = if let Some(ContainerLogConfig { choice: Some(ContainerLogConfigChoice::Automatic(log_config)), - }) = logging.containers.get(&v1alpha1::Container::Vector) + }) = logging.containers.get(&Container::Vector) { Some(log_config) } else { diff --git a/rust/operator-binary/src/service.rs b/rust/operator-binary/src/service.rs index 72cdd6ef..5cfbbd4f 100644 --- a/rust/operator-binary/src/service.rs +++ b/rust/operator-binary/src/service.rs @@ -1,5 +1,4 @@ use snafu::{ResultExt, Snafu}; -use stackable_opa_operator::crd::{APP_NAME, v1alpha1}; use stackable_operator::{ builder::meta::ObjectMetaBuilder, commons::product_image_selection::ResolvedProductImage, @@ -8,7 +7,10 @@ use stackable_operator::{ role_utils::RoleGroupRef, }; -use crate::controller::build_recommended_labels; +use crate::{ + controller::build_recommended_labels, + crd::{APP_NAME, OpaRole, v1alpha2}, +}; pub const APP_PORT: u16 = 8081; pub const APP_TLS_PORT: u16 = 8443; @@ -35,10 +37,10 @@ pub enum Error { /// The server-role service is the primary endpoint that should be used by clients that do not perform internal load balancing, /// including targets outside of the cluster. pub(crate) fn build_server_role_service( - opa: &v1alpha1::OpaCluster, + opa: &v1alpha2::OpaCluster, resolved_product_image: &ResolvedProductImage, ) -> Result { - let role_name = v1alpha1::OpaRole::Server.to_string(); + let role_name = OpaRole::Server.to_string(); let metadata = ObjectMetaBuilder::new() .name_and_namespace(opa) @@ -76,9 +78,9 @@ pub(crate) fn build_server_role_service( /// /// This is mostly useful for internal communication between peers, or for clients that perform client-side load balancing. pub(crate) fn build_rolegroup_headless_service( - opa: &v1alpha1::OpaCluster, + opa: &v1alpha2::OpaCluster, resolved_product_image: &ResolvedProductImage, - rolegroup: &RoleGroupRef, + rolegroup: &RoleGroupRef, ) -> Result { let metadata = ObjectMetaBuilder::new() .name_and_namespace(opa) @@ -120,9 +122,9 @@ pub(crate) fn build_rolegroup_headless_service( /// The rolegroup metrics [`Service`] is a service that exposes metrics and has the /// prometheus.io/scrape label. pub(crate) fn build_rolegroup_metrics_service( - opa: &v1alpha1::OpaCluster, + opa: &v1alpha2::OpaCluster, resolved_product_image: &ResolvedProductImage, - rolegroup: &RoleGroupRef, + rolegroup: &RoleGroupRef, ) -> Result { let metadata = ObjectMetaBuilder::new() .name_and_namespace(opa) @@ -161,8 +163,8 @@ pub(crate) fn build_rolegroup_metrics_service( /// Returns the [`Labels`] that can be used to select all Pods that are part of the roleGroup. fn role_group_selector_labels( - opa: &v1alpha1::OpaCluster, - rolegroup: &RoleGroupRef, + opa: &v1alpha2::OpaCluster, + rolegroup: &RoleGroupRef, ) -> Result { Labels::role_group_selector(opa, APP_NAME, &rolegroup.role, &rolegroup.role_group) .context(BuildLabelSnafu) diff --git a/rust/user-info-fetcher/src/backend/entra.rs b/rust/user-info-fetcher/src/backend/entra.rs index 5d6e663b..721e92ee 100644 --- a/rust/user-info-fetcher/src/backend/entra.rs +++ b/rust/user-info-fetcher/src/backend/entra.rs @@ -4,7 +4,7 @@ use hyper::StatusCode; use reqwest::ClientBuilder; use serde::Deserialize; use snafu::{ResultExt, Snafu}; -use stackable_opa_operator::crd::user_info_fetcher::v1alpha1; +use stackable_opa_operator::crd::user_info_fetcher::v1alpha2; use stackable_operator::commons::{networking::HostName, tls_verification::TlsClientDetails}; use url::Url; @@ -111,7 +111,7 @@ struct GroupMembership { /// This struct combines the CRD configuration with credentials loaded from the filesystem. /// Credentials and the HTTP client are initialized once at startup and stored internally. pub struct ResolvedEntraBackend { - config: v1alpha1::EntraBackend, + config: v1alpha2::EntraBackend, client_id: String, client_secret: String, http_client: reqwest::Client, @@ -123,7 +123,7 @@ impl ResolvedEntraBackend { /// Reads `clientId` and `clientSecret` from the credentials directory and initializes /// the HTTP client with appropriate TLS configuration. pub async fn resolve( - config: v1alpha1::EntraBackend, + config: v1alpha2::EntraBackend, credentials_dir: &Path, ) -> Result { let client_id_path = credentials_dir.join("clientId"); @@ -161,7 +161,7 @@ impl ResolvedEntraBackend { } pub(crate) async fn get_user_info(&self, req: &UserInfoRequest) -> Result { - let v1alpha1::EntraBackend { + let v1alpha2::EntraBackend { client_credentials_secret: _, token_hostname, user_info_hostname, diff --git a/rust/user-info-fetcher/src/backend/keycloak.rs b/rust/user-info-fetcher/src/backend/keycloak.rs index 7d07e7d4..49c19822 100644 --- a/rust/user-info-fetcher/src/backend/keycloak.rs +++ b/rust/user-info-fetcher/src/backend/keycloak.rs @@ -4,7 +4,7 @@ use hyper::StatusCode; use reqwest::ClientBuilder; use serde::Deserialize; use snafu::{OptionExt, ResultExt, Snafu}; -use stackable_opa_operator::crd::user_info_fetcher::v1alpha1; +use stackable_opa_operator::crd::user_info_fetcher::v1alpha2; use stackable_operator::crd::authentication::oidc; use crate::{ @@ -117,7 +117,7 @@ struct GroupMembership { /// This struct combines the CRD configuration with credentials loaded from the filesystem. /// Credentials and the HTTP client are initialized once at startup and stored internally. pub struct ResolvedKeycloakBackend { - config: v1alpha1::KeycloakBackend, + config: v1alpha2::KeycloakBackend, client_id: String, client_secret: String, http_client: reqwest::Client, @@ -129,7 +129,7 @@ impl ResolvedKeycloakBackend { /// Reads `clientId` and `clientSecret` from the credentials directory and initializes /// the HTTP client with appropriate TLS configuration. pub async fn resolve( - config: v1alpha1::KeycloakBackend, + config: v1alpha2::KeycloakBackend, credentials_dir: &Path, ) -> Result { let client_id_path = credentials_dir.join("clientId"); @@ -162,7 +162,7 @@ impl ResolvedKeycloakBackend { } pub(crate) async fn get_user_info(&self, req: &UserInfoRequest) -> Result { - let v1alpha1::KeycloakBackend { + let v1alpha2::KeycloakBackend { client_credentials_secret: _, admin_realm, user_realm, diff --git a/rust/user-info-fetcher/src/backend/openldap.rs b/rust/user-info-fetcher/src/backend/openldap.rs index 632fb88a..92c73d02 100644 --- a/rust/user-info-fetcher/src/backend/openldap.rs +++ b/rust/user-info-fetcher/src/backend/openldap.rs @@ -3,6 +3,7 @@ use std::collections::{BTreeMap, HashMap}; use hyper::StatusCode; use ldap3::{LdapConnAsync, LdapConnSettings, LdapError, Scope, SearchEntry, ldap_escape}; use snafu::{OptionExt, ResultExt, Snafu}; +use stackable_opa_operator::crd::user_info_fetcher::v1alpha2; use stackable_operator::crd::authentication::ldap; use crate::{ErrorRenderUserInfoRequest, UserInfo, UserInfoRequest, http_error, utils}; @@ -68,7 +69,7 @@ impl http_error::Error for Error { /// This struct combines the CRD configuration with credentials loaded from the filesystem. /// Credentials are loaded once at startup and stored internally. pub struct ResolvedOpenLdapBackend { - config: stackable_opa_operator::crd::user_info_fetcher::v1alpha1::OpenLdapBackend, + config: v1alpha2::OpenLdapBackend, bind_user: String, bind_password: String, } @@ -77,9 +78,7 @@ impl ResolvedOpenLdapBackend { /// Resolves an OpenLDAP backend by loading credentials from the filesystem. /// /// Reads bind credentials from paths specified in the configuration. - pub async fn resolve( - config: stackable_opa_operator::crd::user_info_fetcher::v1alpha1::OpenLdapBackend, - ) -> Result { + pub async fn resolve(config: v1alpha2::OpenLdapBackend) -> Result { let ldap_provider = config.to_ldap_provider(); // Bind credentials are guaranteed to be present because they are required in the CRD let (user_path, password_path) = ldap_provider @@ -201,7 +200,7 @@ impl ResolvedOpenLdapBackend { async fn search_user_groups( ldap: &mut ldap3::Ldap, user: &SearchEntry, - config: &stackable_opa_operator::crd::user_info_fetcher::v1alpha1::OpenLdapBackend, + config: &v1alpha2::OpenLdapBackend, ) -> Result, Error> { let group_member_attribute = &config.group_member_attribute; let groups_search_base = config diff --git a/rust/user-info-fetcher/src/backend/xfsc_aas.rs b/rust/user-info-fetcher/src/backend/xfsc_aas.rs index ec057810..0b4df775 100644 --- a/rust/user-info-fetcher/src/backend/xfsc_aas.rs +++ b/rust/user-info-fetcher/src/backend/xfsc_aas.rs @@ -16,7 +16,7 @@ use hyper::StatusCode; use reqwest::ClientBuilder; use serde::Deserialize; use snafu::{ResultExt, Snafu}; -use stackable_opa_operator::crd::user_info_fetcher::v1alpha1; +use stackable_opa_operator::crd::user_info_fetcher::v1alpha2; use url::Url; use crate::{UserInfo, UserInfoRequest, http_error, utils::http::send_json_request}; @@ -84,13 +84,13 @@ impl TryFrom for UserInfo { /// /// This struct combines the CRD configuration with an HTTP client initialized at startup. pub struct ResolvedXfscAasBackend { - config: v1alpha1::AasBackend, + config: v1alpha2::AasBackend, http_client: reqwest::Client, } impl ResolvedXfscAasBackend { /// Resolves an XFSC AAS backend by initializing the HTTP client. - pub fn resolve(config: v1alpha1::AasBackend) -> Result { + pub fn resolve(config: v1alpha2::AasBackend) -> Result { let http_client = ClientBuilder::new() .build() .context(ConstructHttpClientSnafu)?; @@ -103,7 +103,7 @@ impl ResolvedXfscAasBackend { /// Only `UserInfoRequestById` is supported because the endpoint has no username concept. pub(crate) async fn get_user_info(&self, req: &UserInfoRequest) -> Result { - let v1alpha1::AasBackend { hostname, port } = &self.config; + let v1alpha2::AasBackend { hostname, port } = &self.config; let cip_endpoint_raw = format!("http://{hostname}:{port}{API_PATH}"); let cip_endpoint = Url::parse(&cip_endpoint_raw).context(ParseAasEndpointUrlSnafu { diff --git a/rust/user-info-fetcher/src/main.rs b/rust/user-info-fetcher/src/main.rs index c2f18026..1776b3be 100644 --- a/rust/user-info-fetcher/src/main.rs +++ b/rust/user-info-fetcher/src/main.rs @@ -11,7 +11,7 @@ use futures::{FutureExt, future, pin_mut}; use moka::future::Cache; use serde::{Deserialize, Serialize}; use snafu::{ResultExt, Snafu}; -use stackable_opa_operator::crd::user_info_fetcher::v1alpha1; +use stackable_opa_operator::crd::user_info_fetcher::v1alpha2; use stackable_operator::{cli::CommonOptions, telemetry::Tracing}; use tokio::net::TcpListener; @@ -111,37 +111,37 @@ async fn read_config_file(path: &Path) -> Result { /// This function reads credentials from the filesystem once at startup and returns a backend that /// contains both the configuration and the resolved credentials. async fn resolve_backend( - backend: v1alpha1::Backend, + backend: v1alpha2::Backend, credentials_dir: &Path, ) -> Result { match backend { - v1alpha1::Backend::None {} => Ok(ResolvedBackend::None), - v1alpha1::Backend::Keycloak(config) => { + v1alpha2::Backend::None {} => Ok(ResolvedBackend::None), + v1alpha2::Backend::Keycloak(config) => { let resolved = backend::keycloak::ResolvedKeycloakBackend::resolve(config, credentials_dir) .await .context(ResolveKeycloakBackendSnafu)?; Ok(ResolvedBackend::Keycloak(resolved)) } - v1alpha1::Backend::ExperimentalXfscAas(config) => { + v1alpha2::Backend::ExperimentalXfscAas(config) => { let resolved = backend::xfsc_aas::ResolvedXfscAasBackend::resolve(config) .context(ResolveXfscAasBackendSnafu)?; Ok(ResolvedBackend::ExperimentalXfscAas(resolved)) } - v1alpha1::Backend::ActiveDirectory(config) => Ok(ResolvedBackend::ActiveDirectory { + v1alpha2::Backend::ActiveDirectory(config) => Ok(ResolvedBackend::ActiveDirectory { ldap_server: config.ldap_server, tls: config.tls, base_distinguished_name: config.base_distinguished_name, custom_attribute_mappings: config.custom_attribute_mappings, additional_group_attribute_filters: config.additional_group_attribute_filters, }), - v1alpha1::Backend::Entra(config) => { + v1alpha2::Backend::Entra(config) => { let resolved = backend::entra::ResolvedEntraBackend::resolve(config, credentials_dir) .await .context(ResolveEntraBackendSnafu)?; Ok(ResolvedBackend::Entra(resolved)) } - v1alpha1::Backend::OpenLdap(config) => { + v1alpha2::Backend::OpenLdap(config) => { let resolved = backend::openldap::ResolvedOpenLdapBackend::resolve(config) .await .context(ResolveOpenLdapBackendSnafu)?; @@ -184,13 +184,13 @@ async fn main() -> Result<(), StartupError> { } }; - let config: v1alpha1::Config = + let config: v1alpha2::Config = serde_json::from_str(&read_config_file(&args.config).await?).context(ParseConfigSnafu)?; let backend = Arc::new(resolve_backend(config.backend, &args.credentials_dir).await?); let user_info_cache = { - let v1alpha1::Cache { entry_time_to_live } = config.cache; + let v1alpha2::Cache { entry_time_to_live } = config.cache; Cache::builder() .name("user-info") .time_to_live(*entry_time_to_live) From 481d3273944ee29a9cd04a3a42cb92206b11e65a Mon Sep 17 00:00:00 2001 From: Techassi Date: Fri, 23 Jan 2026 14:32:29 +0100 Subject: [PATCH 3/3] feat: Add conversion webhook server --- Cargo.lock | 457 +++- Cargo.nix | 1724 ++++++++++++- Cargo.toml | 6 +- Makefile | 4 +- Tiltfile | 24 +- crate-hashes.json | 2 + deploy/helm/opa-operator/crds/crds.yaml | 2250 ----------------- extra/crds.yaml | 2248 ++++++++++++++++ rust/operator-binary/src/crd/mod.rs | 1 + rust/operator-binary/src/main.rs | 26 +- .../src/webhooks/conversion.rs | 49 + rust/operator-binary/src/webhooks/mod.rs | 1 + 12 files changed, 4471 insertions(+), 2321 deletions(-) delete mode 100644 deploy/helm/opa-operator/crds/crds.yaml create mode 100644 extra/crds.yaml create mode 100644 rust/operator-binary/src/webhooks/conversion.rs create mode 100644 rust/operator-binary/src/webhooks/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 213029d2..3f0c5d37 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,6 +101,15 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +[[package]] +name = "arc-swap" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d03449bb8ca2cc2ef70869af31463d1ae5ccc8fa3e334b307203fbf815207e" +dependencies = [ + "rustversion", +] + [[package]] name = "async-broadcast" version = "0.7.2" @@ -232,12 +241,24 @@ dependencies = [ "tokio", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + [[package]] name = "bindgen" version = "0.71.1" @@ -421,6 +442,12 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "const_format" version = "0.2.35" @@ -531,6 +558,18 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -621,6 +660,30 @@ dependencies = [ "syn 2.0.108", ] +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "der_derive", + "flagset", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.108", +] + [[package]] name = "deranged" version = "0.5.5" @@ -657,7 +720,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", + "subtle", ] [[package]] @@ -697,6 +762,20 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "educe" version = "0.6.0" @@ -715,6 +794,26 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pem-rfc7468", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "encoding_rs" version = "0.8.35" @@ -807,6 +906,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "filetime" version = "0.2.26" @@ -825,6 +934,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" +[[package]] +name = "flagset" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" + [[package]] name = "flate2" version = "1.1.5" @@ -968,6 +1083,7 @@ checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1024,6 +1140,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "h2" version = "0.4.12" @@ -1066,6 +1193,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "home" version = "0.5.12" @@ -1646,6 +1782,9 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] name = "lber" @@ -1733,6 +1872,12 @@ dependencies = [ "windows-link 0.2.1", ] +[[package]] +name = "libm" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" + [[package]] name = "libredox" version = "0.1.10" @@ -1894,12 +2039,48 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" +dependencies = [ + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -1907,6 +2088,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -2053,7 +2235,7 @@ dependencies = [ "futures-util", "opentelemetry", "percent-encoding", - "rand", + "rand 0.9.2", "thiserror 2.0.17", "tokio", "tokio-stream", @@ -2068,6 +2250,18 @@ dependencies = [ "num-traits", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "parking" version = "2.2.1" @@ -2107,6 +2301,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.2" @@ -2188,6 +2391,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.32" @@ -2234,6 +2458,15 @@ dependencies = [ "syn 2.0.108", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.103" @@ -2297,14 +2530,34 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "rand_chacha", - "rand_core", + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", ] [[package]] @@ -2314,7 +2567,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.9.3", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", ] [[package]] @@ -2426,6 +2688,16 @@ dependencies = [ "web-sys", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "ring" version = "0.17.14" @@ -2440,6 +2712,27 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rsa" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "sha2", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rustc-hash" version = "2.1.1" @@ -2568,6 +2861,20 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "secrecy" version = "0.10.3" @@ -2719,6 +3026,17 @@ dependencies = [ "unsafe-libyaml", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.9" @@ -2754,6 +3072,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -2824,12 +3152,52 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" +[[package]] +name = "stackable-certs" +version = "0.4.0" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.101.2#13cf69454684ccf105d7377ca369d62b7b07250c" +dependencies = [ + "const-oid", + "ecdsa", + "k8s-openapi", + "kube", + "p256", + "rand 0.9.2", + "rand_core 0.6.4", + "rsa", + "sha2", + "signature", + "snafu 0.8.9", + "stackable-shared", + "tokio", + "tokio-rustls", + "tracing", + "x509-cert", + "zeroize", +] + [[package]] name = "stackable-opa-bundle-builder" version = "0.0.0-dev" @@ -2935,6 +3303,7 @@ dependencies = [ "stackable-shared", "stackable-telemetry", "stackable-versioned", + "stackable-webhook", "strum", "tokio", "tracing", @@ -3025,6 +3394,37 @@ dependencies = [ "syn 2.0.108", ] +[[package]] +name = "stackable-webhook" +version = "0.8.1" +source = "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.101.2#13cf69454684ccf105d7377ca369d62b7b07250c" +dependencies = [ + "arc-swap", + "async-trait", + "axum", + "futures-util", + "hyper", + "hyper-util", + "k8s-openapi", + "kube", + "opentelemetry", + "opentelemetry-semantic-conventions", + "rand 0.9.2", + "serde", + "serde_json", + "snafu 0.8.9", + "stackable-certs", + "stackable-shared", + "stackable-telemetry", + "tokio", + "tokio-rustls", + "tower", + "tower-http", + "tracing", + "tracing-opentelemetry", + "x509-cert", +] + [[package]] name = "strsim" version = "0.11.1" @@ -3241,6 +3641,27 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tls_codec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de2e01245e2bb89d6f05801c564fa27624dbd7b1846859876c7dad82e90bf6b" +dependencies = [ + "tls_codec_derive", + "zeroize", +] + +[[package]] +name = "tls_codec_derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d2e76690929402faae40aebdda620a2c0e25dd6d3b9afe48867dfd95991f4bd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.108", +] + [[package]] name = "tokio" version = "1.48.0" @@ -4040,6 +4461,20 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +[[package]] +name = "x509-cert" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" +dependencies = [ + "const-oid", + "der", + "sha1", + "signature", + "spki", + "tls_codec", +] + [[package]] name = "xattr" version = "1.6.1" @@ -4126,6 +4561,20 @@ name = "zeroize" version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.108", +] [[package]] name = "zerotrie" diff --git a/Cargo.nix b/Cargo.nix index 46f26925..bb5bca64 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -357,6 +357,25 @@ rec { }; resolvedDefaultFeatures = [ "default" "std" ]; }; + "arc-swap" = rec { + crateName = "arc-swap"; + version = "1.8.0"; + edition = "2018"; + sha256 = "0zi02pwgn0vj615k6gpsr36fa6ix8qqsys88ywpcr8lcpd4k9l2i"; + libName = "arc_swap"; + authors = [ + "Michal 'vorner' Vaner " + ]; + dependencies = [ + { + name = "rustversion"; + packageId = "rustversion"; + } + ]; + features = { + "serde" = [ "dep:serde" ]; + }; + }; "async-broadcast" = rec { crateName = "async-broadcast"; version = "0.7.2"; @@ -807,6 +826,19 @@ rec { }; resolvedDefaultFeatures = [ "default" "gloo-timers" "gloo-timers-sleep" "std" "std-blocking-sleep" "tokio" "tokio-sleep" ]; }; + "base16ct" = rec { + crateName = "base16ct"; + version = "0.2.0"; + edition = "2021"; + sha256 = "1kylrjhdzk7qpknrvlphw8ywdnvvg39dizw9622w3wk5xba04zsc"; + authors = [ + "RustCrypto Developers" + ]; + features = { + "std" = [ "alloc" ]; + }; + resolvedDefaultFeatures = [ "alloc" ]; + }; "base64" = rec { crateName = "base64"; version = "0.22.1"; @@ -821,6 +853,19 @@ rec { }; resolvedDefaultFeatures = [ "alloc" "default" "std" ]; }; + "base64ct" = rec { + crateName = "base64ct"; + version = "1.8.3"; + edition = "2024"; + sha256 = "01nyyyx84bhwrcc168hn47d8gvz2pzpv3y3lmck7mq4hw5vh3x9a"; + authors = [ + "RustCrypto Developers" + ]; + features = { + "std" = [ "alloc" ]; + }; + resolvedDefaultFeatures = [ "alloc" ]; + }; "bindgen" = rec { crateName = "bindgen"; version = "0.71.1"; @@ -1393,6 +1438,20 @@ rec { }; resolvedDefaultFeatures = [ "std" ]; }; + "const-oid" = rec { + crateName = "const-oid"; + version = "0.9.6"; + edition = "2021"; + sha256 = "1y0jnqaq7p2wvspnx7qj76m7hjcqpz73qzvr9l2p9n2s51vr6if2"; + libName = "const_oid"; + authors = [ + "RustCrypto Developers" + ]; + features = { + "arbitrary" = [ "dep:arbitrary" ]; + }; + resolvedDefaultFeatures = [ "db" "std" ]; + }; "const_format" = rec { crateName = "const_format"; version = "0.2.35"; @@ -1699,6 +1758,58 @@ rec { }; resolvedDefaultFeatures = [ "default" "std" ]; }; + "crypto-bigint" = rec { + crateName = "crypto-bigint"; + version = "0.5.5"; + edition = "2021"; + sha256 = "0xmbdff3g6ii5sbxjxc31xfkv9lrmyril4arh3dzckd4gjsjzj8d"; + libName = "crypto_bigint"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "generic-array"; + packageId = "generic-array"; + optional = true; + } + { + name = "rand_core"; + packageId = "rand_core 0.6.4"; + optional = true; + } + { + name = "subtle"; + packageId = "subtle"; + usesDefaultFeatures = false; + } + { + name = "zeroize"; + packageId = "zeroize"; + optional = true; + usesDefaultFeatures = false; + } + ]; + devDependencies = [ + { + name = "rand_core"; + packageId = "rand_core 0.6.4"; + features = [ "std" ]; + } + ]; + features = { + "alloc" = [ "serdect?/alloc" ]; + "default" = [ "rand" ]; + "der" = [ "dep:der" ]; + "generic-array" = [ "dep:generic-array" ]; + "rand" = [ "rand_core/std" ]; + "rand_core" = [ "dep:rand_core" ]; + "rlp" = [ "dep:rlp" ]; + "serde" = [ "dep:serdect" ]; + "zeroize" = [ "dep:zeroize" ]; + }; + resolvedDefaultFeatures = [ "generic-array" "rand_core" "zeroize" ]; + }; "crypto-common" = rec { crateName = "crypto-common"; version = "0.1.6"; @@ -1723,6 +1834,7 @@ rec { "getrandom" = [ "rand_core/getrandom" ]; "rand_core" = [ "dep:rand_core" ]; }; + resolvedDefaultFeatures = [ "std" ]; }; "darling 0.21.3" = rec { crateName = "darling"; @@ -1934,6 +2046,83 @@ rec { } ]; + }; + "der" = rec { + crateName = "der"; + version = "0.7.10"; + edition = "2021"; + sha256 = "1jyxacyxdx6mxbkfw99jz59dzvcd9k17rq01a7xvn1dr6wl87hg7"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "const-oid"; + packageId = "const-oid"; + optional = true; + } + { + name = "der_derive"; + packageId = "der_derive"; + optional = true; + } + { + name = "flagset"; + packageId = "flagset"; + optional = true; + } + { + name = "pem-rfc7468"; + packageId = "pem-rfc7468"; + optional = true; + features = [ "alloc" ]; + } + { + name = "zeroize"; + packageId = "zeroize"; + optional = true; + usesDefaultFeatures = false; + } + ]; + features = { + "alloc" = [ "zeroize?/alloc" ]; + "arbitrary" = [ "dep:arbitrary" "const-oid?/arbitrary" "std" ]; + "bytes" = [ "dep:bytes" "alloc" ]; + "derive" = [ "dep:der_derive" ]; + "flagset" = [ "dep:flagset" ]; + "oid" = [ "dep:const-oid" ]; + "pem" = [ "dep:pem-rfc7468" "alloc" "zeroize" ]; + "std" = [ "alloc" ]; + "time" = [ "dep:time" ]; + "zeroize" = [ "dep:zeroize" ]; + }; + resolvedDefaultFeatures = [ "alloc" "derive" "flagset" "oid" "pem" "std" "zeroize" ]; + }; + "der_derive" = rec { + crateName = "der_derive"; + version = "0.7.3"; + edition = "2021"; + sha256 = "065d2wy7zd0dank99hh58l5x7lv50hxnr7j6f3sphlb7i4ihjd40"; + procMacro = true; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "proc-macro2"; + packageId = "proc-macro2"; + } + { + name = "quote"; + packageId = "quote"; + } + { + name = "syn"; + packageId = "syn 2.0.108"; + features = [ "extra-traits" ]; + } + ]; + }; "deranged" = rec { crateName = "deranged"; @@ -2065,10 +2254,21 @@ rec { packageId = "block-buffer"; optional = true; } + { + name = "const-oid"; + packageId = "const-oid"; + optional = true; + } { name = "crypto-common"; packageId = "crypto-common"; } + { + name = "subtle"; + packageId = "subtle"; + optional = true; + usesDefaultFeatures = false; + } ]; features = { "blobby" = [ "dep:blobby" ]; @@ -2083,7 +2283,7 @@ rec { "std" = [ "alloc" "crypto-common/std" ]; "subtle" = [ "dep:subtle" ]; }; - resolvedDefaultFeatures = [ "block-buffer" "core-api" "default" ]; + resolvedDefaultFeatures = [ "alloc" "block-buffer" "const-oid" "core-api" "default" "mac" "oid" "std" "subtle" ]; }; "displaydoc" = rec { crateName = "displaydoc"; @@ -2172,6 +2372,79 @@ rec { ]; }; + "ecdsa" = rec { + crateName = "ecdsa"; + version = "0.16.9"; + edition = "2021"; + sha256 = "1jhb0bcbkaz4001sdmfyv8ajrv8a1cg7z7aa5myrd4jjbhmz69zf"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "der"; + packageId = "der"; + optional = true; + } + { + name = "digest"; + packageId = "digest"; + optional = true; + usesDefaultFeatures = false; + features = [ "oid" ]; + } + { + name = "elliptic-curve"; + packageId = "elliptic-curve"; + usesDefaultFeatures = false; + features = [ "digest" "sec1" ]; + } + { + name = "rfc6979"; + packageId = "rfc6979"; + optional = true; + } + { + name = "signature"; + packageId = "signature"; + usesDefaultFeatures = false; + features = [ "rand_core" ]; + } + { + name = "spki"; + packageId = "spki"; + optional = true; + usesDefaultFeatures = false; + } + ]; + devDependencies = [ + { + name = "elliptic-curve"; + packageId = "elliptic-curve"; + usesDefaultFeatures = false; + features = [ "dev" ]; + } + ]; + features = { + "alloc" = [ "elliptic-curve/alloc" "signature/alloc" "spki/alloc" ]; + "arithmetic" = [ "elliptic-curve/arithmetic" ]; + "default" = [ "digest" ]; + "der" = [ "dep:der" ]; + "dev" = [ "arithmetic" "digest" "elliptic-curve/dev" "hazmat" ]; + "digest" = [ "dep:digest" "signature/digest" ]; + "pem" = [ "elliptic-curve/pem" "pkcs8" ]; + "pkcs8" = [ "digest" "elliptic-curve/pkcs8" "der" ]; + "rfc6979" = [ "dep:rfc6979" ]; + "serde" = [ "elliptic-curve/serde" "serdect" ]; + "serdect" = [ "dep:serdect" ]; + "sha2" = [ "dep:sha2" ]; + "signing" = [ "arithmetic" "digest" "hazmat" "rfc6979" ]; + "spki" = [ "dep:spki" ]; + "std" = [ "alloc" "elliptic-curve/std" "signature/std" ]; + "verifying" = [ "arithmetic" "digest" "hazmat" ]; + }; + resolvedDefaultFeatures = [ "alloc" "arithmetic" "default" "der" "digest" "hazmat" "pem" "pkcs8" "rfc6979" "signing" "spki" "std" "verifying" ]; + }; "educe" = rec { crateName = "educe"; version = "0.6.0"; @@ -2229,6 +2502,104 @@ rec { }; resolvedDefaultFeatures = [ "default" "std" "use_std" ]; }; + "elliptic-curve" = rec { + crateName = "elliptic-curve"; + version = "0.13.8"; + edition = "2021"; + sha256 = "0ixx4brgnzi61z29r3g1606nh2za88hzyz8c5r3p6ydzhqq09rmm"; + libName = "elliptic_curve"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "base16ct"; + packageId = "base16ct"; + } + { + name = "crypto-bigint"; + packageId = "crypto-bigint"; + usesDefaultFeatures = false; + features = [ "rand_core" "generic-array" "zeroize" ]; + } + { + name = "digest"; + packageId = "digest"; + optional = true; + } + { + name = "ff"; + packageId = "ff"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "generic-array"; + packageId = "generic-array"; + usesDefaultFeatures = false; + features = [ "zeroize" ]; + } + { + name = "group"; + packageId = "group"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "pem-rfc7468"; + packageId = "pem-rfc7468"; + optional = true; + features = [ "alloc" ]; + } + { + name = "pkcs8"; + packageId = "pkcs8"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "rand_core"; + packageId = "rand_core 0.6.4"; + usesDefaultFeatures = false; + } + { + name = "sec1"; + packageId = "sec1"; + optional = true; + features = [ "subtle" "zeroize" ]; + } + { + name = "subtle"; + packageId = "subtle"; + usesDefaultFeatures = false; + } + { + name = "zeroize"; + packageId = "zeroize"; + usesDefaultFeatures = false; + } + ]; + features = { + "alloc" = [ "base16ct/alloc" "ff?/alloc" "group?/alloc" "pkcs8?/alloc" "sec1?/alloc" "zeroize/alloc" ]; + "arithmetic" = [ "group" ]; + "bits" = [ "arithmetic" "ff/bits" "dep:tap" ]; + "default" = [ "arithmetic" ]; + "dev" = [ "arithmetic" "dep:hex-literal" "pem" "pkcs8" ]; + "digest" = [ "dep:digest" ]; + "ecdh" = [ "arithmetic" "digest" "dep:hkdf" ]; + "ff" = [ "dep:ff" ]; + "group" = [ "dep:group" "ff" ]; + "hash2curve" = [ "arithmetic" "digest" ]; + "jwk" = [ "dep:base64ct" "dep:serde_json" "alloc" "serde" "zeroize/alloc" ]; + "pem" = [ "dep:pem-rfc7468" "alloc" "arithmetic" "pkcs8" "sec1/pem" ]; + "pkcs8" = [ "dep:pkcs8" "sec1" ]; + "sec1" = [ "dep:sec1" ]; + "serde" = [ "dep:serdect" "alloc" "pkcs8" "sec1/serde" ]; + "std" = [ "alloc" "rand_core/std" "pkcs8?/std" "sec1?/std" ]; + "voprf" = [ "digest" ]; + }; + resolvedDefaultFeatures = [ "alloc" "arithmetic" "digest" "ff" "group" "hazmat" "pem" "pkcs8" "sec1" "std" ]; + }; "encoding_rs" = rec { crateName = "encoding_rs"; version = "0.8.35"; @@ -2481,6 +2852,40 @@ rec { }; resolvedDefaultFeatures = [ "alloc" "default" "std" ]; }; + "ff" = rec { + crateName = "ff"; + version = "0.13.1"; + edition = "2021"; + sha256 = "14v3bc6q24gbcjnxjfbq2dddgf4as2z2gd4mj35gjlrncpxhpdf0"; + authors = [ + "Sean Bowe " + "Jack Grigg " + ]; + dependencies = [ + { + name = "rand_core"; + packageId = "rand_core 0.6.4"; + usesDefaultFeatures = false; + } + { + name = "subtle"; + packageId = "subtle"; + usesDefaultFeatures = false; + features = [ "i128" ]; + } + ]; + features = { + "bits" = [ "bitvec" ]; + "bitvec" = [ "dep:bitvec" ]; + "byteorder" = [ "dep:byteorder" ]; + "default" = [ "bits" "std" ]; + "derive" = [ "byteorder" "ff_derive" ]; + "derive_bits" = [ "bits" "ff_derive/bits" ]; + "ff_derive" = [ "dep:ff_derive" ]; + "std" = [ "alloc" ]; + }; + resolvedDefaultFeatures = [ "alloc" ]; + }; "filetime" = rec { crateName = "filetime"; version = "0.2.26"; @@ -2521,7 +2926,19 @@ rec { libName = "find_msvc_tools"; }; - "flate2" = rec { + "flagset" = rec { + crateName = "flagset"; + version = "0.4.7"; + edition = "2021"; + sha256 = "1zplx30g76kl5la3ayl9ns5p3diqd9zphbcggqcm4nm7411q5b5p"; + authors = [ + "Nathaniel McCallum " + ]; + features = { + "serde" = [ "dep:serde" ]; + }; + }; + "flate2" = rec { crateName = "flate2"; version = "1.1.5"; edition = "2018"; @@ -2938,6 +3355,12 @@ rec { name = "typenum"; packageId = "typenum"; } + { + name = "zeroize"; + packageId = "zeroize"; + optional = true; + usesDefaultFeatures = false; + } ]; buildDependencies = [ { @@ -2949,7 +3372,7 @@ rec { "serde" = [ "dep:serde" ]; "zeroize" = [ "dep:zeroize" ]; }; - resolvedDefaultFeatures = [ "more_lengths" ]; + resolvedDefaultFeatures = [ "more_lengths" "zeroize" ]; }; "getrandom 0.2.16" = rec { crateName = "getrandom"; @@ -2985,6 +3408,7 @@ rec { "rustc-dep-of-std" = [ "compiler_builtins" "core" "libc/rustc-dep-of-std" "wasi/rustc-dep-of-std" ]; "wasm-bindgen" = [ "dep:wasm-bindgen" ]; }; + resolvedDefaultFeatures = [ "std" ]; }; "getrandom 0.3.4" = rec { crateName = "getrandom"; @@ -3153,6 +3577,42 @@ rec { }; resolvedDefaultFeatures = [ "default" "futures" "futures-channel" "futures-core" ]; }; + "group" = rec { + crateName = "group"; + version = "0.13.0"; + edition = "2021"; + sha256 = "0qqs2p5vqnv3zvq9mfjkmw3qlvgqb0c3cm6p33srkh7pc9sfzygh"; + authors = [ + "Sean Bowe " + "Jack Grigg " + ]; + dependencies = [ + { + name = "ff"; + packageId = "ff"; + usesDefaultFeatures = false; + } + { + name = "rand_core"; + packageId = "rand_core 0.6.4"; + usesDefaultFeatures = false; + } + { + name = "subtle"; + packageId = "subtle"; + usesDefaultFeatures = false; + } + ]; + features = { + "default" = [ "alloc" ]; + "memuse" = [ "dep:memuse" ]; + "rand" = [ "dep:rand" ]; + "rand_xorshift" = [ "dep:rand_xorshift" ]; + "tests" = [ "alloc" "rand" "rand_xorshift" ]; + "wnaf-memuse" = [ "alloc" "memuse" ]; + }; + resolvedDefaultFeatures = [ "alloc" ]; + }; "h2" = rec { crateName = "h2"; version = "0.4.12"; @@ -3296,6 +3756,33 @@ rec { sha256 = "1sjmpsdl8czyh9ywl3qcsfsq9a307dg4ni2vnlwgnzzqhc4y0113"; }; + "hmac" = rec { + crateName = "hmac"; + version = "0.12.1"; + edition = "2018"; + sha256 = "0pmbr069sfg76z7wsssfk5ddcqd9ncp79fyz6zcm6yn115yc6jbc"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "digest"; + packageId = "digest"; + features = [ "mac" ]; + } + ]; + devDependencies = [ + { + name = "digest"; + packageId = "digest"; + features = [ "dev" ]; + } + ]; + features = { + "std" = [ "digest/std" ]; + }; + resolvedDefaultFeatures = [ "reset" ]; + }; "home" = rec { crateName = "home"; version = "0.5.12"; @@ -3562,7 +4049,7 @@ rec { "server" = [ "dep:httpdate" "dep:pin-project-lite" "dep:smallvec" ]; "tracing" = [ "dep:tracing" ]; }; - resolvedDefaultFeatures = [ "client" "default" "http1" "http2" "server" ]; + resolvedDefaultFeatures = [ "client" "default" "full" "http1" "http2" "server" ]; }; "hyper-rustls" = rec { crateName = "hyper-rustls"; @@ -5425,10 +5912,20 @@ rec { authors = [ "Marvin Löbel " ]; + dependencies = [ + { + name = "spin"; + packageId = "spin"; + optional = true; + usesDefaultFeatures = false; + features = [ "once" ]; + } + ]; features = { "spin" = [ "dep:spin" ]; "spin_no_std" = [ "spin" ]; }; + resolvedDefaultFeatures = [ "spin" "spin_no_std" ]; }; "lber" = rec { crateName = "lber"; @@ -5697,6 +6194,20 @@ rec { ]; }; + "libm" = rec { + crateName = "libm"; + version = "0.2.15"; + edition = "2021"; + sha256 = "1plpzf0p829viazdj57yw5dhmlr8ywf3apayxc2f2bq5a6mvryzr"; + authors = [ + "Jorge Aparicio " + ]; + features = { + "default" = [ "arch" ]; + "unstable" = [ "unstable-intrinsics" "unstable-float" ]; + }; + resolvedDefaultFeatures = [ "arch" "default" ]; + }; "libredox" = rec { crateName = "libredox"; version = "0.1.10"; @@ -6202,6 +6713,81 @@ rec { }; resolvedDefaultFeatures = [ "default" "std" ]; }; + "num-bigint-dig" = rec { + crateName = "num-bigint-dig"; + version = "0.8.6"; + edition = "2021"; + sha256 = "1dxh3d8pzjc5k0kpy8gy2qhhhqs7zw8a7m564zl3ib8gcjkdsqg6"; + libName = "num_bigint_dig"; + authors = [ + "dignifiedquire " + "The Rust Project Developers" + ]; + dependencies = [ + { + name = "lazy_static"; + packageId = "lazy_static"; + usesDefaultFeatures = false; + features = [ "spin_no_std" ]; + } + { + name = "libm"; + packageId = "libm"; + } + { + name = "num-integer"; + packageId = "num-integer"; + usesDefaultFeatures = false; + features = [ "i128" ]; + } + { + name = "num-iter"; + packageId = "num-iter"; + usesDefaultFeatures = false; + } + { + name = "num-traits"; + packageId = "num-traits"; + usesDefaultFeatures = false; + features = [ "i128" ]; + } + { + name = "rand"; + packageId = "rand 0.8.5"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "smallvec"; + packageId = "smallvec"; + usesDefaultFeatures = false; + } + { + name = "zeroize"; + packageId = "zeroize"; + optional = true; + usesDefaultFeatures = false; + } + ]; + devDependencies = [ + { + name = "rand"; + packageId = "rand 0.8.5"; + features = [ "small_rng" ]; + } + ]; + features = { + "arbitrary" = [ "dep:arbitrary" ]; + "default" = [ "std" "u64_digit" ]; + "fuzz" = [ "arbitrary" "smallvec/arbitrary" ]; + "prime" = [ "rand/std_rng" ]; + "rand" = [ "dep:rand" ]; + "serde" = [ "dep:serde" ]; + "std" = [ "num-integer/std" "num-traits/std" "smallvec/write" "rand/std" "serde/std" ]; + "zeroize" = [ "dep:zeroize" ]; + }; + resolvedDefaultFeatures = [ "i128" "prime" "rand" "u64_digit" "zeroize" ]; + }; "num-conv" = rec { crateName = "num-conv"; version = "0.1.0"; @@ -6213,6 +6799,63 @@ rec { ]; }; + "num-integer" = rec { + crateName = "num-integer"; + version = "0.1.46"; + edition = "2018"; + sha256 = "13w5g54a9184cqlbsq80rnxw4jj4s0d8wv75jsq5r2lms8gncsbr"; + libName = "num_integer"; + authors = [ + "The Rust Project Developers" + ]; + dependencies = [ + { + name = "num-traits"; + packageId = "num-traits"; + usesDefaultFeatures = false; + features = [ "i128" ]; + } + ]; + features = { + "default" = [ "std" ]; + "std" = [ "num-traits/std" ]; + }; + resolvedDefaultFeatures = [ "i128" ]; + }; + "num-iter" = rec { + crateName = "num-iter"; + version = "0.1.45"; + edition = "2018"; + sha256 = "1gzm7vc5g9qsjjl3bqk9rz1h6raxhygbrcpbfl04swlh0i506a8l"; + libName = "num_iter"; + authors = [ + "The Rust Project Developers" + ]; + dependencies = [ + { + name = "num-integer"; + packageId = "num-integer"; + usesDefaultFeatures = false; + features = [ "i128" ]; + } + { + name = "num-traits"; + packageId = "num-traits"; + usesDefaultFeatures = false; + features = [ "i128" ]; + } + ]; + buildDependencies = [ + { + name = "autocfg"; + packageId = "autocfg"; + } + ]; + features = { + "default" = [ "std" ]; + "std" = [ "num-integer/std" "num-traits/std" ]; + }; + }; "num-traits" = rec { crateName = "num-traits"; version = "0.2.19"; @@ -6222,6 +6865,13 @@ rec { authors = [ "The Rust Project Developers" ]; + dependencies = [ + { + name = "libm"; + packageId = "libm"; + optional = true; + } + ]; buildDependencies = [ { name = "autocfg"; @@ -6232,7 +6882,7 @@ rec { "default" = [ "std" ]; "libm" = [ "dep:libm" ]; }; - resolvedDefaultFeatures = [ "std" ]; + resolvedDefaultFeatures = [ "i128" "libm" "std" ]; }; "once_cell" = rec { crateName = "once_cell"; @@ -6777,7 +7427,7 @@ rec { } { name = "rand"; - packageId = "rand"; + packageId = "rand 0.9.2"; optional = true; usesDefaultFeatures = false; features = [ "std" "std_rng" "small_rng" "os_rng" "thread_rng" ]; @@ -6859,6 +7509,79 @@ rec { }; resolvedDefaultFeatures = [ "default" "std" ]; }; + "p256" = rec { + crateName = "p256"; + version = "0.13.2"; + edition = "2021"; + sha256 = "0jyd3c3k239ybs59ixpnl7dqkmm072fr1js8kh7ldx58bzc3m1n9"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "ecdsa"; + packageId = "ecdsa"; + rename = "ecdsa-core"; + optional = true; + usesDefaultFeatures = false; + features = [ "der" ]; + } + { + name = "elliptic-curve"; + packageId = "elliptic-curve"; + usesDefaultFeatures = false; + features = [ "hazmat" "sec1" ]; + } + { + name = "primeorder"; + packageId = "primeorder"; + optional = true; + } + { + name = "sha2"; + packageId = "sha2"; + optional = true; + usesDefaultFeatures = false; + } + ]; + devDependencies = [ + { + name = "ecdsa"; + packageId = "ecdsa"; + rename = "ecdsa-core"; + usesDefaultFeatures = false; + features = [ "dev" ]; + } + { + name = "primeorder"; + packageId = "primeorder"; + features = [ "dev" ]; + } + ]; + features = { + "alloc" = [ "ecdsa-core?/alloc" "elliptic-curve/alloc" ]; + "arithmetic" = [ "dep:primeorder" "elliptic-curve/arithmetic" ]; + "bits" = [ "arithmetic" "elliptic-curve/bits" ]; + "default" = [ "arithmetic" "ecdsa" "pem" "std" ]; + "digest" = [ "ecdsa-core/digest" "ecdsa-core/hazmat" ]; + "ecdh" = [ "arithmetic" "elliptic-curve/ecdh" ]; + "ecdsa" = [ "arithmetic" "ecdsa-core/signing" "ecdsa-core/verifying" "sha256" ]; + "ecdsa-core" = [ "dep:ecdsa-core" ]; + "expose-field" = [ "arithmetic" ]; + "hash2curve" = [ "arithmetic" "elliptic-curve/hash2curve" ]; + "jwk" = [ "elliptic-curve/jwk" ]; + "pem" = [ "elliptic-curve/pem" "ecdsa-core/pem" "pkcs8" ]; + "pkcs8" = [ "ecdsa-core?/pkcs8" "elliptic-curve/pkcs8" ]; + "serde" = [ "ecdsa-core?/serde" "elliptic-curve/serde" "primeorder?/serde" "serdect" ]; + "serdect" = [ "dep:serdect" ]; + "sha2" = [ "dep:sha2" ]; + "sha256" = [ "digest" "sha2" ]; + "std" = [ "alloc" "ecdsa-core?/std" "elliptic-curve/std" ]; + "test-vectors" = [ "dep:hex-literal" ]; + "voprf" = [ "elliptic-curve/voprf" "sha2" ]; + }; + resolvedDefaultFeatures = [ "alloc" "arithmetic" "default" "digest" "ecdsa" "ecdsa-core" "pem" "pkcs8" "sha2" "sha256" "std" ]; + }; "parking" = rec { crateName = "parking"; version = "2.2.1"; @@ -6967,6 +7690,27 @@ rec { }; resolvedDefaultFeatures = [ "default" "std" ]; }; + "pem-rfc7468" = rec { + crateName = "pem-rfc7468"; + version = "0.7.0"; + edition = "2021"; + sha256 = "04l4852scl4zdva31c1z6jafbak0ni5pi0j38ml108zwzjdrrcw8"; + libName = "pem_rfc7468"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "base64ct"; + packageId = "base64ct"; + } + ]; + features = { + "alloc" = [ "base64ct/alloc" ]; + "std" = [ "alloc" "base64ct/std" ]; + }; + resolvedDefaultFeatures = [ "alloc" ]; + }; "percent-encoding" = rec { crateName = "percent-encoding"; version = "2.3.2"; @@ -7163,6 +7907,74 @@ rec { ]; }; + "pkcs1" = rec { + crateName = "pkcs1"; + version = "0.7.5"; + edition = "2021"; + sha256 = "0zz4mil3nchnxljdfs2k5ab1cjqn7kq5lqp62n9qfix01zqvkzy8"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "der"; + packageId = "der"; + features = [ "oid" ]; + } + { + name = "pkcs8"; + packageId = "pkcs8"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "spki"; + packageId = "spki"; + } + ]; + features = { + "alloc" = [ "der/alloc" "zeroize" "pkcs8?/alloc" ]; + "pem" = [ "alloc" "der/pem" "pkcs8?/pem" ]; + "pkcs8" = [ "dep:pkcs8" ]; + "std" = [ "der/std" "alloc" ]; + "zeroize" = [ "der/zeroize" ]; + }; + resolvedDefaultFeatures = [ "alloc" "pem" "pkcs8" "std" "zeroize" ]; + }; + "pkcs8" = rec { + crateName = "pkcs8"; + version = "0.10.2"; + edition = "2021"; + sha256 = "1dx7w21gvn07azszgqd3ryjhyphsrjrmq5mmz1fbxkj5g0vv4l7r"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "der"; + packageId = "der"; + features = [ "oid" ]; + } + { + name = "spki"; + packageId = "spki"; + } + ]; + features = { + "3des" = [ "encryption" "pkcs5/3des" ]; + "alloc" = [ "der/alloc" "der/zeroize" "spki/alloc" ]; + "des-insecure" = [ "encryption" "pkcs5/des-insecure" ]; + "encryption" = [ "alloc" "pkcs5/alloc" "pkcs5/pbes2" "rand_core" ]; + "getrandom" = [ "rand_core/getrandom" ]; + "pem" = [ "alloc" "der/pem" "spki/pem" ]; + "pkcs5" = [ "dep:pkcs5" ]; + "rand_core" = [ "dep:rand_core" ]; + "sha1-insecure" = [ "encryption" "pkcs5/sha1-insecure" ]; + "std" = [ "alloc" "der/std" "spki/std" ]; + "subtle" = [ "dep:subtle" ]; + }; + resolvedDefaultFeatures = [ "alloc" "pem" "std" ]; + }; "pkg-config" = rec { crateName = "pkg-config"; version = "0.3.32"; @@ -7287,8 +8099,31 @@ rec { }; resolvedDefaultFeatures = [ "verbatim" ]; }; - "proc-macro2" = rec { - crateName = "proc-macro2"; + "primeorder" = rec { + crateName = "primeorder"; + version = "0.13.6"; + edition = "2021"; + sha256 = "1rp16710mxksagcjnxqjjq9r9wf5vf72fs8wxffnvhb6i6hiqgim"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "elliptic-curve"; + packageId = "elliptic-curve"; + usesDefaultFeatures = false; + features = [ "arithmetic" "sec1" ]; + } + ]; + features = { + "alloc" = [ "elliptic-curve/alloc" ]; + "serde" = [ "elliptic-curve/serde" "serdect" ]; + "serdect" = [ "dep:serdect" ]; + "std" = [ "alloc" "elliptic-curve/std" ]; + }; + }; + "proc-macro2" = rec { + crateName = "proc-macro2"; version = "1.0.103"; edition = "2021"; sha256 = "1s29bz20xl2qk5ffs2mbdqknaj43ri673dz86axdbf47xz25psay"; @@ -7463,7 +8298,44 @@ rec { "rustc-dep-of-std" = [ "core" ]; }; }; - "rand" = rec { + "rand 0.8.5" = rec { + crateName = "rand"; + version = "0.8.5"; + edition = "2018"; + sha256 = "013l6931nn7gkc23jz5mm3qdhf93jjf0fg64nz2lp4i51qd8vbrl"; + authors = [ + "The Rand Project Developers" + "The Rust Project Developers" + ]; + dependencies = [ + { + name = "rand_chacha"; + packageId = "rand_chacha 0.3.1"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "rand_core"; + packageId = "rand_core 0.6.4"; + } + ]; + features = { + "alloc" = [ "rand_core/alloc" ]; + "default" = [ "std" "std_rng" ]; + "getrandom" = [ "rand_core/getrandom" ]; + "libc" = [ "dep:libc" ]; + "log" = [ "dep:log" ]; + "packed_simd" = [ "dep:packed_simd" ]; + "rand_chacha" = [ "dep:rand_chacha" ]; + "serde" = [ "dep:serde" ]; + "serde1" = [ "serde" "rand_core/serde1" ]; + "simd_support" = [ "packed_simd" ]; + "std" = [ "rand_core/std" "rand_chacha/std" "alloc" "getrandom" "libc" ]; + "std_rng" = [ "rand_chacha" ]; + }; + resolvedDefaultFeatures = [ "rand_chacha" "std_rng" ]; + }; + "rand 0.9.2" = rec { crateName = "rand"; version = "0.9.2"; edition = "2021"; @@ -7475,13 +8347,13 @@ rec { dependencies = [ { name = "rand_chacha"; - packageId = "rand_chacha"; + packageId = "rand_chacha 0.9.0"; optional = true; usesDefaultFeatures = false; } { name = "rand_core"; - packageId = "rand_core"; + packageId = "rand_core 0.9.3"; usesDefaultFeatures = false; } ]; @@ -7494,9 +8366,38 @@ rec { "std_rng" = [ "dep:rand_chacha" ]; "thread_rng" = [ "std" "std_rng" "os_rng" ]; }; - resolvedDefaultFeatures = [ "alloc" "os_rng" "small_rng" "std" "std_rng" "thread_rng" ]; + resolvedDefaultFeatures = [ "alloc" "default" "os_rng" "small_rng" "std" "std_rng" "thread_rng" ]; + }; + "rand_chacha 0.3.1" = rec { + crateName = "rand_chacha"; + version = "0.3.1"; + edition = "2018"; + sha256 = "123x2adin558xbhvqb8w4f6syjsdkmqff8cxwhmjacpsl1ihmhg6"; + authors = [ + "The Rand Project Developers" + "The Rust Project Developers" + "The CryptoCorrosion Contributors" + ]; + dependencies = [ + { + name = "ppv-lite86"; + packageId = "ppv-lite86"; + usesDefaultFeatures = false; + features = [ "simd" ]; + } + { + name = "rand_core"; + packageId = "rand_core 0.6.4"; + } + ]; + features = { + "default" = [ "std" ]; + "serde" = [ "dep:serde" ]; + "serde1" = [ "serde" ]; + "std" = [ "ppv-lite86/std" ]; + }; }; - "rand_chacha" = rec { + "rand_chacha 0.9.0" = rec { crateName = "rand_chacha"; version = "0.9.0"; edition = "2021"; @@ -7515,13 +8416,13 @@ rec { } { name = "rand_core"; - packageId = "rand_core"; + packageId = "rand_core 0.9.3"; } ]; devDependencies = [ { name = "rand_core"; - packageId = "rand_core"; + packageId = "rand_core 0.9.3"; features = [ "os_rng" ]; } ]; @@ -7533,7 +8434,31 @@ rec { }; resolvedDefaultFeatures = [ "std" ]; }; - "rand_core" = rec { + "rand_core 0.6.4" = rec { + crateName = "rand_core"; + version = "0.6.4"; + edition = "2018"; + sha256 = "0b4j2v4cb5krak1pv6kakv4sz6xcwbrmy2zckc32hsigbrwy82zc"; + authors = [ + "The Rand Project Developers" + "The Rust Project Developers" + ]; + dependencies = [ + { + name = "getrandom"; + packageId = "getrandom 0.2.16"; + optional = true; + } + ]; + features = { + "getrandom" = [ "dep:getrandom" ]; + "serde" = [ "dep:serde" ]; + "serde1" = [ "serde" ]; + "std" = [ "alloc" "getrandom" "getrandom/std" ]; + }; + resolvedDefaultFeatures = [ "alloc" "getrandom" "std" ]; + }; + "rand_core 0.9.3" = rec { crateName = "rand_core"; version = "0.9.3"; edition = "2021"; @@ -8042,6 +8967,29 @@ rec { }; resolvedDefaultFeatures = [ "__tls" "blocking" "charset" "default" "default-tls" "h2" "http2" "json" "system-proxy" ]; }; + "rfc6979" = rec { + crateName = "rfc6979"; + version = "0.4.0"; + edition = "2021"; + sha256 = "1chw95jgcfrysyzsq6a10b1j5qb7bagkx8h0wda4lv25in02mpgq"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "hmac"; + packageId = "hmac"; + usesDefaultFeatures = false; + features = [ "reset" ]; + } + { + name = "subtle"; + packageId = "subtle"; + usesDefaultFeatures = false; + } + ]; + + }; "ring" = rec { crateName = "ring"; version = "0.17.14"; @@ -8103,6 +9051,119 @@ rec { }; resolvedDefaultFeatures = [ "alloc" "default" "dev_urandom_fallback" ]; }; + "rsa" = rec { + crateName = "rsa"; + version = "0.9.10"; + edition = "2021"; + sha256 = "0bdikdwhcvl1gfh4637m5rdw3fgcl752aiygvzmwlgc8yl1kymxq"; + authors = [ + "RustCrypto Developers" + "dignifiedquire " + ]; + dependencies = [ + { + name = "const-oid"; + packageId = "const-oid"; + usesDefaultFeatures = false; + } + { + name = "digest"; + packageId = "digest"; + usesDefaultFeatures = false; + features = [ "alloc" "oid" ]; + } + { + name = "num-bigint-dig"; + packageId = "num-bigint-dig"; + rename = "num-bigint"; + usesDefaultFeatures = false; + features = [ "i128" "prime" "zeroize" ]; + } + { + name = "num-integer"; + packageId = "num-integer"; + usesDefaultFeatures = false; + } + { + name = "num-traits"; + packageId = "num-traits"; + usesDefaultFeatures = false; + features = [ "libm" ]; + } + { + name = "pkcs1"; + packageId = "pkcs1"; + usesDefaultFeatures = false; + features = [ "alloc" "pkcs8" ]; + } + { + name = "pkcs8"; + packageId = "pkcs8"; + usesDefaultFeatures = false; + features = [ "alloc" ]; + } + { + name = "rand_core"; + packageId = "rand_core 0.6.4"; + usesDefaultFeatures = false; + } + { + name = "sha2"; + packageId = "sha2"; + optional = true; + usesDefaultFeatures = false; + features = [ "oid" ]; + } + { + name = "signature"; + packageId = "signature"; + usesDefaultFeatures = false; + features = [ "alloc" "digest" "rand_core" ]; + } + { + name = "spki"; + packageId = "spki"; + usesDefaultFeatures = false; + features = [ "alloc" ]; + } + { + name = "subtle"; + packageId = "subtle"; + usesDefaultFeatures = false; + } + { + name = "zeroize"; + packageId = "zeroize"; + features = [ "alloc" ]; + } + ]; + devDependencies = [ + { + name = "rand_core"; + packageId = "rand_core 0.6.4"; + usesDefaultFeatures = false; + } + { + name = "sha2"; + packageId = "sha2"; + usesDefaultFeatures = false; + features = [ "oid" ]; + } + ]; + features = { + "default" = [ "std" "pem" "u64_digit" ]; + "getrandom" = [ "rand_core/getrandom" ]; + "nightly" = [ "num-bigint/nightly" ]; + "pem" = [ "pkcs1/pem" "pkcs8/pem" ]; + "pkcs5" = [ "pkcs8/encryption" ]; + "serde" = [ "dep:serde" "num-bigint/serde" ]; + "sha1" = [ "dep:sha1" ]; + "sha2" = [ "dep:sha2" ]; + "std" = [ "digest/std" "pkcs1/std" "pkcs8/std" "rand_core/std" "signature/std" ]; + "u64_digit" = [ "num-bigint/u64_digit" ]; + }; + resolvedDefaultFeatures = [ "default" "pem" "sha2" "std" "u64_digit" ]; + }; "rustc-hash" = rec { crateName = "rustc-hash"; version = "2.1.1"; @@ -8570,6 +9631,66 @@ rec { "default" = [ "use_std" ]; }; }; + "sec1" = rec { + crateName = "sec1"; + version = "0.7.3"; + edition = "2021"; + sha256 = "1p273j8c87pid6a1iyyc7vxbvifrw55wbxgr0dh3l8vnbxb7msfk"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "base16ct"; + packageId = "base16ct"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "der"; + packageId = "der"; + optional = true; + features = [ "oid" ]; + } + { + name = "generic-array"; + packageId = "generic-array"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "pkcs8"; + packageId = "pkcs8"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "subtle"; + packageId = "subtle"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "zeroize"; + packageId = "zeroize"; + optional = true; + usesDefaultFeatures = false; + } + ]; + features = { + "alloc" = [ "der?/alloc" "pkcs8?/alloc" "zeroize?/alloc" ]; + "default" = [ "der" "point" ]; + "der" = [ "dep:der" "zeroize" ]; + "pem" = [ "alloc" "der/pem" "pkcs8/pem" ]; + "pkcs8" = [ "dep:pkcs8" ]; + "point" = [ "dep:base16ct" "dep:generic-array" ]; + "serde" = [ "dep:serdect" ]; + "std" = [ "alloc" "der?/std" ]; + "subtle" = [ "dep:subtle" ]; + "zeroize" = [ "dep:zeroize" "der?/zeroize" ]; + }; + resolvedDefaultFeatures = [ "alloc" "default" "der" "pem" "pkcs8" "point" "std" "subtle" "zeroize" ]; + }; "secrecy" = rec { crateName = "secrecy"; version = "0.10.3"; @@ -9016,6 +10137,45 @@ rec { ]; }; + "sha1" = rec { + crateName = "sha1"; + version = "0.10.6"; + edition = "2018"; + sha256 = "1fnnxlfg08xhkmwf2ahv634as30l1i3xhlhkvxflmasi5nd85gz3"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "cfg-if"; + packageId = "cfg-if"; + } + { + name = "cpufeatures"; + packageId = "cpufeatures"; + target = { target, features }: (("aarch64" == target."arch" or null) || ("x86" == target."arch" or null) || ("x86_64" == target."arch" or null)); + } + { + name = "digest"; + packageId = "digest"; + } + ]; + devDependencies = [ + { + name = "digest"; + packageId = "digest"; + features = [ "dev" ]; + } + ]; + features = { + "asm" = [ "sha1-asm" ]; + "default" = [ "std" ]; + "oid" = [ "digest/oid" ]; + "sha1-asm" = [ "dep:sha1-asm" ]; + "std" = [ "digest/std" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; "sha2" = rec { crateName = "sha2"; version = "0.10.9"; @@ -9054,6 +10214,7 @@ rec { "sha2-asm" = [ "dep:sha2-asm" ]; "std" = [ "digest/std" ]; }; + resolvedDefaultFeatures = [ "default" "oid" "std" ]; }; "sharded-slab" = rec { crateName = "sharded-slab"; @@ -9110,6 +10271,36 @@ rec { ]; }; + "signature" = rec { + crateName = "signature"; + version = "2.2.0"; + edition = "2021"; + sha256 = "1pi9hd5vqfr3q3k49k37z06p7gs5si0in32qia4mmr1dancr6m3p"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "digest"; + packageId = "digest"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "rand_core"; + packageId = "rand_core 0.6.4"; + optional = true; + usesDefaultFeatures = false; + } + ]; + features = { + "derive" = [ "dep:derive" ]; + "digest" = [ "dep:digest" ]; + "rand_core" = [ "dep:rand_core" ]; + "std" = [ "alloc" "rand_core?/std" ]; + }; + resolvedDefaultFeatures = [ "alloc" "digest" "rand_core" "std" ]; + }; "simd-adler32" = rec { crateName = "simd-adler32"; version = "0.3.7"; @@ -9296,34 +10487,194 @@ rec { ]; dependencies = [ { - name = "libc"; - packageId = "libc"; - target = { target, features }: (target."unix" or false); + name = "libc"; + packageId = "libc"; + target = { target, features }: (target."unix" or false); + } + { + name = "windows-sys"; + packageId = "windows-sys 0.60.2"; + target = { target, features }: (target."windows" or false); + features = [ "Win32_Foundation" "Win32_Networking_WinSock" "Win32_System_IO" "Win32_System_Threading" "Win32_System_WindowsProgramming" ]; + } + ]; + features = { + }; + resolvedDefaultFeatures = [ "all" ]; + }; + "spin" = rec { + crateName = "spin"; + version = "0.9.8"; + edition = "2015"; + sha256 = "0rvam5r0p3a6qhc18scqpvpgb3ckzyqxpgdfyjnghh8ja7byi039"; + authors = [ + "Mathijs van de Nes " + "John Ericson " + "Joshua Barretto " + ]; + features = { + "barrier" = [ "mutex" ]; + "default" = [ "lock_api" "mutex" "spin_mutex" "rwlock" "once" "lazy" "barrier" ]; + "fair_mutex" = [ "mutex" ]; + "lazy" = [ "once" ]; + "lock_api" = [ "lock_api_crate" ]; + "lock_api_crate" = [ "dep:lock_api_crate" ]; + "portable-atomic" = [ "dep:portable-atomic" ]; + "portable_atomic" = [ "portable-atomic" ]; + "spin_mutex" = [ "mutex" ]; + "ticket_mutex" = [ "mutex" ]; + "use_ticket_mutex" = [ "mutex" "ticket_mutex" ]; + }; + resolvedDefaultFeatures = [ "once" ]; + }; + "spki" = rec { + crateName = "spki"; + version = "0.7.3"; + edition = "2021"; + sha256 = "17fj8k5fmx4w9mp27l970clrh5qa7r5sjdvbsln987xhb34dc7nr"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "base64ct"; + packageId = "base64ct"; + optional = true; + usesDefaultFeatures = false; + } + { + name = "der"; + packageId = "der"; + features = [ "oid" ]; + } + ]; + features = { + "alloc" = [ "base64ct?/alloc" "der/alloc" ]; + "arbitrary" = [ "std" "dep:arbitrary" "der/arbitrary" ]; + "base64" = [ "dep:base64ct" ]; + "fingerprint" = [ "sha2" ]; + "pem" = [ "alloc" "der/pem" ]; + "sha2" = [ "dep:sha2" ]; + "std" = [ "der/std" "alloc" ]; + }; + resolvedDefaultFeatures = [ "alloc" "pem" "std" ]; + }; + "stable_deref_trait" = rec { + crateName = "stable_deref_trait"; + version = "1.2.1"; + edition = "2015"; + sha256 = "15h5h73ppqyhdhx6ywxfj88azmrpml9gl6zp3pwy2malqa6vxqkc"; + authors = [ + "Robert Grosse " + ]; + features = { + "default" = [ "std" ]; + "std" = [ "alloc" ]; + }; + resolvedDefaultFeatures = [ "alloc" ]; + }; + "stackable-certs" = rec { + crateName = "stackable-certs"; + version = "0.4.0"; + edition = "2024"; + workspace_member = null; + src = pkgs.fetchgit { + url = "https://github.com/stackabletech/operator-rs.git"; + rev = "13cf69454684ccf105d7377ca369d62b7b07250c"; + sha256 = "09nmd5pqrmc49dzm7y26qlh1np528d9xq4q8vm4d04sd8z9rd46j"; + }; + libName = "stackable_certs"; + authors = [ + "Stackable GmbH " + ]; + dependencies = [ + { + name = "const-oid"; + packageId = "const-oid"; + features = [ "db" ]; + } + { + name = "ecdsa"; + packageId = "ecdsa"; + features = [ "digest" "pem" ]; + } + { + name = "k8s-openapi"; + packageId = "k8s-openapi"; + usesDefaultFeatures = false; + features = [ "schemars" "v1_34" ]; + } + { + name = "kube"; + packageId = "kube"; + usesDefaultFeatures = false; + features = [ "client" "jsonpatch" "runtime" "derive" "admission" "rustls-tls" "ring" ]; + } + { + name = "p256"; + packageId = "p256"; + features = [ "ecdsa" ]; + } + { + name = "rand"; + packageId = "rand 0.9.2"; + } + { + name = "rand_core"; + packageId = "rand_core 0.6.4"; + } + { + name = "rsa"; + packageId = "rsa"; + features = [ "sha2" ]; + } + { + name = "sha2"; + packageId = "sha2"; + features = [ "oid" ]; + } + { + name = "signature"; + packageId = "signature"; + } + { + name = "snafu"; + packageId = "snafu 0.8.9"; + } + { + name = "stackable-shared"; + packageId = "stackable-shared"; + } + { + name = "tokio"; + packageId = "tokio"; + features = [ "macros" "rt-multi-thread" "fs" ]; + } + { + name = "tokio-rustls"; + packageId = "tokio-rustls"; + optional = true; + usesDefaultFeatures = false; + features = [ "ring" "logging" "tls12" ]; } { - name = "windows-sys"; - packageId = "windows-sys 0.60.2"; - target = { target, features }: (target."windows" or false); - features = [ "Win32_Foundation" "Win32_Networking_WinSock" "Win32_System_IO" "Win32_System_Threading" "Win32_System_WindowsProgramming" ]; + name = "tracing"; + packageId = "tracing"; + } + { + name = "x509-cert"; + packageId = "x509-cert"; + features = [ "builder" ]; + } + { + name = "zeroize"; + packageId = "zeroize"; } ]; features = { + "rustls" = [ "dep:tokio-rustls" ]; }; - resolvedDefaultFeatures = [ "all" ]; - }; - "stable_deref_trait" = rec { - crateName = "stable_deref_trait"; - version = "1.2.1"; - edition = "2015"; - sha256 = "15h5h73ppqyhdhx6ywxfj88azmrpml9gl6zp3pwy2malqa6vxqkc"; - authors = [ - "Robert Grosse " - ]; - features = { - "default" = [ "std" ]; - "std" = [ "alloc" ]; - }; - resolvedDefaultFeatures = [ "alloc" ]; + resolvedDefaultFeatures = [ "default" "rustls" ]; }; "stackable-opa-bundle-builder" = rec { crateName = "stackable-opa-bundle-builder"; @@ -9372,7 +10723,7 @@ rec { { name = "stackable-operator"; packageId = "stackable-operator"; - features = [ "telemetry" "versioned" ]; + features = [ "telemetry" "versioned" "webhook" ]; } { name = "tar"; @@ -9466,7 +10817,7 @@ rec { { name = "stackable-operator"; packageId = "stackable-operator"; - features = [ "telemetry" "versioned" ]; + features = [ "telemetry" "versioned" "webhook" ]; } { name = "strum"; @@ -9598,7 +10949,7 @@ rec { { name = "stackable-operator"; packageId = "stackable-operator"; - features = [ "telemetry" "versioned" ]; + features = [ "telemetry" "versioned" "webhook" ]; } { name = "tokio"; @@ -9756,6 +11107,11 @@ rec { packageId = "stackable-versioned"; optional = true; } + { + name = "stackable-webhook"; + packageId = "stackable-webhook"; + optional = true; + } { name = "strum"; packageId = "strum"; @@ -9794,7 +11150,7 @@ rec { "versioned" = [ "dep:stackable-versioned" ]; "webhook" = [ "dep:stackable-webhook" ]; }; - resolvedDefaultFeatures = [ "clap" "default" "telemetry" "versioned" ]; + resolvedDefaultFeatures = [ "clap" "default" "telemetry" "versioned" "webhook" ]; }; "stackable-operator-derive" = rec { crateName = "stackable-operator-derive"; @@ -10130,6 +11486,134 @@ rec { } ]; + }; + "stackable-webhook" = rec { + crateName = "stackable-webhook"; + version = "0.8.1"; + edition = "2024"; + workspace_member = null; + src = pkgs.fetchgit { + url = "https://github.com/stackabletech/operator-rs.git"; + rev = "13cf69454684ccf105d7377ca369d62b7b07250c"; + sha256 = "09nmd5pqrmc49dzm7y26qlh1np528d9xq4q8vm4d04sd8z9rd46j"; + }; + libName = "stackable_webhook"; + authors = [ + "Stackable GmbH " + ]; + dependencies = [ + { + name = "arc-swap"; + packageId = "arc-swap"; + } + { + name = "async-trait"; + packageId = "async-trait"; + } + { + name = "axum"; + packageId = "axum"; + features = [ "http2" ]; + } + { + name = "futures-util"; + packageId = "futures-util"; + } + { + name = "hyper"; + packageId = "hyper"; + features = [ "full" ]; + } + { + name = "hyper-util"; + packageId = "hyper-util"; + } + { + name = "k8s-openapi"; + packageId = "k8s-openapi"; + usesDefaultFeatures = false; + features = [ "schemars" "v1_34" ]; + } + { + name = "kube"; + packageId = "kube"; + usesDefaultFeatures = false; + features = [ "client" "jsonpatch" "runtime" "derive" "admission" "rustls-tls" "ring" ]; + } + { + name = "opentelemetry"; + packageId = "opentelemetry"; + } + { + name = "opentelemetry-semantic-conventions"; + packageId = "opentelemetry-semantic-conventions"; + } + { + name = "rand"; + packageId = "rand 0.9.2"; + } + { + name = "serde"; + packageId = "serde"; + features = [ "derive" ]; + } + { + name = "serde_json"; + packageId = "serde_json"; + } + { + name = "snafu"; + packageId = "snafu 0.8.9"; + } + { + name = "stackable-certs"; + packageId = "stackable-certs"; + features = [ "rustls" ]; + } + { + name = "stackable-shared"; + packageId = "stackable-shared"; + } + { + name = "stackable-telemetry"; + packageId = "stackable-telemetry"; + } + { + name = "tokio"; + packageId = "tokio"; + features = [ "macros" "rt-multi-thread" "fs" ]; + } + { + name = "tokio-rustls"; + packageId = "tokio-rustls"; + usesDefaultFeatures = false; + features = [ "ring" "logging" "tls12" ]; + } + { + name = "tower"; + packageId = "tower"; + features = [ "util" ]; + } + { + name = "tower-http"; + packageId = "tower-http"; + features = [ "trace" ]; + } + { + name = "tracing"; + packageId = "tracing"; + } + { + name = "tracing-opentelemetry"; + packageId = "tracing-opentelemetry"; + } + { + name = "x509-cert"; + packageId = "x509-cert"; + features = [ "builder" ]; + } + ]; + }; "strsim" = rec { crateName = "strsim"; @@ -10207,6 +11691,7 @@ rec { features = { "default" = [ "std" "i128" ]; }; + resolvedDefaultFeatures = [ "i128" ]; }; "syn 1.0.109" = rec { crateName = "syn"; @@ -10716,6 +12201,68 @@ rec { }; resolvedDefaultFeatures = [ "alloc" "zerovec" ]; }; + "tls_codec" = rec { + crateName = "tls_codec"; + version = "0.4.2"; + edition = "2021"; + sha256 = "0sxzj0pdinn7fsc8aihqgfylsqi7z9jca0aqy3b8kfz28l9f1qhd"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "tls_codec_derive"; + packageId = "tls_codec_derive"; + optional = true; + } + { + name = "zeroize"; + packageId = "zeroize"; + usesDefaultFeatures = false; + features = [ "alloc" "zeroize_derive" ]; + } + ]; + features = { + "arbitrary" = [ "std" "dep:arbitrary" ]; + "conditional_deserialization" = [ "derive" "tls_codec_derive/conditional_deserialization" ]; + "default" = [ "std" ]; + "derive" = [ "tls_codec_derive" ]; + "serde" = [ "std" "dep:serde" ]; + "std" = [ "tls_codec_derive?/std" ]; + "tls_codec_derive" = [ "dep:tls_codec_derive" ]; + }; + resolvedDefaultFeatures = [ "derive" "std" "tls_codec_derive" ]; + }; + "tls_codec_derive" = rec { + crateName = "tls_codec_derive"; + version = "0.4.2"; + edition = "2021"; + sha256 = "1gglj5cxkpv7i3jazffksrfy5h5242kdvsqawjm2yh1915lpcbid"; + procMacro = true; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "proc-macro2"; + packageId = "proc-macro2"; + } + { + name = "quote"; + packageId = "quote"; + } + { + name = "syn"; + packageId = "syn 2.0.108"; + features = [ "parsing" ]; + } + ]; + features = { + "conditional_deserialization" = [ "syn/full" ]; + "default" = [ "std" ]; + }; + resolvedDefaultFeatures = [ "default" "std" ]; + }; "tokio" = rec { crateName = "tokio"; version = "1.48.0"; @@ -10924,7 +12471,7 @@ rec { "tls12" = [ "rustls/tls12" ]; "zlib" = [ "rustls/zlib" ]; }; - resolvedDefaultFeatures = [ "logging" "tls12" ]; + resolvedDefaultFeatures = [ "logging" "ring" "tls12" ]; }; "tokio-stream" = rec { crateName = "tokio-stream"; @@ -15021,6 +16568,62 @@ rec { "either" = [ "dep:either" ]; }; }; + "x509-cert" = rec { + crateName = "x509-cert"; + version = "0.2.5"; + edition = "2021"; + sha256 = "155f42vm6m7phn8w7s2wmk9vli3ws45dqpk5z3jilw0a04syj08k"; + libName = "x509_cert"; + authors = [ + "RustCrypto Developers" + ]; + dependencies = [ + { + name = "const-oid"; + packageId = "const-oid"; + features = [ "db" ]; + } + { + name = "der"; + packageId = "der"; + features = [ "alloc" "derive" "flagset" "oid" ]; + } + { + name = "sha1"; + packageId = "sha1"; + optional = true; + } + { + name = "signature"; + packageId = "signature"; + optional = true; + features = [ "rand_core" ]; + } + { + name = "spki"; + packageId = "spki"; + features = [ "alloc" ]; + } + { + name = "tls_codec"; + packageId = "tls_codec"; + optional = true; + usesDefaultFeatures = false; + features = [ "derive" ]; + } + ]; + features = { + "arbitrary" = [ "dep:arbitrary" "std" "der/arbitrary" "spki/arbitrary" ]; + "builder" = [ "std" "sha1/default" "signature" ]; + "default" = [ "pem" "std" ]; + "pem" = [ "der/pem" "spki/pem" ]; + "sct" = [ "dep:tls_codec" ]; + "sha1" = [ "dep:sha1" ]; + "signature" = [ "dep:signature" ]; + "std" = [ "const-oid/std" "der/std" "spki/std" "tls_codec?/std" ]; + }; + resolvedDefaultFeatures = [ "builder" "default" "pem" "sha1" "signature" "std" ]; + }; "xattr" = rec { crateName = "xattr"; version = "1.6.1"; @@ -15264,6 +16867,13 @@ rec { authors = [ "The RustCrypto Project Developers" ]; + dependencies = [ + { + name = "zeroize_derive"; + packageId = "zeroize_derive"; + optional = true; + } + ]; features = { "default" = [ "alloc" ]; "derive" = [ "zeroize_derive" ]; @@ -15271,7 +16881,33 @@ rec { "std" = [ "alloc" ]; "zeroize_derive" = [ "dep:zeroize_derive" ]; }; - resolvedDefaultFeatures = [ "alloc" "default" ]; + resolvedDefaultFeatures = [ "alloc" "default" "zeroize_derive" ]; + }; + "zeroize_derive" = rec { + crateName = "zeroize_derive"; + version = "1.4.3"; + edition = "2021"; + sha256 = "0bl5vd1lz27p4z336nximg5wrlw5j7jc8fxh7iv6r1wrhhav99c5"; + procMacro = true; + authors = [ + "The RustCrypto Project Developers" + ]; + dependencies = [ + { + name = "proc-macro2"; + packageId = "proc-macro2"; + } + { + name = "quote"; + packageId = "quote"; + } + { + name = "syn"; + packageId = "syn 2.0.108"; + features = [ "full" "extra-traits" "visit" ]; + } + ]; + }; "zerotrie" = rec { crateName = "zerotrie"; diff --git a/Cargo.toml b/Cargo.toml index 56ce4a17..e2e0689b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,11 @@ repository = "https://github.com/stackabletech/opa-operator" [workspace.dependencies] product-config = { git = "https://github.com/stackabletech/product-config.git", tag = "0.8.0" } -stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.101.2", features = ["telemetry", "versioned"] } +stackable-operator = { git = "https://github.com/stackabletech/operator-rs.git", tag = "stackable-operator-0.101.2", features = [ + "telemetry", + "versioned", + "webhook", +] } krb5 = { git = "https://github.com/stackabletech/krb5-rs.git", tag = "v0.1.0" } anyhow = "1.0" diff --git a/Makefile b/Makefile index abaaea4a..91f3e2f8 100644 --- a/Makefile +++ b/Makefile @@ -45,8 +45,8 @@ config: fi crds: - mkdir -p deploy/helm/"${OPERATOR_NAME}"/crds - cargo run --bin stackable-"${OPERATOR_NAME}" -- crd | yq eval '.metadata.annotations["helm.sh/resource-policy"]="keep"' - > "deploy/helm/${OPERATOR_NAME}/crds/crds.yaml" + mkdir -p extra + cargo run --bin stackable-"${OPERATOR_NAME}" -- crd > extra/crds.yaml chart-lint: compile-chart docker run -it -v $(shell pwd):/build/helm-charts -w /build/helm-charts quay.io/helmpack/chart-testing:v3.5.0 ct lint --config deploy/helm/ct.yaml diff --git a/Tiltfile b/Tiltfile index ee0941c3..31808985 100644 --- a/Tiltfile +++ b/Tiltfile @@ -35,18 +35,12 @@ helm_values = settings.get('helm_values', None) helm_override_image_repository = 'image.repository=' + registry + '/' + operator_name -# Exclude stale CRDs from Helm chart, and apply the rest -helm_crds, helm_non_crds = filter_yaml( - helm( - 'deploy/helm/' + operator_name, - name=operator_name, - namespace="stackable-operators", - set=[ - helm_override_image_repository, - ], - values=helm_values, - ), - api_version = "^apiextensions\\.k8s\\.io/.*$", - kind = "^CustomResourceDefinition$", -) -k8s_yaml(helm_non_crds) +k8s_yaml(helm( + 'deploy/helm/' + operator_name, + name=operator_name, + namespace="stackable-operators", + set=[ + helm_override_image_repository, + ], + values=helm_values, +)) diff --git a/crate-hashes.json b/crate-hashes.json index 37335d97..be5b7d64 100644 --- a/crate-hashes.json +++ b/crate-hashes.json @@ -7,11 +7,13 @@ "git+https://github.com/stackabletech/kube-rs?branch=2.0.1-fix-schema-hoisting#kube-runtime@2.0.1": "1a7bcl0w1jg71jc4iml0vjp8dpzy71mhxl012grxcy2xp5i6xvgf", "git+https://github.com/stackabletech/kube-rs?branch=2.0.1-fix-schema-hoisting#kube@2.0.1": "1a7bcl0w1jg71jc4iml0vjp8dpzy71mhxl012grxcy2xp5i6xvgf", "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.101.2#k8s-version@0.1.3": "09nmd5pqrmc49dzm7y26qlh1np528d9xq4q8vm4d04sd8z9rd46j", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.101.2#stackable-certs@0.4.0": "09nmd5pqrmc49dzm7y26qlh1np528d9xq4q8vm4d04sd8z9rd46j", "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.101.2#stackable-operator-derive@0.3.1": "09nmd5pqrmc49dzm7y26qlh1np528d9xq4q8vm4d04sd8z9rd46j", "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.101.2#stackable-operator@0.101.2": "09nmd5pqrmc49dzm7y26qlh1np528d9xq4q8vm4d04sd8z9rd46j", "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.101.2#stackable-shared@0.0.3": "09nmd5pqrmc49dzm7y26qlh1np528d9xq4q8vm4d04sd8z9rd46j", "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.101.2#stackable-telemetry@0.6.1": "09nmd5pqrmc49dzm7y26qlh1np528d9xq4q8vm4d04sd8z9rd46j", "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.101.2#stackable-versioned-macros@0.8.3": "09nmd5pqrmc49dzm7y26qlh1np528d9xq4q8vm4d04sd8z9rd46j", "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.101.2#stackable-versioned@0.8.3": "09nmd5pqrmc49dzm7y26qlh1np528d9xq4q8vm4d04sd8z9rd46j", + "git+https://github.com/stackabletech/operator-rs.git?tag=stackable-operator-0.101.2#stackable-webhook@0.8.1": "09nmd5pqrmc49dzm7y26qlh1np528d9xq4q8vm4d04sd8z9rd46j", "git+https://github.com/stackabletech/product-config.git?tag=0.8.0#product-config@0.8.0": "1dz70kapm2wdqcr7ndyjji0lhsl98bsq95gnb2lw487wf6yr7987" } \ No newline at end of file diff --git a/deploy/helm/opa-operator/crds/crds.yaml b/deploy/helm/opa-operator/crds/crds.yaml deleted file mode 100644 index 4b32aaff..00000000 --- a/deploy/helm/opa-operator/crds/crds.yaml +++ /dev/null @@ -1,2250 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - name: opaclusters.opa.stackable.tech - annotations: - helm.sh/resource-policy: keep -spec: - group: opa.stackable.tech - names: - categories: [] - kind: OpaCluster - plural: opaclusters - shortNames: - - opa - singular: opacluster - scope: Namespaced - versions: - - additionalPrinterColumns: [] - name: v1alpha2 - schema: - openAPIV3Schema: - description: Auto-generated derived type for OpaClusterSpec via `CustomResource` - properties: - spec: - properties: - clusterConfig: - default: - listenerClass: cluster-internal - tls: null - userInfo: null - description: Global OPA cluster configuration that applies to all roles and role groups. - properties: - listenerClass: - default: cluster-internal - description: |- - This field controls which type of Service the operator creates for this OpaCluster: - - * cluster-internal: Use a ClusterIP service - - * external-unstable: Use a NodePort service - - * external-stable: Use a LoadBalancer service - - This is a temporary solution with the goal to keep yaml manifests forward compatible. - In the future, this setting will control which ListenerClass - will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change. - enum: - - cluster-internal - - external-unstable - - external-stable - type: string - tls: - description: |- - TLS encryption settings for the OPA server. - When configured, OPA will use HTTPS (port 8443) instead of HTTP (port 8081). - Clients must connect using HTTPS and trust the certificates provided by the configured SecretClass. - nullable: true - properties: - serverSecretClass: - description: Name of the SecretClass which will provide TLS certificates for the OPA server. - type: string - required: - - serverSecretClass - type: object - userInfo: - description: |- - Configures how to fetch additional metadata about users (such as group memberships) - from an external directory service. - nullable: true - properties: - backend: - default: - none: {} - description: The backend directory service to use. - oneOf: - - required: - - none - - required: - - keycloak - - required: - - experimentalXfscAas - - required: - - experimentalActiveDirectory - - required: - - entra - - required: - - experimentalOpenLdap - properties: - entra: - description: Backend that fetches user information from Microsoft Entra - properties: - clientCredentialsSecret: - description: |- - Name of a Secret that contains client credentials of an Entra account with - permissions `User.ReadAll` and `GroupMemberShip.ReadAll`. - - Must contain the fields `clientId` and `clientSecret`. - type: string - port: - description: Port of the identity provider. If TLS is used defaults to `443`, otherwise to `80`. - format: uint16 - maximum: 65535.0 - minimum: 0.0 - nullable: true - type: integer - tenantId: - description: The Microsoft Entra tenant ID. - type: string - tls: - default: - verification: - server: - caCert: - webPki: {} - description: Use a TLS connection. Should usually be set to WebPki. - nullable: true - properties: - verification: - description: The verification method used to verify the certificates of the server and/or the client. - oneOf: - - required: - - none - - required: - - server - properties: - none: - description: Use TLS but don't verify certificates. - type: object - server: - description: Use TLS and a CA certificate to verify the server. - properties: - caCert: - description: CA cert to verify the server. - oneOf: - - required: - - webPki - - required: - - secretClass - properties: - secretClass: - description: |- - Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. - Note that a SecretClass does not need to have a key but can also work with just a CA certificate, - so if you got provided with a CA cert but don't have access to the key you can still use this method. - type: string - webPki: - description: |- - Use TLS and the CA certificates trusted by the common web browsers to verify the server. - This can be useful when you e.g. use public AWS S3 or other public available services. - type: object - type: object - required: - - caCert - type: object - type: object - required: - - verification - type: object - tokenHostname: - default: login.microsoft.com - description: Hostname of the token provider, defaults to `login.microsoft.com`. - type: string - userInfoHostname: - default: graph.microsoft.com - description: Hostname of the user info provider, defaults to `graph.microsoft.com`. - type: string - required: - - clientCredentialsSecret - - tenantId - type: object - experimentalActiveDirectory: - description: Backend that fetches user information from Active Directory - properties: - additionalGroupAttributeFilters: - additionalProperties: - type: string - default: {} - description: |- - Attributes that groups must have to be returned. - - These fields will be spliced into an LDAP Search Query, so wildcards can be used, - but characters with a special meaning in LDAP will need to be escaped. - type: object - baseDistinguishedName: - description: The root Distinguished Name (DN) where users and groups are located. - type: string - customAttributeMappings: - additionalProperties: - type: string - default: {} - description: Custom attributes, and their LDAP attribute names. - type: object - kerberosSecretClassName: - description: The name of the Kerberos SecretClass. - type: string - ldapServer: - description: Hostname of the domain controller, e.g. `ad-ds-1.contoso.com`. - type: string - tls: - description: Use a TLS connection. If not specified no TLS will be used. - nullable: true - properties: - verification: - description: The verification method used to verify the certificates of the server and/or the client. - oneOf: - - required: - - none - - required: - - server - properties: - none: - description: Use TLS but don't verify certificates. - type: object - server: - description: Use TLS and a CA certificate to verify the server. - properties: - caCert: - description: CA cert to verify the server. - oneOf: - - required: - - webPki - - required: - - secretClass - properties: - secretClass: - description: |- - Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. - Note that a SecretClass does not need to have a key but can also work with just a CA certificate, - so if you got provided with a CA cert but don't have access to the key you can still use this method. - type: string - webPki: - description: |- - Use TLS and the CA certificates trusted by the common web browsers to verify the server. - This can be useful when you e.g. use public AWS S3 or other public available services. - type: object - type: object - required: - - caCert - type: object - type: object - required: - - verification - type: object - required: - - baseDistinguishedName - - kerberosSecretClassName - - ldapServer - type: object - experimentalOpenLdap: - description: Backend that fetches user information from OpenLDAP - properties: - bindCredentials: - description: |- - Credentials for binding to the LDAP server. - - The bind account is used to search for users and groups in the LDAP directory. - properties: - scope: - description: |- - [Scope](https://docs.stackable.tech/home/nightly/secret-operator/scope) of the - [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass). - nullable: true - properties: - listenerVolumes: - default: [] - description: |- - The listener volume scope allows Node and Service scopes to be inferred from the applicable listeners. - This must correspond to Volume names in the Pod that mount Listeners. - items: - type: string - type: array - node: - default: false - description: |- - The node scope is resolved to the name of the Kubernetes Node object that the Pod is running on. - This will typically be the DNS name of the node. - type: boolean - pod: - default: false - description: |- - The pod scope is resolved to the name of the Kubernetes Pod. - This allows the secret to differentiate between StatefulSet replicas. - type: boolean - services: - default: [] - description: |- - The service scope allows Pod objects to specify custom scopes. - This should typically correspond to Service objects that the Pod participates in. - items: - type: string - type: array - type: object - secretClass: - description: '[SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) containing the LDAP bind credentials.' - type: string - required: - - secretClass - type: object - customAttributeMappings: - additionalProperties: - type: string - default: {} - description: Custom attributes, and their LDAP attribute names. - type: object - groupMemberAttribute: - default: member - description: |- - LDAP attribute on group objects that contains member references. - - Common values: - - `member`: For `groupOfNames` objects (uses full DN) - - `memberUid`: For `posixGroup` objects (uses username) - - Defaults to `member`. - type: string - groupsSearchBase: - description: |- - LDAP search base for groups, e.g. `ou=groups,dc=example,dc=org`. - - If not specified, uses the main `searchBase`. - nullable: true - type: string - hostname: - description: Hostname of the LDAP server, e.g. `my.ldap.server`. - type: string - port: - description: Port of the LDAP server. If TLS is used defaults to `636`, otherwise to `389`. - format: uint16 - maximum: 65535.0 - minimum: 0.0 - nullable: true - type: integer - searchBase: - default: '' - description: LDAP search base, e.g. `ou=users,dc=example,dc=org`. - type: string - tls: - description: Use a TLS connection. If not specified no TLS will be used. - nullable: true - properties: - verification: - description: The verification method used to verify the certificates of the server and/or the client. - oneOf: - - required: - - none - - required: - - server - properties: - none: - description: Use TLS but don't verify certificates. - type: object - server: - description: Use TLS and a CA certificate to verify the server. - properties: - caCert: - description: CA cert to verify the server. - oneOf: - - required: - - webPki - - required: - - secretClass - properties: - secretClass: - description: |- - Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. - Note that a SecretClass does not need to have a key but can also work with just a CA certificate, - so if you got provided with a CA cert but don't have access to the key you can still use this method. - type: string - webPki: - description: |- - Use TLS and the CA certificates trusted by the common web browsers to verify the server. - This can be useful when you e.g. use public AWS S3 or other public available services. - type: object - type: object - required: - - caCert - type: object - type: object - required: - - verification - type: object - userIdAttribute: - default: entryUUID - description: LDAP attribute used for the user's unique identifier. Defaults to `entryUUID`. - type: string - userNameAttribute: - default: uid - description: LDAP attribute used for the username. Defaults to `uid`. - type: string - required: - - bindCredentials - - hostname - type: object - experimentalXfscAas: - description: |- - Backend that fetches user information from the Gaia-X - Cross Federation Services Components (XFSC) Authentication & Authorization Service. - properties: - hostname: - description: Hostname of the identity provider, e.g. `my.aas.corp`. - type: string - port: - default: 5000 - description: Port of the identity provider. Defaults to port 5000. - format: uint16 - maximum: 65535.0 - minimum: 0.0 - type: integer - required: - - hostname - type: object - keycloak: - description: Backend that fetches user information from Keycloak. - properties: - adminRealm: - description: |- - The Keycloak realm that OPA's Keycloak account (as specified by `credentialsSecretName` exists in). - - Typically `master`. - type: string - clientCredentialsSecret: - description: |- - Name of a Secret that contains client credentials of a Keycloak account with permission to read user metadata. - - Must contain the fields `clientId` and `clientSecret`. - type: string - hostname: - description: Hostname of the identity provider, e.g. `my.keycloak.corp`. - type: string - port: - description: Port of the identity provider. If TLS is used defaults to `443`, otherwise to `80`. - format: uint16 - maximum: 65535.0 - minimum: 0.0 - nullable: true - type: integer - rootPath: - default: / - description: Root HTTP path of the identity provider. Defaults to `/`. - type: string - tls: - description: Use a TLS connection. If not specified no TLS will be used. - nullable: true - properties: - verification: - description: The verification method used to verify the certificates of the server and/or the client. - oneOf: - - required: - - none - - required: - - server - properties: - none: - description: Use TLS but don't verify certificates. - type: object - server: - description: Use TLS and a CA certificate to verify the server. - properties: - caCert: - description: CA cert to verify the server. - oneOf: - - required: - - webPki - - required: - - secretClass - properties: - secretClass: - description: |- - Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. - Note that a SecretClass does not need to have a key but can also work with just a CA certificate, - so if you got provided with a CA cert but don't have access to the key you can still use this method. - type: string - webPki: - description: |- - Use TLS and the CA certificates trusted by the common web browsers to verify the server. - This can be useful when you e.g. use public AWS S3 or other public available services. - type: object - type: object - required: - - caCert - type: object - type: object - required: - - verification - type: object - userRealm: - description: The Keycloak realm that user metadata should be resolved from. - type: string - required: - - adminRealm - - clientCredentialsSecret - - hostname - - userRealm - type: object - none: - description: Dummy backend that adds no extra user information. - type: object - type: object - cache: - default: - entryTimeToLive: 1m - description: Caching configuration. - properties: - entryTimeToLive: - default: 1m - description: How long metadata about each user should be cached for. - type: string - type: object - type: object - vectorAggregatorConfigMapName: - description: |- - Name of the Vector aggregator discovery ConfigMap. - It must contain the key `ADDRESS` with the address of the Vector aggregator. - nullable: true - type: string - type: object - clusterOperation: - default: - reconciliationPaused: false - stopped: false - description: Cluster operations like pause reconciliation or cluster stop. - properties: - reconciliationPaused: - default: false - description: |- - Flag to stop cluster reconciliation by the operator. This means that all changes in the - custom resource spec are ignored until this flag is set to false or removed. The operator - will however still watch the deployed resources at the time and update the custom resource - status field. - If applied at the same time with `stopped`, `reconciliationPaused` will take precedence over - `stopped` and stop the reconciliation immediately. - type: boolean - stopped: - default: false - description: |- - Flag to stop the cluster. This means all deployed resources (e.g. Services, StatefulSets, - ConfigMaps) are kept but all deployed Pods (e.g. replicas from a StatefulSet) are scaled to 0 - and therefore stopped and removed. - If applied at the same time with `reconciliationPaused`, the latter will pause reconciliation - and `stopped` will take no effect until `reconciliationPaused` is set to false or removed. - type: boolean - type: object - image: - anyOf: - - required: - - custom - - productVersion - - required: - - productVersion - description: The OPA image to use - properties: - custom: - description: |- - Overwrite the docker image. - Specify the full docker image name, e.g. `oci.stackable.tech/sdp/superset:1.4.1-stackable2.1.0` - type: string - productVersion: - description: Version of the product, e.g. `1.4.1`. - type: string - pullPolicy: - default: Always - description: '[Pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) used when pulling the image.' - enum: - - IfNotPresent - - Always - - Never - type: string - pullSecrets: - description: '[Image pull secrets](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) to pull images from a private registry.' - items: - description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. - properties: - name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - required: - - name - type: object - nullable: true - type: array - repo: - description: Name of the docker repo, e.g. `oci.stackable.tech/sdp` - nullable: true - type: string - stackableVersion: - description: |- - Stackable version of the product, e.g. `23.4`, `23.4.1` or `0.0.0-dev`. - If not specified, the operator will use its own version, e.g. `23.4.1`. - When using a nightly operator or a pr version, it will use the nightly `0.0.0-dev` image. - nullable: true - type: string - type: object - objectOverrides: - default: [] - description: |- - A list of generic Kubernetes objects, which are merged into the objects that the operator - creates. - - List entries are arbitrary YAML objects, which need to be valid Kubernetes objects. - - Read the [Object overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#object-overrides) - for more information. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - servers: - description: OPA server configuration. - properties: - cliOverrides: - additionalProperties: - type: string - default: {} - type: object - config: - default: {} - properties: - affinity: - default: - nodeAffinity: null - nodeSelector: null - podAffinity: null - podAntiAffinity: null - description: |- - These configuration settings control - [Pod placement](https://docs.stackable.tech/home/nightly/concepts/operations/pod_placement). - properties: - nodeAffinity: - description: Same as the `spec.affinity.nodeAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - nodeSelector: - additionalProperties: - type: string - description: Simple key-value pairs forming a nodeSelector, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - podAffinity: - description: Same as the `spec.affinity.podAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - podAntiAffinity: - description: Same as the `spec.affinity.podAntiAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - gracefulShutdownTimeout: - description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. - nullable: true - type: string - logging: - default: - containers: {} - enableVectorAgent: null - description: Logging configuration, learn more in the [logging concept documentation](https://docs.stackable.tech/home/nightly/concepts/logging). - properties: - containers: - additionalProperties: - anyOf: - - required: - - custom - - {} - description: Log configuration of the container - properties: - console: - description: Configuration for the console appender - nullable: true - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - custom: - description: Log configuration provided in a ConfigMap - properties: - configMap: - description: ConfigMap containing the log configuration files - nullable: true - type: string - type: object - file: - description: Configuration for the file appender - nullable: true - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - loggers: - additionalProperties: - description: Configuration of a logger - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - default: {} - description: Configuration per logger - type: object - type: object - description: Log configuration per container. - type: object - enableVectorAgent: - description: Wether or not to deploy a container with the Vector log agent. - nullable: true - type: boolean - type: object - resources: - default: - cpu: - max: null - min: null - memory: - limit: null - runtimeLimits: {} - storage: {} - description: |- - Resource usage is configured here, this includes CPU usage, memory usage and disk storage - usage, if this role needs any. - properties: - cpu: - default: - max: null - min: null - properties: - max: - description: |- - The maximum amount of CPU cores that can be requested by Pods. - Equivalent to the `limit` for Pod resource configuration. - Cores are specified either as a decimal point number or as milli units. - For example:`1.5` will be 1.5 cores, also written as `1500m`. - nullable: true - type: string - min: - description: |- - The minimal amount of CPU cores that Pods need to run. - Equivalent to the `request` for Pod resource configuration. - Cores are specified either as a decimal point number or as milli units. - For example:`1.5` will be 1.5 cores, also written as `1500m`. - nullable: true - type: string - type: object - memory: - properties: - limit: - description: |- - The maximum amount of memory that should be available to the Pod. - Specified as a byte [Quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/), - which means these suffixes are supported: E, P, T, G, M, k. - You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. - For example, the following represent roughly the same value: - `128974848, 129e6, 129M, 128974848000m, 123Mi` - nullable: true - type: string - runtimeLimits: - description: Additional options that can be specified. - type: object - type: object - storage: - type: object - type: object - type: object - configOverrides: - additionalProperties: - additionalProperties: - type: string - type: object - default: {} - description: |- - The `configOverrides` can be used to configure properties in product config files - that are not exposed in the CRD. Read the - [config overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#config-overrides) - and consult the operator specific usage guide documentation for details on the - available config files and settings for the specific product. - type: object - envOverrides: - additionalProperties: - type: string - default: {} - description: |- - `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. - Read the - [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) - for more information and consult the operator specific usage guide to find out about - the product specific environment variables that are available. - type: object - podOverrides: - default: {} - description: |- - In the `podOverrides` property you can define a - [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) - to override any property that can be set on a Kubernetes Pod. - Read the - [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) - for more information. - type: object - x-kubernetes-preserve-unknown-fields: true - roleConfig: - default: {} - description: |- - This is a product-agnostic RoleConfig, with nothing in it. It is used e.g. by products that have - nothing configurable at role level. - type: object - roleGroups: - additionalProperties: - properties: - cliOverrides: - additionalProperties: - type: string - default: {} - type: object - config: - default: {} - properties: - affinity: - default: - nodeAffinity: null - nodeSelector: null - podAffinity: null - podAntiAffinity: null - description: |- - These configuration settings control - [Pod placement](https://docs.stackable.tech/home/nightly/concepts/operations/pod_placement). - properties: - nodeAffinity: - description: Same as the `spec.affinity.nodeAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - nodeSelector: - additionalProperties: - type: string - description: Simple key-value pairs forming a nodeSelector, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - podAffinity: - description: Same as the `spec.affinity.podAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - podAntiAffinity: - description: Same as the `spec.affinity.podAntiAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - gracefulShutdownTimeout: - description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. - nullable: true - type: string - logging: - default: - containers: {} - enableVectorAgent: null - description: Logging configuration, learn more in the [logging concept documentation](https://docs.stackable.tech/home/nightly/concepts/logging). - properties: - containers: - additionalProperties: - anyOf: - - required: - - custom - - {} - description: Log configuration of the container - properties: - console: - description: Configuration for the console appender - nullable: true - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - custom: - description: Log configuration provided in a ConfigMap - properties: - configMap: - description: ConfigMap containing the log configuration files - nullable: true - type: string - type: object - file: - description: Configuration for the file appender - nullable: true - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - loggers: - additionalProperties: - description: Configuration of a logger - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - default: {} - description: Configuration per logger - type: object - type: object - description: Log configuration per container. - type: object - enableVectorAgent: - description: Wether or not to deploy a container with the Vector log agent. - nullable: true - type: boolean - type: object - resources: - default: - cpu: - max: null - min: null - memory: - limit: null - runtimeLimits: {} - storage: {} - description: |- - Resource usage is configured here, this includes CPU usage, memory usage and disk storage - usage, if this role needs any. - properties: - cpu: - default: - max: null - min: null - properties: - max: - description: |- - The maximum amount of CPU cores that can be requested by Pods. - Equivalent to the `limit` for Pod resource configuration. - Cores are specified either as a decimal point number or as milli units. - For example:`1.5` will be 1.5 cores, also written as `1500m`. - nullable: true - type: string - min: - description: |- - The minimal amount of CPU cores that Pods need to run. - Equivalent to the `request` for Pod resource configuration. - Cores are specified either as a decimal point number or as milli units. - For example:`1.5` will be 1.5 cores, also written as `1500m`. - nullable: true - type: string - type: object - memory: - properties: - limit: - description: |- - The maximum amount of memory that should be available to the Pod. - Specified as a byte [Quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/), - which means these suffixes are supported: E, P, T, G, M, k. - You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. - For example, the following represent roughly the same value: - `128974848, 129e6, 129M, 128974848000m, 123Mi` - nullable: true - type: string - runtimeLimits: - description: Additional options that can be specified. - type: object - type: object - storage: - type: object - type: object - type: object - configOverrides: - additionalProperties: - additionalProperties: - type: string - type: object - default: {} - description: |- - The `configOverrides` can be used to configure properties in product config files - that are not exposed in the CRD. Read the - [config overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#config-overrides) - and consult the operator specific usage guide documentation for details on the - available config files and settings for the specific product. - type: object - envOverrides: - additionalProperties: - type: string - default: {} - description: |- - `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. - Read the - [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) - for more information and consult the operator specific usage guide to find out about - the product specific environment variables that are available. - type: object - podOverrides: - default: {} - description: |- - In the `podOverrides` property you can define a - [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) - to override any property that can be set on a Kubernetes Pod. - Read the - [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) - for more information. - type: object - x-kubernetes-preserve-unknown-fields: true - replicas: - format: uint16 - maximum: 65535.0 - minimum: 0.0 - nullable: true - type: integer - type: object - type: object - required: - - roleGroups - type: object - required: - - image - - servers - type: object - status: - nullable: true - properties: - conditions: - default: [] - items: - properties: - lastTransitionTime: - description: Last time the condition transitioned from one status to another. - format: date-time - nullable: true - type: string - message: - description: A human readable message indicating details about the transition. - nullable: true - type: string - reason: - description: The reason for the condition's last transition. - nullable: true - type: string - status: - description: Status of the condition, one of True, False, Unknown. - enum: - - 'True' - - 'False' - - Unknown - type: string - type: - description: Type of deployment condition. - enum: - - Available - - Degraded - - Progressing - - ReconciliationPaused - - Stopped - type: string - required: - - status - - type - type: object - type: array - type: object - required: - - spec - title: OpaCluster - type: object - served: true - storage: true - subresources: - status: {} - - additionalPrinterColumns: [] - name: v1alpha1 - schema: - openAPIV3Schema: - description: Auto-generated derived type for OpaClusterSpec via `CustomResource` - properties: - spec: - properties: - clusterConfig: - default: - listenerClass: cluster-internal - tls: null - userInfo: null - description: Global OPA cluster configuration that applies to all roles and role groups. - properties: - listenerClass: - default: cluster-internal - description: |- - This field controls which type of Service the operator creates for this OpaCluster: - - * cluster-internal: Use a ClusterIP service - - * external-unstable: Use a NodePort service - - * external-stable: Use a LoadBalancer service - - This is a temporary solution with the goal to keep yaml manifests forward compatible. - In the future, this setting will control which ListenerClass - will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change. - enum: - - cluster-internal - - external-unstable - - external-stable - type: string - tls: - description: |- - TLS encryption settings for the OPA server. - When configured, OPA will use HTTPS (port 8443) instead of HTTP (port 8081). - Clients must connect using HTTPS and trust the certificates provided by the configured SecretClass. - nullable: true - properties: - serverSecretClass: - description: Name of the SecretClass which will provide TLS certificates for the OPA server. - type: string - required: - - serverSecretClass - type: object - userInfo: - description: |- - Configures how to fetch additional metadata about users (such as group memberships) - from an external directory service. - nullable: true - properties: - backend: - default: - none: {} - description: The backend directory service to use. - oneOf: - - required: - - none - - required: - - keycloak - - required: - - experimentalXfscAas - - required: - - experimentalActiveDirectory - - required: - - experimentalEntra - - required: - - experimentalOpenLdap - properties: - experimentalActiveDirectory: - description: Backend that fetches user information from Active Directory - properties: - additionalGroupAttributeFilters: - additionalProperties: - type: string - default: {} - description: |- - Attributes that groups must have to be returned. - - These fields will be spliced into an LDAP Search Query, so wildcards can be used, - but characters with a special meaning in LDAP will need to be escaped. - type: object - baseDistinguishedName: - description: The root Distinguished Name (DN) where users and groups are located. - type: string - customAttributeMappings: - additionalProperties: - type: string - default: {} - description: Custom attributes, and their LDAP attribute names. - type: object - kerberosSecretClassName: - description: The name of the Kerberos SecretClass. - type: string - ldapServer: - description: Hostname of the domain controller, e.g. `ad-ds-1.contoso.com`. - type: string - tls: - description: Use a TLS connection. If not specified no TLS will be used. - nullable: true - properties: - verification: - description: The verification method used to verify the certificates of the server and/or the client. - oneOf: - - required: - - none - - required: - - server - properties: - none: - description: Use TLS but don't verify certificates. - type: object - server: - description: Use TLS and a CA certificate to verify the server. - properties: - caCert: - description: CA cert to verify the server. - oneOf: - - required: - - webPki - - required: - - secretClass - properties: - secretClass: - description: |- - Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. - Note that a SecretClass does not need to have a key but can also work with just a CA certificate, - so if you got provided with a CA cert but don't have access to the key you can still use this method. - type: string - webPki: - description: |- - Use TLS and the CA certificates trusted by the common web browsers to verify the server. - This can be useful when you e.g. use public AWS S3 or other public available services. - type: object - type: object - required: - - caCert - type: object - type: object - required: - - verification - type: object - required: - - baseDistinguishedName - - kerberosSecretClassName - - ldapServer - type: object - experimentalEntra: - description: Backend that fetches user information from Microsoft Entra - properties: - clientCredentialsSecret: - description: |- - Name of a Secret that contains client credentials of an Entra account with - permissions `User.ReadAll` and `GroupMemberShip.ReadAll`. - - Must contain the fields `clientId` and `clientSecret`. - type: string - port: - description: Port of the identity provider. If TLS is used defaults to `443`, otherwise to `80`. - format: uint16 - maximum: 65535.0 - minimum: 0.0 - nullable: true - type: integer - tenantId: - description: The Microsoft Entra tenant ID. - type: string - tls: - default: - verification: - server: - caCert: - webPki: {} - description: Use a TLS connection. Should usually be set to WebPki. - nullable: true - properties: - verification: - description: The verification method used to verify the certificates of the server and/or the client. - oneOf: - - required: - - none - - required: - - server - properties: - none: - description: Use TLS but don't verify certificates. - type: object - server: - description: Use TLS and a CA certificate to verify the server. - properties: - caCert: - description: CA cert to verify the server. - oneOf: - - required: - - webPki - - required: - - secretClass - properties: - secretClass: - description: |- - Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. - Note that a SecretClass does not need to have a key but can also work with just a CA certificate, - so if you got provided with a CA cert but don't have access to the key you can still use this method. - type: string - webPki: - description: |- - Use TLS and the CA certificates trusted by the common web browsers to verify the server. - This can be useful when you e.g. use public AWS S3 or other public available services. - type: object - type: object - required: - - caCert - type: object - type: object - required: - - verification - type: object - tokenHostname: - default: login.microsoft.com - description: Hostname of the token provider, defaults to `login.microsoft.com`. - type: string - userInfoHostname: - default: graph.microsoft.com - description: Hostname of the user info provider, defaults to `graph.microsoft.com`. - type: string - required: - - clientCredentialsSecret - - tenantId - type: object - experimentalOpenLdap: - description: Backend that fetches user information from OpenLDAP - properties: - bindCredentials: - description: |- - Credentials for binding to the LDAP server. - - The bind account is used to search for users and groups in the LDAP directory. - properties: - scope: - description: |- - [Scope](https://docs.stackable.tech/home/nightly/secret-operator/scope) of the - [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass). - nullable: true - properties: - listenerVolumes: - default: [] - description: |- - The listener volume scope allows Node and Service scopes to be inferred from the applicable listeners. - This must correspond to Volume names in the Pod that mount Listeners. - items: - type: string - type: array - node: - default: false - description: |- - The node scope is resolved to the name of the Kubernetes Node object that the Pod is running on. - This will typically be the DNS name of the node. - type: boolean - pod: - default: false - description: |- - The pod scope is resolved to the name of the Kubernetes Pod. - This allows the secret to differentiate between StatefulSet replicas. - type: boolean - services: - default: [] - description: |- - The service scope allows Pod objects to specify custom scopes. - This should typically correspond to Service objects that the Pod participates in. - items: - type: string - type: array - type: object - secretClass: - description: '[SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) containing the LDAP bind credentials.' - type: string - required: - - secretClass - type: object - customAttributeMappings: - additionalProperties: - type: string - default: {} - description: Custom attributes, and their LDAP attribute names. - type: object - groupMemberAttribute: - default: member - description: |- - LDAP attribute on group objects that contains member references. - - Common values: - - `member`: For `groupOfNames` objects (uses full DN) - - `memberUid`: For `posixGroup` objects (uses username) - - Defaults to `member`. - type: string - groupsSearchBase: - description: |- - LDAP search base for groups, e.g. `ou=groups,dc=example,dc=org`. - - If not specified, uses the main `searchBase`. - nullable: true - type: string - hostname: - description: Hostname of the LDAP server, e.g. `my.ldap.server`. - type: string - port: - description: Port of the LDAP server. If TLS is used defaults to `636`, otherwise to `389`. - format: uint16 - maximum: 65535.0 - minimum: 0.0 - nullable: true - type: integer - searchBase: - default: '' - description: LDAP search base, e.g. `ou=users,dc=example,dc=org`. - type: string - tls: - description: Use a TLS connection. If not specified no TLS will be used. - nullable: true - properties: - verification: - description: The verification method used to verify the certificates of the server and/or the client. - oneOf: - - required: - - none - - required: - - server - properties: - none: - description: Use TLS but don't verify certificates. - type: object - server: - description: Use TLS and a CA certificate to verify the server. - properties: - caCert: - description: CA cert to verify the server. - oneOf: - - required: - - webPki - - required: - - secretClass - properties: - secretClass: - description: |- - Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. - Note that a SecretClass does not need to have a key but can also work with just a CA certificate, - so if you got provided with a CA cert but don't have access to the key you can still use this method. - type: string - webPki: - description: |- - Use TLS and the CA certificates trusted by the common web browsers to verify the server. - This can be useful when you e.g. use public AWS S3 or other public available services. - type: object - type: object - required: - - caCert - type: object - type: object - required: - - verification - type: object - userIdAttribute: - default: entryUUID - description: LDAP attribute used for the user's unique identifier. Defaults to `entryUUID`. - type: string - userNameAttribute: - default: uid - description: LDAP attribute used for the username. Defaults to `uid`. - type: string - required: - - bindCredentials - - hostname - type: object - experimentalXfscAas: - description: |- - Backend that fetches user information from the Gaia-X - Cross Federation Services Components (XFSC) Authentication & Authorization Service. - properties: - hostname: - description: Hostname of the identity provider, e.g. `my.aas.corp`. - type: string - port: - default: 5000 - description: Port of the identity provider. Defaults to port 5000. - format: uint16 - maximum: 65535.0 - minimum: 0.0 - type: integer - required: - - hostname - type: object - keycloak: - description: Backend that fetches user information from Keycloak. - properties: - adminRealm: - description: |- - The Keycloak realm that OPA's Keycloak account (as specified by `credentialsSecretName` exists in). - - Typically `master`. - type: string - clientCredentialsSecret: - description: |- - Name of a Secret that contains client credentials of a Keycloak account with permission to read user metadata. - - Must contain the fields `clientId` and `clientSecret`. - type: string - hostname: - description: Hostname of the identity provider, e.g. `my.keycloak.corp`. - type: string - port: - description: Port of the identity provider. If TLS is used defaults to `443`, otherwise to `80`. - format: uint16 - maximum: 65535.0 - minimum: 0.0 - nullable: true - type: integer - rootPath: - default: / - description: Root HTTP path of the identity provider. Defaults to `/`. - type: string - tls: - description: Use a TLS connection. If not specified no TLS will be used. - nullable: true - properties: - verification: - description: The verification method used to verify the certificates of the server and/or the client. - oneOf: - - required: - - none - - required: - - server - properties: - none: - description: Use TLS but don't verify certificates. - type: object - server: - description: Use TLS and a CA certificate to verify the server. - properties: - caCert: - description: CA cert to verify the server. - oneOf: - - required: - - webPki - - required: - - secretClass - properties: - secretClass: - description: |- - Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. - Note that a SecretClass does not need to have a key but can also work with just a CA certificate, - so if you got provided with a CA cert but don't have access to the key you can still use this method. - type: string - webPki: - description: |- - Use TLS and the CA certificates trusted by the common web browsers to verify the server. - This can be useful when you e.g. use public AWS S3 or other public available services. - type: object - type: object - required: - - caCert - type: object - type: object - required: - - verification - type: object - userRealm: - description: The Keycloak realm that user metadata should be resolved from. - type: string - required: - - adminRealm - - clientCredentialsSecret - - hostname - - userRealm - type: object - none: - description: Dummy backend that adds no extra user information. - type: object - type: object - cache: - default: - entryTimeToLive: 1m - description: Caching configuration. - properties: - entryTimeToLive: - default: 1m - description: How long metadata about each user should be cached for. - type: string - type: object - type: object - vectorAggregatorConfigMapName: - description: |- - Name of the Vector aggregator discovery ConfigMap. - It must contain the key `ADDRESS` with the address of the Vector aggregator. - nullable: true - type: string - type: object - clusterOperation: - default: - reconciliationPaused: false - stopped: false - description: Cluster operations like pause reconciliation or cluster stop. - properties: - reconciliationPaused: - default: false - description: |- - Flag to stop cluster reconciliation by the operator. This means that all changes in the - custom resource spec are ignored until this flag is set to false or removed. The operator - will however still watch the deployed resources at the time and update the custom resource - status field. - If applied at the same time with `stopped`, `reconciliationPaused` will take precedence over - `stopped` and stop the reconciliation immediately. - type: boolean - stopped: - default: false - description: |- - Flag to stop the cluster. This means all deployed resources (e.g. Services, StatefulSets, - ConfigMaps) are kept but all deployed Pods (e.g. replicas from a StatefulSet) are scaled to 0 - and therefore stopped and removed. - If applied at the same time with `reconciliationPaused`, the latter will pause reconciliation - and `stopped` will take no effect until `reconciliationPaused` is set to false or removed. - type: boolean - type: object - image: - anyOf: - - required: - - custom - - productVersion - - required: - - productVersion - description: The OPA image to use - properties: - custom: - description: |- - Overwrite the docker image. - Specify the full docker image name, e.g. `oci.stackable.tech/sdp/superset:1.4.1-stackable2.1.0` - type: string - productVersion: - description: Version of the product, e.g. `1.4.1`. - type: string - pullPolicy: - default: Always - description: '[Pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) used when pulling the image.' - enum: - - IfNotPresent - - Always - - Never - type: string - pullSecrets: - description: '[Image pull secrets](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) to pull images from a private registry.' - items: - description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. - properties: - name: - description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - required: - - name - type: object - nullable: true - type: array - repo: - description: Name of the docker repo, e.g. `oci.stackable.tech/sdp` - nullable: true - type: string - stackableVersion: - description: |- - Stackable version of the product, e.g. `23.4`, `23.4.1` or `0.0.0-dev`. - If not specified, the operator will use its own version, e.g. `23.4.1`. - When using a nightly operator or a pr version, it will use the nightly `0.0.0-dev` image. - nullable: true - type: string - type: object - objectOverrides: - default: [] - description: |- - A list of generic Kubernetes objects, which are merged into the objects that the operator - creates. - - List entries are arbitrary YAML objects, which need to be valid Kubernetes objects. - - Read the [Object overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#object-overrides) - for more information. - items: - type: object - x-kubernetes-preserve-unknown-fields: true - type: array - servers: - description: OPA server configuration. - properties: - cliOverrides: - additionalProperties: - type: string - default: {} - type: object - config: - default: {} - properties: - affinity: - default: - nodeAffinity: null - nodeSelector: null - podAffinity: null - podAntiAffinity: null - description: |- - These configuration settings control - [Pod placement](https://docs.stackable.tech/home/nightly/concepts/operations/pod_placement). - properties: - nodeAffinity: - description: Same as the `spec.affinity.nodeAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - nodeSelector: - additionalProperties: - type: string - description: Simple key-value pairs forming a nodeSelector, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - podAffinity: - description: Same as the `spec.affinity.podAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - podAntiAffinity: - description: Same as the `spec.affinity.podAntiAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - gracefulShutdownTimeout: - description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. - nullable: true - type: string - logging: - default: - containers: {} - enableVectorAgent: null - description: Logging configuration, learn more in the [logging concept documentation](https://docs.stackable.tech/home/nightly/concepts/logging). - properties: - containers: - additionalProperties: - anyOf: - - required: - - custom - - {} - description: Log configuration of the container - properties: - console: - description: Configuration for the console appender - nullable: true - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - custom: - description: Log configuration provided in a ConfigMap - properties: - configMap: - description: ConfigMap containing the log configuration files - nullable: true - type: string - type: object - file: - description: Configuration for the file appender - nullable: true - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - loggers: - additionalProperties: - description: Configuration of a logger - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - default: {} - description: Configuration per logger - type: object - type: object - description: Log configuration per container. - type: object - enableVectorAgent: - description: Wether or not to deploy a container with the Vector log agent. - nullable: true - type: boolean - type: object - resources: - default: - cpu: - max: null - min: null - memory: - limit: null - runtimeLimits: {} - storage: {} - description: |- - Resource usage is configured here, this includes CPU usage, memory usage and disk storage - usage, if this role needs any. - properties: - cpu: - default: - max: null - min: null - properties: - max: - description: |- - The maximum amount of CPU cores that can be requested by Pods. - Equivalent to the `limit` for Pod resource configuration. - Cores are specified either as a decimal point number or as milli units. - For example:`1.5` will be 1.5 cores, also written as `1500m`. - nullable: true - type: string - min: - description: |- - The minimal amount of CPU cores that Pods need to run. - Equivalent to the `request` for Pod resource configuration. - Cores are specified either as a decimal point number or as milli units. - For example:`1.5` will be 1.5 cores, also written as `1500m`. - nullable: true - type: string - type: object - memory: - properties: - limit: - description: |- - The maximum amount of memory that should be available to the Pod. - Specified as a byte [Quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/), - which means these suffixes are supported: E, P, T, G, M, k. - You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. - For example, the following represent roughly the same value: - `128974848, 129e6, 129M, 128974848000m, 123Mi` - nullable: true - type: string - runtimeLimits: - description: Additional options that can be specified. - type: object - type: object - storage: - type: object - type: object - type: object - configOverrides: - additionalProperties: - additionalProperties: - type: string - type: object - default: {} - description: |- - The `configOverrides` can be used to configure properties in product config files - that are not exposed in the CRD. Read the - [config overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#config-overrides) - and consult the operator specific usage guide documentation for details on the - available config files and settings for the specific product. - type: object - envOverrides: - additionalProperties: - type: string - default: {} - description: |- - `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. - Read the - [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) - for more information and consult the operator specific usage guide to find out about - the product specific environment variables that are available. - type: object - podOverrides: - default: {} - description: |- - In the `podOverrides` property you can define a - [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) - to override any property that can be set on a Kubernetes Pod. - Read the - [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) - for more information. - type: object - x-kubernetes-preserve-unknown-fields: true - roleConfig: - default: {} - description: |- - This is a product-agnostic RoleConfig, with nothing in it. It is used e.g. by products that have - nothing configurable at role level. - type: object - roleGroups: - additionalProperties: - properties: - cliOverrides: - additionalProperties: - type: string - default: {} - type: object - config: - default: {} - properties: - affinity: - default: - nodeAffinity: null - nodeSelector: null - podAffinity: null - podAntiAffinity: null - description: |- - These configuration settings control - [Pod placement](https://docs.stackable.tech/home/nightly/concepts/operations/pod_placement). - properties: - nodeAffinity: - description: Same as the `spec.affinity.nodeAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - nodeSelector: - additionalProperties: - type: string - description: Simple key-value pairs forming a nodeSelector, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - podAffinity: - description: Same as the `spec.affinity.podAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - podAntiAffinity: - description: Same as the `spec.affinity.podAntiAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) - nullable: true - type: object - x-kubernetes-preserve-unknown-fields: true - type: object - gracefulShutdownTimeout: - description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. - nullable: true - type: string - logging: - default: - containers: {} - enableVectorAgent: null - description: Logging configuration, learn more in the [logging concept documentation](https://docs.stackable.tech/home/nightly/concepts/logging). - properties: - containers: - additionalProperties: - anyOf: - - required: - - custom - - {} - description: Log configuration of the container - properties: - console: - description: Configuration for the console appender - nullable: true - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - custom: - description: Log configuration provided in a ConfigMap - properties: - configMap: - description: ConfigMap containing the log configuration files - nullable: true - type: string - type: object - file: - description: Configuration for the file appender - nullable: true - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - loggers: - additionalProperties: - description: Configuration of a logger - properties: - level: - description: |- - The log level threshold. - Log events with a lower log level are discarded. - enum: - - TRACE - - DEBUG - - INFO - - WARN - - ERROR - - FATAL - - NONE - nullable: true - type: string - type: object - default: {} - description: Configuration per logger - type: object - type: object - description: Log configuration per container. - type: object - enableVectorAgent: - description: Wether or not to deploy a container with the Vector log agent. - nullable: true - type: boolean - type: object - resources: - default: - cpu: - max: null - min: null - memory: - limit: null - runtimeLimits: {} - storage: {} - description: |- - Resource usage is configured here, this includes CPU usage, memory usage and disk storage - usage, if this role needs any. - properties: - cpu: - default: - max: null - min: null - properties: - max: - description: |- - The maximum amount of CPU cores that can be requested by Pods. - Equivalent to the `limit` for Pod resource configuration. - Cores are specified either as a decimal point number or as milli units. - For example:`1.5` will be 1.5 cores, also written as `1500m`. - nullable: true - type: string - min: - description: |- - The minimal amount of CPU cores that Pods need to run. - Equivalent to the `request` for Pod resource configuration. - Cores are specified either as a decimal point number or as milli units. - For example:`1.5` will be 1.5 cores, also written as `1500m`. - nullable: true - type: string - type: object - memory: - properties: - limit: - description: |- - The maximum amount of memory that should be available to the Pod. - Specified as a byte [Quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/), - which means these suffixes are supported: E, P, T, G, M, k. - You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. - For example, the following represent roughly the same value: - `128974848, 129e6, 129M, 128974848000m, 123Mi` - nullable: true - type: string - runtimeLimits: - description: Additional options that can be specified. - type: object - type: object - storage: - type: object - type: object - type: object - configOverrides: - additionalProperties: - additionalProperties: - type: string - type: object - default: {} - description: |- - The `configOverrides` can be used to configure properties in product config files - that are not exposed in the CRD. Read the - [config overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#config-overrides) - and consult the operator specific usage guide documentation for details on the - available config files and settings for the specific product. - type: object - envOverrides: - additionalProperties: - type: string - default: {} - description: |- - `envOverrides` configure environment variables to be set in the Pods. - It is a map from strings to strings - environment variables and the value to set. - Read the - [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) - for more information and consult the operator specific usage guide to find out about - the product specific environment variables that are available. - type: object - podOverrides: - default: {} - description: |- - In the `podOverrides` property you can define a - [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) - to override any property that can be set on a Kubernetes Pod. - Read the - [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) - for more information. - type: object - x-kubernetes-preserve-unknown-fields: true - replicas: - format: uint16 - maximum: 65535.0 - minimum: 0.0 - nullable: true - type: integer - type: object - type: object - required: - - roleGroups - type: object - required: - - image - - servers - type: object - status: - nullable: true - properties: - conditions: - default: [] - items: - properties: - lastTransitionTime: - description: Last time the condition transitioned from one status to another. - format: date-time - nullable: true - type: string - message: - description: A human readable message indicating details about the transition. - nullable: true - type: string - reason: - description: The reason for the condition's last transition. - nullable: true - type: string - status: - description: Status of the condition, one of True, False, Unknown. - enum: - - 'True' - - 'False' - - Unknown - type: string - type: - description: Type of deployment condition. - enum: - - Available - - Degraded - - Progressing - - ReconciliationPaused - - Stopped - type: string - required: - - status - - type - type: object - type: array - type: object - required: - - spec - title: OpaCluster - type: object - served: true - storage: false - subresources: - status: {} diff --git a/extra/crds.yaml b/extra/crds.yaml new file mode 100644 index 00000000..c096690c --- /dev/null +++ b/extra/crds.yaml @@ -0,0 +1,2248 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: opaclusters.opa.stackable.tech +spec: + group: opa.stackable.tech + names: + categories: [] + kind: OpaCluster + plural: opaclusters + shortNames: + - opa + singular: opacluster + scope: Namespaced + versions: + - additionalPrinterColumns: [] + name: v1alpha2 + schema: + openAPIV3Schema: + description: Auto-generated derived type for OpaClusterSpec via `CustomResource` + properties: + spec: + properties: + clusterConfig: + default: + listenerClass: cluster-internal + tls: null + userInfo: null + description: Global OPA cluster configuration that applies to all roles and role groups. + properties: + listenerClass: + default: cluster-internal + description: |- + This field controls which type of Service the operator creates for this OpaCluster: + + * cluster-internal: Use a ClusterIP service + + * external-unstable: Use a NodePort service + + * external-stable: Use a LoadBalancer service + + This is a temporary solution with the goal to keep yaml manifests forward compatible. + In the future, this setting will control which ListenerClass + will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change. + enum: + - cluster-internal + - external-unstable + - external-stable + type: string + tls: + description: |- + TLS encryption settings for the OPA server. + When configured, OPA will use HTTPS (port 8443) instead of HTTP (port 8081). + Clients must connect using HTTPS and trust the certificates provided by the configured SecretClass. + nullable: true + properties: + serverSecretClass: + description: Name of the SecretClass which will provide TLS certificates for the OPA server. + type: string + required: + - serverSecretClass + type: object + userInfo: + description: |- + Configures how to fetch additional metadata about users (such as group memberships) + from an external directory service. + nullable: true + properties: + backend: + default: + none: {} + description: The backend directory service to use. + oneOf: + - required: + - none + - required: + - keycloak + - required: + - experimentalXfscAas + - required: + - experimentalActiveDirectory + - required: + - entra + - required: + - experimentalOpenLdap + properties: + entra: + description: Backend that fetches user information from Microsoft Entra + properties: + clientCredentialsSecret: + description: |- + Name of a Secret that contains client credentials of an Entra account with + permissions `User.ReadAll` and `GroupMemberShip.ReadAll`. + + Must contain the fields `clientId` and `clientSecret`. + type: string + port: + description: Port of the identity provider. If TLS is used defaults to `443`, otherwise to `80`. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + tenantId: + description: The Microsoft Entra tenant ID. + type: string + tls: + default: + verification: + server: + caCert: + webPki: {} + description: Use a TLS connection. Should usually be set to WebPki. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + tokenHostname: + default: login.microsoft.com + description: Hostname of the token provider, defaults to `login.microsoft.com`. + type: string + userInfoHostname: + default: graph.microsoft.com + description: Hostname of the user info provider, defaults to `graph.microsoft.com`. + type: string + required: + - clientCredentialsSecret + - tenantId + type: object + experimentalActiveDirectory: + description: Backend that fetches user information from Active Directory + properties: + additionalGroupAttributeFilters: + additionalProperties: + type: string + default: {} + description: |- + Attributes that groups must have to be returned. + + These fields will be spliced into an LDAP Search Query, so wildcards can be used, + but characters with a special meaning in LDAP will need to be escaped. + type: object + baseDistinguishedName: + description: The root Distinguished Name (DN) where users and groups are located. + type: string + customAttributeMappings: + additionalProperties: + type: string + default: {} + description: Custom attributes, and their LDAP attribute names. + type: object + kerberosSecretClassName: + description: The name of the Kerberos SecretClass. + type: string + ldapServer: + description: Hostname of the domain controller, e.g. `ad-ds-1.contoso.com`. + type: string + tls: + description: Use a TLS connection. If not specified no TLS will be used. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + required: + - baseDistinguishedName + - kerberosSecretClassName + - ldapServer + type: object + experimentalOpenLdap: + description: Backend that fetches user information from OpenLDAP + properties: + bindCredentials: + description: |- + Credentials for binding to the LDAP server. + + The bind account is used to search for users and groups in the LDAP directory. + properties: + scope: + description: |- + [Scope](https://docs.stackable.tech/home/nightly/secret-operator/scope) of the + [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass). + nullable: true + properties: + listenerVolumes: + default: [] + description: |- + The listener volume scope allows Node and Service scopes to be inferred from the applicable listeners. + This must correspond to Volume names in the Pod that mount Listeners. + items: + type: string + type: array + node: + default: false + description: |- + The node scope is resolved to the name of the Kubernetes Node object that the Pod is running on. + This will typically be the DNS name of the node. + type: boolean + pod: + default: false + description: |- + The pod scope is resolved to the name of the Kubernetes Pod. + This allows the secret to differentiate between StatefulSet replicas. + type: boolean + services: + default: [] + description: |- + The service scope allows Pod objects to specify custom scopes. + This should typically correspond to Service objects that the Pod participates in. + items: + type: string + type: array + type: object + secretClass: + description: '[SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) containing the LDAP bind credentials.' + type: string + required: + - secretClass + type: object + customAttributeMappings: + additionalProperties: + type: string + default: {} + description: Custom attributes, and their LDAP attribute names. + type: object + groupMemberAttribute: + default: member + description: |- + LDAP attribute on group objects that contains member references. + + Common values: + - `member`: For `groupOfNames` objects (uses full DN) + - `memberUid`: For `posixGroup` objects (uses username) + + Defaults to `member`. + type: string + groupsSearchBase: + description: |- + LDAP search base for groups, e.g. `ou=groups,dc=example,dc=org`. + + If not specified, uses the main `searchBase`. + nullable: true + type: string + hostname: + description: Hostname of the LDAP server, e.g. `my.ldap.server`. + type: string + port: + description: Port of the LDAP server. If TLS is used defaults to `636`, otherwise to `389`. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + searchBase: + default: '' + description: LDAP search base, e.g. `ou=users,dc=example,dc=org`. + type: string + tls: + description: Use a TLS connection. If not specified no TLS will be used. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + userIdAttribute: + default: entryUUID + description: LDAP attribute used for the user's unique identifier. Defaults to `entryUUID`. + type: string + userNameAttribute: + default: uid + description: LDAP attribute used for the username. Defaults to `uid`. + type: string + required: + - bindCredentials + - hostname + type: object + experimentalXfscAas: + description: |- + Backend that fetches user information from the Gaia-X + Cross Federation Services Components (XFSC) Authentication & Authorization Service. + properties: + hostname: + description: Hostname of the identity provider, e.g. `my.aas.corp`. + type: string + port: + default: 5000 + description: Port of the identity provider. Defaults to port 5000. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + type: integer + required: + - hostname + type: object + keycloak: + description: Backend that fetches user information from Keycloak. + properties: + adminRealm: + description: |- + The Keycloak realm that OPA's Keycloak account (as specified by `credentialsSecretName` exists in). + + Typically `master`. + type: string + clientCredentialsSecret: + description: |- + Name of a Secret that contains client credentials of a Keycloak account with permission to read user metadata. + + Must contain the fields `clientId` and `clientSecret`. + type: string + hostname: + description: Hostname of the identity provider, e.g. `my.keycloak.corp`. + type: string + port: + description: Port of the identity provider. If TLS is used defaults to `443`, otherwise to `80`. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + rootPath: + default: / + description: Root HTTP path of the identity provider. Defaults to `/`. + type: string + tls: + description: Use a TLS connection. If not specified no TLS will be used. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + userRealm: + description: The Keycloak realm that user metadata should be resolved from. + type: string + required: + - adminRealm + - clientCredentialsSecret + - hostname + - userRealm + type: object + none: + description: Dummy backend that adds no extra user information. + type: object + type: object + cache: + default: + entryTimeToLive: 1m + description: Caching configuration. + properties: + entryTimeToLive: + default: 1m + description: How long metadata about each user should be cached for. + type: string + type: object + type: object + vectorAggregatorConfigMapName: + description: |- + Name of the Vector aggregator discovery ConfigMap. + It must contain the key `ADDRESS` with the address of the Vector aggregator. + nullable: true + type: string + type: object + clusterOperation: + default: + reconciliationPaused: false + stopped: false + description: Cluster operations like pause reconciliation or cluster stop. + properties: + reconciliationPaused: + default: false + description: |- + Flag to stop cluster reconciliation by the operator. This means that all changes in the + custom resource spec are ignored until this flag is set to false or removed. The operator + will however still watch the deployed resources at the time and update the custom resource + status field. + If applied at the same time with `stopped`, `reconciliationPaused` will take precedence over + `stopped` and stop the reconciliation immediately. + type: boolean + stopped: + default: false + description: |- + Flag to stop the cluster. This means all deployed resources (e.g. Services, StatefulSets, + ConfigMaps) are kept but all deployed Pods (e.g. replicas from a StatefulSet) are scaled to 0 + and therefore stopped and removed. + If applied at the same time with `reconciliationPaused`, the latter will pause reconciliation + and `stopped` will take no effect until `reconciliationPaused` is set to false or removed. + type: boolean + type: object + image: + anyOf: + - required: + - custom + - productVersion + - required: + - productVersion + description: The OPA image to use + properties: + custom: + description: |- + Overwrite the docker image. + Specify the full docker image name, e.g. `oci.stackable.tech/sdp/superset:1.4.1-stackable2.1.0` + type: string + productVersion: + description: Version of the product, e.g. `1.4.1`. + type: string + pullPolicy: + default: Always + description: '[Pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) used when pulling the image.' + enum: + - IfNotPresent + - Always + - Never + type: string + pullSecrets: + description: '[Image pull secrets](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) to pull images from a private registry.' + items: + description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + required: + - name + type: object + nullable: true + type: array + repo: + description: Name of the docker repo, e.g. `oci.stackable.tech/sdp` + nullable: true + type: string + stackableVersion: + description: |- + Stackable version of the product, e.g. `23.4`, `23.4.1` or `0.0.0-dev`. + If not specified, the operator will use its own version, e.g. `23.4.1`. + When using a nightly operator or a pr version, it will use the nightly `0.0.0-dev` image. + nullable: true + type: string + type: object + objectOverrides: + default: [] + description: |- + A list of generic Kubernetes objects, which are merged into the objects that the operator + creates. + + List entries are arbitrary YAML objects, which need to be valid Kubernetes objects. + + Read the [Object overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#object-overrides) + for more information. + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + servers: + description: OPA server configuration. + properties: + cliOverrides: + additionalProperties: + type: string + default: {} + type: object + config: + default: {} + properties: + affinity: + default: + nodeAffinity: null + nodeSelector: null + podAffinity: null + podAntiAffinity: null + description: |- + These configuration settings control + [Pod placement](https://docs.stackable.tech/home/nightly/concepts/operations/pod_placement). + properties: + nodeAffinity: + description: Same as the `spec.affinity.nodeAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + nodeSelector: + additionalProperties: + type: string + description: Simple key-value pairs forming a nodeSelector, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + podAffinity: + description: Same as the `spec.affinity.podAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + podAntiAffinity: + description: Same as the `spec.affinity.podAntiAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + gracefulShutdownTimeout: + description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. + nullable: true + type: string + logging: + default: + containers: {} + enableVectorAgent: null + description: Logging configuration, learn more in the [logging concept documentation](https://docs.stackable.tech/home/nightly/concepts/logging). + properties: + containers: + additionalProperties: + anyOf: + - required: + - custom + - {} + description: Log configuration of the container + properties: + console: + description: Configuration for the console appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + custom: + description: Log configuration provided in a ConfigMap + properties: + configMap: + description: ConfigMap containing the log configuration files + nullable: true + type: string + type: object + file: + description: Configuration for the file appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + loggers: + additionalProperties: + description: Configuration of a logger + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + default: {} + description: Configuration per logger + type: object + type: object + description: Log configuration per container. + type: object + enableVectorAgent: + description: Wether or not to deploy a container with the Vector log agent. + nullable: true + type: boolean + type: object + resources: + default: + cpu: + max: null + min: null + memory: + limit: null + runtimeLimits: {} + storage: {} + description: |- + Resource usage is configured here, this includes CPU usage, memory usage and disk storage + usage, if this role needs any. + properties: + cpu: + default: + max: null + min: null + properties: + max: + description: |- + The maximum amount of CPU cores that can be requested by Pods. + Equivalent to the `limit` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + min: + description: |- + The minimal amount of CPU cores that Pods need to run. + Equivalent to the `request` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + type: object + memory: + properties: + limit: + description: |- + The maximum amount of memory that should be available to the Pod. + Specified as a byte [Quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/), + which means these suffixes are supported: E, P, T, G, M, k. + You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. + For example, the following represent roughly the same value: + `128974848, 129e6, 129M, 128974848000m, 123Mi` + nullable: true + type: string + runtimeLimits: + description: Additional options that can be specified. + type: object + type: object + storage: + type: object + type: object + type: object + configOverrides: + additionalProperties: + additionalProperties: + type: string + type: object + default: {} + description: |- + The `configOverrides` can be used to configure properties in product config files + that are not exposed in the CRD. Read the + [config overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#config-overrides) + and consult the operator specific usage guide documentation for details on the + available config files and settings for the specific product. + type: object + envOverrides: + additionalProperties: + type: string + default: {} + description: |- + `envOverrides` configure environment variables to be set in the Pods. + It is a map from strings to strings - environment variables and the value to set. + Read the + [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) + for more information and consult the operator specific usage guide to find out about + the product specific environment variables that are available. + type: object + podOverrides: + default: {} + description: |- + In the `podOverrides` property you can define a + [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) + to override any property that can be set on a Kubernetes Pod. + Read the + [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) + for more information. + type: object + x-kubernetes-preserve-unknown-fields: true + roleConfig: + default: {} + description: |- + This is a product-agnostic RoleConfig, with nothing in it. It is used e.g. by products that have + nothing configurable at role level. + type: object + roleGroups: + additionalProperties: + properties: + cliOverrides: + additionalProperties: + type: string + default: {} + type: object + config: + default: {} + properties: + affinity: + default: + nodeAffinity: null + nodeSelector: null + podAffinity: null + podAntiAffinity: null + description: |- + These configuration settings control + [Pod placement](https://docs.stackable.tech/home/nightly/concepts/operations/pod_placement). + properties: + nodeAffinity: + description: Same as the `spec.affinity.nodeAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + nodeSelector: + additionalProperties: + type: string + description: Simple key-value pairs forming a nodeSelector, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + podAffinity: + description: Same as the `spec.affinity.podAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + podAntiAffinity: + description: Same as the `spec.affinity.podAntiAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + gracefulShutdownTimeout: + description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. + nullable: true + type: string + logging: + default: + containers: {} + enableVectorAgent: null + description: Logging configuration, learn more in the [logging concept documentation](https://docs.stackable.tech/home/nightly/concepts/logging). + properties: + containers: + additionalProperties: + anyOf: + - required: + - custom + - {} + description: Log configuration of the container + properties: + console: + description: Configuration for the console appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + custom: + description: Log configuration provided in a ConfigMap + properties: + configMap: + description: ConfigMap containing the log configuration files + nullable: true + type: string + type: object + file: + description: Configuration for the file appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + loggers: + additionalProperties: + description: Configuration of a logger + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + default: {} + description: Configuration per logger + type: object + type: object + description: Log configuration per container. + type: object + enableVectorAgent: + description: Wether or not to deploy a container with the Vector log agent. + nullable: true + type: boolean + type: object + resources: + default: + cpu: + max: null + min: null + memory: + limit: null + runtimeLimits: {} + storage: {} + description: |- + Resource usage is configured here, this includes CPU usage, memory usage and disk storage + usage, if this role needs any. + properties: + cpu: + default: + max: null + min: null + properties: + max: + description: |- + The maximum amount of CPU cores that can be requested by Pods. + Equivalent to the `limit` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + min: + description: |- + The minimal amount of CPU cores that Pods need to run. + Equivalent to the `request` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + type: object + memory: + properties: + limit: + description: |- + The maximum amount of memory that should be available to the Pod. + Specified as a byte [Quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/), + which means these suffixes are supported: E, P, T, G, M, k. + You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. + For example, the following represent roughly the same value: + `128974848, 129e6, 129M, 128974848000m, 123Mi` + nullable: true + type: string + runtimeLimits: + description: Additional options that can be specified. + type: object + type: object + storage: + type: object + type: object + type: object + configOverrides: + additionalProperties: + additionalProperties: + type: string + type: object + default: {} + description: |- + The `configOverrides` can be used to configure properties in product config files + that are not exposed in the CRD. Read the + [config overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#config-overrides) + and consult the operator specific usage guide documentation for details on the + available config files and settings for the specific product. + type: object + envOverrides: + additionalProperties: + type: string + default: {} + description: |- + `envOverrides` configure environment variables to be set in the Pods. + It is a map from strings to strings - environment variables and the value to set. + Read the + [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) + for more information and consult the operator specific usage guide to find out about + the product specific environment variables that are available. + type: object + podOverrides: + default: {} + description: |- + In the `podOverrides` property you can define a + [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) + to override any property that can be set on a Kubernetes Pod. + Read the + [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) + for more information. + type: object + x-kubernetes-preserve-unknown-fields: true + replicas: + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + type: object + type: object + required: + - roleGroups + type: object + required: + - image + - servers + type: object + status: + nullable: true + properties: + conditions: + default: [] + items: + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + format: date-time + nullable: true + type: string + message: + description: A human readable message indicating details about the transition. + nullable: true + type: string + reason: + description: The reason for the condition's last transition. + nullable: true + type: string + status: + description: Status of the condition, one of True, False, Unknown. + enum: + - 'True' + - 'False' + - Unknown + type: string + type: + description: Type of deployment condition. + enum: + - Available + - Degraded + - Progressing + - ReconciliationPaused + - Stopped + type: string + required: + - status + - type + type: object + type: array + type: object + required: + - spec + title: OpaCluster + type: object + served: true + storage: true + subresources: + status: {} + - additionalPrinterColumns: [] + name: v1alpha1 + schema: + openAPIV3Schema: + description: Auto-generated derived type for OpaClusterSpec via `CustomResource` + properties: + spec: + properties: + clusterConfig: + default: + listenerClass: cluster-internal + tls: null + userInfo: null + description: Global OPA cluster configuration that applies to all roles and role groups. + properties: + listenerClass: + default: cluster-internal + description: |- + This field controls which type of Service the operator creates for this OpaCluster: + + * cluster-internal: Use a ClusterIP service + + * external-unstable: Use a NodePort service + + * external-stable: Use a LoadBalancer service + + This is a temporary solution with the goal to keep yaml manifests forward compatible. + In the future, this setting will control which ListenerClass + will be used to expose the service, and ListenerClass names will stay the same, allowing for a non-breaking change. + enum: + - cluster-internal + - external-unstable + - external-stable + type: string + tls: + description: |- + TLS encryption settings for the OPA server. + When configured, OPA will use HTTPS (port 8443) instead of HTTP (port 8081). + Clients must connect using HTTPS and trust the certificates provided by the configured SecretClass. + nullable: true + properties: + serverSecretClass: + description: Name of the SecretClass which will provide TLS certificates for the OPA server. + type: string + required: + - serverSecretClass + type: object + userInfo: + description: |- + Configures how to fetch additional metadata about users (such as group memberships) + from an external directory service. + nullable: true + properties: + backend: + default: + none: {} + description: The backend directory service to use. + oneOf: + - required: + - none + - required: + - keycloak + - required: + - experimentalXfscAas + - required: + - experimentalActiveDirectory + - required: + - experimentalEntra + - required: + - experimentalOpenLdap + properties: + experimentalActiveDirectory: + description: Backend that fetches user information from Active Directory + properties: + additionalGroupAttributeFilters: + additionalProperties: + type: string + default: {} + description: |- + Attributes that groups must have to be returned. + + These fields will be spliced into an LDAP Search Query, so wildcards can be used, + but characters with a special meaning in LDAP will need to be escaped. + type: object + baseDistinguishedName: + description: The root Distinguished Name (DN) where users and groups are located. + type: string + customAttributeMappings: + additionalProperties: + type: string + default: {} + description: Custom attributes, and their LDAP attribute names. + type: object + kerberosSecretClassName: + description: The name of the Kerberos SecretClass. + type: string + ldapServer: + description: Hostname of the domain controller, e.g. `ad-ds-1.contoso.com`. + type: string + tls: + description: Use a TLS connection. If not specified no TLS will be used. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + required: + - baseDistinguishedName + - kerberosSecretClassName + - ldapServer + type: object + experimentalEntra: + description: Backend that fetches user information from Microsoft Entra + properties: + clientCredentialsSecret: + description: |- + Name of a Secret that contains client credentials of an Entra account with + permissions `User.ReadAll` and `GroupMemberShip.ReadAll`. + + Must contain the fields `clientId` and `clientSecret`. + type: string + port: + description: Port of the identity provider. If TLS is used defaults to `443`, otherwise to `80`. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + tenantId: + description: The Microsoft Entra tenant ID. + type: string + tls: + default: + verification: + server: + caCert: + webPki: {} + description: Use a TLS connection. Should usually be set to WebPki. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + tokenHostname: + default: login.microsoft.com + description: Hostname of the token provider, defaults to `login.microsoft.com`. + type: string + userInfoHostname: + default: graph.microsoft.com + description: Hostname of the user info provider, defaults to `graph.microsoft.com`. + type: string + required: + - clientCredentialsSecret + - tenantId + type: object + experimentalOpenLdap: + description: Backend that fetches user information from OpenLDAP + properties: + bindCredentials: + description: |- + Credentials for binding to the LDAP server. + + The bind account is used to search for users and groups in the LDAP directory. + properties: + scope: + description: |- + [Scope](https://docs.stackable.tech/home/nightly/secret-operator/scope) of the + [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass). + nullable: true + properties: + listenerVolumes: + default: [] + description: |- + The listener volume scope allows Node and Service scopes to be inferred from the applicable listeners. + This must correspond to Volume names in the Pod that mount Listeners. + items: + type: string + type: array + node: + default: false + description: |- + The node scope is resolved to the name of the Kubernetes Node object that the Pod is running on. + This will typically be the DNS name of the node. + type: boolean + pod: + default: false + description: |- + The pod scope is resolved to the name of the Kubernetes Pod. + This allows the secret to differentiate between StatefulSet replicas. + type: boolean + services: + default: [] + description: |- + The service scope allows Pod objects to specify custom scopes. + This should typically correspond to Service objects that the Pod participates in. + items: + type: string + type: array + type: object + secretClass: + description: '[SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) containing the LDAP bind credentials.' + type: string + required: + - secretClass + type: object + customAttributeMappings: + additionalProperties: + type: string + default: {} + description: Custom attributes, and their LDAP attribute names. + type: object + groupMemberAttribute: + default: member + description: |- + LDAP attribute on group objects that contains member references. + + Common values: + - `member`: For `groupOfNames` objects (uses full DN) + - `memberUid`: For `posixGroup` objects (uses username) + + Defaults to `member`. + type: string + groupsSearchBase: + description: |- + LDAP search base for groups, e.g. `ou=groups,dc=example,dc=org`. + + If not specified, uses the main `searchBase`. + nullable: true + type: string + hostname: + description: Hostname of the LDAP server, e.g. `my.ldap.server`. + type: string + port: + description: Port of the LDAP server. If TLS is used defaults to `636`, otherwise to `389`. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + searchBase: + default: '' + description: LDAP search base, e.g. `ou=users,dc=example,dc=org`. + type: string + tls: + description: Use a TLS connection. If not specified no TLS will be used. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + userIdAttribute: + default: entryUUID + description: LDAP attribute used for the user's unique identifier. Defaults to `entryUUID`. + type: string + userNameAttribute: + default: uid + description: LDAP attribute used for the username. Defaults to `uid`. + type: string + required: + - bindCredentials + - hostname + type: object + experimentalXfscAas: + description: |- + Backend that fetches user information from the Gaia-X + Cross Federation Services Components (XFSC) Authentication & Authorization Service. + properties: + hostname: + description: Hostname of the identity provider, e.g. `my.aas.corp`. + type: string + port: + default: 5000 + description: Port of the identity provider. Defaults to port 5000. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + type: integer + required: + - hostname + type: object + keycloak: + description: Backend that fetches user information from Keycloak. + properties: + adminRealm: + description: |- + The Keycloak realm that OPA's Keycloak account (as specified by `credentialsSecretName` exists in). + + Typically `master`. + type: string + clientCredentialsSecret: + description: |- + Name of a Secret that contains client credentials of a Keycloak account with permission to read user metadata. + + Must contain the fields `clientId` and `clientSecret`. + type: string + hostname: + description: Hostname of the identity provider, e.g. `my.keycloak.corp`. + type: string + port: + description: Port of the identity provider. If TLS is used defaults to `443`, otherwise to `80`. + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + rootPath: + default: / + description: Root HTTP path of the identity provider. Defaults to `/`. + type: string + tls: + description: Use a TLS connection. If not specified no TLS will be used. + nullable: true + properties: + verification: + description: The verification method used to verify the certificates of the server and/or the client. + oneOf: + - required: + - none + - required: + - server + properties: + none: + description: Use TLS but don't verify certificates. + type: object + server: + description: Use TLS and a CA certificate to verify the server. + properties: + caCert: + description: CA cert to verify the server. + oneOf: + - required: + - webPki + - required: + - secretClass + properties: + secretClass: + description: |- + Name of the [SecretClass](https://docs.stackable.tech/home/nightly/secret-operator/secretclass) which will provide the CA certificate. + Note that a SecretClass does not need to have a key but can also work with just a CA certificate, + so if you got provided with a CA cert but don't have access to the key you can still use this method. + type: string + webPki: + description: |- + Use TLS and the CA certificates trusted by the common web browsers to verify the server. + This can be useful when you e.g. use public AWS S3 or other public available services. + type: object + type: object + required: + - caCert + type: object + type: object + required: + - verification + type: object + userRealm: + description: The Keycloak realm that user metadata should be resolved from. + type: string + required: + - adminRealm + - clientCredentialsSecret + - hostname + - userRealm + type: object + none: + description: Dummy backend that adds no extra user information. + type: object + type: object + cache: + default: + entryTimeToLive: 1m + description: Caching configuration. + properties: + entryTimeToLive: + default: 1m + description: How long metadata about each user should be cached for. + type: string + type: object + type: object + vectorAggregatorConfigMapName: + description: |- + Name of the Vector aggregator discovery ConfigMap. + It must contain the key `ADDRESS` with the address of the Vector aggregator. + nullable: true + type: string + type: object + clusterOperation: + default: + reconciliationPaused: false + stopped: false + description: Cluster operations like pause reconciliation or cluster stop. + properties: + reconciliationPaused: + default: false + description: |- + Flag to stop cluster reconciliation by the operator. This means that all changes in the + custom resource spec are ignored until this flag is set to false or removed. The operator + will however still watch the deployed resources at the time and update the custom resource + status field. + If applied at the same time with `stopped`, `reconciliationPaused` will take precedence over + `stopped` and stop the reconciliation immediately. + type: boolean + stopped: + default: false + description: |- + Flag to stop the cluster. This means all deployed resources (e.g. Services, StatefulSets, + ConfigMaps) are kept but all deployed Pods (e.g. replicas from a StatefulSet) are scaled to 0 + and therefore stopped and removed. + If applied at the same time with `reconciliationPaused`, the latter will pause reconciliation + and `stopped` will take no effect until `reconciliationPaused` is set to false or removed. + type: boolean + type: object + image: + anyOf: + - required: + - custom + - productVersion + - required: + - productVersion + description: The OPA image to use + properties: + custom: + description: |- + Overwrite the docker image. + Specify the full docker image name, e.g. `oci.stackable.tech/sdp/superset:1.4.1-stackable2.1.0` + type: string + productVersion: + description: Version of the product, e.g. `1.4.1`. + type: string + pullPolicy: + default: Always + description: '[Pull policy](https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy) used when pulling the image.' + enum: + - IfNotPresent + - Always + - Never + type: string + pullSecrets: + description: '[Image pull secrets](https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod) to pull images from a private registry.' + items: + description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. This field is effectively required, but due to backwards compatibility is allowed to be empty. Instances of this type with an empty value here are almost certainly wrong. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + required: + - name + type: object + nullable: true + type: array + repo: + description: Name of the docker repo, e.g. `oci.stackable.tech/sdp` + nullable: true + type: string + stackableVersion: + description: |- + Stackable version of the product, e.g. `23.4`, `23.4.1` or `0.0.0-dev`. + If not specified, the operator will use its own version, e.g. `23.4.1`. + When using a nightly operator or a pr version, it will use the nightly `0.0.0-dev` image. + nullable: true + type: string + type: object + objectOverrides: + default: [] + description: |- + A list of generic Kubernetes objects, which are merged into the objects that the operator + creates. + + List entries are arbitrary YAML objects, which need to be valid Kubernetes objects. + + Read the [Object overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#object-overrides) + for more information. + items: + type: object + x-kubernetes-preserve-unknown-fields: true + type: array + servers: + description: OPA server configuration. + properties: + cliOverrides: + additionalProperties: + type: string + default: {} + type: object + config: + default: {} + properties: + affinity: + default: + nodeAffinity: null + nodeSelector: null + podAffinity: null + podAntiAffinity: null + description: |- + These configuration settings control + [Pod placement](https://docs.stackable.tech/home/nightly/concepts/operations/pod_placement). + properties: + nodeAffinity: + description: Same as the `spec.affinity.nodeAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + nodeSelector: + additionalProperties: + type: string + description: Simple key-value pairs forming a nodeSelector, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + podAffinity: + description: Same as the `spec.affinity.podAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + podAntiAffinity: + description: Same as the `spec.affinity.podAntiAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + gracefulShutdownTimeout: + description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. + nullable: true + type: string + logging: + default: + containers: {} + enableVectorAgent: null + description: Logging configuration, learn more in the [logging concept documentation](https://docs.stackable.tech/home/nightly/concepts/logging). + properties: + containers: + additionalProperties: + anyOf: + - required: + - custom + - {} + description: Log configuration of the container + properties: + console: + description: Configuration for the console appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + custom: + description: Log configuration provided in a ConfigMap + properties: + configMap: + description: ConfigMap containing the log configuration files + nullable: true + type: string + type: object + file: + description: Configuration for the file appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + loggers: + additionalProperties: + description: Configuration of a logger + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + default: {} + description: Configuration per logger + type: object + type: object + description: Log configuration per container. + type: object + enableVectorAgent: + description: Wether or not to deploy a container with the Vector log agent. + nullable: true + type: boolean + type: object + resources: + default: + cpu: + max: null + min: null + memory: + limit: null + runtimeLimits: {} + storage: {} + description: |- + Resource usage is configured here, this includes CPU usage, memory usage and disk storage + usage, if this role needs any. + properties: + cpu: + default: + max: null + min: null + properties: + max: + description: |- + The maximum amount of CPU cores that can be requested by Pods. + Equivalent to the `limit` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + min: + description: |- + The minimal amount of CPU cores that Pods need to run. + Equivalent to the `request` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + type: object + memory: + properties: + limit: + description: |- + The maximum amount of memory that should be available to the Pod. + Specified as a byte [Quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/), + which means these suffixes are supported: E, P, T, G, M, k. + You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. + For example, the following represent roughly the same value: + `128974848, 129e6, 129M, 128974848000m, 123Mi` + nullable: true + type: string + runtimeLimits: + description: Additional options that can be specified. + type: object + type: object + storage: + type: object + type: object + type: object + configOverrides: + additionalProperties: + additionalProperties: + type: string + type: object + default: {} + description: |- + The `configOverrides` can be used to configure properties in product config files + that are not exposed in the CRD. Read the + [config overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#config-overrides) + and consult the operator specific usage guide documentation for details on the + available config files and settings for the specific product. + type: object + envOverrides: + additionalProperties: + type: string + default: {} + description: |- + `envOverrides` configure environment variables to be set in the Pods. + It is a map from strings to strings - environment variables and the value to set. + Read the + [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) + for more information and consult the operator specific usage guide to find out about + the product specific environment variables that are available. + type: object + podOverrides: + default: {} + description: |- + In the `podOverrides` property you can define a + [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) + to override any property that can be set on a Kubernetes Pod. + Read the + [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) + for more information. + type: object + x-kubernetes-preserve-unknown-fields: true + roleConfig: + default: {} + description: |- + This is a product-agnostic RoleConfig, with nothing in it. It is used e.g. by products that have + nothing configurable at role level. + type: object + roleGroups: + additionalProperties: + properties: + cliOverrides: + additionalProperties: + type: string + default: {} + type: object + config: + default: {} + properties: + affinity: + default: + nodeAffinity: null + nodeSelector: null + podAffinity: null + podAntiAffinity: null + description: |- + These configuration settings control + [Pod placement](https://docs.stackable.tech/home/nightly/concepts/operations/pod_placement). + properties: + nodeAffinity: + description: Same as the `spec.affinity.nodeAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + nodeSelector: + additionalProperties: + type: string + description: Simple key-value pairs forming a nodeSelector, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + podAffinity: + description: Same as the `spec.affinity.podAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + podAntiAffinity: + description: Same as the `spec.affinity.podAntiAffinity` field on the Pod, see the [Kubernetes docs](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node) + nullable: true + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + gracefulShutdownTimeout: + description: Time period Pods have to gracefully shut down, e.g. `30m`, `1h` or `2d`. Consult the operator documentation for details. + nullable: true + type: string + logging: + default: + containers: {} + enableVectorAgent: null + description: Logging configuration, learn more in the [logging concept documentation](https://docs.stackable.tech/home/nightly/concepts/logging). + properties: + containers: + additionalProperties: + anyOf: + - required: + - custom + - {} + description: Log configuration of the container + properties: + console: + description: Configuration for the console appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + custom: + description: Log configuration provided in a ConfigMap + properties: + configMap: + description: ConfigMap containing the log configuration files + nullable: true + type: string + type: object + file: + description: Configuration for the file appender + nullable: true + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + loggers: + additionalProperties: + description: Configuration of a logger + properties: + level: + description: |- + The log level threshold. + Log events with a lower log level are discarded. + enum: + - TRACE + - DEBUG + - INFO + - WARN + - ERROR + - FATAL + - NONE + nullable: true + type: string + type: object + default: {} + description: Configuration per logger + type: object + type: object + description: Log configuration per container. + type: object + enableVectorAgent: + description: Wether or not to deploy a container with the Vector log agent. + nullable: true + type: boolean + type: object + resources: + default: + cpu: + max: null + min: null + memory: + limit: null + runtimeLimits: {} + storage: {} + description: |- + Resource usage is configured here, this includes CPU usage, memory usage and disk storage + usage, if this role needs any. + properties: + cpu: + default: + max: null + min: null + properties: + max: + description: |- + The maximum amount of CPU cores that can be requested by Pods. + Equivalent to the `limit` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + min: + description: |- + The minimal amount of CPU cores that Pods need to run. + Equivalent to the `request` for Pod resource configuration. + Cores are specified either as a decimal point number or as milli units. + For example:`1.5` will be 1.5 cores, also written as `1500m`. + nullable: true + type: string + type: object + memory: + properties: + limit: + description: |- + The maximum amount of memory that should be available to the Pod. + Specified as a byte [Quantity](https://kubernetes.io/docs/reference/kubernetes-api/common-definitions/quantity/), + which means these suffixes are supported: E, P, T, G, M, k. + You can also use the power-of-two equivalents: Ei, Pi, Ti, Gi, Mi, Ki. + For example, the following represent roughly the same value: + `128974848, 129e6, 129M, 128974848000m, 123Mi` + nullable: true + type: string + runtimeLimits: + description: Additional options that can be specified. + type: object + type: object + storage: + type: object + type: object + type: object + configOverrides: + additionalProperties: + additionalProperties: + type: string + type: object + default: {} + description: |- + The `configOverrides` can be used to configure properties in product config files + that are not exposed in the CRD. Read the + [config overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#config-overrides) + and consult the operator specific usage guide documentation for details on the + available config files and settings for the specific product. + type: object + envOverrides: + additionalProperties: + type: string + default: {} + description: |- + `envOverrides` configure environment variables to be set in the Pods. + It is a map from strings to strings - environment variables and the value to set. + Read the + [environment variable overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#env-overrides) + for more information and consult the operator specific usage guide to find out about + the product specific environment variables that are available. + type: object + podOverrides: + default: {} + description: |- + In the `podOverrides` property you can define a + [PodTemplateSpec](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#podtemplatespec-v1-core) + to override any property that can be set on a Kubernetes Pod. + Read the + [Pod overrides documentation](https://docs.stackable.tech/home/nightly/concepts/overrides#pod-overrides) + for more information. + type: object + x-kubernetes-preserve-unknown-fields: true + replicas: + format: uint16 + maximum: 65535.0 + minimum: 0.0 + nullable: true + type: integer + type: object + type: object + required: + - roleGroups + type: object + required: + - image + - servers + type: object + status: + nullable: true + properties: + conditions: + default: [] + items: + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status to another. + format: date-time + nullable: true + type: string + message: + description: A human readable message indicating details about the transition. + nullable: true + type: string + reason: + description: The reason for the condition's last transition. + nullable: true + type: string + status: + description: Status of the condition, one of True, False, Unknown. + enum: + - 'True' + - 'False' + - Unknown + type: string + type: + description: Type of deployment condition. + enum: + - Available + - Degraded + - Progressing + - ReconciliationPaused + - Stopped + type: string + required: + - status + - type + type: object + type: array + type: object + required: + - spec + title: OpaCluster + type: object + served: true + storage: false + subresources: + status: {} diff --git a/rust/operator-binary/src/crd/mod.rs b/rust/operator-binary/src/crd/mod.rs index fea6e9a0..6a0745ce 100644 --- a/rust/operator-binary/src/crd/mod.rs +++ b/rust/operator-binary/src/crd/mod.rs @@ -36,6 +36,7 @@ pub mod user_info_fetcher; pub const APP_NAME: &str = "opa"; pub const OPERATOR_NAME: &str = "opa.stackable.tech"; +pub const FIELD_MANAGER: &str = "opa-operator"; pub const DEFAULT_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT: Duration = Duration::from_minutes_unchecked(2); /// Safety puffer to guarantee the graceful shutdown works every time. diff --git a/rust/operator-binary/src/main.rs b/rust/operator-binary/src/main.rs index 64447bc8..eba41803 100644 --- a/rust/operator-binary/src/main.rs +++ b/rust/operator-binary/src/main.rs @@ -3,8 +3,9 @@ #![allow(clippy::result_large_err)] use std::sync::Arc; +use anyhow::anyhow; use clap::Parser; -use futures::StreamExt; +use futures::{FutureExt, StreamExt, TryFutureExt}; use product_config::ProductConfigManager; use stackable_operator::{ YamlSchema, @@ -34,6 +35,7 @@ use stackable_operator::{ use crate::{ controller::OPA_FULL_CONTROLLER_NAME, crd::{OPERATOR_NAME, OpaCluster, OpaClusterVersion, v1alpha2}, + webhooks::conversion::create_webhook_server, }; mod controller; @@ -42,6 +44,7 @@ mod discovery; mod operations; mod product_logging; mod service; +mod webhooks; pub mod built_info { include!(concat!(env!("OUT_DIR"), "/built.rs")); @@ -76,7 +79,7 @@ async fn main() -> anyhow::Result<()> { operator_image, common: RunArguments { - operator_environment: _, + operator_environment, watch_namespace, product_config, maintenance, @@ -102,7 +105,8 @@ async fn main() -> anyhow::Result<()> { let eos_checker = EndOfSupportChecker::new(built_info::BUILT_TIME_UTC, maintenance.end_of_support)? - .run(); + .run() + .map(anyhow::Ok); let product_config = product_config.load(&[ "deploy/config-spec/properties.yaml", @@ -115,6 +119,17 @@ async fn main() -> anyhow::Result<()> { let kubernetes_cluster_info = client.kubernetes_cluster_info.clone(); + let webhook_server = create_webhook_server( + &operator_environment, + maintenance.disable_crd_maintenance, + client.as_kube_client(), + ) + .await?; + + let webhook_server = webhook_server + .run() + .map_err(|err| anyhow!(err).context("failed to run webhook server")); + let controller = create_controller( client, product_config, @@ -122,9 +137,10 @@ async fn main() -> anyhow::Result<()> { operator_image.clone(), operator_image, kubernetes_cluster_info, - ); + ) + .map(anyhow::Ok); - futures::join!(controller, eos_checker); + futures::try_join!(controller, webhook_server, eos_checker)?; } }; diff --git a/rust/operator-binary/src/webhooks/conversion.rs b/rust/operator-binary/src/webhooks/conversion.rs new file mode 100644 index 00000000..f224b07b --- /dev/null +++ b/rust/operator-binary/src/webhooks/conversion.rs @@ -0,0 +1,49 @@ +use snafu::{ResultExt, Snafu}; +use stackable_operator::{ + cli::OperatorEnvironmentOptions, + kube::{Client, core::crd::MergeError}, + webhook::{ + WebhookServer, WebhookServerError, WebhookServerOptions, + webhooks::{ConversionWebhook, ConversionWebhookOptions}, + }, +}; + +use crate::crd::{FIELD_MANAGER, OpaCluster, OpaClusterVersion}; + +#[derive(Debug, Snafu)] +pub enum Error { + #[snafu(display("failed to merge CRD"))] + MergeCrd { source: MergeError }, + + #[snafu(display("failed to create conversion webhook server"))] + CreateWebhookServer { source: WebhookServerError }, +} + +pub async fn create_webhook_server( + operator_environment: &OperatorEnvironmentOptions, + disable_crd_maintenance: bool, + client: Client, +) -> Result { + let crds_and_handlers = vec![( + OpaCluster::merged_crd(OpaClusterVersion::V1Alpha2).context(MergeCrdSnafu)?, + OpaCluster::try_convert, + )]; + + let conversion_webhook_options = ConversionWebhookOptions { + field_manager: FIELD_MANAGER.to_owned(), + disable_crd_maintenance, + }; + + let (conversion_webhook, _initial_reconcile_rx) = + ConversionWebhook::new(crds_and_handlers, client, conversion_webhook_options); + + let webhook_server_options = WebhookServerOptions { + webhook_service_name: operator_environment.operator_service_name.to_owned(), + webhook_namespace: operator_environment.operator_namespace.to_owned(), + socket_addr: WebhookServer::DEFAULT_SOCKET_ADDRESS, + }; + + WebhookServer::new(vec![Box::new(conversion_webhook)], webhook_server_options) + .await + .context(CreateWebhookServerSnafu) +} diff --git a/rust/operator-binary/src/webhooks/mod.rs b/rust/operator-binary/src/webhooks/mod.rs new file mode 100644 index 00000000..11eb2fc0 --- /dev/null +++ b/rust/operator-binary/src/webhooks/mod.rs @@ -0,0 +1 @@ +pub mod conversion;