From 6bd5727613139808ae89da6269043c4bbbce0101 Mon Sep 17 00:00:00 2001 From: Zane Williamson Date: Wed, 8 Apr 2020 14:27:22 -0700 Subject: [PATCH] Adding feature/tolerations and node selector to PodOptions (#107) --- README.md | 6 +- api/v1beta1/common_types.go | 11 ++- api/v1beta1/zz_generated.deepcopy.go | 14 +++ .../bases/solr.bloomberg.com_solrclouds.yaml | 47 ++++++++++ ...bloomberg.com_solrprometheusexporters.yaml | 47 ++++++++++ controllers/controller_utils_test.go | 27 +++++- controllers/solrcloud_controller_test.go | 11 ++- .../solrprometheusexporter_controller_test.go | 17 +++- controllers/util/prometheus_exporter_util.go | 11 ++- controllers/util/solr_util.go | 20 ++++ controllers/util/zk_util.go | 12 +++ example/test_solrcloud.yaml | 15 +-- .../test_solrcloud_toleration_example.yaml | 46 +++++++++ helm/solr-operator/crds/crds.yaml | 94 +++++++++++++++++++ 14 files changed, 357 insertions(+), 21 deletions(-) create mode 100644 example/test_solrcloud_toleration_example.yaml diff --git a/README.md b/README.md index fa85c6a4..0a8ca0b8 100644 --- a/README.md +++ b/README.md @@ -375,16 +375,16 @@ Two Docker images are published to [DockerHub](https://hub.docker.com/r/bloomber #### Building -Building and releasing a test operator image with a custom namespace. +Building and releasing a test operator image with a custom Docker namespace. ```bash -$ NAMESPACE=your-namespace make docker-build docker-push +$ NAMESPACE=your-namespace/ make docker-build docker-push ``` You can test the vendor docker container by running ```bash -$ NAMESPACE=your-namespace make docker-vendor-build docker-vendor-push +$ NAMESPACE=your-namespace/ make docker-vendor-build docker-vendor-push ``` ### Docker for Mac Local Development Setup diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go index 7e3da2de..c572f56b 100644 --- a/api/v1beta1/common_types.go +++ b/api/v1beta1/common_types.go @@ -17,8 +17,9 @@ limitations under the License. package v1beta1 import ( - corev1 "k8s.io/api/core/v1" "strings" + + corev1 "k8s.io/api/core/v1" ) // StatefulSetOptions defines custom options for StatefulSets @@ -74,6 +75,14 @@ type PodOptions struct { // Labels to be added for pods. // +optional Labels map[string]string `json:"labels,omitempty"` + + // Tolerations to be added for the StatefulSet. + // +optional + Tolerations []corev1.Toleration `json:"tolerations,omitempty"` + + // Node Selector to be added for the StatefulSet. + // +optional + NodeSelector map[string]string `json:"nodeSelector,omitempty"` } // ServiceOptions defines custom options for services diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 8b85e7ed..71cafb0e 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -430,6 +430,20 @@ func (in *PodOptions) DeepCopyInto(out *PodOptions) { (*out)[key] = val } } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]v1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodOptions. diff --git a/config/crd/bases/solr.bloomberg.com_solrclouds.yaml b/config/crd/bases/solr.bloomberg.com_solrclouds.yaml index dc5cb6f4..404bdffc 100644 --- a/config/crd/bases/solr.bloomberg.com_solrclouds.yaml +++ b/config/crd/bases/solr.bloomberg.com_solrclouds.yaml @@ -2069,6 +2069,11 @@ spec: type: string description: Labels to be added for pods. type: object + nodeSelector: + additionalProperties: + type: string + description: Node Selector to be added for the StatefulSet. + type: object podSecurityContext: description: PodSecurityContext is the security context for the pod. @@ -2217,6 +2222,48 @@ spec: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' type: object type: object + tolerations: + description: Tolerations to be added for the StatefulSet. + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, + allowed values are NoSchedule, PreferNoSchedule and + NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. If the + key is empty, operator must be Exists; this combination + means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and Equal. + Defaults to Equal. Exists is equivalent to wildcard + for value, so that a pod can tolerate all taints of + a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of + time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the + taint forever (do not evict). Zero and negative values + will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array volumes: description: Additional non-data volumes to load into the default container. diff --git a/config/crd/bases/solr.bloomberg.com_solrprometheusexporters.yaml b/config/crd/bases/solr.bloomberg.com_solrprometheusexporters.yaml index ebaa057a..634764e7 100644 --- a/config/crd/bases/solr.bloomberg.com_solrprometheusexporters.yaml +++ b/config/crd/bases/solr.bloomberg.com_solrprometheusexporters.yaml @@ -833,6 +833,11 @@ spec: type: string description: Labels to be added for pods. type: object + nodeSelector: + additionalProperties: + type: string + description: Node Selector to be added for the StatefulSet. + type: object podSecurityContext: description: PodSecurityContext is the security context for the pod. @@ -981,6 +986,48 @@ spec: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' type: object type: object + tolerations: + description: Tolerations to be added for the StatefulSet. + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, + allowed values are NoSchedule, PreferNoSchedule and + NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. If the + key is empty, operator must be Exists; this combination + means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and Equal. + Defaults to Equal. Exists is equivalent to wildcard + for value, so that a pod can tolerate all taints of + a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of + time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the + taint forever (do not evict). Zero and negative values + will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array volumes: description: Additional non-data volumes to load into the default container. diff --git a/controllers/controller_utils_test.go b/controllers/controller_utils_test.go index b25544b0..c41c7b8b 100644 --- a/controllers/controller_utils_test.go +++ b/controllers/controller_utils_test.go @@ -17,6 +17,9 @@ limitations under the License. package controllers import ( + "reflect" + "testing" + solr "github.com/bloomberg/solr-operator/api/v1beta1" "github.com/onsi/gomega" "github.com/stretchr/testify/assert" @@ -30,7 +33,6 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "testing" ) func expectStatefulSet(t *testing.T, g *gomega.GomegaWithT, requests chan reconcile.Request, expectedRequest reconcile.Request, statefulSetKey types.NamespacedName) *appsv1.StatefulSet { @@ -173,6 +175,10 @@ func testPodEnvVariables(t *testing.T, expectedEnvVars map[string]string, foundE assert.Equal(t, len(expectedEnvVars), matchCount, "Not all expected env variables found in podSpec") } +func testPodTolerations(t *testing.T, expectedTolerations []corev1.Toleration, foundTolerations []corev1.Toleration) { + assert.True(t, reflect.DeepEqual(expectedTolerations, foundTolerations), "Expected tolerations and found tolerations don't match") +} + func testMapsEqual(t *testing.T, mapName string, expected map[string]string, found map[string]string) { assert.Equal(t, expected, found, "Expected and found %s are not the same", mapName) } @@ -295,6 +301,25 @@ var ( "testS3": "valueS3", "testS4": "valueS4", } + testNodeSelectors = map[string]string{ + "beta.kubernetes.io/arch": "amd64", + "beta.kubernetes.io/os": "linux", + "solrclouds": "true", + } + testTolerations = []corev1.Toleration{ + { + Effect: "NoSchedule", + Key: "node-restriction.kubernetes.io/dedicated", + Value: "solrclouds", + Operator: "Exists", + }, + } + testTolerationsPromExporter = []corev1.Toleration{ + { + Effect: "NoSchedule", + Operator: "Exists", + }, + } extraVars = []corev1.EnvVar{ { Name: "VAR_1", diff --git a/controllers/solrcloud_controller_test.go b/controllers/solrcloud_controller_test.go index 72c285bc..851b2b65 100644 --- a/controllers/solrcloud_controller_test.go +++ b/controllers/solrcloud_controller_test.go @@ -17,9 +17,10 @@ limitations under the License. package controllers import ( + "testing" + "github.com/bloomberg/solr-operator/controllers/util" "github.com/stretchr/testify/assert" - "testing" solr "github.com/bloomberg/solr-operator/api/v1beta1" "github.com/onsi/gomega" @@ -171,8 +172,10 @@ func TestCloudReconcileWithIngress(t *testing.T) { SolrGCTune: "gc Options", CustomSolrKubeOptions: solr.CustomSolrKubeOptions{ PodOptions: &solr.PodOptions{ - Annotations: testPodAnnotations, - Labels: testPodLabels, + Annotations: testPodAnnotations, + Labels: testPodLabels, + Tolerations: testTolerations, + NodeSelector: testNodeSelectors, }, StatefulSetOptions: &solr.StatefulSetOptions{ Annotations: testSSAnnotations, @@ -257,6 +260,8 @@ func TestCloudReconcileWithIngress(t *testing.T) { testMapsEqual(t, "statefulSet annotations", util.MergeLabelsOrAnnotations(expectedStatefulSetAnnotations, testSSAnnotations), statefulSet.Annotations) testMapsEqual(t, "pod labels", util.MergeLabelsOrAnnotations(expectedStatefulSetLabels, testPodLabels), statefulSet.Spec.Template.ObjectMeta.Labels) testMapsEqual(t, "pod annotations", testPodAnnotations, statefulSet.Spec.Template.Annotations) + testMapsEqual(t, "pod node selectors", testNodeSelectors, statefulSet.Spec.Template.Spec.NodeSelector) + testPodTolerations(t, testTolerations, statefulSet.Spec.Template.Spec.Tolerations) // Check the client Service service := expectService(t, g, requests, expectedCloudRequest, cloudCsKey, statefulSet.Spec.Selector.MatchLabels) diff --git a/controllers/solrprometheusexporter_controller_test.go b/controllers/solrprometheusexporter_controller_test.go index 1edb39ce..9e3617b7 100644 --- a/controllers/solrprometheusexporter_controller_test.go +++ b/controllers/solrprometheusexporter_controller_test.go @@ -17,6 +17,8 @@ limitations under the License. package controllers import ( + "testing" + solr "github.com/bloomberg/solr-operator/api/v1beta1" "github.com/bloomberg/solr-operator/controllers/util" "github.com/onsi/gomega" @@ -28,7 +30,6 @@ import ( ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" - "testing" ) var _ reconcile.Reconciler = &SolrPrometheusExporterReconciler{} @@ -121,9 +122,11 @@ func TestMetricsReconcileWithExporterConfig(t *testing.T) { Config: testExporterConfig, CustomKubeOptions: solr.CustomExporterKubeOptions{ PodOptions: &solr.PodOptions{ - Annotations: testPodAnnotations, - Labels: testPodLabels, - Volumes: extraVolumes, + Annotations: testPodAnnotations, + Labels: testPodLabels, + Volumes: extraVolumes, + Tolerations: testTolerationsPromExporter, + NodeSelector: testNodeSelectors, }, DeploymentOptions: &solr.DeploymentOptions{ Annotations: testDeploymentAnnotations, @@ -161,6 +164,8 @@ func TestMetricsReconcileWithExporterConfig(t *testing.T) { mgrStopped.Wait() }() + cleanupTest(g, instance.Namespace) + // Create the SolrPrometheusExporter object and expect the Reconcile and Deployment to be created err = testClient.Create(context.TODO(), instance) // The instance object may not be a valid object because it might be missing some required fields. @@ -184,6 +189,10 @@ func TestMetricsReconcileWithExporterConfig(t *testing.T) { testMapsEqual(t, "pod labels", util.MergeLabelsOrAnnotations(expectedDeploymentLabels, testPodLabels), deployment.Spec.Template.ObjectMeta.Labels) testMapsEqual(t, "pod annotations", testPodAnnotations, deployment.Spec.Template.ObjectMeta.Annotations) + // Test tolerations and node selectors + testMapsEqual(t, "pod node selectors", testNodeSelectors, deployment.Spec.Template.Spec.NodeSelector) + testPodTolerations(t, testTolerationsPromExporter, deployment.Spec.Template.Spec.Tolerations) + // Other Pod Options extraVolumes[0].DefaultContainerMount.Name = extraVolumes[0].Name assert.Equal(t, len(extraVolumes)+1, len(deployment.Spec.Template.Spec.Containers[0].VolumeMounts), "Container has wrong number of volumeMounts") diff --git a/controllers/util/prometheus_exporter_util.go b/controllers/util/prometheus_exporter_util.go index 2cbb6810..1a75a13c 100644 --- a/controllers/util/prometheus_exporter_util.go +++ b/controllers/util/prometheus_exporter_util.go @@ -217,12 +217,20 @@ func GenerateSolrPrometheusExporterDeployment(solrPrometheusExporter *solr.SolrP if customPodOptions.PodSecurityContext != nil { deployment.Spec.Template.Spec.SecurityContext = customPodOptions.PodSecurityContext } + + if customPodOptions.Tolerations != nil { + deployment.Spec.Template.Spec.Tolerations = customPodOptions.Tolerations + } + + if customPodOptions.NodeSelector != nil { + deployment.Spec.Template.Spec.NodeSelector = customPodOptions.NodeSelector + } } return deployment } -// GenerateConfigMap returns a new corev1.ConfigMap pointer generated for the Solr Prometheus Exporter instance solr-prometheus-exporter.xml +// GenerateMetricsConfigMap returns a new corev1.ConfigMap pointer generated for the Solr Prometheus Exporter instance solr-prometheus-exporter.xml // solrPrometheusExporter: SolrPrometheusExporter instance func GenerateMetricsConfigMap(solrPrometheusExporter *solr.SolrPrometheusExporter) *corev1.ConfigMap { labels := solrPrometheusExporter.SharedLabelsWith(solrPrometheusExporter.GetLabels()) @@ -293,7 +301,6 @@ func GenerateSolrMetricsService(solrPrometheusExporter *solr.SolrPrometheusExpor // CreateMetricsIngressRule returns a new Ingress Rule generated for the solr metrics endpoint // This is not currently used, as an ingress is not created for the metrics endpoint. - // solrCloud: SolrCloud instance // nodeName: string Name of the node // ingressBaseDomain: string base domain for the ingress controller diff --git a/controllers/util/solr_util.go b/controllers/util/solr_util.go index c6a2c816..f8abb323 100644 --- a/controllers/util/solr_util.go +++ b/controllers/util/solr_util.go @@ -348,6 +348,14 @@ func GenerateStatefulSet(solrCloud *solr.SolrCloud, solrCloudStatus *solr.SolrCl if customPodOptions.PodSecurityContext != nil { stateful.Spec.Template.Spec.SecurityContext = customPodOptions.PodSecurityContext } + + if customPodOptions.Tolerations != nil { + stateful.Spec.Template.Spec.Tolerations = customPodOptions.Tolerations + } + + if customPodOptions.NodeSelector != nil { + stateful.Spec.Template.Spec.NodeSelector = customPodOptions.NodeSelector + } } return stateful @@ -445,6 +453,18 @@ func CopyStatefulSetFields(from, to *appsv1.StatefulSet) bool { to.Spec.Template.Spec.SecurityContext = from.Spec.Template.Spec.SecurityContext } + if !DeepEqualWithNils(to.Spec.Template.Spec.NodeSelector, from.Spec.Template.Spec.NodeSelector) { + requireUpdate = true + log.Info("Update required because:", "Spec.Template.Spec.NodeSelector changed from", to.Spec.Template.Spec.NodeSelector, "To:", from.Spec.Template.Spec.NodeSelector) + to.Spec.Template.Spec.NodeSelector = from.Spec.Template.Spec.NodeSelector + } + + if !DeepEqualWithNils(to.Spec.Template.Spec.Tolerations, from.Spec.Template.Spec.Tolerations) { + requireUpdate = true + log.Info("Update required because:", "Spec.Template.Spec.Tolerations changed from", to.Spec.Template.Spec.Tolerations, "To:", from.Spec.Template.Spec.Tolerations) + to.Spec.Template.Spec.Tolerations = from.Spec.Template.Spec.Tolerations + } + return requireUpdate } diff --git a/controllers/util/zk_util.go b/controllers/util/zk_util.go index ffc08005..92e5c17a 100644 --- a/controllers/util/zk_util.go +++ b/controllers/util/zk_util.go @@ -382,6 +382,18 @@ func CopyDeploymentFields(from, to *appsv1.Deployment) bool { to.Spec.Template.Spec.SecurityContext = from.Spec.Template.Spec.SecurityContext } + if !DeepEqualWithNils(to.Spec.Template.Spec.Tolerations, from.Spec.Template.Spec.Tolerations) { + requireUpdate = true + log.Info("Update required because:", "Spec.Template.Spec.Tolerations canged from", to.Spec.Template.Spec.Tolerations, "To:", from.Spec.Template.Spec.Tolerations) + to.Spec.Template.Spec.Tolerations = from.Spec.Template.Spec.Tolerations + } + + if !DeepEqualWithNils(to.Spec.Template.Spec.NodeSelector, from.Spec.Template.Spec.NodeSelector) { + requireUpdate = true + log.Info("Update required because:", "Spec.Template.Spec.NodeSelector canged from", to.Spec.Template.Spec.NodeSelector, "To:", from.Spec.Template.Spec.NodeSelector) + to.Spec.Template.Spec.NodeSelector = from.Spec.Template.Spec.NodeSelector + } + return requireUpdate } diff --git a/example/test_solrcloud.yaml b/example/test_solrcloud.yaml index 5768ab76..6c2fce99 100644 --- a/example/test_solrcloud.yaml +++ b/example/test_solrcloud.yaml @@ -14,13 +14,14 @@ spec: solrImage: tag: 8.2.0 solrJavaMem: "-Xms1g -Xmx3g" - solrPodPolicy: - resources: - limits: - memory: "1G" - requests: - cpu: "65m" - memory: "156Mi" + customSolrKubeOptions: + podOptions: + resources: + limits: + memory: "1G" + requests: + cpu: "65m" + memory: "156Mi" zookeeperRef: provided: chroot: "/this/will/be/auto/created" diff --git a/example/test_solrcloud_toleration_example.yaml b/example/test_solrcloud_toleration_example.yaml new file mode 100644 index 00000000..91de0d1e --- /dev/null +++ b/example/test_solrcloud_toleration_example.yaml @@ -0,0 +1,46 @@ +apiVersion: solr.bloomberg.com/v1beta1 +kind: SolrCloud +metadata: + name: example-with-tolerations +spec: + dataPvcSpec: + resources: + requests: + storage: "5Gi" + replicas: 1 + solrImage: + tag: 8.2.0 + solrJavaMem: "-Xms1g -Xmx3g" + customSolrKubeOptions: + podOptions: + nodeSelector: + beta.kubernetes.io/os: linux + beta.kubernetes.io/arch: amd64 + tolerations: + - effect: NoSchedule + key: node-restriction.kubernetes.io/workloads + operator: Equal + value: solrclouds + resources: + limits: + memory: "1G" + requests: + cpu: "65m" + memory: "156Mi" + zookeeperRef: + provided: + zookeeper: + persistence: + spec: + storageClassName: "hostpath" + resources: + requests: + storage: "5Gi" + replicas: 1 + zookeeperPodPolicy: + resources: + limits: + memory: "1G" + requests: + cpu: "65m" + memory: "156Mi" diff --git a/helm/solr-operator/crds/crds.yaml b/helm/solr-operator/crds/crds.yaml index 1563e5d4..e8b5ad37 100644 --- a/helm/solr-operator/crds/crds.yaml +++ b/helm/solr-operator/crds/crds.yaml @@ -3547,6 +3547,11 @@ spec: type: string description: Labels to be added for pods. type: object + nodeSelector: + additionalProperties: + type: string + description: Node Selector to be added for the StatefulSet. + type: object podSecurityContext: description: PodSecurityContext is the security context for the pod. @@ -3695,6 +3700,48 @@ spec: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' type: object type: object + tolerations: + description: Tolerations to be added for the StatefulSet. + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, + allowed values are NoSchedule, PreferNoSchedule and + NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. If the + key is empty, operator must be Exists; this combination + means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and Equal. + Defaults to Equal. Exists is equivalent to wildcard + for value, so that a pod can tolerate all taints of + a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of + time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the + taint forever (do not evict). Zero and negative values + will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array volumes: description: Additional non-data volumes to load into the default container. @@ -9644,6 +9691,11 @@ spec: type: string description: Labels to be added for pods. type: object + nodeSelector: + additionalProperties: + type: string + description: Node Selector to be added for the StatefulSet. + type: object podSecurityContext: description: PodSecurityContext is the security context for the pod. @@ -9792,6 +9844,48 @@ spec: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/' type: object type: object + tolerations: + description: Tolerations to be added for the StatefulSet. + items: + description: The pod this Toleration is attached to tolerates + any taint that matches the triple using + the matching operator . + properties: + effect: + description: Effect indicates the taint effect to match. + Empty means match all taint effects. When specified, + allowed values are NoSchedule, PreferNoSchedule and + NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. If the + key is empty, operator must be Exists; this combination + means to match all values and all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and Equal. + Defaults to Equal. Exists is equivalent to wildcard + for value, so that a pod can tolerate all taints of + a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the period of + time the toleration (which must be of effect NoExecute, + otherwise this field is ignored) tolerates the taint. + By default, it is not set, which means tolerate the + taint forever (do not evict). Zero and negative values + will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration matches + to. If the operator is Exists, the value should be empty, + otherwise just a regular string. + type: string + type: object + type: array volumes: description: Additional non-data volumes to load into the default container.