diff --git a/CHANGELOG.md b/CHANGELOG.md index 4de17e34e2a..f729a41a484 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Add support for Apache Kafka 3.8.0. Remove support for Apache Kafka 3.6.0, 3.6.1, and 3.6.2. * Added alerts for Connectors/Tasks in failed state. +* Support for specifying additional volumes and volume mounts in Strimzi custom resources * Additional OAuth configuration options have been added for 'oauth' authentication on the listener and the client. On the listener `serverBearerTokenLocation` and `userNamePrefix` have been added. On the client `accessTokenLocation`, `clientAssertion`, `clientAssertionLocation`, `clientAssertionType`, and `saslExtensions` have been added. diff --git a/api/src/main/java/io/strimzi/api/kafka/model/common/template/AdditionalVolume.java b/api/src/main/java/io/strimzi/api/kafka/model/common/template/AdditionalVolume.java new file mode 100644 index 00000000000..79d456e9be8 --- /dev/null +++ b/api/src/main/java/io/strimzi/api/kafka/model/common/template/AdditionalVolume.java @@ -0,0 +1,112 @@ +/* + * Copyright Strimzi authors. + * License: Apache License 2.0 (see the file LICENSE or http://apache.org/licenses/LICENSE-2.0.html). + */ +package io.strimzi.api.kafka.model.common.template; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import io.fabric8.kubernetes.api.model.ConfigMapVolumeSource; +import io.fabric8.kubernetes.api.model.EmptyDirVolumeSource; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSource; +import io.fabric8.kubernetes.api.model.SecretVolumeSource; +import io.strimzi.api.kafka.model.common.Constants; +import io.strimzi.api.kafka.model.common.UnknownPropertyPreserving; +import io.strimzi.crdgenerator.annotations.Description; +import io.strimzi.crdgenerator.annotations.KubeLink; +import io.strimzi.crdgenerator.annotations.OneOf; +import io.sundr.builder.annotations.Buildable; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.HashMap; +import java.util.Map; + +/** + * Representation of additional volumes for Strimzi resources. + */ +@Buildable(editableEnabled = false, builderPackage = Constants.FABRIC8_KUBERNETES_API) +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonPropertyOrder({ "name", "path", "subPath", "secret", "configMap", "emptyDir", "persistentVolumeClaim" }) +@OneOf({ + @OneOf.Alternative({ + @OneOf.Alternative.Property(value = "secret", required = false), + @OneOf.Alternative.Property(value = "configMap", required = false), + @OneOf.Alternative.Property(value = "emptyDir", required = false), + @OneOf.Alternative.Property(value = "persistentVolumeClaim", required = false) + }) +}) +@EqualsAndHashCode +@ToString +public class AdditionalVolume implements UnknownPropertyPreserving { + private String name; + private SecretVolumeSource secret; + private ConfigMapVolumeSource configMap; + private EmptyDirVolumeSource emptyDir; + private PersistentVolumeClaimVolumeSource persistentVolumeClaim; + private Map additionalProperties = new HashMap<>(0); + + @Description("Name to use for the volume. Required.") + @JsonInclude(JsonInclude.Include.NON_EMPTY) + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Description("Secret to use populate the volume.") + @KubeLink(group = "core", version = "v1", kind = "secretvolumesource") + @JsonInclude(JsonInclude.Include.NON_EMPTY) + public SecretVolumeSource getSecret() { + return secret; + } + + public void setSecret(SecretVolumeSource secret) { + this.secret = secret; + } + + @Description("ConfigMap to use to populate the volume.") + @KubeLink(group = "core", version = "v1", kind = "configmapvolumesource") + @JsonInclude(JsonInclude.Include.NON_EMPTY) + public ConfigMapVolumeSource getConfigMap() { + return configMap; + } + + public void setConfigMap(ConfigMapVolumeSource configMap) { + this.configMap = configMap; + } + + @Description("EmptyDir to use to populate the volume.") + @KubeLink(group = "core", version = "v1", kind = "emptydirvolumesource") + @JsonInclude(JsonInclude.Include.NON_EMPTY) + public EmptyDirVolumeSource getEmptyDir() { + return emptyDir; + } + + public void setEmptyDir(EmptyDirVolumeSource emptyDir) { + this.emptyDir = emptyDir; + } + + @Description("PersistentVolumeClaim object to use to populate the volume.") + @KubeLink(group = "core", version = "v1", kind = "persistentvolumeclaimvolumesource") + @JsonInclude(JsonInclude.Include.NON_EMPTY) + public PersistentVolumeClaimVolumeSource getPersistentVolumeClaim() { + return persistentVolumeClaim; + } + + public void setPersistentVolumeClaim(PersistentVolumeClaimVolumeSource persistentVolumeClaim) { + this.persistentVolumeClaim = persistentVolumeClaim; + } + + @Override + public Map getAdditionalProperties() { + return this.additionalProperties; + } + + @Override + public void setAdditionalProperty(String name, Object value) { + this.additionalProperties.put(name, value); + } +} \ No newline at end of file diff --git a/api/src/main/java/io/strimzi/api/kafka/model/common/template/ContainerTemplate.java b/api/src/main/java/io/strimzi/api/kafka/model/common/template/ContainerTemplate.java index aec0e8b2591..754ea7b7051 100644 --- a/api/src/main/java/io/strimzi/api/kafka/model/common/template/ContainerTemplate.java +++ b/api/src/main/java/io/strimzi/api/kafka/model/common/template/ContainerTemplate.java @@ -5,8 +5,10 @@ package io.strimzi.api.kafka.model.common.template; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; import io.fabric8.kubernetes.api.model.SecurityContext; +import io.fabric8.kubernetes.api.model.VolumeMount; import io.strimzi.api.kafka.model.common.Constants; import io.strimzi.api.kafka.model.common.ContainerEnvVar; import io.strimzi.api.kafka.model.common.UnknownPropertyPreserving; @@ -29,7 +31,7 @@ builderPackage = Constants.FABRIC8_KUBERNETES_API ) @JsonInclude(JsonInclude.Include.NON_NULL) -@JsonPropertyOrder({"env", "securityContext"}) +@JsonPropertyOrder({"env", "securityContext", "volumeMounts"}) @DescriptionFile @EqualsAndHashCode @ToString @@ -37,6 +39,17 @@ public class ContainerTemplate implements UnknownPropertyPreserving { private List env; private SecurityContext securityContext; private Map additionalProperties; + private List volumeMounts; + + @Description("Additional volume mounts which should be applied to the container") + @JsonProperty("volumeMounts") + public List getVolumeMounts() { + return volumeMounts; + } + + public void setVolumeMounts(List volumeMounts) { + this.volumeMounts = volumeMounts; + } @Description("Environment variables which should be applied to the container.") public List getEnv() { diff --git a/api/src/main/java/io/strimzi/api/kafka/model/common/template/PodTemplate.java b/api/src/main/java/io/strimzi/api/kafka/model/common/template/PodTemplate.java index 2108148140f..e8a43e58ba1 100644 --- a/api/src/main/java/io/strimzi/api/kafka/model/common/template/PodTemplate.java +++ b/api/src/main/java/io/strimzi/api/kafka/model/common/template/PodTemplate.java @@ -38,7 +38,7 @@ @JsonInclude(JsonInclude.Include.NON_DEFAULT) @JsonPropertyOrder({"metadata", "imagePullSecrets", "securityContext", "terminationGracePeriodSeconds", "affinity", "tolerations", "topologySpreadConstraints", "priorityClassName", "schedulerName", "hostAliases", - "enableServiceLinks", "tmpDirSizeLimit"}) + "enableServiceLinks", "tmpDirSizeLimit", "volumes"}) @EqualsAndHashCode @ToString @DescriptionFile @@ -55,6 +55,7 @@ public class PodTemplate implements HasMetadataTemplate, UnknownPropertyPreservi private List hostAliases; private Boolean enableServiceLinks; private String tmpDirSizeLimit; + private List volumes; private Map additionalProperties; @Description("Metadata applied to the resource.") @@ -197,6 +198,16 @@ public void setTmpDirSizeLimit(String tmpDirSizeLimit) { this.tmpDirSizeLimit = tmpDirSizeLimit; } + @Description("Additional volumes that can be mounted to the pod.") + @JsonInclude(JsonInclude.Include.NON_EMPTY) + public List getVolumes() { + return volumes; + } + + public void setVolumes(List volumes) { + this.volumes = volumes; + } + @Override public Map getAdditionalProperties() { return this.additionalProperties != null ? this.additionalProperties : Map.of(); diff --git a/api/src/test/resources/io/strimzi/api/kafka/model/bridge/KafkaBridge-with-template.yaml b/api/src/test/resources/io/strimzi/api/kafka/model/bridge/KafkaBridge-with-template.yaml index 227d2c7f69d..336ad5c0aca 100644 --- a/api/src/test/resources/io/strimzi/api/kafka/model/bridge/KafkaBridge-with-template.yaml +++ b/api/src/test/resources/io/strimzi/api/kafka/model/bridge/KafkaBridge-with-template.yaml @@ -30,7 +30,23 @@ spec: runAsUser: 1000001 runAsGroup: 1000001 fsGroup: 0 + volumes: + - name: example-secret + secret: + secretName: secret-name + - name: example-configmap + configMap: + name: config-map-name terminationGracePeriodSeconds: 30 + bridgeContainer: + volumeMounts: + - name: example-secret + mountPath: /path/to/mount/secret-volume + subPath: subPath1 + initContainer: + volumeMounts: + - name: example-configmap + mountPath: /path/to/mount/cm-volume podDisruptionBudget: metadata: labels: @@ -39,4 +55,4 @@ spec: annotations: key1: label1 key2: label2 - maxUnavailable: 1 \ No newline at end of file + maxUnavailable: 1 diff --git a/api/src/test/resources/io/strimzi/api/kafka/model/connect/KafkaConnect-with-template.yaml b/api/src/test/resources/io/strimzi/api/kafka/model/connect/KafkaConnect-with-template.yaml index 065cce8a4c1..bc7476e9887 100644 --- a/api/src/test/resources/io/strimzi/api/kafka/model/connect/KafkaConnect-with-template.yaml +++ b/api/src/test/resources/io/strimzi/api/kafka/model/connect/KafkaConnect-with-template.yaml @@ -31,6 +31,22 @@ spec: runAsGroup: 1000001 fsGroup: 0 terminationGracePeriodSeconds: 30 + volumes: + - name: example-secret + secret: + secretName: secret-name + - name: example-configmap + configMap: + name: config-map-name + connectContainer: + volumeMounts: + - name: example-secret + mountPath: /path/to/mount/secret-volume + subPath: subPath1 + initContainer: + volumeMounts: + - name: example-configmap + mountPath: /path/to/mount/cm-volume podDisruptionBudget: metadata: labels: @@ -47,4 +63,4 @@ spec: key2: label2 annotations: key1: label1 - key2: label2 \ No newline at end of file + key2: label2 diff --git a/api/src/test/resources/io/strimzi/api/kafka/model/kafka/Kafka-with-template.yaml b/api/src/test/resources/io/strimzi/api/kafka/model/kafka/Kafka-with-template.yaml index bcdfd0f80b5..49381007b9c 100644 --- a/api/src/test/resources/io/strimzi/api/kafka/model/kafka/Kafka-with-template.yaml +++ b/api/src/test/resources/io/strimzi/api/kafka/model/kafka/Kafka-with-template.yaml @@ -42,6 +42,28 @@ spec: runAsGroup: 1000001 fsGroup: 0 terminationGracePeriodSeconds: 30 + volumes: + - name: example-secret + secret: + secretName: secret-name + - name: example-configmap + configMap: + name: config-map-name + - name: temp + emptyDir: {} + - name: example-pvc-volume + persistentVolumeClaim: + claimName: myclaim + kafkaContainer: + volumeMounts: + - name: example-secret + mountPath: /mnt/secret-volume + - name: example-configmap + mountPath: /mnt/cm-volume + - name: temp + mountPath: /tmp/logs + - name: example-pvc-volume + mountPath: "/mnt/data" bootstrapService: metadata: labels: @@ -120,6 +142,27 @@ spec: annotations: key1: label1 key2: label2 + volumes: + - name: example-secret + secret: + secretName: secret-name + - name: example-configmap + configMap: + name: config-map-name + - name: temp + emptyDir: {} + - name: example-pvc-volume + persistentVolumeClaim: + claimName: example-pvc-volume + zookeeperContainer: + volumeMounts: + - name: example-secret + mountPath: /mnt/secret-volume + subPath: subPath1 + - name: example-configmap + mountPath: /mnt/cm-volume + - name: example-pvc-volume + mountPath: "/mnt/data" clientService: metadata: labels: @@ -156,4 +199,16 @@ spec: annotations: key1: label1 key2: label2 + volumes: + - name: example-secret + secret: + secretName: secret-name + - name: example-configmap + configMap: + name: config-map-name + - name: temp + emptyDir: {} + - name: example-pvc-volume + persistentVolumeClaim: + claimName: example-pvc-volume diff --git a/api/src/test/resources/io/strimzi/api/kafka/model/mirrormaker2/KafkaMirrorMaker2-with-template.yaml b/api/src/test/resources/io/strimzi/api/kafka/model/mirrormaker2/KafkaMirrorMaker2-with-template.yaml index 3e7204c7a87..1f3b58ff03c 100644 --- a/api/src/test/resources/io/strimzi/api/kafka/model/mirrormaker2/KafkaMirrorMaker2-with-template.yaml +++ b/api/src/test/resources/io/strimzi/api/kafka/model/mirrormaker2/KafkaMirrorMaker2-with-template.yaml @@ -41,6 +41,22 @@ spec: runAsGroup: 1000001 fsGroup: 0 terminationGracePeriodSeconds: 30 + volumes: + - name: example-secret + secret: + secretName: secret-name + - name: example-configmap + configMap: + name: config-map-name + connectContainer: + volumeMounts: + - name: example-secret + mountPath: /path/to/mount/secret-volume + subPath: subPath1 + initContainer: + volumeMounts: + - name: example-configmap + mountPath: /path/to/mount/cm-volume podDisruptionBudget: metadata: labels: @@ -57,4 +73,4 @@ spec: key2: label2 annotations: key1: label1 - key2: label2 \ No newline at end of file + key2: label2 diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CruiseControl.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CruiseControl.java index 085e660d33f..be00e961acc 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CruiseControl.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/CruiseControl.java @@ -59,9 +59,6 @@ import java.util.Set; import static io.strimzi.api.kafka.model.common.template.DeploymentStrategy.ROLLING_UPDATE; -import static io.strimzi.operator.cluster.model.VolumeUtils.createConfigMapVolume; -import static io.strimzi.operator.cluster.model.VolumeUtils.createSecretVolume; -import static io.strimzi.operator.cluster.model.VolumeUtils.createVolumeMount; import static io.strimzi.operator.cluster.model.cruisecontrol.CruiseControlConfiguration.CRUISE_CONTROL_DEFAULT_ANOMALY_DETECTION_GOALS; import static io.strimzi.operator.cluster.model.cruisecontrol.CruiseControlConfiguration.CRUISE_CONTROL_GOALS; import static io.strimzi.operator.common.model.cruisecontrol.CruiseControlApiProperties.API_ADMIN_NAME; @@ -321,19 +318,29 @@ protected List getContainerPortList() { } protected List getVolumes(boolean isOpenShift) { - return List.of(VolumeUtils.createTempDirVolume(templatePod), - createSecretVolume(TLS_CC_CERTS_VOLUME_NAME, CruiseControlResources.secretName(cluster), isOpenShift), - createSecretVolume(TLS_CA_CERTS_VOLUME_NAME, AbstractModel.clusterCaCertSecretName(cluster), isOpenShift), - createSecretVolume(API_AUTH_CONFIG_VOLUME_NAME, CruiseControlResources.apiSecretName(cluster), isOpenShift), - createConfigMapVolume(CONFIG_VOLUME_NAME, CruiseControlResources.configMapName(cluster))); + List volumes = new ArrayList<>(); + volumes.add(VolumeUtils.createTempDirVolume(templatePod)); + volumes.add(VolumeUtils.createSecretVolume(TLS_CC_CERTS_VOLUME_NAME, CruiseControlResources.secretName(cluster), isOpenShift)); + volumes.add(VolumeUtils.createSecretVolume(TLS_CA_CERTS_VOLUME_NAME, AbstractModel.clusterCaCertSecretName(cluster), isOpenShift)); + volumes.add(VolumeUtils.createSecretVolume(API_AUTH_CONFIG_VOLUME_NAME, CruiseControlResources.apiSecretName(cluster), isOpenShift)); + volumes.add(VolumeUtils.createConfigMapVolume(CONFIG_VOLUME_NAME, CruiseControlResources.configMapName(cluster))); + + TemplateUtils.addAdditionalVolumes(templatePod, volumes); + + return volumes; } protected List getVolumeMounts() { - return List.of(VolumeUtils.createTempDirVolumeMount(), - createVolumeMount(CruiseControl.TLS_CC_CERTS_VOLUME_NAME, CruiseControl.TLS_CC_CERTS_VOLUME_MOUNT), - createVolumeMount(CruiseControl.TLS_CA_CERTS_VOLUME_NAME, CruiseControl.TLS_CA_CERTS_VOLUME_MOUNT), - createVolumeMount(CruiseControl.API_AUTH_CONFIG_VOLUME_NAME, CruiseControl.API_AUTH_CONFIG_VOLUME_MOUNT), - createVolumeMount(CONFIG_VOLUME_NAME, CONFIG_VOLUME_MOUNT)); + List volumeMounts = new ArrayList<>(); + volumeMounts.add(VolumeUtils.createTempDirVolumeMount()); + volumeMounts.add(VolumeUtils.createVolumeMount(CruiseControl.TLS_CC_CERTS_VOLUME_NAME, CruiseControl.TLS_CC_CERTS_VOLUME_MOUNT)); + volumeMounts.add(VolumeUtils.createVolumeMount(CruiseControl.TLS_CA_CERTS_VOLUME_NAME, CruiseControl.TLS_CA_CERTS_VOLUME_MOUNT)); + volumeMounts.add(VolumeUtils.createVolumeMount(CruiseControl.API_AUTH_CONFIG_VOLUME_NAME, CruiseControl.API_AUTH_CONFIG_VOLUME_MOUNT)); + volumeMounts.add(VolumeUtils.createVolumeMount(CONFIG_VOLUME_NAME, CONFIG_VOLUME_MOUNT)); + + TemplateUtils.addAdditionalVolumeMounts(volumeMounts, templateContainer); + + return volumeMounts; } /** diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityOperator.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityOperator.java index a2ebd3cb1e8..b83f1ff8749 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityOperator.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityOperator.java @@ -43,6 +43,7 @@ import static io.strimzi.api.kafka.model.common.template.DeploymentStrategy.RECREATE; import static io.strimzi.operator.cluster.model.EntityTopicOperator.TOPIC_OPERATOR_TMP_DIRECTORY_DEFAULT_VOLUME_NAME; import static io.strimzi.operator.cluster.model.EntityUserOperator.USER_OPERATOR_TMP_DIRECTORY_DEFAULT_VOLUME_NAME; +import static io.strimzi.operator.cluster.model.TemplateUtils.addAdditionalVolumes; /** * Represents the Entity Operator deployment @@ -231,6 +232,8 @@ private List getVolumes(boolean isOpenShift) { volumeList.add(VolumeUtils.createSecretVolume(EUO_CERTS_VOLUME_NAME, KafkaResources.entityUserOperatorSecretName(cluster), isOpenShift)); } + addAdditionalVolumes(templatePod, volumeList); + volumeList.add(VolumeUtils.createSecretVolume(TLS_SIDECAR_CA_CERTS_VOLUME_NAME, AbstractModel.clusterCaCertSecretName(cluster), isOpenShift)); return volumeList; } diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityTopicOperator.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityTopicOperator.java index edbb4108ba1..8fcb13d5ee2 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityTopicOperator.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityTopicOperator.java @@ -232,6 +232,8 @@ private List getVolumeMounts() { if (this.cruiseControlEnabled) { result.add(VolumeUtils.createVolumeMount(EntityOperator.ETO_CC_API_VOLUME_NAME, EntityOperator.ETO_CC_API_VOLUME_MOUNT)); } + TemplateUtils.addAdditionalVolumeMounts(result, templateContainer); + return Collections.unmodifiableList(result); } diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityUserOperator.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityUserOperator.java index d63ed4bfabe..fa4c180b136 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityUserOperator.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/EntityUserOperator.java @@ -234,10 +234,15 @@ protected List getVolumes() { } private List getVolumeMounts() { - return List.of(VolumeUtils.createTempDirVolumeMount(USER_OPERATOR_TMP_DIRECTORY_DEFAULT_VOLUME_NAME), - VolumeUtils.createVolumeMount(LOG_AND_METRICS_CONFIG_VOLUME_NAME, LOG_AND_METRICS_CONFIG_VOLUME_MOUNT), - VolumeUtils.createVolumeMount(EntityOperator.EUO_CERTS_VOLUME_NAME, EntityOperator.EUO_CERTS_VOLUME_MOUNT), - VolumeUtils.createVolumeMount(EntityOperator.TLS_SIDECAR_CA_CERTS_VOLUME_NAME, EntityOperator.TLS_SIDECAR_CA_CERTS_VOLUME_MOUNT)); + List volumeMounts = new ArrayList<>(); + volumeMounts.add(VolumeUtils.createTempDirVolumeMount(USER_OPERATOR_TMP_DIRECTORY_DEFAULT_VOLUME_NAME)); + volumeMounts.add(VolumeUtils.createVolumeMount(LOG_AND_METRICS_CONFIG_VOLUME_NAME, LOG_AND_METRICS_CONFIG_VOLUME_MOUNT)); + volumeMounts.add(VolumeUtils.createVolumeMount(EntityOperator.EUO_CERTS_VOLUME_NAME, EntityOperator.EUO_CERTS_VOLUME_MOUNT)); + volumeMounts.add(VolumeUtils.createVolumeMount(EntityOperator.TLS_SIDECAR_CA_CERTS_VOLUME_NAME, EntityOperator.TLS_SIDECAR_CA_CERTS_VOLUME_MOUNT)); + + TemplateUtils.addAdditionalVolumeMounts(volumeMounts, templateContainer); + + return volumeMounts; } /** diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeCluster.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeCluster.java index ca28cc56a95..2db39b75041 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeCluster.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaBridgeCluster.java @@ -298,6 +298,8 @@ protected List getVolumes(boolean isOpenShift) { AuthenticationUtils.configureClientAuthenticationVolumes(authentication, volumeList, "oauth-certs", isOpenShift); + TemplateUtils.addAdditionalVolumes(templatePod, volumeList); + return volumeList; } @@ -317,6 +319,17 @@ protected List getVolumeMounts() { AuthenticationUtils.configureClientAuthenticationVolumeMounts(authentication, volumeMountList, TLS_CERTS_BASE_VOLUME_MOUNT, PASSWORD_VOLUME_MOUNT, OAUTH_TLS_CERTS_BASE_VOLUME_MOUNT, "oauth-certs"); + TemplateUtils.addAdditionalVolumeMounts(volumeMountList, templateContainer); + + return volumeMountList; + } + + private List getInitContainerVolumeMounts() { + List volumeMountList = new ArrayList<>(); + volumeMountList.add(VolumeUtils.createVolumeMount(INIT_VOLUME_NAME, INIT_VOLUME_MOUNT)); + + TemplateUtils.addAdditionalVolumeMounts(volumeMountList, templateInitContainer); + return volumeMountList; } @@ -366,7 +379,7 @@ private Container createInitContainer(ImagePullPolicy imagePullPolicy) { resources, getInitContainerEnvVars(), null, - List.of(VolumeUtils.createVolumeMount(INIT_VOLUME_NAME, INIT_VOLUME_MOUNT)), + getInitContainerVolumeMounts(), null, null, imagePullPolicy diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaCluster.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaCluster.java index e5eb05fa4dd..019a303d92a 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaCluster.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaCluster.java @@ -41,6 +41,7 @@ import io.strimzi.api.kafka.model.common.CertAndKeySecretSource; import io.strimzi.api.kafka.model.common.Condition; import io.strimzi.api.kafka.model.common.Rack; +import io.strimzi.api.kafka.model.common.template.ContainerTemplate; import io.strimzi.api.kafka.model.common.template.ExternalTrafficPolicy; import io.strimzi.api.kafka.model.common.template.InternalServiceTemplate; import io.strimzi.api.kafka.model.common.template.PodDisruptionBudgetTemplate; @@ -98,8 +99,6 @@ import java.util.function.Function; import java.util.stream.Collectors; -import static io.strimzi.operator.cluster.model.ListenersUtils.isListenerWithCustomAuth; -import static io.strimzi.operator.cluster.model.ListenersUtils.isListenerWithOAuth; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonMap; @@ -1326,6 +1325,8 @@ private List generatePersistentVolumeClaimsForPool(KafkaP volumeList.add(VolumeUtils.createConfigMapVolume(LOG_AND_METRICS_CONFIG_VOLUME_NAME, podName)); volumeList.add(VolumeUtils.createEmptyDirVolume("ready-files", "1Ki", "Memory")); + TemplateUtils.addAdditionalVolumes(templatePod, volumeList); + for (GenericKafkaListener listener : listeners) { if (listener.isTls() && listener.getConfiguration() != null @@ -1346,12 +1347,12 @@ private List generatePersistentVolumeClaimsForPool(KafkaP ); } - if (isListenerWithOAuth(listener)) { + if (ListenersUtils.isListenerWithOAuth(listener)) { KafkaListenerAuthenticationOAuth oauth = (KafkaListenerAuthenticationOAuth) listener.getAuth(); CertUtils.createTrustedCertificatesVolumes(volumeList, oauth.getTlsTrustedCertificates(), isOpenShift, "oauth-" + ListenersUtils.identifier(listener)); } - if (isListenerWithCustomAuth(listener)) { + if (ListenersUtils.isListenerWithCustomAuth(listener)) { KafkaListenerAuthenticationCustom custom = (KafkaListenerAuthenticationCustom) listener.getAuth(); volumeList.addAll(AuthenticationUtils.configureGenericSecretVolumes("custom-listener-" + ListenersUtils.identifier(listener), custom.getSecrets(), isOpenShift)); } @@ -1392,10 +1393,11 @@ private List getPodSetVolumes(String podName, Storage storage, PodTempla * Generates the volume mounts for a Kafka container * * @param storage Storage configuration for which the volume mounts should be generated + * @param containerTemplate The container template that contains additional volume mounts to include in the returned list * * @return List of volume mounts */ - private List getVolumeMounts(Storage storage) { + private List getVolumeMounts(Storage storage, ContainerTemplate containerTemplate) { List volumeMountList = new ArrayList<>(VolumeUtils.createVolumeMounts(storage, false)); volumeMountList.add(VolumeUtils.createTempDirVolumeMount()); volumeMountList.add(VolumeUtils.createVolumeMount(CLUSTER_CA_CERTS_VOLUME, CLUSTER_CA_CERTS_VOLUME_MOUNT)); @@ -1417,12 +1419,12 @@ private List getVolumeMounts(Storage storage) { volumeMountList.add(VolumeUtils.createVolumeMount("custom-" + identifier + "-certs", "/opt/kafka/certificates/custom-" + identifier + "-certs")); } - if (isListenerWithOAuth(listener)) { + if (ListenersUtils.isListenerWithOAuth(listener)) { KafkaListenerAuthenticationOAuth oauth = (KafkaListenerAuthenticationOAuth) listener.getAuth(); CertUtils.createTrustedCertificatesVolumeMounts(volumeMountList, oauth.getTlsTrustedCertificates(), TRUSTED_CERTS_BASE_VOLUME_MOUNT + "/oauth-" + identifier + "-certs/", "oauth-" + identifier); } - if (isListenerWithCustomAuth(listener)) { + if (ListenersUtils.isListenerWithCustomAuth(listener)) { KafkaListenerAuthenticationCustom custom = (KafkaListenerAuthenticationCustom) listener.getAuth(); volumeMountList.addAll(AuthenticationUtils.configureGenericSecretVolumeMounts("custom-listener-" + identifier, custom.getSecrets(), CUSTOM_AUTHN_SECRETS_VOLUME_MOUNT + "/custom-listener-" + identifier)); } @@ -1435,9 +1437,18 @@ private List getVolumeMounts(Storage storage) { if (authorization instanceof KafkaAuthorizationKeycloak keycloakAuthz) { CertUtils.createTrustedCertificatesVolumeMounts(volumeMountList, keycloakAuthz.getTlsTrustedCertificates(), TRUSTED_CERTS_BASE_VOLUME_MOUNT + "/authz-keycloak-certs/", "authz-keycloak"); } + + TemplateUtils.addAdditionalVolumeMounts(volumeMountList, containerTemplate); return volumeMountList; } + + private List getInitContainerVolumeMounts(KafkaPool pool) { + List volumeMountList = new ArrayList<>(); + volumeMountList.add(VolumeUtils.createVolumeMount(INIT_VOLUME_NAME, INIT_VOLUME_MOUNT)); + TemplateUtils.addAdditionalVolumeMounts(volumeMountList, pool.templateInitContainer); + return volumeMountList; + } /** * Returns a combined affinity: Adding the affinity needed for the "kafka-rack" to the user-provided affinity. @@ -1501,7 +1512,7 @@ protected List getInitContainerEnvVars(KafkaPool pool) { pool.resources, getInitContainerEnvVars(pool), null, - List.of(VolumeUtils.createVolumeMount(INIT_VOLUME_NAME, INIT_VOLUME_MOUNT)), + getInitContainerVolumeMounts(pool), null, null, imagePullPolicy @@ -1528,7 +1539,7 @@ protected List getInitContainerEnvVars(KafkaPool pool) { pool.resources, getEnvVars(pool), getContainerPortList(pool), - getVolumeMounts(pool.storage), + getVolumeMounts(pool.storage, pool.templateContainer), ProbeUtils.defaultBuilder(livenessProbeOptions).withNewExec().withCommand("/opt/kafka/kafka_liveness.sh").endExec().build(), ProbeUtils.defaultBuilder(readinessProbeOptions).withNewExec().withCommand("/opt/kafka/kafka_readiness.sh").endExec().build(), imagePullPolicy @@ -1552,7 +1563,7 @@ protected List getEnvVars(KafkaPool pool) { JvmOptionUtils.jvmSystemProperties(varList, pool.jvmOptions); for (GenericKafkaListener listener : listeners) { - if (isListenerWithOAuth(listener)) { + if (ListenersUtils.isListenerWithOAuth(listener)) { KafkaListenerAuthenticationOAuth oauth = (KafkaListenerAuthenticationOAuth) listener.getAuth(); if (oauth.getTlsTrustedCertificates() != null && !oauth.getTlsTrustedCertificates().isEmpty()) { diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaConnectBuild.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaConnectBuild.java index c8020ffdb0c..b210c807039 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaConnectBuild.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaConnectBuild.java @@ -279,6 +279,8 @@ private List getVolumes(boolean isOpenShift) { } else { throw new RuntimeException("Kubernetes build requires output of type `docker`."); } + + TemplateUtils.addAdditionalVolumes(templatePod, volumes); return volumes; } @@ -301,6 +303,7 @@ private List getVolumeMounts() { } else { throw new RuntimeException("Kubernetes build requires output of type `docker`."); } + TemplateUtils.addAdditionalVolumeMounts(volumeMounts, templateContainer); return volumeMounts; } diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaConnectCluster.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaConnectCluster.java index 723bbc706e7..6740b6fc1cd 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaConnectCluster.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaConnectCluster.java @@ -378,6 +378,8 @@ protected List getVolumes(boolean isOpenShift) { } AuthenticationUtils.configureClientAuthenticationVolumes(authentication, volumeList, "oauth-certs", isOpenShift); volumeList.addAll(getExternalConfigurationVolumes(isOpenShift)); + + TemplateUtils.addAdditionalVolumes(templatePod, volumeList); return volumeList; } @@ -440,6 +442,15 @@ protected List getVolumeMounts() { AuthenticationUtils.configureClientAuthenticationVolumeMounts(authentication, volumeMountList, TLS_CERTS_BASE_VOLUME_MOUNT, PASSWORD_VOLUME_MOUNT, OAUTH_TLS_CERTS_BASE_VOLUME_MOUNT, "oauth-certs"); volumeMountList.addAll(getExternalConfigurationVolumeMounts()); + TemplateUtils.addAdditionalVolumeMounts(volumeMountList, templateContainer); + + return volumeMountList; + } + + private List getInitContainerVolumeMounts() { + List volumeMountList = new ArrayList<>(); + volumeMountList.add(VolumeUtils.createVolumeMount(INIT_VOLUME_NAME, INIT_VOLUME_MOUNT)); + TemplateUtils.addAdditionalVolumeMounts(volumeMountList, templateInitContainer); return volumeMountList; } @@ -546,7 +557,7 @@ public StrimziPodSet generatePodSet(int replicas, resources, getInitContainerEnvVars(), null, - List.of(VolumeUtils.createVolumeMount(INIT_VOLUME_NAME, INIT_VOLUME_MOUNT)), + getInitContainerVolumeMounts(), null, null, imagePullPolicy diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaExporter.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaExporter.java index 50f31b7d896..68fc9168140 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaExporter.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaExporter.java @@ -11,6 +11,7 @@ import io.fabric8.kubernetes.api.model.LocalObjectReference; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.Volume; +import io.fabric8.kubernetes.api.model.VolumeMount; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicy; import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicyIngressRule; @@ -208,9 +209,7 @@ public Deployment generateDeployment(Map podAnnotations, boolean resources, getEnvVars(), getContainerPortList(), - List.of(VolumeUtils.createTempDirVolumeMount(), - VolumeUtils.createVolumeMount(KAFKA_EXPORTER_CERTS_VOLUME_NAME, KAFKA_EXPORTER_CERTS_VOLUME_MOUNT), - VolumeUtils.createVolumeMount(CLUSTER_CA_CERTS_VOLUME_NAME, CLUSTER_CA_CERTS_VOLUME_MOUNT)), + getVolumeMounts(), ProbeUtils.httpProbe(livenessProbeOptions, "/healthz", MetricsModel.METRICS_PORT_NAME), ProbeUtils.httpProbe(readinessProbeOptions, "/healthz", MetricsModel.METRICS_PORT_NAME), imagePullPolicy @@ -260,6 +259,19 @@ private List getVolumes(boolean isOpenShift) { volumeList.add(VolumeUtils.createTempDirVolume(templatePod)); volumeList.add(VolumeUtils.createSecretVolume(KAFKA_EXPORTER_CERTS_VOLUME_NAME, KafkaExporterResources.secretName(cluster), isOpenShift)); volumeList.add(VolumeUtils.createSecretVolume(CLUSTER_CA_CERTS_VOLUME_NAME, AbstractModel.clusterCaCertSecretName(cluster), isOpenShift)); + + TemplateUtils.addAdditionalVolumes(templatePod, volumeList); + + return volumeList; + } + + private List getVolumeMounts() { + List volumeList = new ArrayList<>(3); + volumeList.add(VolumeUtils.createTempDirVolumeMount()); + volumeList.add(VolumeUtils.createVolumeMount(KAFKA_EXPORTER_CERTS_VOLUME_NAME, KAFKA_EXPORTER_CERTS_VOLUME_MOUNT)); + volumeList.add(VolumeUtils.createVolumeMount(CLUSTER_CA_CERTS_VOLUME_NAME, CLUSTER_CA_CERTS_VOLUME_MOUNT)); + + TemplateUtils.addAdditionalVolumeMounts(volumeList, templateContainer); return volumeList; } diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaMirrorMaker2Cluster.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaMirrorMaker2Cluster.java index afbaceaa791..3f1d5aedab9 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaMirrorMaker2Cluster.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/KafkaMirrorMaker2Cluster.java @@ -197,6 +197,9 @@ protected List getVolumeMounts() { AuthenticationUtils.configureClientAuthenticationVolumeMounts(mirrorMaker2Cluster.getAuthentication(), volumeMountList, tlsVolumeMountPath, passwordVolumeMountPath, oauthTlsVolumeMountPath, mirrorMaker2Cluster.getAlias() + "-oauth-certs", mirrorMaker2Cluster.getAlias() + '-', true, oauthVolumeMountPath); } + + TemplateUtils.addAdditionalVolumeMounts(volumeMountList, templateContainer); + return volumeMountList; } diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/TemplateUtils.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/TemplateUtils.java index a1aeec68396..9812725a29e 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/TemplateUtils.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/TemplateUtils.java @@ -4,16 +4,39 @@ */ package io.strimzi.operator.cluster.model; +import io.fabric8.kubernetes.api.model.Volume; +import io.fabric8.kubernetes.api.model.VolumeBuilder; +import io.fabric8.kubernetes.api.model.VolumeMount; +import io.strimzi.api.kafka.model.common.template.AdditionalVolume; +import io.strimzi.api.kafka.model.common.template.ContainerTemplate; import io.strimzi.api.kafka.model.common.template.DeploymentStrategy; import io.strimzi.api.kafka.model.common.template.DeploymentTemplate; import io.strimzi.api.kafka.model.common.template.HasMetadataTemplate; +import io.strimzi.api.kafka.model.common.template.PodTemplate; +import io.strimzi.operator.common.model.InvalidResourceException; +import java.util.List; import java.util.Map; +import java.util.regex.Pattern; /** * Shared methods for working with Strimzi API templates */ public class TemplateUtils { + /** + * This is a constant that represents an allowed mountable path in the file system. + * It is used to prevent the creation of volumes outside this path. + */ + protected static final String ALLOWED_MOUNT_PATH = "/mnt"; + /** + * This Pattern defines a regex for validating volume names with the following criteria: + * Length: Must contain at most 63 characters. + * Characters: Can only contain lowercase alphanumeric characters, '-', '.', or '_'. + * Start: Must start with an alphanumeric character. + * End: Must end with an alphanumeric character. + **/ + /* test */ final static Pattern VOLUME_NAME_REGEX = Pattern.compile("^(?=.{0,63}$)[a-zA-Z0-9][a-zA-Z0-9-._]*[a-zA-Z0-9]$"); + /** * Extracts custom labels configured through the Strimzi API resource templates. This method deals the null checks * and makes the code using it more easy to read. @@ -31,6 +54,85 @@ public static Map labels(HasMetadataTemplate template) { } } + /** + * Add additional volumes for a given pod template and a list of existing volumes. + * + * @param templatePod The pod template that contains the additional volumes. + * @param existingVolumes The list of existing volumes to which the additional volumes will be added. + */ + public static void addAdditionalVolumes(PodTemplate templatePod, List existingVolumes) { + if (templatePod == null || templatePod.getVolumes() == null) { + return; + } + + // Extract the names and paths of the existing volumes + List existingVolumeNames = existingVolumes.stream().map(Volume::getName).toList(); + + // Check if there are any invalid volume names + List invalidNames = existingVolumeNames.stream().filter(name -> !VOLUME_NAME_REGEX.matcher(name).matches()).toList(); + + // Find duplicate names in the additional volumes + List duplicateNames = templatePod.getVolumes().stream() + .map(AdditionalVolume::getName) + .filter(existingVolumeNames::contains) + .toList(); + + // Throw an exception if there are any invalid volume names + if (!invalidNames.isEmpty()) { + throw new InvalidResourceException("Volume names " + invalidNames + " are invalid and do not match the pattern " + VOLUME_NAME_REGEX); + } + + // Throw an exception if duplicates are found + if (!duplicateNames.isEmpty()) { + throw new InvalidResourceException("Duplicate volume names found in additional volumes: " + duplicateNames); + } + + templatePod.getVolumes().forEach(volumeConfig -> existingVolumes.add(createVolumeFromConfig(volumeConfig))); + } + + /** + * Add additional volume mounts to the given list of volume mounts. Validation is performed to ensure none of the + * additional volume mount paths are forbidden. + * + * @param volumeMounts The list of volume mounts to be added to + * @param containerTemplate The container template that contains the additional volumes. + * @throws RuntimeException If a forbidden mount path is used. + */ + public static void addAdditionalVolumeMounts(List volumeMounts, ContainerTemplate containerTemplate) { + if (containerTemplate == null || containerTemplate.getVolumeMounts() == null || volumeMounts == null) { + return; + } + + boolean isForbiddenPath = containerTemplate.getVolumeMounts().stream().anyMatch(additionalVolume -> !additionalVolume.getMountPath().startsWith(ALLOWED_MOUNT_PATH)); + + if (isForbiddenPath) { + throw new InvalidResourceException(String.format("Forbidden path found in additional volumes. Should start with %s", ALLOWED_MOUNT_PATH)); + } + + volumeMounts.addAll(containerTemplate.getVolumeMounts()); + } + + /** + * Creates a kubernetes Volume object from the provided Volume configuration + * + * @param volumeConfig The configuration for the additional volume + * @return A Volume object + */ + private static Volume createVolumeFromConfig(AdditionalVolume volumeConfig) { + VolumeBuilder volumeBuilder = new VolumeBuilder().withName(volumeConfig.getName()); + if (volumeConfig.getConfigMap() != null) { + volumeBuilder.withNewConfigMap().withName(volumeConfig.getConfigMap().getName()).endConfigMap(); + } else if (volumeConfig.getSecret() != null) { + volumeBuilder.withNewSecret().withSecretName(volumeConfig.getSecret().getSecretName()).endSecret(); + } else if (volumeConfig.getEmptyDir() != null) { + volumeBuilder.withNewEmptyDir().withMedium(volumeConfig.getEmptyDir().getMedium()).endEmptyDir(); + } else if (volumeConfig.getPersistentVolumeClaim() != null) { + volumeBuilder.withPersistentVolumeClaim(volumeConfig.getPersistentVolumeClaim()); + } + + return volumeBuilder.build(); + } + /** * Extracts custom annotations configured through the Strimzi API resource templates. This method deals the null * checks and makes the code using it more easy to read. @@ -56,7 +158,7 @@ public static Map annotations(HasMetadataTemplate template) { * * @return Custom deployment strategy or default value if not defined */ - public static DeploymentStrategy deploymentStrategy(DeploymentTemplate template, DeploymentStrategy defaultValue) { + public static DeploymentStrategy deploymentStrategy(DeploymentTemplate template, DeploymentStrategy defaultValue) { return template != null && template.getDeploymentStrategy() != null ? template.getDeploymentStrategy() : defaultValue; } } diff --git a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/ZookeeperCluster.java b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/ZookeeperCluster.java index 17e1852d65f..b4b10b5ae55 100644 --- a/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/ZookeeperCluster.java +++ b/cluster-operator/src/main/java/io/strimzi/operator/cluster/model/ZookeeperCluster.java @@ -537,6 +537,8 @@ private List getPodSetVolumes(String podName, boolean isOpenShift) { volumeList.add(VolumeUtils.createSecretVolume(ZOOKEEPER_NODE_CERTIFICATES_VOLUME_NAME, KafkaResources.zookeeperSecretName(cluster), isOpenShift)); volumeList.add(VolumeUtils.createSecretVolume(ZOOKEEPER_CLUSTER_CA_VOLUME_NAME, AbstractModel.clusterCaCertSecretName(cluster), isOpenShift)); volumeList.addAll(VolumeUtils.createPodSetVolumes(podName, storage, false)); + + TemplateUtils.addAdditionalVolumes(templatePod, volumeList); return volumeList; } @@ -568,6 +570,8 @@ private List getVolumeMounts() { volumeMountList.add(VolumeUtils.createVolumeMount(ZOOKEEPER_NODE_CERTIFICATES_VOLUME_NAME, ZOOKEEPER_NODE_CERTIFICATES_VOLUME_MOUNT)); volumeMountList.add(VolumeUtils.createVolumeMount(ZOOKEEPER_CLUSTER_CA_VOLUME_NAME, ZOOKEEPER_CLUSTER_CA_VOLUME_MOUNT)); + TemplateUtils.addAdditionalVolumeMounts(volumeMountList, templateContainer); + return volumeMountList; } diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/CruiseControlTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/CruiseControlTest.java index e0a220e0396..6105d182c13 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/CruiseControlTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/CruiseControlTest.java @@ -20,6 +20,8 @@ import io.fabric8.kubernetes.api.model.ResourceRequirements; import io.fabric8.kubernetes.api.model.ResourceRequirementsBuilder; import io.fabric8.kubernetes.api.model.SecretBuilder; +import io.fabric8.kubernetes.api.model.SecretVolumeSource; +import io.fabric8.kubernetes.api.model.SecretVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.SecurityContext; import io.fabric8.kubernetes.api.model.SecurityContextBuilder; import io.fabric8.kubernetes.api.model.Service; @@ -28,6 +30,7 @@ import io.fabric8.kubernetes.api.model.TolerationBuilder; import io.fabric8.kubernetes.api.model.Volume; import io.fabric8.kubernetes.api.model.VolumeMount; +import io.fabric8.kubernetes.api.model.VolumeMountBuilder; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicy; import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicyIngressRule; @@ -39,6 +42,8 @@ import io.strimzi.api.kafka.model.common.SystemPropertyBuilder; import io.strimzi.api.kafka.model.common.metrics.JmxPrometheusExporterMetricsBuilder; import io.strimzi.api.kafka.model.common.metrics.MetricsConfig; +import io.strimzi.api.kafka.model.common.template.AdditionalVolume; +import io.strimzi.api.kafka.model.common.template.AdditionalVolumeBuilder; import io.strimzi.api.kafka.model.common.template.IpFamily; import io.strimzi.api.kafka.model.common.template.IpFamilyPolicy; import io.strimzi.api.kafka.model.kafka.EphemeralStorage; @@ -108,7 +113,6 @@ import static org.hamcrest.Matchers.hasProperty; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; - @SuppressWarnings({ "checkstyle:ClassDataAbstractionCoupling", "checkstyle:ClassFanOutComplexity" @@ -692,6 +696,21 @@ public void testTemplate() { .withHostnames("my-host-3") .withIp("192.168.1.87") .build(); + + SecretVolumeSource secret = new SecretVolumeSourceBuilder() + .withSecretName("secret1") + .build(); + + List additionalVolumes = singletonList(new AdditionalVolumeBuilder() + .withName("secret-volume-name") + .withSecret(secret) + .build()); + + List additionalVolumeMounts = singletonList(new VolumeMountBuilder() + .withName("secret-volume-name") + .withMountPath("/mnt/secret-volume-path") + .withSubPath("def") + .build()); CruiseControlSpec cruiseControlSpec = new CruiseControlSpecBuilder() .withImage(ccImage) @@ -702,31 +721,35 @@ public void testTemplate() { .withAnnotations(depAnots) .endMetadata() .endDeployment() - .withNewPod() - .withNewMetadata() - .withLabels(podLabels) - .withAnnotations(podAnots) - .endMetadata() - .withPriorityClassName("top-priority") - .withSchedulerName("my-scheduler") - .withHostAliases(hostAlias1, hostAlias2) - .withAffinity(affinity) - .withTolerations(tolerations) - .endPod() - .withNewApiService() - .withNewMetadata() - .withLabels(svcLabels) - .withAnnotations(svcAnots) - .endMetadata() - .withIpFamilyPolicy(IpFamilyPolicy.PREFER_DUAL_STACK) - .withIpFamilies(IpFamily.IPV6, IpFamily.IPV4) - .endApiService() - .withNewServiceAccount() - .withNewMetadata() - .withLabels(saLabels) - .withAnnotations(saAnots) - .endMetadata() - .endServiceAccount() + .withNewPod() + .withNewMetadata() + .withLabels(podLabels) + .withAnnotations(podAnots) + .endMetadata() + .withPriorityClassName("top-priority") + .withSchedulerName("my-scheduler") + .withHostAliases(hostAlias1, hostAlias2) + .withAffinity(affinity) + .withTolerations(tolerations) + .withVolumes(additionalVolumes) + .endPod() + .withNewCruiseControlContainer() + .withVolumeMounts(additionalVolumeMounts) + .endCruiseControlContainer() + .withNewApiService() + .withNewMetadata() + .withLabels(svcLabels) + .withAnnotations(svcAnots) + .endMetadata() + .withIpFamilyPolicy(IpFamilyPolicy.PREFER_DUAL_STACK) + .withIpFamilies(IpFamily.IPV6, IpFamily.IPV4) + .endApiService() + .withNewServiceAccount() + .withNewMetadata() + .withLabels(saLabels) + .withAnnotations(saAnots) + .endMetadata() + .endServiceAccount() .endTemplate() .build(); @@ -748,7 +771,9 @@ public void testTemplate() { assertThat(dep.getSpec().getTemplate().getSpec().getAffinity(), is(affinity)); assertThat(dep.getSpec().getTemplate().getSpec().getTolerations(), is(tolerations)); assertThat(dep.getSpec().getTemplate().getSpec().getHostAliases(), containsInAnyOrder(hostAlias1, hostAlias2)); - + assertThat(dep.getSpec().getTemplate().getSpec().getVolumes().stream().filter(volume -> "secret-volume-name".equals(volume.getName())).iterator().next().getSecret(), is(secret)); + assertThat(dep.getSpec().getTemplate().getSpec().getContainers().get(0).getVolumeMounts().stream().filter(volumeMount -> "secret-volume-name".equals(volumeMount.getName())).iterator().next(), is(additionalVolumeMounts.get(0))); + // Check Service svcLabels.putAll(expectedLabels()); Service svc = cc.generateService(); diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/EntityOperatorTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/EntityOperatorTest.java index 00b5a38d3df..75b574f3b35 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/EntityOperatorTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/EntityOperatorTest.java @@ -11,6 +11,8 @@ import io.fabric8.kubernetes.api.model.LocalObjectReference; import io.fabric8.kubernetes.api.model.PodSecurityContextBuilder; import io.fabric8.kubernetes.api.model.Quantity; +import io.fabric8.kubernetes.api.model.SecretVolumeSource; +import io.fabric8.kubernetes.api.model.SecretVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.SecurityContext; import io.fabric8.kubernetes.api.model.SecurityContextBuilder; import io.fabric8.kubernetes.api.model.ServiceAccount; @@ -20,6 +22,7 @@ import io.fabric8.kubernetes.api.model.TopologySpreadConstraintBuilder; import io.fabric8.kubernetes.api.model.Volume; import io.fabric8.kubernetes.api.model.VolumeMount; +import io.fabric8.kubernetes.api.model.VolumeMountBuilder; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicy; import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicyIngressRule; @@ -29,6 +32,8 @@ import io.fabric8.kubernetes.api.model.rbac.Role; import io.strimzi.api.kafka.model.common.Constants; import io.strimzi.api.kafka.model.common.ContainerEnvVar; +import io.strimzi.api.kafka.model.common.template.AdditionalVolume; +import io.strimzi.api.kafka.model.common.template.AdditionalVolumeBuilder; import io.strimzi.api.kafka.model.common.template.ContainerTemplate; import io.strimzi.api.kafka.model.kafka.Kafka; import io.strimzi.api.kafka.model.kafka.KafkaBuilder; @@ -238,6 +243,21 @@ public void testTemplate() { .withWhenUnsatisfiable("ScheduleAnyway") .withLabelSelector(new LabelSelectorBuilder().withMatchLabels(singletonMap("label", "value")).build()) .build(); + + SecretVolumeSource secret = new SecretVolumeSourceBuilder() + .withSecretName("secret1") + .build(); + + List additionalVolumes = singletonList(new AdditionalVolumeBuilder() + .withName("secret-volume-name") + .withSecret(secret) + .build()); + + List additionalVolumeMounts = singletonList(new VolumeMountBuilder() + .withName("secret-volume-name") + .withMountPath("/mnt/secret") + .withSubPath("def") + .build()); Kafka resource = new KafkaBuilder(ResourceUtils.createKafka(namespace, cluster, replicas, image, healthDelay, healthTimeout)) @@ -262,7 +282,14 @@ public void testTemplate() { .withTolerations(singletonList(toleration)) .withTopologySpreadConstraints(tsc1, tsc2) .withEnableServiceLinks(false) + .withVolumes(additionalVolumes) .endPod() + .withNewTopicOperatorContainer() + .withVolumeMounts(additionalVolumeMounts) + .endTopicOperatorContainer() + .withNewUserOperatorContainer() + .withVolumeMounts(additionalVolumeMounts) + .endUserOperatorContainer() .withNewEntityOperatorRole() .withNewMetadata() .withLabels(rLabels) @@ -295,6 +322,9 @@ public void testTemplate() { assertThat(dep.getSpec().getTemplate().getSpec().getTopologySpreadConstraints(), containsInAnyOrder(tsc1, tsc2)); assertThat(dep.getSpec().getTemplate().getSpec().getEnableServiceLinks(), is(false)); assertThat(dep.getSpec().getTemplate().getSpec().getTolerations(), is(singletonList(toleration))); + assertThat(dep.getSpec().getTemplate().getSpec().getVolumes().stream().filter(volume -> "secret-volume-name".equals(volume.getName())).iterator().next().getSecret(), is(secret)); + assertThat(dep.getSpec().getTemplate().getSpec().getContainers().get(0).getVolumeMounts().stream().filter(volumeMount -> "secret-volume-name".equals(volumeMount.getName())).iterator().next(), is(additionalVolumeMounts.get(0))); + assertThat(dep.getSpec().getTemplate().getSpec().getContainers().get(1).getVolumeMounts().stream().filter(volumeMount -> "secret-volume-name".equals(volumeMount.getName())).iterator().next(), is(additionalVolumeMounts.get(0))); // Generate Role metadata Role crb = entityOperator.generateRole(null, namespace); diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeClusterTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeClusterTest.java index e80d52573fe..258e2db3e14 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeClusterTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaBridgeClusterTest.java @@ -6,6 +6,8 @@ import io.fabric8.kubernetes.api.model.Affinity; import io.fabric8.kubernetes.api.model.AffinityBuilder; +import io.fabric8.kubernetes.api.model.ConfigMapVolumeSource; +import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.EnvVar; import io.fabric8.kubernetes.api.model.EnvVarBuilder; @@ -17,13 +19,17 @@ import io.fabric8.kubernetes.api.model.PodSpec; import io.fabric8.kubernetes.api.model.Quantity; import io.fabric8.kubernetes.api.model.ResourceRequirementsBuilder; +import io.fabric8.kubernetes.api.model.SecretVolumeSource; +import io.fabric8.kubernetes.api.model.SecretVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServiceAccount; import io.fabric8.kubernetes.api.model.Toleration; import io.fabric8.kubernetes.api.model.TolerationBuilder; import io.fabric8.kubernetes.api.model.TopologySpreadConstraint; import io.fabric8.kubernetes.api.model.TopologySpreadConstraintBuilder; +import io.fabric8.kubernetes.api.model.Volume; import io.fabric8.kubernetes.api.model.VolumeMount; +import io.fabric8.kubernetes.api.model.VolumeMountBuilder; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.policy.v1.PodDisruptionBudget; import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding; @@ -42,6 +48,8 @@ import io.strimzi.api.kafka.model.common.SystemPropertyBuilder; import io.strimzi.api.kafka.model.common.authentication.KafkaClientAuthenticationOAuthBuilder; import io.strimzi.api.kafka.model.common.authentication.KafkaClientAuthenticationTlsBuilder; +import io.strimzi.api.kafka.model.common.template.AdditionalVolume; +import io.strimzi.api.kafka.model.common.template.AdditionalVolumeBuilder; import io.strimzi.api.kafka.model.common.template.ContainerTemplate; import io.strimzi.api.kafka.model.common.template.DeploymentStrategy; import io.strimzi.api.kafka.model.common.template.IpFamily; @@ -84,7 +92,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; @ParallelSuite -@SuppressWarnings({"checkstyle:ClassDataAbstractionCoupling"}) +@SuppressWarnings({"checkstyle:ClassDataAbstractionCoupling", "checkstyle:ClassFanOutComplexity"}) public class KafkaBridgeClusterTest { private static final SharedEnvironmentProvider SHARED_ENV_PROVIDER = new MockSharedEnvironmentProvider(); @@ -163,6 +171,14 @@ protected List getExpectedEnvVars() { return expected; } + private static Volume getVolume(Deployment dep, String volumeName) { + return dep.getSpec().getTemplate().getSpec().getVolumes().stream().filter(volume -> volumeName.equals(volume.getName())).iterator().next(); + } + + private static VolumeMount getVolumeMount(Container container, String volumeName) { + return container.getVolumeMounts().stream().filter(volumeMount -> volumeName.equals(volumeMount.getName())).iterator().next(); + } + @ParallelTest public void testDefaultValues() { KafkaBridgeCluster kbc = KafkaBridgeCluster.fromCrd(Reconciliation.DUMMY_RECONCILIATION, ResourceUtils.createEmptyKafkaBridge(namespace, cluster), SHARED_ENV_PROVIDER); @@ -407,6 +423,7 @@ public void testGenerateDeploymentWithPlainAuth() { } @ParallelTest + @SuppressWarnings({"checkstyle:methodlength"}) public void testTemplate() { Map depLabels = TestUtils.map("l1", "v1", "l2", "v2", Labels.KUBERNETES_PART_OF_LABEL, "custom-part", @@ -461,6 +478,21 @@ public void testTemplate() { .withWhenUnsatisfiable("ScheduleAnyway") .withLabelSelector(new LabelSelectorBuilder().withMatchLabels(singletonMap("label", "value")).build()) .build(); + + SecretVolumeSource secret = new SecretVolumeSourceBuilder() + .withSecretName("secret1") + .build(); + + List additionalVolumes = singletonList(new AdditionalVolumeBuilder() + .withName("secret-volume-name") + .withSecret(secret) + .build()); + + List additionalVolumeMounts = singletonList(new VolumeMountBuilder() + .withName("secret-volume-name") + .withMountPath("/mnt/secret") + .withSubPath("def") + .build()); KafkaBridge resource = new KafkaBridgeBuilder(this.resource) .editSpec() @@ -484,7 +516,11 @@ public void testTemplate() { .withTopologySpreadConstraints(tsc1, tsc2) .withEnableServiceLinks(false) .withTmpDirSizeLimit("10Mi") + .withVolumes(additionalVolumes) .endPod() + .withNewBridgeContainer() + .withVolumeMounts(additionalVolumeMounts) + .endBridgeContainer() .withNewApiService() .withNewMetadata() .withLabels(svcLabels) @@ -526,7 +562,9 @@ public void testTemplate() { assertThat(dep.getSpec().getTemplate().getSpec().getTolerations(), is(tolerations)); assertThat(dep.getSpec().getTemplate().getSpec().getTopologySpreadConstraints(), containsInAnyOrder(tsc1, tsc2)); assertThat(dep.getSpec().getTemplate().getSpec().getEnableServiceLinks(), is(false)); - assertThat(dep.getSpec().getTemplate().getSpec().getVolumes().get(0).getEmptyDir().getSizeLimit(), is(new Quantity("10Mi"))); + assertThat(getVolume(dep, VolumeUtils.STRIMZI_TMP_DIRECTORY_DEFAULT_VOLUME_NAME).getEmptyDir().getSizeLimit(), is(new Quantity("10Mi"))); + assertThat(getVolume(dep, "secret-volume-name").getSecret(), is(secret)); + assertThat(getVolumeMount(dep.getSpec().getTemplate().getSpec().getContainers().get(0), "secret-volume-name"), is(additionalVolumeMounts.get(0))); // Check Service Service svc = kbc.generateService(); @@ -811,15 +849,54 @@ public void testGenerateDeploymentWithRackAndCustomInitImage() { assertRackAwareDeploymentConfigured(resource, customImage); } + + @ParallelTest + public void testGenerateDeploymentWithRackAndInitVolumeMounts() { + + ConfigMapVolumeSource configMap = new ConfigMapVolumeSourceBuilder() + .withName("config-map-name") + .build(); + + AdditionalVolume additionalVolume = new AdditionalVolumeBuilder() + .withName("config-map-volume-name") + .withConfigMap(configMap) + .build(); + + VolumeMount additionalVolumeMount = new VolumeMountBuilder() + .withName("config-map-volume-name-2") + .withMountPath("/mnt/config-map") + .withSubPath("def") + .build(); + + KafkaBridge resource = new KafkaBridgeBuilder(this.resource) + .editOrNewSpec() + .withNewRack() + .withTopologyKey("topology-key") + .endRack() + .withNewTemplate() + .withNewPod() + .withVolumes(singletonList(additionalVolume)) + .endPod() + .withNewInitContainer() + .withVolumeMounts(singletonList(additionalVolumeMount)) + .endInitContainer() + .endTemplate() + .endSpec() + .build(); + Deployment deployment = assertRackAwareDeploymentConfigured(resource, "quay.io/strimzi/operator:latest"); + assertThat(getVolume(deployment, "config-map-volume-name").getConfigMap(), is(configMap)); + assertThat(getVolumeMount(deployment.getSpec().getTemplate().getSpec().getInitContainers().get(0), "config-map-volume-name-2"), is(additionalVolumeMount)); - private static void assertRackAwareDeploymentConfigured(final KafkaBridge resource, final String expectedInitImage) { + } + + private static Deployment assertRackAwareDeploymentConfigured(final KafkaBridge resource, final String expectedInitImage) { KafkaBridgeCluster bridgeCluster = KafkaBridgeCluster.fromCrd(Reconciliation.DUMMY_RECONCILIATION, resource, SHARED_ENV_PROVIDER); Deployment deployment = bridgeCluster.generateDeployment(new HashMap<>(), false, null, null); assertThat(resource.getSpec().getRack(), is(notNullValue())); PodSpec podSpec = deployment.getSpec().getTemplate().getSpec(); - + List containers = podSpec.getContainers(); assertThat(containers, is(notNullValue())); assertThat(containers, hasSize(1)); @@ -849,13 +926,11 @@ private static void assertRackAwareDeploymentConfigured(final KafkaBridge resour assertThat(initEnv.stream().filter(var -> ENV_VAR_KAFKA_INIT_INIT_FOLDER_KEY.equals(var.getName())).findFirst().orElseThrow().getValue(), is(KafkaBridgeCluster.INIT_VOLUME_MOUNT)); assertThat(initEnv.stream().filter(var -> AbstractModel.ENV_VAR_KAFKA_INIT_NODE_NAME.equals(var.getName())).findFirst().orElseThrow().getValueFrom().getFieldRef().getFieldPath(), is("spec.nodeName")); - assertThat(container.getVolumeMounts(), hasSize(1)); - final VolumeMount volumeMount = container.getVolumeMounts().get(0); - assertThat(volumeMount.getName(), is(KafkaBridgeCluster.INIT_VOLUME_NAME)); - assertThat(volumeMount.getMountPath(), is(KafkaBridgeCluster.INIT_VOLUME_MOUNT)); + assertThat(getVolumeMount(container, KafkaBridgeCluster.INIT_VOLUME_NAME).getMountPath(), is(KafkaBridgeCluster.INIT_VOLUME_MOUNT)); + + return deployment; } - @ParallelTest public void testClusterRoleBindingRack() { String testNamespace = "other-namespace"; diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaClusterTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaClusterTest.java index 5e0ce40b4b0..1b953e5b595 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaClusterTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaClusterTest.java @@ -12,16 +12,20 @@ import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.LabelSelectorRequirementBuilder; import io.fabric8.kubernetes.api.model.PersistentVolumeClaim; +import io.fabric8.kubernetes.api.model.PodSpec; import io.fabric8.kubernetes.api.model.Quantity; import io.fabric8.kubernetes.api.model.ResourceRequirements; import io.fabric8.kubernetes.api.model.ResourceRequirementsBuilder; import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretVolumeSource; +import io.fabric8.kubernetes.api.model.SecretVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.SecurityContext; import io.fabric8.kubernetes.api.model.SecurityContextBuilder; import io.fabric8.kubernetes.api.model.Service; import io.fabric8.kubernetes.api.model.ServiceAccount; import io.fabric8.kubernetes.api.model.Volume; import io.fabric8.kubernetes.api.model.VolumeMount; +import io.fabric8.kubernetes.api.model.VolumeMountBuilder; import io.fabric8.kubernetes.api.model.networking.v1.Ingress; import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicy; import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicyIngressRule; @@ -41,6 +45,8 @@ import io.strimzi.api.kafka.model.common.jmx.KafkaJmxOptionsBuilder; import io.strimzi.api.kafka.model.common.metrics.JmxPrometheusExporterMetricsBuilder; import io.strimzi.api.kafka.model.common.metrics.MetricsConfig; +import io.strimzi.api.kafka.model.common.template.AdditionalVolume; +import io.strimzi.api.kafka.model.common.template.AdditionalVolumeBuilder; import io.strimzi.api.kafka.model.common.template.ContainerTemplate; import io.strimzi.api.kafka.model.common.template.ExternalTrafficPolicy; import io.strimzi.api.kafka.model.common.template.IpFamily; @@ -66,6 +72,7 @@ import io.strimzi.api.kafka.model.kafka.listener.KafkaListenerAuthenticationOAuthBuilder; import io.strimzi.api.kafka.model.kafka.listener.KafkaListenerType; import io.strimzi.api.kafka.model.kafka.listener.NodeAddressType; +import io.strimzi.api.kafka.model.podset.StrimziPodSet; import io.strimzi.certs.OpenSslCertManager; import io.strimzi.operator.cluster.KafkaVersionTestUtils; import io.strimzi.operator.cluster.model.jmx.JmxModel; @@ -519,6 +526,21 @@ public void testTemplate() { Map saLabels = TestUtils.map("l21", "v21", "l22", "v22"); Map saAnnotations = TestUtils.map("a21", "v21", "a22", "v22"); + + SecretVolumeSource secret = new SecretVolumeSourceBuilder() + .withSecretName("secret1") + .build(); + + AdditionalVolume additionalVolume = new AdditionalVolumeBuilder() + .withName("secret-volume-name") + .withSecret(secret) + .build(); + + VolumeMount additionalVolumeMount = new VolumeMountBuilder() + .withName("secret-volume-name") + .withMountPath("/mnt/secret-volume") + .withSubPath("def") + .build(); Kafka kafkaAssembly = new KafkaBuilder(KAFKA) .editSpec() @@ -536,6 +558,12 @@ public void testTemplate() { .withTls(true) .build()) .withNewTemplate() + .withNewPod() + .withVolumes(additionalVolume) + .endPod() + .withNewKafkaContainer() + .withVolumeMounts(additionalVolumeMount) + .endKafkaContainer() .withNewBootstrapService() .withNewMetadata() .withLabels(svcLabels) @@ -650,6 +678,11 @@ public void testTemplate() { ServiceAccount sa = kc.generateServiceAccount(); assertThat(sa.getMetadata().getLabels().entrySet().containsAll(saLabels.entrySet()), is(true)); assertThat(sa.getMetadata().getAnnotations().entrySet().containsAll(saAnnotations.entrySet()), is(true)); + + List podSets = kc.generatePodSets(false, null, null, i -> Map.of()); + PodSpec podSpec = podSets.get(0).getSpec().getPods().stream().map(PodSetUtils::mapToPod).toList().get(0).getSpec(); + assertThat(podSpec.getVolumes().stream().filter(volume -> "secret-volume-name".equals(volume.getName())).iterator().next().getSecret(), is(secret)); + assertThat(podSpec.getContainers().get(0).getVolumeMounts().stream().filter(volumeMount -> "secret-volume-name".equals(volumeMount.getName())).iterator().next(), is(additionalVolumeMount)); } @ParallelTest diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaConnectBuildTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaConnectBuildTest.java index 2c8bbb1c621..c26818909c2 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaConnectBuildTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaConnectBuildTest.java @@ -8,9 +8,15 @@ import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.Quantity; import io.fabric8.kubernetes.api.model.ResourceRequirementsBuilder; +import io.fabric8.kubernetes.api.model.SecretVolumeSource; +import io.fabric8.kubernetes.api.model.SecretVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.ServiceAccount; +import io.fabric8.kubernetes.api.model.VolumeMount; +import io.fabric8.kubernetes.api.model.VolumeMountBuilder; import io.fabric8.openshift.api.model.BuildConfig; import io.strimzi.api.kafka.model.common.ContainerEnvVarBuilder; +import io.strimzi.api.kafka.model.common.template.AdditionalVolume; +import io.strimzi.api.kafka.model.common.template.AdditionalVolumeBuilder; import io.strimzi.api.kafka.model.connect.KafkaConnect; import io.strimzi.api.kafka.model.connect.KafkaConnectBuilder; import io.strimzi.api.kafka.model.connect.KafkaConnectResources; @@ -428,6 +434,21 @@ public void testTemplate() { Map saLabels = TestUtils.map("l5", "v5", "l6", "v6"); Map saAnots = TestUtils.map("a5", "v5", "a6", "v6"); + SecretVolumeSource secret = new SecretVolumeSourceBuilder() + .withSecretName("secret1") + .build(); + + AdditionalVolume additionalVolume = new AdditionalVolumeBuilder() + .withName("secret-volume-name") + .withSecret(secret) + .build(); + + VolumeMount additionalVolumeMount = new VolumeMountBuilder() + .withName("secret-volume-name") + .withMountPath("/mnt/secret-volume") + .withSubPath("def") + .build(); + KafkaConnect kc = new KafkaConnectBuilder() .withNewMetadata() .withName(cluster) @@ -452,9 +473,11 @@ public void testTemplate() { .withPriorityClassName("top-priority") .withSchedulerName("my-scheduler") .withEnableServiceLinks(false) + .withVolumes(additionalVolume) .endBuildPod() .withNewBuildContainer() .withEnv(new ContainerEnvVarBuilder().withName("TEST_ENV_VAR").withValue("testValue").build()) + .withVolumeMounts(additionalVolumeMount) .endBuildContainer() .withNewBuildConfig() .withNewMetadata() @@ -482,6 +505,8 @@ public void testTemplate() { assertThat(pod.getSpec().getSchedulerName(), is("my-scheduler")); assertThat(pod.getSpec().getEnableServiceLinks(), is(false)); assertThat(pod.getSpec().getContainers().get(0).getEnv().stream().filter(env -> "TEST_ENV_VAR".equals(env.getName())).findFirst().orElseThrow().getValue(), is("testValue")); + assertThat(pod.getSpec().getContainers().get(0).getVolumeMounts().stream().filter(volumeMount -> "secret-volume-name".equals(volumeMount.getName())).iterator().next(), is(additionalVolumeMount)); + assertThat(pod.getSpec().getVolumes().stream().filter(volume -> "secret-volume-name".equals(volume.getName())).iterator().next().getSecret(), is(secret)); KafkaConnectDockerfile dockerfile = new KafkaConnectDockerfile("my-image:latest", kc.getSpec().getBuild(), SHARED_ENV_PROVIDER); BuildConfig bc = build.generateBuildConfig(dockerfile); diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaConnectClusterTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaConnectClusterTest.java index abfd0ba89d6..0f4ad84214c 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaConnectClusterTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaConnectClusterTest.java @@ -6,8 +6,11 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapKeySelectorBuilder; +import io.fabric8.kubernetes.api.model.ConfigMapVolumeSource; import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Container; +import io.fabric8.kubernetes.api.model.EmptyDirVolumeSource; +import io.fabric8.kubernetes.api.model.EmptyDirVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.EnvVar; import io.fabric8.kubernetes.api.model.EnvVarBuilder; import io.fabric8.kubernetes.api.model.HostAlias; @@ -22,6 +25,7 @@ import io.fabric8.kubernetes.api.model.ResourceRequirementsBuilder; import io.fabric8.kubernetes.api.model.Secret; import io.fabric8.kubernetes.api.model.SecretKeySelectorBuilder; +import io.fabric8.kubernetes.api.model.SecretVolumeSource; import io.fabric8.kubernetes.api.model.SecretVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.SecurityContext; import io.fabric8.kubernetes.api.model.SecurityContextBuilder; @@ -31,6 +35,7 @@ import io.fabric8.kubernetes.api.model.TopologySpreadConstraintBuilder; import io.fabric8.kubernetes.api.model.Volume; import io.fabric8.kubernetes.api.model.VolumeMount; +import io.fabric8.kubernetes.api.model.VolumeMountBuilder; import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicy; import io.fabric8.kubernetes.api.model.policy.v1.PodDisruptionBudget; import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding; @@ -46,6 +51,8 @@ import io.strimzi.api.kafka.model.common.metrics.JmxPrometheusExporterMetrics; import io.strimzi.api.kafka.model.common.metrics.JmxPrometheusExporterMetricsBuilder; import io.strimzi.api.kafka.model.common.metrics.MetricsConfig; +import io.strimzi.api.kafka.model.common.template.AdditionalVolume; +import io.strimzi.api.kafka.model.common.template.AdditionalVolumeBuilder; import io.strimzi.api.kafka.model.common.template.ContainerTemplate; import io.strimzi.api.kafka.model.common.template.IpFamily; import io.strimzi.api.kafka.model.common.template.IpFamilyPolicy; @@ -707,6 +714,7 @@ public void testPodSet() { } @ParallelTest + @SuppressWarnings({"checkstyle:methodlength"}) public void testTemplate() { Map spsLabels = TestUtils.map("l1", "v1", "l2", "v2", Labels.KUBERNETES_PART_OF_LABEL, "custom-part", @@ -752,6 +760,51 @@ public void testTemplate() { .withWhenUnsatisfiable("ScheduleAnyway") .withLabelSelector(new LabelSelectorBuilder().withMatchLabels(singletonMap("label", "value")).build()) .build(); + + ConfigMapVolumeSource configMap = new ConfigMapVolumeSourceBuilder() + .withName("configMap1") + .build(); + + SecretVolumeSource secret = new SecretVolumeSourceBuilder() + .withSecretName("secret1") + .build(); + + EmptyDirVolumeSource emptyDir = new EmptyDirVolumeSourceBuilder() + .withMedium("Memory") + .build(); + + AdditionalVolume additionalVolumeConfigMap = new AdditionalVolumeBuilder() + .withName("config-map-volume-name") + .withConfigMap(configMap) + .build(); + + AdditionalVolume additionalVolumeSecret = new AdditionalVolumeBuilder() + .withName("secret-volume-name") + .withSecret(secret) + .build(); + + AdditionalVolume additionalVolumeEmptyDir = new AdditionalVolumeBuilder() + .withName("empty-dir-volume-name") + .withEmptyDir(emptyDir) + .build(); + + VolumeMount additionalVolumeMountConfigMap = new VolumeMountBuilder() + .withName("config-map-volume-name") + .withMountPath("/mnt/config") + .withSubPath("def") + .build(); + + VolumeMount additionalVolumeMountSecret = new VolumeMountBuilder() + .withName("secret-volume-name") + .withMountPath("/mnt/secret") + .withSubPath("abc") + .build(); + + VolumeMount additionalVolumeMountEmptyDir = new VolumeMountBuilder() + .withName("empty-dir-volume-name") + .withMountPath("/mnt/empty-dir") + .withSubPath("def") + .build(); KafkaConnect resource = new KafkaConnectBuilder(this.resource) .editSpec() @@ -774,7 +827,14 @@ public void testTemplate() { .withTopologySpreadConstraints(tsc1, tsc2) .withEnableServiceLinks(false) .withTmpDirSizeLimit("10Mi") + .withVolumes(additionalVolumeSecret, additionalVolumeEmptyDir, additionalVolumeConfigMap) .endPod() + .withNewConnectContainer() + .withVolumeMounts(additionalVolumeMountSecret, additionalVolumeMountEmptyDir) + .endConnectContainer() + .withNewInitContainer() + .withVolumeMounts(additionalVolumeMountConfigMap) + .endInitContainer() .withNewApiService() .withNewMetadata() .withLabels(svcLabels) @@ -819,7 +879,13 @@ public void testTemplate() { assertThat(pod.getSpec().getHostAliases(), containsInAnyOrder(hostAlias1, hostAlias2)); assertThat(pod.getSpec().getTopologySpreadConstraints(), containsInAnyOrder(tsc1, tsc2)); assertThat(pod.getSpec().getEnableServiceLinks(), is(false)); - assertThat(pod.getSpec().getVolumes().get(0).getEmptyDir().getSizeLimit(), is(new Quantity("10Mi"))); + assertThat(getVolume(pod, VolumeUtils.STRIMZI_TMP_DIRECTORY_DEFAULT_VOLUME_NAME).getEmptyDir().getSizeLimit(), is(new Quantity("10Mi"))); + assertThat(getVolume(pod, additionalVolumeMountEmptyDir.getName()).getEmptyDir(), is(emptyDir)); + assertThat(getVolume(pod, additionalVolumeMountSecret.getName()).getSecret(), is(secret)); + assertThat(getVolume(pod, additionalVolumeMountConfigMap.getName()).getConfigMap(), is(configMap)); + assertThat(getVolumeMount(pod.getSpec().getContainers().get(0), additionalVolumeMountEmptyDir.getName()), is(additionalVolumeMountEmptyDir)); + assertThat(getVolumeMount(pod.getSpec().getContainers().get(0), additionalVolumeMountSecret.getName()), is(additionalVolumeMountSecret)); + assertThat(getVolumeMount(pod.getSpec().getInitContainers().get(0), additionalVolumeMountConfigMap.getName()), is(additionalVolumeMountConfigMap)); }); // Check Service @@ -844,6 +910,14 @@ public void testTemplate() { assertThat(sa.getMetadata().getLabels().entrySet().containsAll(saLabels.entrySet()), is(true)); assertThat(sa.getMetadata().getAnnotations().entrySet().containsAll(saAnots.entrySet()), is(true)); } + + private static Volume getVolume(Pod pod, String volumeName) { + return pod.getSpec().getVolumes().stream().filter(volume -> volumeName.equals(volume.getName())).iterator().next(); + } + + private static VolumeMount getVolumeMount(Container container, String volumeName) { + return container.getVolumeMounts().stream().filter(volumeMount -> volumeName.equals(volumeMount.getName())).iterator().next(); + } @ParallelTest public void testExternalConfigurationSecretEnvs() { diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaExporterTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaExporterTest.java index 9f24fb41dd2..de356b74d5f 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaExporterTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaExporterTest.java @@ -6,6 +6,8 @@ import io.fabric8.kubernetes.api.model.Affinity; import io.fabric8.kubernetes.api.model.AffinityBuilder; +import io.fabric8.kubernetes.api.model.ConfigMapVolumeSource; +import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.EnvVar; import io.fabric8.kubernetes.api.model.EnvVarBuilder; @@ -14,6 +16,7 @@ import io.fabric8.kubernetes.api.model.LabelSelectorBuilder; import io.fabric8.kubernetes.api.model.NodeSelectorTermBuilder; import io.fabric8.kubernetes.api.model.OwnerReference; +import io.fabric8.kubernetes.api.model.PodSpec; import io.fabric8.kubernetes.api.model.Quantity; import io.fabric8.kubernetes.api.model.ServiceAccount; import io.fabric8.kubernetes.api.model.Toleration; @@ -22,11 +25,14 @@ import io.fabric8.kubernetes.api.model.TopologySpreadConstraintBuilder; import io.fabric8.kubernetes.api.model.Volume; import io.fabric8.kubernetes.api.model.VolumeMount; +import io.fabric8.kubernetes.api.model.VolumeMountBuilder; import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicy; import io.strimzi.api.kafka.model.common.ContainerEnvVar; import io.strimzi.api.kafka.model.common.InlineLogging; import io.strimzi.api.kafka.model.common.metrics.JmxPrometheusExporterMetrics; +import io.strimzi.api.kafka.model.common.template.AdditionalVolume; +import io.strimzi.api.kafka.model.common.template.AdditionalVolumeBuilder; import io.strimzi.api.kafka.model.common.template.DeploymentStrategy; import io.strimzi.api.kafka.model.kafka.EphemeralStorage; import io.strimzi.api.kafka.model.kafka.Kafka; @@ -141,6 +147,14 @@ private List getExpectedEnvVars() { return expected; } + private static Volume getVolume(PodSpec podSpec, String volumeName) { + return podSpec.getVolumes().stream().filter(volume -> volumeName.equals(volume.getName())).iterator().next(); + } + + private static VolumeMount getVolumeMount(Container container, String volumeName) { + return container.getVolumeMounts().stream().filter(volumeMount -> volumeName.equals(volumeMount.getName())).iterator().next(); + } + @ParallelTest public void testFromConfigMapDefaultConfig() { Kafka resource = ResourceUtils.createKafka(namespace, cluster, replicas, null, @@ -388,6 +402,21 @@ public void testTemplate() { .withWhenUnsatisfiable("ScheduleAnyway") .withLabelSelector(new LabelSelectorBuilder().withMatchLabels(singletonMap("label", "value")).build()) .build(); + + ConfigMapVolumeSource configMap = new ConfigMapVolumeSourceBuilder() + .withName("configMap1") + .build(); + + AdditionalVolume additionalVolumeConfigMap = new AdditionalVolumeBuilder() + .withName("config-map-volume-name") + .withConfigMap(configMap) + .build(); + + VolumeMount additionalVolumeMountConfigMap = new VolumeMountBuilder() + .withName("config-map-volume-name-2") + .withMountPath("/mnt/config-map-path") + .withSubPath("def") + .build(); Kafka resource = new KafkaBuilder(ResourceUtils.createKafka(namespace, cluster, replicas, image, healthDelay, healthTimeout)) @@ -411,7 +440,11 @@ public void testTemplate() { .withTolerations(tolerations) .withTopologySpreadConstraints(tsc1, tsc2) .withEnableServiceLinks(false) + .withVolumes(additionalVolumeConfigMap) .endPod() + .withNewContainer() + .withVolumeMounts(additionalVolumeMountConfigMap) + .endContainer() .withNewServiceAccount() .withNewMetadata() .withLabels(saLabels) @@ -439,6 +472,8 @@ public void testTemplate() { assertThat(dep.getSpec().getTemplate().getSpec().getTolerations(), is(tolerations)); assertThat(dep.getSpec().getTemplate().getSpec().getTopologySpreadConstraints(), containsInAnyOrder(tsc1, tsc2)); assertThat(dep.getSpec().getTemplate().getSpec().getEnableServiceLinks(), is(false)); + assertThat(getVolume(dep.getSpec().getTemplate().getSpec(), additionalVolumeConfigMap.getName()).getConfigMap(), is(configMap)); + assertThat(getVolumeMount(dep.getSpec().getTemplate().getSpec().getContainers().get(0), additionalVolumeMountConfigMap.getName()), is(additionalVolumeMountConfigMap)); // Check Service Account ServiceAccount sa = ke.generateServiceAccount(); diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaMirrorMaker2ClusterTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaMirrorMaker2ClusterTest.java index ecbf61c1079..0e6a3ade087 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaMirrorMaker2ClusterTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/KafkaMirrorMaker2ClusterTest.java @@ -6,6 +6,7 @@ import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapKeySelectorBuilder; +import io.fabric8.kubernetes.api.model.ConfigMapVolumeSource; import io.fabric8.kubernetes.api.model.ConfigMapVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Container; import io.fabric8.kubernetes.api.model.EnvVar; @@ -14,6 +15,8 @@ import io.fabric8.kubernetes.api.model.HostAliasBuilder; import io.fabric8.kubernetes.api.model.IntOrString; import io.fabric8.kubernetes.api.model.LocalObjectReference; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSource; +import io.fabric8.kubernetes.api.model.PersistentVolumeClaimVolumeSourceBuilder; import io.fabric8.kubernetes.api.model.Pod; import io.fabric8.kubernetes.api.model.PodSecurityContextBuilder; import io.fabric8.kubernetes.api.model.Quantity; @@ -25,6 +28,7 @@ import io.fabric8.kubernetes.api.model.ServiceAccount; import io.fabric8.kubernetes.api.model.Volume; import io.fabric8.kubernetes.api.model.VolumeMount; +import io.fabric8.kubernetes.api.model.VolumeMountBuilder; import io.fabric8.kubernetes.api.model.networking.v1.NetworkPolicy; import io.fabric8.kubernetes.api.model.policy.v1.PodDisruptionBudget; import io.fabric8.kubernetes.api.model.rbac.ClusterRoleBinding; @@ -40,6 +44,8 @@ import io.strimzi.api.kafka.model.common.metrics.JmxPrometheusExporterMetrics; import io.strimzi.api.kafka.model.common.metrics.JmxPrometheusExporterMetricsBuilder; import io.strimzi.api.kafka.model.common.metrics.MetricsConfig; +import io.strimzi.api.kafka.model.common.template.AdditionalVolume; +import io.strimzi.api.kafka.model.common.template.AdditionalVolumeBuilder; import io.strimzi.api.kafka.model.common.template.ContainerTemplate; import io.strimzi.api.kafka.model.common.template.IpFamily; import io.strimzi.api.kafka.model.common.template.IpFamilyPolicy; @@ -93,7 +99,6 @@ public class KafkaMirrorMaker2ClusterTest { private static final KafkaVersion.Lookup VERSIONS = KafkaVersionTestUtils.getKafkaVersionLookup(); private static final SharedEnvironmentProvider SHARED_ENV_PROVIDER = new MockSharedEnvironmentProvider(); - private final String namespace = "test"; private final String clusterName = "foo"; private final int replicas = 2; @@ -196,6 +201,14 @@ protected List getExpectedEnvVars() { return expected; } + private static Volume getVolume(Pod pod, String volumeName) { + return pod.getSpec().getVolumes().stream().filter(volume -> volumeName.equals(volume.getName())).iterator().next(); + } + + private static VolumeMount getVolumeMount(Container container, String volumeName) { + return container.getVolumeMounts().stream().filter(volumeMount -> volumeName.equals(volumeMount.getName())).iterator().next(); + } + @ParallelTest public void testDefaultValues() { @@ -488,7 +501,7 @@ public void testPodSetWithScramSha512Auth() { .withSecretName("user1-secret") .withPassword("password") .endPasswordSecret() - .endKafkaClientAuthenticationScramSha512() + .endKafkaClientAuthenticationScramSha512() .build(); KafkaMirrorMaker2 resource = new KafkaMirrorMaker2Builder(this.resource) .editSpec() @@ -886,6 +899,7 @@ public void testPodSetWithPlainAuthAndTLSSameSecret() { } @ParallelTest + @SuppressWarnings({"checkstyle:methodlength"}) public void testTemplate() { Map podSetLabels = TestUtils.map("l1", "v1", "l2", "v2", Labels.KUBERNETES_PART_OF_LABEL, "custom-part", @@ -918,6 +932,36 @@ public void testTemplate() { .withIp("192.168.1.87") .build(); + ConfigMapVolumeSource configMap = new ConfigMapVolumeSourceBuilder() + .withName("configMap1") + .build(); + + PersistentVolumeClaimVolumeSource pvc = new PersistentVolumeClaimVolumeSourceBuilder() + .withClaimName("pvc-name") + .withReadOnly(true) + .build(); + + AdditionalVolume additionalVolumeConfigMap = new AdditionalVolumeBuilder() + .withName("config-map-volume-name") + .withConfigMap(configMap) + .build(); + + AdditionalVolume additionalVolumePvc = new AdditionalVolumeBuilder() + .withName("pvc-volume-name") + .withPersistentVolumeClaim(pvc) + .build(); + + VolumeMount additionalVolumeMountConfigMap = new VolumeMountBuilder() + .withName("config-map-volume-name-2") + .withMountPath("/mnt/myconfigmap") + .withSubPath("def") + .build(); + + VolumeMount additionalVolumeMountPvc = new VolumeMountBuilder() + .withName("pvc-volume-name-2") + .withMountPath("/mnt/mypvc") + .build(); + KafkaMirrorMaker2 resource = new KafkaMirrorMaker2Builder(this.resource) .editSpec() .withNewRack("my-topology-key") @@ -938,7 +982,14 @@ public void testTemplate() { .withHostAliases(hostAlias1, hostAlias2) .withEnableServiceLinks(false) .withTmpDirSizeLimit("10Mi") + .withVolumes(additionalVolumeConfigMap, additionalVolumePvc) .endPod() + .withNewInitContainer() + .withVolumeMounts(additionalVolumeMountPvc) + .endInitContainer() + .withNewConnectContainer() + .withVolumeMounts(additionalVolumeMountConfigMap) + .endConnectContainer() .withNewApiService() .withNewMetadata() .withLabels(svcLabels) @@ -982,11 +1033,13 @@ public void testTemplate() { assertThat(pod.getSpec().getSchedulerName(), is("my-scheduler")); assertThat(pod.getSpec().getHostAliases(), containsInAnyOrder(hostAlias1, hostAlias2)); assertThat(pod.getSpec().getEnableServiceLinks(), is(false)); - assertThat(pod.getSpec().getVolumes().stream() - .filter(volume -> volume.getName().equalsIgnoreCase("strimzi-tmp")) - .findFirst().get().getEmptyDir().getSizeLimit(), is(new Quantity("10Mi"))); - }); + assertThat(getVolume(pod, "strimzi-tmp").getEmptyDir().getSizeLimit(), is(new Quantity("10Mi"))); + assertThat(getVolume(pod, additionalVolumeConfigMap.getName()).getConfigMap(), is(configMap)); + assertThat(getVolume(pod, additionalVolumePvc.getName()).getPersistentVolumeClaim(), is(pvc)); + assertThat(getVolumeMount(pod.getSpec().getContainers().get(0), additionalVolumeMountConfigMap.getName()), is(additionalVolumeMountConfigMap)); + assertThat(getVolumeMount(pod.getSpec().getInitContainers().get(0), additionalVolumeMountPvc.getName()), is(additionalVolumeMountPvc)); + }); // Check Service Service svc = kmm2.generateService(); assertThat(svc.getMetadata().getLabels().entrySet().containsAll(svcLabels.entrySet()), is(true)); @@ -1615,7 +1668,7 @@ public void testPodSetWithOAuthWithAccessToken() { .withSecretName("my-token-secret") .withKey("my-token-key") .endAccessToken() - .build()) + .build()) .build(); KafkaMirrorMaker2 resource = new KafkaMirrorMaker2Builder(this.resource) .editSpec() @@ -1741,7 +1794,7 @@ public void testPodSetWithOAuthWithClientSecret() { .build(); KafkaMirrorMaker2 resource = new KafkaMirrorMaker2Builder(this.resource) .editSpec() - .withClusters(targetClusterWithOAuthWithClientSecret) + .withClusters(targetClusterWithOAuthWithClientSecret) .endSpec() .build(); @@ -1886,7 +1939,7 @@ public void testPodSetWithOAuthWithMissingClientSecret() { .build(); KafkaMirrorMaker2 resource = new KafkaMirrorMaker2Builder(this.resource) .editSpec() - .withClusters(targetClusterWithOAuthWithMissingClientSecret) + .withClusters(targetClusterWithOAuthWithMissingClientSecret) .endSpec() .build(); @@ -1909,7 +1962,7 @@ public void testPodSetWithOAuthWithMissingUri() { .build(); KafkaMirrorMaker2 resource = new KafkaMirrorMaker2Builder(this.resource) .editSpec() - .withClusters(targetClusterWithOAuthWithMissingUri) + .withClusters(targetClusterWithOAuthWithMissingUri) .endSpec() .build(); @@ -1949,7 +2002,7 @@ public void testPodSetWithOAuthWithTls() { .build(); KafkaMirrorMaker2 resource = new KafkaMirrorMaker2Builder(this.resource) .editSpec() - .withClusters(targetClusterWithOAuthWithTls) + .withClusters(targetClusterWithOAuthWithTls) .endSpec() .build(); diff --git a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/TemplateUtilsTest.java b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/TemplateUtilsTest.java index d4723f31b5a..f3f3101a1bf 100644 --- a/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/TemplateUtilsTest.java +++ b/cluster-operator/src/test/java/io/strimzi/operator/cluster/model/TemplateUtilsTest.java @@ -4,22 +4,35 @@ */ package io.strimzi.operator.cluster.model; -import io.strimzi.api.kafka.model.common.template.DeploymentStrategy; -import io.strimzi.api.kafka.model.common.template.DeploymentTemplate; -import io.strimzi.api.kafka.model.common.template.DeploymentTemplateBuilder; +import io.fabric8.kubernetes.api.model.Volume; +import io.fabric8.kubernetes.api.model.VolumeBuilder; +import io.fabric8.kubernetes.api.model.VolumeMount; +import io.fabric8.kubernetes.api.model.VolumeMountBuilder; +import io.strimzi.api.kafka.model.common.template.AdditionalVolume; +import io.strimzi.api.kafka.model.common.template.AdditionalVolumeBuilder; +import io.strimzi.api.kafka.model.common.template.ContainerTemplate; +import io.strimzi.api.kafka.model.common.template.PodTemplate; +import io.strimzi.api.kafka.model.common.template.PodTemplateBuilder; import io.strimzi.api.kafka.model.common.template.ResourceTemplate; import io.strimzi.api.kafka.model.common.template.ResourceTemplateBuilder; +import io.strimzi.operator.common.model.InvalidResourceException; import io.strimzi.test.annotations.ParallelSuite; import io.strimzi.test.annotations.ParallelTest; +import java.util.ArrayList; +import java.util.List; import java.util.Map; +import static io.strimzi.operator.cluster.model.TemplateUtils.ALLOWED_MOUNT_PATH; +import static io.strimzi.operator.cluster.model.TemplateUtils.VOLUME_NAME_REGEX; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; @ParallelSuite public class TemplateUtilsTest { + @ParallelTest public void testMetadataWithNullTemplate() { assertThat(TemplateUtils.annotations(null), is(nullValue())); @@ -60,9 +73,83 @@ public void testLabels() { } @ParallelTest - public void testDeploymentStrategy() { - assertThat(TemplateUtils.deploymentStrategy(null, DeploymentStrategy.RECREATE), is(DeploymentStrategy.RECREATE)); - assertThat(TemplateUtils.deploymentStrategy(new DeploymentTemplate(), DeploymentStrategy.ROLLING_UPDATE), is(DeploymentStrategy.ROLLING_UPDATE)); - assertThat(TemplateUtils.deploymentStrategy(new DeploymentTemplateBuilder().withDeploymentStrategy(DeploymentStrategy.RECREATE).build(), DeploymentStrategy.ROLLING_UPDATE), is(DeploymentStrategy.RECREATE)); + public void testAddAdditionalVolumes_InvalidNames() { + List existingVolumes = new ArrayList<>(); + existingVolumes.add(new VolumeBuilder().withName("invalid_name!").build()); + PodTemplate templatePod = new PodTemplateBuilder().withVolumes(new ArrayList<>()).build(); + + InvalidResourceException exception = assertThrows(InvalidResourceException.class, () -> { + TemplateUtils.addAdditionalVolumes(templatePod, existingVolumes); + }); + + assertThat(exception.getMessage(), is("Volume names [invalid_name!] are invalid and do not match the pattern " + VOLUME_NAME_REGEX)); + } + + @ParallelTest + public void testAddAdditionalVolumes_DuplicateNames() { + List existingVolumes = new ArrayList<>(); + existingVolumes.add(new VolumeBuilder().withName("duplicate").build()); + List additionalVolumes = new ArrayList<>(); + additionalVolumes.add(new AdditionalVolumeBuilder().withName("duplicate").build()); + PodTemplate templatePod = new PodTemplateBuilder().withVolumes(additionalVolumes).build(); + + InvalidResourceException exception = assertThrows(InvalidResourceException.class, () -> { + TemplateUtils.addAdditionalVolumes(templatePod, existingVolumes); + }); + + assertThat(exception.getMessage(), is("Duplicate volume names found in additional volumes: [duplicate]")); } + + @ParallelTest + public void testAddAdditionalVolumes_ValidInputs() { + List existingVolumes = new ArrayList<>(); + existingVolumes.add(new VolumeBuilder().withName("existingVolume1").build()); + List additionalVolumes = new ArrayList<>(); + additionalVolumes.add(new AdditionalVolumeBuilder().withName("newVolume1").build()); + additionalVolumes.add(new AdditionalVolumeBuilder().withName("newVolume2").build()); + PodTemplate templatePod = new PodTemplateBuilder().withVolumes(additionalVolumes).build(); + + TemplateUtils.addAdditionalVolumes(templatePod, existingVolumes); + + assertThat(existingVolumes.size(), is(3)); + assertThat(existingVolumes.get(1).getName(), is("newVolume1")); + assertThat(existingVolumes.get(2).getName(), is("newVolume2")); + } + + + @ParallelTest + public void testAddAdditionalVolumeMounts_ValidInputs() { + List volumeMounts = new ArrayList<>(); + List additionalVolumeMounts = new ArrayList<>(); + additionalVolumeMounts.add(new VolumeMountBuilder().withMountPath(ALLOWED_MOUNT_PATH + "/path1").build()); + additionalVolumeMounts.add(new VolumeMountBuilder().withMountPath(ALLOWED_MOUNT_PATH + "/path2").build()); + + ContainerTemplate containerTemplate = new ContainerTemplate(); + containerTemplate.setVolumeMounts(additionalVolumeMounts); + + TemplateUtils.addAdditionalVolumeMounts(volumeMounts, containerTemplate); + + assertThat(volumeMounts.size(), is(2)); + assertThat(volumeMounts.get(0).getMountPath(), is(ALLOWED_MOUNT_PATH + "/path1")); + assertThat(volumeMounts.get(1).getMountPath(), is(ALLOWED_MOUNT_PATH + "/path2")); + } + + @ParallelTest + public void testAddAdditionalVolumeMounts_InvalidInputs() { + List volumeMounts = new ArrayList<>(); + List additionalVolumeMounts = new ArrayList<>(); + additionalVolumeMounts.add(new VolumeMountBuilder().withMountPath("/forbidden/path1").build()); + ContainerTemplate containerTemplate = new ContainerTemplate(); + containerTemplate.setVolumeMounts(additionalVolumeMounts); + + InvalidResourceException exception = assertThrows(InvalidResourceException.class, () -> { + TemplateUtils.addAdditionalVolumeMounts(volumeMounts, containerTemplate); + }); + + assertThat(exception.getMessage(), is(String.format("Forbidden path found in additional volumes. Should start with %s", ALLOWED_MOUNT_PATH))); + } + + + + } diff --git a/crd-generator/src/main/java/io/strimzi/crdgenerator/CrdGenerator.java b/crd-generator/src/main/java/io/strimzi/crdgenerator/CrdGenerator.java index d42eb51afc1..4c261917270 100644 --- a/crd-generator/src/main/java/io/strimzi/crdgenerator/CrdGenerator.java +++ b/crd-generator/src/main/java/io/strimzi/crdgenerator/CrdGenerator.java @@ -630,8 +630,6 @@ private ArrayNode buildSchemaOneOf(Class crdClass) { } private void checkClass(Class crdClass) { - checkJsonInclude(crdClass); - checkJsonPropertyOrder(crdClass); if (!isAbstract(crdClass.getModifiers())) { checkForBuilderClass(crdClass, crdClass.getName() + "Builder"); @@ -647,8 +645,10 @@ private void checkClass(Class crdClass) { } } - if (crdClass.getName().startsWith("io.strimzi.api.")) { + if (crdClass.getName().startsWith("io.strimzi.")) { checkInherits(crdClass, "io.strimzi.api.kafka.model.common.UnknownPropertyPreserving"); + checkJsonInclude(crdClass); + checkJsonPropertyOrder(crdClass); } checkClassOverrides(crdClass, "equals", Object.class); diff --git a/crd-generator/src/test/java/io/strimzi/crdgenerator/CrdGeneratorTest.java b/crd-generator/src/test/java/io/strimzi/crdgenerator/CrdGeneratorTest.java index 98f72e5eb84..c09cbf16540 100644 --- a/crd-generator/src/test/java/io/strimzi/crdgenerator/CrdGeneratorTest.java +++ b/crd-generator/src/test/java/io/strimzi/crdgenerator/CrdGeneratorTest.java @@ -132,4 +132,4 @@ void simpleTestWithErrors() throws IOException { assertFalse(errors.contains("class io.strimzi.crdgenerator.ExampleCrdWithErrors$ObjectProperty is missing @JsonPropertyOrder"), errors.toString()); assertTrue(errors.contains("class io.strimzi.crdgenerator.ExampleCrdWithErrors$ObjectProperty has a property bar which is not in the @JsonPropertyOrder"), errors.toString()); } -} +} \ No newline at end of file diff --git a/documentation/modules/appendix_crds.adoc b/documentation/modules/appendix_crds.adoc index 19c6b47a547..8eea2e9e57c 100644 --- a/documentation/modules/appendix_crds.adoc +++ b/documentation/modules/appendix_crds.adoc @@ -1235,6 +1235,35 @@ include::../api/io.strimzi.api.kafka.model.common.template.PodTemplate.adoc[leve |tmpDirSizeLimit |string |Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources. +|volumes +|xref:type-AdditionalVolume-{context}[`AdditionalVolume`] array +|Additional volumes that can be mounted to the pod. +|==== + +[id='type-AdditionalVolume-{context}'] += `AdditionalVolume` schema reference + +Used in: xref:type-PodTemplate-{context}[`PodTemplate`] + + +[cols="2,2,3a",options="header"] +|==== +|Property |Property type |Description +|name +|string +|Name to use for the volume. Required. +|secret +|https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#secretvolumesource-v1-core[SecretVolumeSource] +|Secret to use populate the volume. +|configMap +|https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#configmapvolumesource-v1-core[ConfigMapVolumeSource] +|ConfigMap to use to populate the volume. +|emptyDir +|https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#emptydirvolumesource-v1-core[EmptyDirVolumeSource] +|EmptyDir to use to populate the volume. +|persistentVolumeClaim +|https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#persistentvolumeclaimvolumesource-v1-core[PersistentVolumeClaimVolumeSource] +|PersistentVolumeClaim object to use to populate the volume. |==== [id='type-InternalServiceTemplate-{context}'] @@ -1317,6 +1346,9 @@ include::../api/io.strimzi.api.kafka.model.common.template.ContainerTemplate.ado |securityContext |https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.23/#securitycontext-v1-core[SecurityContext] |Security context for the container. +|volumeMounts +|xref:type-VolumeMount-{context}[`VolumeMount`] array +|Additional volume mounts which should be applied to the container. |==== [id='type-ContainerEnvVar-{context}'] @@ -1336,6 +1368,38 @@ Used in: xref:type-ContainerTemplate-{context}[`ContainerTemplate`] |The environment variable value. |==== +[id='type-VolumeMount-{context}'] += `VolumeMount` schema reference + +Used in: xref:type-ContainerTemplate-{context}[`ContainerTemplate`] + + +[cols="2,2,3a",options="header"] +|==== +|Property |Property type |Description +|mountPath +|string +| +|mountPropagation +|string +| +|name +|string +| +|readOnly +|boolean +| +|recursiveReadOnly +|string +| +|subPath +|string +| +|subPathExpr +|string +| +|==== + [id='type-TieredStorageCustom-{context}'] = `TieredStorageCustom` schema reference diff --git a/documentation/modules/overview/con-configuration-points-common.adoc b/documentation/modules/overview/con-configuration-points-common.adoc index 59347676dfe..7245bb3e78f 100644 --- a/documentation/modules/overview/con-configuration-points-common.adoc +++ b/documentation/modules/overview/con-configuration-points-common.adoc @@ -65,3 +65,61 @@ spec: - fast-network # ... ---- + +== Additional Volumes + +Strimzi supports specifying additional volumes and volume mounts in the following components: + +* Kafka +* Kafka Connect +* Kafka Bridge +* Kafka MirrorMaker2 +* Entity Operator +* Cruise Control +* Kafka Exporter +* Zookeeper +* User Operator +* Topic Operator + +All additional mounted paths are located inside `/mnt` to ensure compatibility with future Kafka and Strimzi updates. + +Supported Volume Types + +* Secret +* ConfigMap +* EmptyDir +* PersistentVolumeClaims + +[discrete] +== Example configuration for additional volumes: +[source,yaml,subs=attributes+] +---- +kind: Kafka +spec: + kafka: + # ... + template: + pod: + volumes: + - name: example-secret + secret: + secretName: secret-name + - name: example-configmap + configMap: + name: config-map-name + - name: temp + emptyDir: {} + - name: example-pvc-volume + persistentVolumeClaim: + claimName: myclaim + kafkaContainer: + volumeMounts: + - name: example-secret + mountPath: /mnt/secret-volume + - name: example-configmap + mountPath: /mnt/cm-volume + - name: temp + mountPath: /mnt/temp + - name: example-pvc-volume + mountPath: /mnt/data +---- diff --git a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/040-Crd-kafka.yaml b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/040-Crd-kafka.yaml index dfd33ce33b0..1d9ccfbb5af 100644 --- a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/040-Crd-kafka.yaml +++ b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/040-Crd-kafka.yaml @@ -1490,6 +1490,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka `Pods`. bootstrapService: type: object @@ -1785,6 +1864,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka broker container. initContainer: type: object @@ -1866,6 +1965,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka init container. clusterCaCert: type: object @@ -2822,6 +2941,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for ZooKeeper `Pods`. clientService: type: object @@ -3009,6 +3207,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the ZooKeeper container. serviceAccount: type: object @@ -4030,6 +4248,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Entity Operator `Pods`. topicOperatorContainer: type: object @@ -4111,6 +4408,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Entity Topic Operator container. userOperatorContainer: type: object @@ -4192,6 +4509,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Entity User Operator container. tlsSidecarContainer: type: object @@ -4273,6 +4610,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Entity Operator TLS sidecar container. serviceAccount: type: object @@ -5165,6 +5522,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Cruise Control `Pods`. apiService: type: object @@ -5301,6 +5737,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Cruise Control container. tlsSidecarContainer: type: object @@ -5382,6 +5838,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Cruise Control TLS sidecar container. serviceAccount: type: object @@ -6102,6 +6578,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for JmxTrans `Pods`. container: type: object @@ -6183,6 +6738,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for JmxTrans container. serviceAccount: type: object @@ -6840,6 +7415,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Exporter `Pods`. service: type: object @@ -6939,6 +7593,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Exporter container. serviceAccount: type: object diff --git a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/041-Crd-kafkaconnect.yaml b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/041-Crd-kafkaconnect.yaml index 2be5b9a26a0..560ac7e8301 100644 --- a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/041-Crd-kafkaconnect.yaml +++ b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/041-Crd-kafkaconnect.yaml @@ -1032,6 +1032,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Connect `Pods`. apiService: type: object @@ -1179,6 +1258,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Connect container. initContainer: type: object @@ -1260,6 +1359,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka init container. podDisruptionBudget: type: object @@ -1823,6 +1942,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Connect Build `Pods`. The build pod is used only on Kubernetes. buildContainer: type: object @@ -1904,6 +2102,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Connect Build container. The build container is used only on Kubernetes. buildConfig: type: object diff --git a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/045-Crd-kafkamirrormaker.yaml b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/045-Crd-kafkamirrormaker.yaml index 08f2b5c73f2..7d988b36cc5 100644 --- a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/045-Crd-kafkamirrormaker.yaml +++ b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/045-Crd-kafkamirrormaker.yaml @@ -1197,6 +1197,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka MirrorMaker `Pods`. podDisruptionBudget: type: object @@ -1300,6 +1379,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for Kafka MirrorMaker container. serviceAccount: type: object diff --git a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/046-Crd-kafkabridge.yaml b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/046-Crd-kafkabridge.yaml index 136c8d258df..5109f40a9b5 100644 --- a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/046-Crd-kafkabridge.yaml +++ b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/046-Crd-kafkabridge.yaml @@ -1021,6 +1021,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Bridge `Pods`. apiService: type: object @@ -1157,6 +1236,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Bridge container. clusterRoleBinding: type: object @@ -1274,6 +1373,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Bridge init container. description: Template for Kafka Bridge resources. The template allows users to specify how a `Deployment` and `Pod` is generated. tracing: diff --git a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/048-Crd-kafkamirrormaker2.yaml b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/048-Crd-kafkamirrormaker2.yaml index 36402be7854..18f2a1b66fd 100644 --- a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/048-Crd-kafkamirrormaker2.yaml +++ b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/048-Crd-kafkamirrormaker2.yaml @@ -1177,6 +1177,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Connect `Pods`. apiService: type: object @@ -1324,6 +1403,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Connect container. initContainer: type: object @@ -1405,6 +1504,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka init container. podDisruptionBudget: type: object @@ -1968,6 +2087,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Connect Build `Pods`. The build pod is used only on Kubernetes. buildContainer: type: object @@ -2049,6 +2247,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Connect Build container. The build container is used only on Kubernetes. buildConfig: type: object diff --git a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/04A-Crd-kafkanodepool.yaml b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/04A-Crd-kafkanodepool.yaml index 0aaec9dba05..744a6917e0f 100644 --- a/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/04A-Crd-kafkanodepool.yaml +++ b/packaging/helm-charts/helm3/strimzi-kafka-operator/crds/04A-Crd-kafkanodepool.yaml @@ -758,6 +758,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka `Pods`. perPodService: type: object @@ -911,6 +990,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka broker container. initContainer: type: object @@ -992,6 +1091,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka init container. description: Template for pool resources. The template allows users to specify how the resources belonging to this pool are generated. required: diff --git a/packaging/install/cluster-operator/040-Crd-kafka.yaml b/packaging/install/cluster-operator/040-Crd-kafka.yaml index 6879e6d019d..700b496aa51 100644 --- a/packaging/install/cluster-operator/040-Crd-kafka.yaml +++ b/packaging/install/cluster-operator/040-Crd-kafka.yaml @@ -1489,6 +1489,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka `Pods`. bootstrapService: type: object @@ -1784,6 +1863,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka broker container. initContainer: type: object @@ -1865,6 +1964,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka init container. clusterCaCert: type: object @@ -2821,6 +2940,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for ZooKeeper `Pods`. clientService: type: object @@ -3008,6 +3206,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the ZooKeeper container. serviceAccount: type: object @@ -4029,6 +4247,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Entity Operator `Pods`. topicOperatorContainer: type: object @@ -4110,6 +4407,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Entity Topic Operator container. userOperatorContainer: type: object @@ -4191,6 +4508,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Entity User Operator container. tlsSidecarContainer: type: object @@ -4272,6 +4609,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Entity Operator TLS sidecar container. serviceAccount: type: object @@ -5164,6 +5521,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Cruise Control `Pods`. apiService: type: object @@ -5300,6 +5736,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Cruise Control container. tlsSidecarContainer: type: object @@ -5381,6 +5837,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Cruise Control TLS sidecar container. serviceAccount: type: object @@ -6101,6 +6577,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for JmxTrans `Pods`. container: type: object @@ -6182,6 +6737,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for JmxTrans container. serviceAccount: type: object @@ -6839,6 +7414,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Exporter `Pods`. service: type: object @@ -6938,6 +7592,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Exporter container. serviceAccount: type: object diff --git a/packaging/install/cluster-operator/041-Crd-kafkaconnect.yaml b/packaging/install/cluster-operator/041-Crd-kafkaconnect.yaml index f80090fe5be..dc21332eb83 100644 --- a/packaging/install/cluster-operator/041-Crd-kafkaconnect.yaml +++ b/packaging/install/cluster-operator/041-Crd-kafkaconnect.yaml @@ -1031,6 +1031,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Connect `Pods`. apiService: type: object @@ -1178,6 +1257,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Connect container. initContainer: type: object @@ -1259,6 +1358,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka init container. podDisruptionBudget: type: object @@ -1822,6 +1941,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Connect Build `Pods`. The build pod is used only on Kubernetes. buildContainer: type: object @@ -1903,6 +2101,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Connect Build container. The build container is used only on Kubernetes. buildConfig: type: object diff --git a/packaging/install/cluster-operator/045-Crd-kafkamirrormaker.yaml b/packaging/install/cluster-operator/045-Crd-kafkamirrormaker.yaml index e6b7f938879..a49f283ff3f 100644 --- a/packaging/install/cluster-operator/045-Crd-kafkamirrormaker.yaml +++ b/packaging/install/cluster-operator/045-Crd-kafkamirrormaker.yaml @@ -1196,6 +1196,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka MirrorMaker `Pods`. podDisruptionBudget: type: object @@ -1299,6 +1378,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for Kafka MirrorMaker container. serviceAccount: type: object diff --git a/packaging/install/cluster-operator/046-Crd-kafkabridge.yaml b/packaging/install/cluster-operator/046-Crd-kafkabridge.yaml index da7382045f9..b200c6f1011 100644 --- a/packaging/install/cluster-operator/046-Crd-kafkabridge.yaml +++ b/packaging/install/cluster-operator/046-Crd-kafkabridge.yaml @@ -1020,6 +1020,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Bridge `Pods`. apiService: type: object @@ -1156,6 +1235,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Bridge container. clusterRoleBinding: type: object @@ -1273,6 +1372,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Bridge init container. description: Template for Kafka Bridge resources. The template allows users to specify how a `Deployment` and `Pod` is generated. tracing: diff --git a/packaging/install/cluster-operator/048-Crd-kafkamirrormaker2.yaml b/packaging/install/cluster-operator/048-Crd-kafkamirrormaker2.yaml index a2a86c6e020..5b80b9f8d1d 100644 --- a/packaging/install/cluster-operator/048-Crd-kafkamirrormaker2.yaml +++ b/packaging/install/cluster-operator/048-Crd-kafkamirrormaker2.yaml @@ -1176,6 +1176,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Connect `Pods`. apiService: type: object @@ -1323,6 +1402,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Connect container. initContainer: type: object @@ -1404,6 +1503,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka init container. podDisruptionBudget: type: object @@ -1967,6 +2086,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka Connect Build `Pods`. The build pod is used only on Kubernetes. buildContainer: type: object @@ -2048,6 +2246,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka Connect Build container. The build container is used only on Kubernetes. buildConfig: type: object diff --git a/packaging/install/cluster-operator/04A-Crd-kafkanodepool.yaml b/packaging/install/cluster-operator/04A-Crd-kafkanodepool.yaml index 0aaec9dba05..744a6917e0f 100644 --- a/packaging/install/cluster-operator/04A-Crd-kafkanodepool.yaml +++ b/packaging/install/cluster-operator/04A-Crd-kafkanodepool.yaml @@ -758,6 +758,85 @@ spec: type: string pattern: "^([0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" description: "Defines the total amount of pod memory allocated for the temporary `EmptyDir` volume `/tmp`. Specify the allocation in memory units, for example, `100Mi` for 100 mebibytes. Default value is `5Mi`. The `/tmp` volume is backed by pod memory, not disk storage, so avoid setting a high value as it consumes pod memory resources." + volumes: + type: array + items: + type: object + properties: + name: + type: string + description: Name to use for the volume. Required. + secret: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + optional: + type: boolean + secretName: + type: string + description: Secret to use populate the volume. + configMap: + type: object + properties: + defaultMode: + type: integer + items: + type: array + items: + type: object + properties: + key: + type: string + mode: + type: integer + path: + type: string + name: + type: string + optional: + type: boolean + description: ConfigMap to use to populate the volume. + emptyDir: + type: object + properties: + medium: + type: string + sizeLimit: + type: object + properties: + amount: + type: string + format: + type: string + description: EmptyDir to use to populate the volume. + persistentVolumeClaim: + type: object + properties: + claimName: + type: string + readOnly: + type: boolean + description: PersistentVolumeClaim object to use to populate the volume. + oneOf: + - properties: + secret: {} + configMap: {} + emptyDir: {} + persistentVolumeClaim: {} + required: [] + description: Additional volumes that can be mounted to the pod. description: Template for Kafka `Pods`. perPodService: type: object @@ -911,6 +990,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka broker container. initContainer: type: object @@ -992,6 +1091,26 @@ spec: runAsUserName: type: string description: Security context for the container. + volumeMounts: + type: array + items: + type: object + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + recursiveReadOnly: + type: string + subPath: + type: string + subPathExpr: + type: string + description: Additional volume mounts which should be applied to the container. description: Template for the Kafka init container. description: Template for pool resources. The template allows users to specify how the resources belonging to this pool are generated. required: