diff --git a/Makefile b/Makefile index 225d5145..b4d12c0c 100644 --- a/Makefile +++ b/Makefile @@ -271,6 +271,7 @@ manager: generate go-fmt go-vet ## Build manager binary .PHONY: manifests manifests: install-controller-gen install-kustomize install-yq ## Generate manifests e.g. CRD, RBAC etc. $(CONTROLLER_GEN) rbac:roleName=apicurio-registry-operator-role crd paths="./..." output:crd:artifacts:config=config/crd/resources output:rbac:artifacts:config=config/rbac/resources + $(YQ) e "del(.. | select(has(\"podTemplateSpecPreview\")).podTemplateSpecPreview | .. | select(has(\"description\")).description)" -i "config/crd/resources/registry.apicur.io_apicurioregistries.yaml" cd config/manager && $(KUSTOMIZE) edit set image REGISTRY_OPERATOR_IMAGE=$(OPERATOR_IMAGE) $(YQ) e ".metadata.annotations.createdAt = \"$(DATE)\"" -i "config/manifests/resources/apicurio-registry-operator.clusterserviceversion.yaml" $(YQ) e ".metadata.annotations.containerImage = \"$(OPERATOR_IMAGE)\"" -i "config/manifests/resources/apicurio-registry-operator.clusterserviceversion.yaml" diff --git a/api/v1/apicurioregistry_types.go b/api/v1/apicurioregistry_types.go index 4fa35fd2..8b29b0c1 100644 --- a/api/v1/apicurioregistry_types.go +++ b/api/v1/apicurioregistry_types.go @@ -19,6 +19,7 @@ package v1 import ( core "k8s.io/api/core/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" ) // ### Spec @@ -113,189 +114,273 @@ type ApicurioRegistrySpecDeployment struct { // Configure how the Operator manages Kubernetes resources ManagedResources ApicurioRegistrySpecDeploymentManagedResources `json:"managedResources,omitempty"` - PodSpecPreview ApicurioRegistrySpecDeploymentPodSpecPreview `json:"podSpecPreview,omitempty"` + PodTemplateSpecPreview ApicurioRegistryPodTemplateSpec `json:"podTemplateSpecPreview,omitempty"` } -// This is a slightly modified copy of k8s.io/api/core/v1.PodSpec: -// - Allow empty field "containers" -// - Comments removed to avoid an error "Too long: must have at most 262144 bytes" when executing "kubectl apply". -// By using kubectl apply to create/update resources, an annotation "kubectl.kubernetes.io/last-applied-configuration" -// is created by K8s API to store the latest version of the resource. -// However, it has a size limit and if the CRD has many long descriptions, it will result the error. -type ApicurioRegistrySpecDeploymentPodSpecPreview struct { +type ApicurioRegistrySpecDeploymentManagedResources struct { + // Operator will not create or manage an Ingress for Apicurio Registry + DisableIngress bool `json:"disableIngress,omitempty"` + // Operator will not create or manage an NetworkPolicy for Apicurio Registry + DisableNetworkPolicy bool `json:"disableNetworkPolicy,omitempty"` + // Operator will not create or manage an PodDisruptionBudget for Apicurio Registry + DisablePodDisruptionBudget bool `json:"disablePodDisruptionBudget,omitempty"` +} + +// ### Status + +type ApicurioRegistryStatus struct { + // Information about the deployed application. + Info ApicurioRegistryStatusInfo `json:"info,omitempty"` + // List of status conditions. + Conditions []meta.Condition `json:"conditions,omitempty"` + // List of resources managed by this operator. + ManagedResources []ApicurioRegistryStatusManagedResource `json:"managedResources,omitempty"` +} + +type ApicurioRegistryStatusInfo struct { + Host string `json:"host,omitempty"` +} + +type ApicurioRegistryStatusManagedResource struct { + Kind string `json:"kind,omitempty"` + Name string `json:"name,omitempty"` + Namespace string `json:"namespace,omitempty"` +} + +// ### Roots + +// ApicurioRegistry represents an Apicurio Registry instance +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status +type ApicurioRegistry struct { + meta.TypeMeta `json:",inline"` + meta.ObjectMeta `json:"metadata,omitempty"` + + Spec ApicurioRegistrySpec `json:"spec,omitempty"` + Status ApicurioRegistryStatus `json:"status,omitempty"` +} + +// ApicurioRegistryList contains a list of ApicurioRegistry +// +kubebuilder:object:root=true +type ApicurioRegistryList struct { + meta.TypeMeta `json:",inline"` + meta.ListMeta `json:"metadata,omitempty"` + Items []ApicurioRegistry `json:"items"` +} + +func init() { + SchemeBuilder.Register(&ApicurioRegistry{}, &ApicurioRegistryList{}) +} + +// These are slightly modified copies of core.PodTemplateSpec and some nested structs, +// for the purpose of: +// - allowing some fields to be empty or nil, +// - for generating a better CRD, +// - working deep equality operation +// +// The modified struct must be de/serializable from/to the original PodTemplateSpec via JSON. +// +// Comments removed to avoid an error "Too long: must have at most 262144 bytes" when executing "kubectl apply". +// By using kubectl apply to create/update resources, an annotation "kubectl.kubernetes.io/last-applied-configuration" +// is created by K8s API to store the latest version of the resource. +// However, it has a size limit and if the CRD has many long descriptions, it will result the error. + +// ApicurioRegistryPodTemplateSpec describes the data a pod should have when created from a template +type ApicurioRegistryPodTemplateSpec struct { + + // +optional + Metadata ApicurioRegistryObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // +optional + Spec ApicurioRegistryPodSpec `json:"spec,omitempty" protobuf:"bytes,2,opt,name=spec"` +} + +// ApicurioRegistryObjectMeta is metadata that all persisted resources must have, which includes all objects +// users must create. +type ApicurioRegistryObjectMeta struct { + + // +optional + Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"` + + // +optional + GenerateName string `json:"generateName,omitempty" protobuf:"bytes,2,opt,name=generateName"` + + // +optional + Namespace string `json:"namespace,omitempty" protobuf:"bytes,3,opt,name=namespace"` + + // +optional + SelfLink string `json:"selfLink,omitempty" protobuf:"bytes,4,opt,name=selfLink"` + + // +optional + UID types.UID `json:"uid,omitempty" protobuf:"bytes,5,opt,name=uid,casttype=k8s.io/kubernetes/pkg/types.UID"` + + // +optional + ResourceVersion string `json:"resourceVersion,omitempty" protobuf:"bytes,6,opt,name=resourceVersion"` + + // +optional + Generation int64 `json:"generation,omitempty" protobuf:"varint,7,opt,name=generation"` + + // +optional + CreationTimestamp *meta.Time `json:"creationTimestamp,omitempty" protobuf:"bytes,8,opt,name=creationTimestamp"` // Modified + + // +optional + DeletionTimestamp *meta.Time `json:"deletionTimestamp,omitempty" protobuf:"bytes,9,opt,name=deletionTimestamp"` + + // +optional + DeletionGracePeriodSeconds *int64 `json:"deletionGracePeriodSeconds,omitempty" protobuf:"varint,10,opt,name=deletionGracePeriodSeconds"` + + // +optional + Labels map[string]string `json:"labels,omitempty" protobuf:"bytes,11,rep,name=labels"` + + // +optional + Annotations map[string]string `json:"annotations,omitempty" protobuf:"bytes,12,rep,name=annotations"` + + // +optional + // +patchMergeKey=uid + // +patchStrategy=merge + OwnerReferences []meta.OwnerReference `json:"ownerReferences,omitempty" patchStrategy:"merge" patchMergeKey:"uid" protobuf:"bytes,13,rep,name=ownerReferences"` + + // +optional + // +patchStrategy=merge + Finalizers []string `json:"finalizers,omitempty" patchStrategy:"merge" protobuf:"bytes,14,rep,name=finalizers"` + + // +optional + ClusterName string `json:"clusterName,omitempty" protobuf:"bytes,15,opt,name=clusterName"` + + // +optional + ManagedFields []meta.ManagedFieldsEntry `json:"managedFields,omitempty" protobuf:"bytes,17,rep,name=managedFields"` +} + +// ApicurioRegistryPodSpec is a description of a pod. +type ApicurioRegistryPodSpec struct { + + // +optional + // +patchMergeKey=name + // +patchStrategy=merge,retainKeys Volumes []core.Volume `json:"volumes,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name" protobuf:"bytes,1,rep,name=volumes"` + // +patchMergeKey=name + // +patchStrategy=merge InitContainers []core.Container `json:"initContainers,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,20,rep,name=initContainers"` - Containers []ApicurioRegistrySpecDeploymentPodSpecPreviewContainer `json:"containers,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=containers"` + // +optional + // +patchMergeKey=name + // +patchStrategy=merge + Containers []core.Container `json:"containers,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,2,rep,name=containers"` // Modified + // +optional + // +patchMergeKey=name + // +patchStrategy=merge EphemeralContainers []core.EphemeralContainer `json:"ephemeralContainers,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,34,rep,name=ephemeralContainers"` + // +optional RestartPolicy core.RestartPolicy `json:"restartPolicy,omitempty" protobuf:"bytes,3,opt,name=restartPolicy,casttype=RestartPolicy"` + // +optional TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty" protobuf:"varint,4,opt,name=terminationGracePeriodSeconds"` + // +optional ActiveDeadlineSeconds *int64 `json:"activeDeadlineSeconds,omitempty" protobuf:"varint,5,opt,name=activeDeadlineSeconds"` + // +optional DNSPolicy core.DNSPolicy `json:"dnsPolicy,omitempty" protobuf:"bytes,6,opt,name=dnsPolicy,casttype=DNSPolicy"` + // +optional + // +mapType=atomic NodeSelector map[string]string `json:"nodeSelector,omitempty" protobuf:"bytes,7,rep,name=nodeSelector"` + // +optional ServiceAccountName string `json:"serviceAccountName,omitempty" protobuf:"bytes,8,opt,name=serviceAccountName"` + // +k8s:conversion-gen=false + // +optional DeprecatedServiceAccount string `json:"serviceAccount,omitempty" protobuf:"bytes,9,opt,name=serviceAccount"` + // +optional AutomountServiceAccountToken *bool `json:"automountServiceAccountToken,omitempty" protobuf:"varint,21,opt,name=automountServiceAccountToken"` + // +optional NodeName string `json:"nodeName,omitempty" protobuf:"bytes,10,opt,name=nodeName"` + // +k8s:conversion-gen=false + // +optional HostNetwork bool `json:"hostNetwork,omitempty" protobuf:"varint,11,opt,name=hostNetwork"` + // +k8s:conversion-gen=false + // +optional HostPID bool `json:"hostPID,omitempty" protobuf:"varint,12,opt,name=hostPID"` + // +k8s:conversion-gen=false + // +optional HostIPC bool `json:"hostIPC,omitempty" protobuf:"varint,13,opt,name=hostIPC"` + // +k8s:conversion-gen=false + // +optional ShareProcessNamespace *bool `json:"shareProcessNamespace,omitempty" protobuf:"varint,27,opt,name=shareProcessNamespace"` + // +optional SecurityContext *core.PodSecurityContext `json:"securityContext,omitempty" protobuf:"bytes,14,opt,name=securityContext"` + // +optional + // +patchMergeKey=name + // +patchStrategy=merge ImagePullSecrets []core.LocalObjectReference `json:"imagePullSecrets,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,15,rep,name=imagePullSecrets"` + // +optional Hostname string `json:"hostname,omitempty" protobuf:"bytes,16,opt,name=hostname"` + // +optional Subdomain string `json:"subdomain,omitempty" protobuf:"bytes,17,opt,name=subdomain"` + // +optional Affinity *core.Affinity `json:"affinity,omitempty" protobuf:"bytes,18,opt,name=affinity"` + // +optional SchedulerName string `json:"schedulerName,omitempty" protobuf:"bytes,19,opt,name=schedulerName"` + // +optional Tolerations []core.Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"` + // +optional + // +patchMergeKey=ip + // +patchStrategy=merge HostAliases []core.HostAlias `json:"hostAliases,omitempty" patchStrategy:"merge" patchMergeKey:"ip" protobuf:"bytes,23,rep,name=hostAliases"` + // +optional PriorityClassName string `json:"priorityClassName,omitempty" protobuf:"bytes,24,opt,name=priorityClassName"` + // +optional Priority *int32 `json:"priority,omitempty" protobuf:"bytes,25,opt,name=priority"` + // +optional DNSConfig *core.PodDNSConfig `json:"dnsConfig,omitempty" protobuf:"bytes,26,opt,name=dnsConfig"` + // +optional ReadinessGates []core.PodReadinessGate `json:"readinessGates,omitempty" protobuf:"bytes,28,opt,name=readinessGates"` + // +optional RuntimeClassName *string `json:"runtimeClassName,omitempty" protobuf:"bytes,29,opt,name=runtimeClassName"` + // +optional EnableServiceLinks *bool `json:"enableServiceLinks,omitempty" protobuf:"varint,30,opt,name=enableServiceLinks"` + // +optional PreemptionPolicy *core.PreemptionPolicy `json:"preemptionPolicy,omitempty" protobuf:"bytes,31,opt,name=preemptionPolicy"` + // +optional Overhead core.ResourceList `json:"overhead,omitempty" protobuf:"bytes,32,opt,name=overhead"` + // +optional + // +patchMergeKey=topologyKey + // +patchStrategy=merge + // +listType=map + // +listMapKey=topologyKey + // +listMapKey=whenUnsatisfiable TopologySpreadConstraints []core.TopologySpreadConstraint `json:"topologySpreadConstraints,omitempty" patchStrategy:"merge" patchMergeKey:"topologyKey" protobuf:"bytes,33,opt,name=topologySpreadConstraints"` + // +optional SetHostnameAsFQDN *bool `json:"setHostnameAsFQDN,omitempty" protobuf:"varint,35,opt,name=setHostnameAsFQDN"` + // +optional OS *core.PodOS `json:"os,omitempty" protobuf:"bytes,36,opt,name=os"` } - -// This is a slightly modified copy of k8s.io/api/core/v1.Container: -// - Allow empty field "name" -// - Comments removed, see ApicurioRegistrySpecDeploymentPodSpecPreview for an explanation -type ApicurioRegistrySpecDeploymentPodSpecPreviewContainer struct { - Name string `json:"name,omitempty" protobuf:"bytes,1,opt,name=name"` - - Image string `json:"image,omitempty" protobuf:"bytes,2,opt,name=image"` - - Command []string `json:"command,omitempty" protobuf:"bytes,3,rep,name=command"` - - Args []string `json:"args,omitempty" protobuf:"bytes,4,rep,name=args"` - - WorkingDir string `json:"workingDir,omitempty" protobuf:"bytes,5,opt,name=workingDir"` - - Ports []core.ContainerPort `json:"ports,omitempty" patchStrategy:"merge" patchMergeKey:"containerPort" protobuf:"bytes,6,rep,name=ports"` - - EnvFrom []core.EnvFromSource `json:"envFrom,omitempty" protobuf:"bytes,19,rep,name=envFrom"` - - Env []core.EnvVar `json:"env,omitempty" patchStrategy:"merge" patchMergeKey:"name" protobuf:"bytes,7,rep,name=env"` - - Resources core.ResourceRequirements `json:"resources,omitempty" protobuf:"bytes,8,opt,name=resources"` - - VolumeMounts []core.VolumeMount `json:"volumeMounts,omitempty" patchStrategy:"merge" patchMergeKey:"mountPath" protobuf:"bytes,9,rep,name=volumeMounts"` - - VolumeDevices []core.VolumeDevice `json:"volumeDevices,omitempty" patchStrategy:"merge" patchMergeKey:"devicePath" protobuf:"bytes,21,rep,name=volumeDevices"` - - LivenessProbe *core.Probe `json:"livenessProbe,omitempty" protobuf:"bytes,10,opt,name=livenessProbe"` - - ReadinessProbe *core.Probe `json:"readinessProbe,omitempty" protobuf:"bytes,11,opt,name=readinessProbe"` - - StartupProbe *core.Probe `json:"startupProbe,omitempty" protobuf:"bytes,22,opt,name=startupProbe"` - - Lifecycle *core.Lifecycle `json:"lifecycle,omitempty" protobuf:"bytes,12,opt,name=lifecycle"` - - TerminationMessagePath string `json:"terminationMessagePath,omitempty" protobuf:"bytes,13,opt,name=terminationMessagePath"` - - TerminationMessagePolicy core.TerminationMessagePolicy `json:"terminationMessagePolicy,omitempty" protobuf:"bytes,20,opt,name=terminationMessagePolicy,casttype=TerminationMessagePolicy"` - - ImagePullPolicy core.PullPolicy `json:"imagePullPolicy,omitempty" protobuf:"bytes,14,opt,name=imagePullPolicy,casttype=PullPolicy"` - - SecurityContext *core.SecurityContext `json:"securityContext,omitempty" protobuf:"bytes,15,opt,name=securityContext"` - - Stdin bool `json:"stdin,omitempty" protobuf:"varint,16,opt,name=stdin"` - - StdinOnce bool `json:"stdinOnce,omitempty" protobuf:"varint,17,opt,name=stdinOnce"` - - TTY bool `json:"tty,omitempty" protobuf:"varint,18,opt,name=tty"` -} - -type ApicurioRegistrySpecDeploymentManagedResources struct { - // Operator will not create or manage an Ingress for Apicurio Registry - DisableIngress bool `json:"disableIngress,omitempty"` - // Operator will not create or manage an NetworkPolicy for Apicurio Registry - DisableNetworkPolicy bool `json:"disableNetworkPolicy,omitempty"` - // Operator will not create or manage an PodDisruptionBudget for Apicurio Registry - DisablePodDisruptionBudget bool `json:"disablePodDisruptionBudget,omitempty"` -} - -// ### Status - -type ApicurioRegistryStatus struct { - // Information about the deployed application. - Info ApicurioRegistryStatusInfo `json:"info,omitempty"` - // List of status conditions. - Conditions []meta.Condition `json:"conditions,omitempty"` - // List of resources managed by this operator. - ManagedResources []ApicurioRegistryStatusManagedResource `json:"managedResources,omitempty"` -} - -type ApicurioRegistryStatusInfo struct { - Host string `json:"host,omitempty"` -} - -type ApicurioRegistryStatusManagedResource struct { - Kind string `json:"kind,omitempty"` - Name string `json:"name,omitempty"` - Namespace string `json:"namespace,omitempty"` -} - -// ### Roots - -// ApicurioRegistry represents an Apicurio Registry instance -// +kubebuilder:object:root=true -// +kubebuilder:subresource:status -type ApicurioRegistry struct { - meta.TypeMeta `json:",inline"` - meta.ObjectMeta `json:"metadata,omitempty"` - - Spec ApicurioRegistrySpec `json:"spec,omitempty"` - Status ApicurioRegistryStatus `json:"status,omitempty"` -} - -// ApicurioRegistryList contains a list of ApicurioRegistry -// +kubebuilder:object:root=true -type ApicurioRegistryList struct { - meta.TypeMeta `json:",inline"` - meta.ListMeta `json:"metadata,omitempty"` - Items []ApicurioRegistry `json:"items"` -} - -func init() { - SchemeBuilder.Register(&ApicurioRegistry{}, &ApicurioRegistryList{}) -} diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 3b39b613..3be94dd0 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -86,6 +86,237 @@ func (in *ApicurioRegistryList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApicurioRegistryObjectMeta) DeepCopyInto(out *ApicurioRegistryObjectMeta) { + *out = *in + if in.CreationTimestamp != nil { + in, out := &in.CreationTimestamp, &out.CreationTimestamp + *out = (*in).DeepCopy() + } + if in.DeletionTimestamp != nil { + in, out := &in.DeletionTimestamp, &out.DeletionTimestamp + *out = (*in).DeepCopy() + } + if in.DeletionGracePeriodSeconds != nil { + in, out := &in.DeletionGracePeriodSeconds, &out.DeletionGracePeriodSeconds + *out = new(int64) + **out = **in + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.OwnerReferences != nil { + in, out := &in.OwnerReferences, &out.OwnerReferences + *out = make([]metav1.OwnerReference, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Finalizers != nil { + in, out := &in.Finalizers, &out.Finalizers + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ManagedFields != nil { + in, out := &in.ManagedFields, &out.ManagedFields + *out = make([]metav1.ManagedFieldsEntry, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApicurioRegistryObjectMeta. +func (in *ApicurioRegistryObjectMeta) DeepCopy() *ApicurioRegistryObjectMeta { + if in == nil { + return nil + } + out := new(ApicurioRegistryObjectMeta) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApicurioRegistryPodSpec) DeepCopyInto(out *ApicurioRegistryPodSpec) { + *out = *in + if in.Volumes != nil { + in, out := &in.Volumes, &out.Volumes + *out = make([]corev1.Volume, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.InitContainers != nil { + in, out := &in.InitContainers, &out.InitContainers + *out = make([]corev1.Container, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Containers != nil { + in, out := &in.Containers, &out.Containers + *out = make([]corev1.Container, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.EphemeralContainers != nil { + in, out := &in.EphemeralContainers, &out.EphemeralContainers + *out = make([]corev1.EphemeralContainer, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.TerminationGracePeriodSeconds != nil { + in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds + *out = new(int64) + **out = **in + } + if in.ActiveDeadlineSeconds != nil { + in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds + *out = new(int64) + **out = **in + } + 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 + } + } + if in.AutomountServiceAccountToken != nil { + in, out := &in.AutomountServiceAccountToken, &out.AutomountServiceAccountToken + *out = new(bool) + **out = **in + } + if in.ShareProcessNamespace != nil { + in, out := &in.ShareProcessNamespace, &out.ShareProcessNamespace + *out = new(bool) + **out = **in + } + if in.SecurityContext != nil { + in, out := &in.SecurityContext, &out.SecurityContext + *out = new(corev1.PodSecurityContext) + (*in).DeepCopyInto(*out) + } + if in.ImagePullSecrets != nil { + in, out := &in.ImagePullSecrets, &out.ImagePullSecrets + *out = make([]corev1.LocalObjectReference, len(*in)) + copy(*out, *in) + } + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(corev1.Affinity) + (*in).DeepCopyInto(*out) + } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]corev1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.HostAliases != nil { + in, out := &in.HostAliases, &out.HostAliases + *out = make([]corev1.HostAlias, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Priority != nil { + in, out := &in.Priority, &out.Priority + *out = new(int32) + **out = **in + } + if in.DNSConfig != nil { + in, out := &in.DNSConfig, &out.DNSConfig + *out = new(corev1.PodDNSConfig) + (*in).DeepCopyInto(*out) + } + if in.ReadinessGates != nil { + in, out := &in.ReadinessGates, &out.ReadinessGates + *out = make([]corev1.PodReadinessGate, len(*in)) + copy(*out, *in) + } + if in.RuntimeClassName != nil { + in, out := &in.RuntimeClassName, &out.RuntimeClassName + *out = new(string) + **out = **in + } + if in.EnableServiceLinks != nil { + in, out := &in.EnableServiceLinks, &out.EnableServiceLinks + *out = new(bool) + **out = **in + } + if in.PreemptionPolicy != nil { + in, out := &in.PreemptionPolicy, &out.PreemptionPolicy + *out = new(corev1.PreemptionPolicy) + **out = **in + } + if in.Overhead != nil { + in, out := &in.Overhead, &out.Overhead + *out = make(corev1.ResourceList, len(*in)) + for key, val := range *in { + (*out)[key] = val.DeepCopy() + } + } + if in.TopologySpreadConstraints != nil { + in, out := &in.TopologySpreadConstraints, &out.TopologySpreadConstraints + *out = make([]corev1.TopologySpreadConstraint, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SetHostnameAsFQDN != nil { + in, out := &in.SetHostnameAsFQDN, &out.SetHostnameAsFQDN + *out = new(bool) + **out = **in + } + if in.OS != nil { + in, out := &in.OS, &out.OS + *out = new(corev1.PodOS) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApicurioRegistryPodSpec. +func (in *ApicurioRegistryPodSpec) DeepCopy() *ApicurioRegistryPodSpec { + if in == nil { + return nil + } + out := new(ApicurioRegistryPodSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ApicurioRegistryPodTemplateSpec) DeepCopyInto(out *ApicurioRegistryPodTemplateSpec) { + *out = *in + in.Metadata.DeepCopyInto(&out.Metadata) + in.Spec.DeepCopyInto(&out.Spec) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApicurioRegistryPodTemplateSpec. +func (in *ApicurioRegistryPodTemplateSpec) DeepCopy() *ApicurioRegistryPodTemplateSpec { + if in == nil { + return nil + } + out := new(ApicurioRegistryPodTemplateSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ApicurioRegistrySpec) DeepCopyInto(out *ApicurioRegistrySpec) { *out = *in @@ -307,7 +538,7 @@ func (in *ApicurioRegistrySpecDeployment) DeepCopyInto(out *ApicurioRegistrySpec copy(*out, *in) } out.ManagedResources = in.ManagedResources - in.PodSpecPreview.DeepCopyInto(&out.PodSpecPreview) + in.PodTemplateSpecPreview.DeepCopyInto(&out.PodTemplateSpecPreview) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApicurioRegistrySpecDeployment. @@ -364,241 +595,6 @@ func (in *ApicurioRegistrySpecDeploymentMetadata) DeepCopy() *ApicurioRegistrySp return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ApicurioRegistrySpecDeploymentPodSpecPreview) DeepCopyInto(out *ApicurioRegistrySpecDeploymentPodSpecPreview) { - *out = *in - if in.Volumes != nil { - in, out := &in.Volumes, &out.Volumes - *out = make([]corev1.Volume, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.InitContainers != nil { - in, out := &in.InitContainers, &out.InitContainers - *out = make([]corev1.Container, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Containers != nil { - in, out := &in.Containers, &out.Containers - *out = make([]ApicurioRegistrySpecDeploymentPodSpecPreviewContainer, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.EphemeralContainers != nil { - in, out := &in.EphemeralContainers, &out.EphemeralContainers - *out = make([]corev1.EphemeralContainer, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.TerminationGracePeriodSeconds != nil { - in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds - *out = new(int64) - **out = **in - } - if in.ActiveDeadlineSeconds != nil { - in, out := &in.ActiveDeadlineSeconds, &out.ActiveDeadlineSeconds - *out = new(int64) - **out = **in - } - 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 - } - } - if in.AutomountServiceAccountToken != nil { - in, out := &in.AutomountServiceAccountToken, &out.AutomountServiceAccountToken - *out = new(bool) - **out = **in - } - if in.ShareProcessNamespace != nil { - in, out := &in.ShareProcessNamespace, &out.ShareProcessNamespace - *out = new(bool) - **out = **in - } - if in.SecurityContext != nil { - in, out := &in.SecurityContext, &out.SecurityContext - *out = new(corev1.PodSecurityContext) - (*in).DeepCopyInto(*out) - } - if in.ImagePullSecrets != nil { - in, out := &in.ImagePullSecrets, &out.ImagePullSecrets - *out = make([]corev1.LocalObjectReference, len(*in)) - copy(*out, *in) - } - if in.Affinity != nil { - in, out := &in.Affinity, &out.Affinity - *out = new(corev1.Affinity) - (*in).DeepCopyInto(*out) - } - if in.Tolerations != nil { - in, out := &in.Tolerations, &out.Tolerations - *out = make([]corev1.Toleration, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.HostAliases != nil { - in, out := &in.HostAliases, &out.HostAliases - *out = make([]corev1.HostAlias, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Priority != nil { - in, out := &in.Priority, &out.Priority - *out = new(int32) - **out = **in - } - if in.DNSConfig != nil { - in, out := &in.DNSConfig, &out.DNSConfig - *out = new(corev1.PodDNSConfig) - (*in).DeepCopyInto(*out) - } - if in.ReadinessGates != nil { - in, out := &in.ReadinessGates, &out.ReadinessGates - *out = make([]corev1.PodReadinessGate, len(*in)) - copy(*out, *in) - } - if in.RuntimeClassName != nil { - in, out := &in.RuntimeClassName, &out.RuntimeClassName - *out = new(string) - **out = **in - } - if in.EnableServiceLinks != nil { - in, out := &in.EnableServiceLinks, &out.EnableServiceLinks - *out = new(bool) - **out = **in - } - if in.PreemptionPolicy != nil { - in, out := &in.PreemptionPolicy, &out.PreemptionPolicy - *out = new(corev1.PreemptionPolicy) - **out = **in - } - if in.Overhead != nil { - in, out := &in.Overhead, &out.Overhead - *out = make(corev1.ResourceList, len(*in)) - for key, val := range *in { - (*out)[key] = val.DeepCopy() - } - } - if in.TopologySpreadConstraints != nil { - in, out := &in.TopologySpreadConstraints, &out.TopologySpreadConstraints - *out = make([]corev1.TopologySpreadConstraint, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.SetHostnameAsFQDN != nil { - in, out := &in.SetHostnameAsFQDN, &out.SetHostnameAsFQDN - *out = new(bool) - **out = **in - } - if in.OS != nil { - in, out := &in.OS, &out.OS - *out = new(corev1.PodOS) - **out = **in - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApicurioRegistrySpecDeploymentPodSpecPreview. -func (in *ApicurioRegistrySpecDeploymentPodSpecPreview) DeepCopy() *ApicurioRegistrySpecDeploymentPodSpecPreview { - if in == nil { - return nil - } - out := new(ApicurioRegistrySpecDeploymentPodSpecPreview) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ApicurioRegistrySpecDeploymentPodSpecPreviewContainer) DeepCopyInto(out *ApicurioRegistrySpecDeploymentPodSpecPreviewContainer) { - *out = *in - if in.Command != nil { - in, out := &in.Command, &out.Command - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Args != nil { - in, out := &in.Args, &out.Args - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Ports != nil { - in, out := &in.Ports, &out.Ports - *out = make([]corev1.ContainerPort, len(*in)) - copy(*out, *in) - } - if in.EnvFrom != nil { - in, out := &in.EnvFrom, &out.EnvFrom - *out = make([]corev1.EnvFromSource, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Env != nil { - in, out := &in.Env, &out.Env - *out = make([]corev1.EnvVar, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - in.Resources.DeepCopyInto(&out.Resources) - if in.VolumeMounts != nil { - in, out := &in.VolumeMounts, &out.VolumeMounts - *out = make([]corev1.VolumeMount, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.VolumeDevices != nil { - in, out := &in.VolumeDevices, &out.VolumeDevices - *out = make([]corev1.VolumeDevice, len(*in)) - copy(*out, *in) - } - if in.LivenessProbe != nil { - in, out := &in.LivenessProbe, &out.LivenessProbe - *out = new(corev1.Probe) - (*in).DeepCopyInto(*out) - } - if in.ReadinessProbe != nil { - in, out := &in.ReadinessProbe, &out.ReadinessProbe - *out = new(corev1.Probe) - (*in).DeepCopyInto(*out) - } - if in.StartupProbe != nil { - in, out := &in.StartupProbe, &out.StartupProbe - *out = new(corev1.Probe) - (*in).DeepCopyInto(*out) - } - if in.Lifecycle != nil { - in, out := &in.Lifecycle, &out.Lifecycle - *out = new(corev1.Lifecycle) - (*in).DeepCopyInto(*out) - } - if in.SecurityContext != nil { - in, out := &in.SecurityContext, &out.SecurityContext - *out = new(corev1.SecurityContext) - (*in).DeepCopyInto(*out) - } -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApicurioRegistrySpecDeploymentPodSpecPreviewContainer. -func (in *ApicurioRegistrySpecDeploymentPodSpecPreviewContainer) DeepCopy() *ApicurioRegistrySpecDeploymentPodSpecPreviewContainer { - if in == nil { - return nil - } - out := new(ApicurioRegistrySpecDeploymentPodSpecPreviewContainer) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ApicurioRegistryStatus) DeepCopyInto(out *ApicurioRegistryStatus) { *out = *in diff --git a/config/crd/resources/registry.apicur.io_apicurioregistries.yaml b/config/crd/resources/registry.apicur.io_apicurioregistries.yaml index d88db6c9..67567637 100644 --- a/config/crd/resources/registry.apicur.io_apicurioregistries.yaml +++ b/config/crd/resources/registry.apicur.io_apicurioregistries.yaml @@ -1,4 +1,3 @@ ---- apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: @@ -15,1253 +14,3895 @@ spec: singular: apicurioregistry scope: Namespaced versions: - - name: v1 - schema: - openAPIV3Schema: - description: ApicurioRegistry represents an Apicurio Registry instance - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: ApicurioRegistrySpec defines the desired state of ApicurioRegistry - properties: - configuration: - properties: - env: - items: - description: EnvVar represents an environment variable present - in a Container. + - name: v1 + schema: + openAPIV3Schema: + description: ApicurioRegistry represents an Apicurio Registry instance + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: ApicurioRegistrySpec defines the desired state of ApicurioRegistry + properties: + configuration: + properties: + env: + items: + description: EnvVar represents an environment variable present in a Container. + properties: + name: + description: Name of the environment variable. Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) are expanded using the previously defined environment variables in the container and any service environment variables. If a variable cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless of whether the variable exists or not. Defaults to "".' + type: string + valueFrom: + description: Source for the environment variable's value. Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap or its key must be defined + type: boolean + required: + - key + type: object + fieldRef: + description: 'Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['''']`, `metadata.annotations['''']`, spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema the FieldPath is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the specified API version. + type: string + required: + - fieldPath + type: object + resourceFieldRef: + description: 'Selects a resource of the container: only resources limits and requests (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported.' + properties: + containerName: + description: 'Container name: required for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + secretKeyRef: + description: Selects a key of a secret in the pod's namespace + properties: + key: + description: The key of the secret to select from. Must be a valid secret key. + type: string + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the Secret or its key must be defined + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + kafkasql: properties: - name: - description: Name of the environment variable. Must be a - C_IDENTIFIER. - type: string - value: - description: 'Variable references $(VAR_NAME) are expanded - using the previously defined environment variables in - the container and any service environment variables. If - a variable cannot be resolved, the reference in the input - string will be unchanged. Double $$ are reduced to a single - $, which allows for escaping the $(VAR_NAME) syntax: i.e. - "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". - Escaped references will never be expanded, regardless - of whether the variable exists or not. Defaults to "".' + bootstrapServers: type: string - valueFrom: - description: Source for the environment variable's value. - Cannot be used if value is not empty. + security: properties: - configMapKeyRef: - description: Selects a key of a ConfigMap. + scram: properties: - key: - description: The key to select. + mechanism: type: string - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, - uid?' - type: string - optional: - description: Specify whether the ConfigMap or its - key must be defined - type: boolean - required: - - key - type: object - fieldRef: - description: 'Selects a field of the pod: supports metadata.name, - metadata.namespace, `metadata.labels['''']`, - `metadata.annotations['''']`, spec.nodeName, - spec.serviceAccountName, status.hostIP, status.podIP, - status.podIPs.' - properties: - apiVersion: - description: Version of the schema the FieldPath - is written in terms of, defaults to "v1". + passwordSecretName: type: string - fieldPath: - description: Path of the field to select in the - specified API version. - type: string - required: - - fieldPath - type: object - resourceFieldRef: - description: 'Selects a resource of the container: only - resources limits and requests (limits.cpu, limits.memory, - limits.ephemeral-storage, requests.cpu, requests.memory - and requests.ephemeral-storage) are currently supported.' - properties: - containerName: - description: 'Container name: required for volumes, - optional for env vars' + truststoreSecretName: type: string - divisor: - anyOf: - - type: integer - - type: string - description: Specifies the output format of the - exposed resources, defaults to "1" - pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ - x-kubernetes-int-or-string: true - resource: - description: 'Required: resource to select' + user: type: string - required: - - resource type: object - secretKeyRef: - description: Selects a key of a secret in the pod's - namespace + tls: properties: - key: - description: The key of the secret to select from. Must - be a valid secret key. + keystoreSecretName: type: string - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, - uid?' + truststoreSecretName: type: string - optional: - description: Specify whether the Secret or its key - must be defined - type: boolean - required: - - key type: object type: object - required: - - name type: object - type: array - kafkasql: - properties: - bootstrapServers: - type: string - security: - properties: - scram: - properties: - mechanism: - type: string - passwordSecretName: - type: string - truststoreSecretName: - type: string - user: - type: string - type: object - tls: - properties: - keystoreSecretName: - type: string - truststoreSecretName: - type: string - type: object - type: object - type: object - logLevel: - type: string - persistence: - type: string - security: - properties: - https: - properties: - certificate: - type: string - enabled: - type: boolean - key: - type: string - secretName: - type: string - type: object - keycloak: - properties: - apiClientId: - type: string - realm: - type: string - uiClientId: - type: string - url: - type: string - type: object - type: object - sql: - properties: - dataSource: - properties: - password: - type: string - url: - type: string - userName: - type: string - type: object - type: object - ui: - properties: - readOnly: - type: boolean - type: object - type: object - deployment: - properties: - affinity: - description: Affinity is a group of affinity scheduling rules. - properties: - nodeAffinity: - description: Describes node affinity scheduling rules for - the pod. - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods - to nodes that satisfy the affinity expressions specified - by this field, but it may choose a node that violates - one or more of the expressions. The node that is most - preferred is the one with the greatest sum of weights, - i.e. for each node that meets all of the scheduling - requirements (resource request, requiredDuringScheduling - affinity expressions, etc.), compute a sum by iterating - through the elements of this field and adding "weight" - to the sum if the node matches the corresponding matchExpressions; - the node(s) with the highest sum are the most preferred. - items: - description: An empty preferred scheduling term matches - all objects with implicit weight 0 (i.e. it's a no-op). - A null preferred scheduling term matches no objects - (i.e. is also a no-op). - properties: - preference: - description: A node selector term, associated with - the corresponding weight. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: A node selector requirement is - a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. - type: string - values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If the - operator is Exists or DoesNotExist, - the values array must be empty. If the - operator is Gt or Lt, the values array - must have a single element, which will - be interpreted as an integer. This array - is replaced during a strategic merge - patch. - items: + logLevel: + type: string + persistence: + type: string + security: + properties: + https: + properties: + disableHttp: + type: boolean + secretName: + type: string + type: object + keycloak: + properties: + apiClientId: + type: string + realm: + type: string + uiClientId: + type: string + url: + type: string + type: object + type: object + sql: + properties: + dataSource: + properties: + password: + type: string + url: + type: string + userName: + type: string + type: object + type: object + ui: + properties: + readOnly: + type: boolean + type: object + type: object + deployment: + properties: + affinity: + description: Affinity is a group of affinity scheduling rules. + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node matches the corresponding matchExpressions; the node(s) with the highest sum are the most preferred. + items: + description: An empty preferred scheduling term matches all objects with implicit weight 0 (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: The label key that the selector applies to. type: string - type: array - required: - - key - - operator - type: object - type: array - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: A node selector requirement is - a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. - type: string - values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If the - operator is Exists or DoesNotExist, - the values array must be empty. If the - operator is Gt or Lt, the values array - must have a single element, which will - be interpreted as an integer. This array - is replaced during a strategic merge - patch. - items: + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string - type: array - required: - - key - - operator - type: object - type: array - type: object - weight: - description: Weight associated with matching the - corresponding nodeSelectorTerm, in the range 1-100. - format: int32 - type: integer - required: - - preference - - weight - type: object - type: array - requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified by - this field are not met at scheduling time, the pod will - not be scheduled onto the node. If the affinity requirements - specified by this field cease to be met at some point - during pod execution (e.g. due to an update), the system - may or may not try to eventually evict the pod from - its node. - properties: - nodeSelectorTerms: - description: Required. A list of node selector terms. - The terms are ORed. - items: - description: A null or empty node selector term - matches no objects. The requirements of them are - ANDed. The TopologySelectorTerm type implements - a subset of the NodeSelectorTerm. - properties: - matchExpressions: - description: A list of node selector requirements - by node's labels. - items: - description: A node selector requirement is - a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. - type: string - values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If the - operator is Exists or DoesNotExist, - the values array must be empty. If the - operator is Gt or Lt, the values array - must have a single element, which will - be interpreted as an integer. This array - is replaced during a strategic merge - patch. - items: + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: The label key that the selector applies to. type: string - type: array - required: - - key - - operator - type: object - type: array - matchFields: - description: A list of node selector requirements - by node's fields. - items: - description: A node selector requirement is - a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: The label key that the selector - applies to. - type: string - operator: - description: Represents a key's relationship - to a set of values. Valid operators - are In, NotIn, Exists, DoesNotExist. - Gt, and Lt. - type: string - values: - description: An array of string values. - If the operator is In or NotIn, the - values array must be non-empty. If the - operator is Exists or DoesNotExist, - the values array must be empty. If the - operator is Gt or Lt, the values array - must have a single element, which will - be interpreted as an integer. This array - is replaced during a strategic merge - patch. - items: + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. type: string - type: array - required: - - key - - operator - type: object - type: array - type: object - type: array - required: - - nodeSelectorTerms - type: object - type: object - podAffinity: - description: Describes pod affinity scheduling rules (e.g. - co-locate this pod in the same node, zone, etc. as some - other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods - to nodes that satisfy the affinity expressions specified - by this field, but it may choose a node that violates - one or more of the expressions. The node that is most - preferred is the one with the greatest sum of weights, - i.e. for each node that meets all of the scheduling - requirements (resource request, requiredDuringScheduling - affinity expressions, etc.), compute a sum by iterating - through the elements of this field and adding "weight" - to the sum if the node has pods which matches the corresponding - podAffinityTerm; the node(s) with the highest sum are - the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: A label query over a set of resources, - in this case pods. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The requirements - are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key - that the selector applies to. - type: string - operator: - description: operator represents a - key's relationship to a set of values. - Valid operators are In, NotIn, Exists - and DoesNotExist. + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + items: type: string - values: - description: values is an array of - string values. If the operator is - In or NotIn, the values array must - be non-empty. If the operator is - Exists or DoesNotExist, the values - array must be empty. This array - is replaced during a strategic merge - patch. - items: - type: string - type: array - required: + type: array + required: - key - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. type: object - type: object - namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by - this field and the ones listed in the namespaces - field. null selector and null or empty namespaces - list means "this pod's namespace". An empty - selector ({}) matches all namespaces. This - field is beta-level and is only honored when - PodAffinityNamespaceSelector feature is enabled. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The requirements - are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key - that the selector applies to. + type: array + type: object + weight: + description: Weight associated with matching the corresponding nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to an update), the system may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The terms are ORed. + items: + description: A null or empty node selector term matches no objects. The requirements of them are ANDed. The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by node's labels. + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + items: type: string - operator: - description: operator represents a - key's relationship to a set of values. - Valid operators are In, NotIn, Exists - and DoesNotExist. + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements by node's fields. + items: + description: A node selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: The label key that the selector applies to. + type: string + operator: + description: Represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: An array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. If the operator is Gt or Lt, the values array must have a single element, which will be interpreted as an integer. This array is replaced during a strategic merge patch. + items: type: string - values: - description: values is an array of - string values. If the operator is - In or NotIn, the values array must - be non-empty. If the operator is - Exists or DoesNotExist, the values - array must be empty. This array - is replaced during a strategic merge - patch. - items: - type: string - type: array - required: + type: array + required: - key - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. type: object - type: object - namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. - The term is applied to the union of the namespaces - listed in this field and the ones selected - by namespaceSelector. null or empty namespaces - list and null namespaceSelector means "this - pod's namespace" - items: - type: string - type: array - topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the - pods matching the labelSelector in the specified - namespaces, where co-located is defined as - running on a node whose value of the label - with key topologyKey matches that of any node - on which any of the selected pods is running. - Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - weight: - description: weight associated with matching the - corresponding podAffinityTerm, in the range 1-100. - format: int32 - type: integer + type: array + type: object + type: array required: - - podAffinityTerm - - weight + - nodeSelectorTerms type: object - type: array - requiredDuringSchedulingIgnoredDuringExecution: - description: If the affinity requirements specified by - this field are not met at scheduling time, the pod will - not be scheduled onto the node. If the affinity requirements - specified by this field cease to be met at some point - during pod execution (e.g. due to a pod label update), - the system may or may not try to eventually evict the - pod from its node. When there are multiple elements, - the lists of nodes corresponding to each podAffinityTerm - are intersected, i.e. all terms must be satisfied. - items: - description: Defines a set of pods (namely those matching - the labelSelector relative to the given namespace(s)) - that this pod should be co-located (affinity) or not - co-located (anti-affinity) with, where co-located - is defined as running on a node whose value of the - label with key matches that of any node - on which a pod of the set of pods is running - properties: - labelSelector: - description: A label query over a set of resources, - in this case pods. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are - ANDed. - items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: key is the label key that - the selector applies to. - type: string - operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic - merge patch. + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - type: string + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object type: array - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. - type: object - type: object - namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by this - field and the ones listed in the namespaces field. - null selector and null or empty namespaces list - means "this pod's namespace". An empty selector - ({}) matches all namespaces. This field is beta-level - and is only honored when PodAffinityNamespaceSelector - feature is enabled. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are - ANDed. - items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: key is the label key that - the selector applies to. - type: string - operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic - merge patch. + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is beta-level and is only honored when PodAffinityNamespaceSelector feature is enabled. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - type: string + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object type: array - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. - type: object - type: object - namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. The - term is applied to the union of the namespaces - listed in this field and the ones selected by - namespaceSelector. null or empty namespaces list - and null namespaceSelector means "this pod's namespace" - items: - type: string - type: array - topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the pods - matching the labelSelector in the specified namespaces, - where co-located is defined as running on a node - whose value of the label with key topologyKey - matches that of any node on which any of the selected - pods is running. Empty topologyKey is not allowed. - type: string - required: - - topologyKey - type: object - type: array - type: object - podAntiAffinity: - description: Describes pod anti-affinity scheduling rules - (e.g. avoid putting this pod in the same node, zone, etc. - as some other pod(s)). - properties: - preferredDuringSchedulingIgnoredDuringExecution: - description: The scheduler will prefer to schedule pods - to nodes that satisfy the anti-affinity expressions - specified by this field, but it may choose a node that - violates one or more of the expressions. The node that - is most preferred is the one with the greatest sum of - weights, i.e. for each node that meets all of the scheduling - requirements (resource request, requiredDuringScheduling - anti-affinity expressions, etc.), compute a sum by iterating - through the elements of this field and adding "weight" - to the sum if the node has pods which matches the corresponding - podAffinityTerm; the node(s) with the highest sum are - the most preferred. - items: - description: The weights of all of the matched WeightedPodAffinityTerm - fields are added per-node to find the most preferred - node(s) - properties: - podAffinityTerm: - description: Required. A pod affinity term, associated - with the corresponding weight. - properties: - labelSelector: - description: A label query over a set of resources, - in this case pods. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The requirements - are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key - that the selector applies to. - type: string - operator: - description: operator represents a - key's relationship to a set of values. - Valid operators are In, NotIn, Exists - and DoesNotExist. + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + items: type: string - values: - description: values is an array of - string values. If the operator is - In or NotIn, the values array must - be non-empty. If the operator is - Exists or DoesNotExist, the values - array must be empty. This array - is replaced during a strategic merge - patch. - items: - type: string - type: array - required: + type: array + required: - key - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. type: object - type: object - namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by - this field and the ones listed in the namespaces - field. null selector and null or empty namespaces - list means "this pod's namespace". An empty - selector ({}) matches all namespaces. This - field is beta-level and is only honored when - PodAffinityNamespaceSelector feature is enabled. - properties: - matchExpressions: - description: matchExpressions is a list - of label selector requirements. The requirements - are ANDed. - items: - description: A label selector requirement - is a selector that contains values, - a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key - that the selector applies to. - type: string - operator: - description: operator represents a - key's relationship to a set of values. - Valid operators are In, NotIn, Exists - and DoesNotExist. + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is beta-level and is only honored when PodAffinityNamespaceSelector feature is enabled. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + items: type: string - values: - description: values is an array of - string values. If the operator is - In or NotIn, the values array must - be non-empty. If the operator is - Exists or DoesNotExist, the values - array must be empty. This array - is replaced during a strategic merge - patch. - items: - type: string - type: array - required: + type: array + required: - key - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator - is "In", and the values array contains - only "value". The requirements are ANDed. type: object - type: object - namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. - The term is applied to the union of the namespaces - listed in this field and the ones selected - by namespaceSelector. null or empty namespaces - list and null namespaceSelector means "this - pod's namespace" - items: - type: string - type: array - topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the - pods matching the labelSelector in the specified - namespaces, where co-located is defined as - running on a node whose value of the label - with key topologyKey matches that of any node - on which any of the selected pods is running. - Empty topologyKey is not allowed. + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace" + items: type: string - required: + type: array + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + required: - topologyKey - type: object - weight: - description: weight associated with matching the - corresponding podAffinityTerm, in the range 1-100. - format: int32 - type: integer - required: - - podAffinityTerm - - weight - type: object - type: array - requiredDuringSchedulingIgnoredDuringExecution: - description: If the anti-affinity requirements specified - by this field are not met at scheduling time, the pod - will not be scheduled onto the node. If the anti-affinity - requirements specified by this field cease to be met - at some point during pod execution (e.g. due to a pod - label update), the system may or may not try to eventually - evict the pod from its node. When there are multiple - elements, the lists of nodes corresponding to each podAffinityTerm - are intersected, i.e. all terms must be satisfied. - items: - description: Defines a set of pods (namely those matching - the labelSelector relative to the given namespace(s)) - that this pod should be co-located (affinity) or not - co-located (anti-affinity) with, where co-located - is defined as running on a node whose value of the - label with key matches that of any node - on which a pod of the set of pods is running - properties: - labelSelector: - description: A label query over a set of resources, - in this case pods. - properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are - ANDed. - items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: key is the label key that - the selector applies to. - type: string - operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic - merge patch. + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule pods to nodes that satisfy the anti-affinity expressions specified by this field, but it may choose a node that violates one or more of the expressions. The node that is most preferred is the one with the greatest sum of weights, i.e. for each node that meets all of the scheduling requirements (resource request, requiredDuringScheduling anti-affinity expressions, etc.), compute a sum by iterating through the elements of this field and adding "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated with the corresponding weight. + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - type: string + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object type: array - required: - - key - - operator + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is beta-level and is only honored when PodAffinityNamespaceSelector feature is enabled. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching the corresponding podAffinityTerm, in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements specified by this field are not met at scheduling time, the pod will not be scheduled onto the node. If the anti-affinity requirements specified by this field cease to be met at some point during pod execution (e.g. due to a pod label update), the system may or may not try to eventually evict the pod from its node. When there are multiple elements, the lists of nodes corresponding to each podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: Defines a set of pods (namely those matching the labelSelector relative to the given namespace(s)) that this pod should be co-located (affinity) or not co-located (anti-affinity) with, where co-located is defined as running on a node whose value of the label with key matches that of any node on which a pod of the set of pods is running + properties: + labelSelector: + description: A label query over a set of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + namespaceSelector: + description: A label query over the set of namespaces that the term applies to. The term is applied to the union of the namespaces selected by this field and the ones listed in the namespaces field. null selector and null or empty namespaces list means "this pod's namespace". An empty selector ({}) matches all namespaces. This field is beta-level and is only honored when PodAffinityNamespaceSelector feature is enabled. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values. + properties: + key: + description: key is the label key that the selector applies to. + type: string + operator: + description: operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + namespaces: + description: namespaces specifies a static list of namespace names that the term applies to. The term is applied to the union of the namespaces listed in this field and the ones selected by namespaceSelector. null or empty namespaces list and null namespaceSelector means "this pod's namespace" + items: + type: string + type: array + topologyKey: + description: This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching the labelSelector in the specified namespaces, where co-located is defined as running on a node whose value of the label with key topologyKey matches that of any node on which any of the selected pods is running. Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + host: + type: string + image: + description: Image set in the Deployment pod template. Overrides the values in the REGISTRY_IMAGE_MEM, REGISTRY_IMAGE_KAFKASQL and REGISTRY_IMAGE_SQL operator environment variables. + type: string + imagePullSecrets: + description: List of secrets in the same namespace to use for pulling the Deployment pod image. + items: + description: LocalObjectReference contains enough information to let you locate the referenced object inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names TODO: Add other useful fields. apiVersion, kind, uid?' + type: string + type: object + type: array + managedResources: + description: Configure how the Operator manages Kubernetes resources + properties: + disableIngress: + description: Operator will not create or manage an Ingress for Apicurio Registry + type: boolean + disableNetworkPolicy: + description: Operator will not create or manage an NetworkPolicy for Apicurio Registry + type: boolean + disablePodDisruptionBudget: + description: Operator will not create or manage an PodDisruptionBudget for Apicurio Registry + type: boolean + type: object + metadata: + description: Metadata applied to the Deployment pod template. + properties: + annotations: + additionalProperties: + type: string + description: Annotations added to the Deployment pod template. + type: object + labels: + additionalProperties: + type: string + description: Labels added to the Deployment pod template. + type: object + type: object + podTemplateSpecPreview: + properties: + metadata: + properties: + annotations: + additionalProperties: + type: string + type: object + clusterName: + type: string + creationTimestamp: + format: date-time + type: string + deletionGracePeriodSeconds: + format: int64 + type: integer + deletionTimestamp: + format: date-time + type: string + finalizers: + items: + type: string + type: array + generateName: + type: string + generation: + format: int64 + type: integer + labels: + additionalProperties: + type: string + type: object + managedFields: + items: + properties: + apiVersion: + type: string + fieldsType: + type: string + fieldsV1: + type: object + manager: + type: string + operation: + type: string + subresource: + type: string + time: + format: date-time + type: string + type: object + type: array + name: + type: string + namespace: + type: string + ownerReferences: + items: + properties: + apiVersion: + type: string + blockOwnerDeletion: + type: boolean + controller: + type: boolean + kind: + type: string + name: + type: string + uid: + type: string + required: + - apiVersion + - kind + - name + - uid + type: object + type: array + resourceVersion: + type: string + selfLink: + type: string + uid: + type: string + type: object + spec: + properties: + activeDeadlineSeconds: + format: int64 + type: integer + affinity: + properties: + nodeAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + preference: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + weight: + format: int32 + type: integer + required: + - preference + - weight type: object type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. + requiredDuringSchedulingIgnoredDuringExecution: + properties: + nodeSelectorTerms: + items: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + type: array + required: + - nodeSelectorTerms type: object type: object - namespaceSelector: - description: A label query over the set of namespaces - that the term applies to. The term is applied - to the union of the namespaces selected by this - field and the ones listed in the namespaces field. - null selector and null or empty namespaces list - means "this pod's namespace". An empty selector - ({}) matches all namespaces. This field is beta-level - and is only honored when PodAffinityNamespaceSelector - feature is enabled. + podAffinity: + properties: + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: properties: - matchExpressions: - description: matchExpressions is a list of label - selector requirements. The requirements are - ANDed. + preferredDuringSchedulingIgnoredDuringExecution: + items: + properties: + podAffinityTerm: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + weight: + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: items: - description: A label selector requirement - is a selector that contains values, a key, - and an operator that relates the key and - values. - properties: - key: - description: key is the label key that - the selector applies to. - type: string - operator: - description: operator represents a key's - relationship to a set of values. Valid - operators are In, NotIn, Exists and - DoesNotExist. - type: string - values: - description: values is an array of string - values. If the operator is In or NotIn, - the values array must be non-empty. - If the operator is Exists or DoesNotExist, - the values array must be empty. This - array is replaced during a strategic - merge patch. + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaceSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + namespaces: + items: + type: string + type: array + topologyKey: + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + automountServiceAccountToken: + type: boolean + containers: + items: + properties: + args: + items: + type: string + type: array + command: + items: + type: string + type: array + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + type: object + type: array + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + type: string + required: + - name + type: object + type: array + dnsConfig: + properties: + nameservers: + items: + type: string + type: array + options: + items: + properties: + name: + type: string + value: + type: string + type: object + type: array + searches: + items: + type: string + type: array + type: object + dnsPolicy: + type: string + enableServiceLinks: + type: boolean + ephemeralContainers: + items: + properties: + args: + items: + type: string + type: array + command: + items: + type: string + type: array + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + type: object + type: array + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + targetContainerName: + type: string + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + type: string + required: + - name + type: object + type: array + hostAliases: + items: + properties: + hostnames: + items: + type: string + type: array + ip: + type: string + type: object + type: array + hostIPC: + type: boolean + hostNetwork: + type: boolean + hostPID: + type: boolean + hostname: + type: string + imagePullSecrets: + items: + properties: + name: + type: string + type: object + type: array + initContainers: + items: + properties: + args: + items: + type: string + type: array + command: + items: + type: string + type: array + env: + items: + properties: + name: + type: string + value: + type: string + valueFrom: + properties: + configMapKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + secretKeyRef: + properties: + key: + type: string + name: + type: string + optional: + type: boolean + required: + - key + type: object + type: object + required: + - name + type: object + type: array + envFrom: + items: + properties: + configMapRef: + properties: + name: + type: string + optional: + type: boolean + type: object + prefix: + type: string + secretRef: + properties: + name: + type: string + optional: + type: boolean + type: object + type: object + type: array + image: + type: string + imagePullPolicy: + type: string + lifecycle: + properties: + postStart: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + name: + type: string + ports: + items: + properties: + containerPort: + format: int32 + type: integer + hostIP: + type: string + hostPort: + format: int32 + type: integer + name: + type: string + protocol: + default: TCP + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + properties: + exec: + properties: + command: + items: + type: string + type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string + required: + - port + type: object + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + securityContext: + properties: + allowPrivilegeEscalation: + type: boolean + capabilities: + properties: + add: + items: + type: string + type: array + drop: + items: + type: string + type: array + type: object + privileged: + type: boolean + procMount: + type: string + readOnlyRootFilesystem: + type: boolean + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + startupProbe: + properties: + exec: + properties: + command: items: type: string type: array + type: object + failureThreshold: + format: int32 + type: integer + grpc: + properties: + port: + format: int32 + type: integer + service: + type: string required: - - key - - operator + - port type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} - pairs. A single {key,value} in the matchLabels - map is equivalent to an element of matchExpressions, - whose key field is "key", the operator is - "In", and the values array contains only "value". - The requirements are ANDed. + httpGet: + properties: + host: + type: string + httpHeaders: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + path: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + scheme: + type: string + required: + - port + type: object + initialDelaySeconds: + format: int32 + type: integer + periodSeconds: + format: int32 + type: integer + successThreshold: + format: int32 + type: integer + tcpSocket: + properties: + host: + type: string + port: + anyOf: + - type: integer + - type: string + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + format: int64 + type: integer + timeoutSeconds: + format: int32 + type: integer + type: object + stdin: + type: boolean + stdinOnce: + type: boolean + terminationMessagePath: + type: string + terminationMessagePolicy: + type: string + tty: + type: boolean + volumeDevices: + items: + properties: + devicePath: + type: string + name: + type: string + required: + - devicePath + - name type: object - type: object - namespaces: - description: namespaces specifies a static list - of namespace names that the term applies to. The - term is applied to the union of the namespaces - listed in this field and the ones selected by - namespaceSelector. null or empty namespaces list - and null namespaceSelector means "this pod's namespace" - items: + type: array + volumeMounts: + items: + properties: + mountPath: + type: string + mountPropagation: + type: string + name: + type: string + readOnly: + type: boolean + subPath: + type: string + subPathExpr: + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: type: string - type: array - topologyKey: - description: This pod should be co-located (affinity) - or not co-located (anti-affinity) with the pods - matching the labelSelector in the specified namespaces, - where co-located is defined as running on a node - whose value of the label with key topologyKey - matches that of any node on which any of the selected - pods is running. Empty topologyKey is not allowed. + required: + - name + type: object + type: array + nodeName: + type: string + nodeSelector: + additionalProperties: + type: string + type: object + x-kubernetes-map-type: atomic + os: + properties: + name: type: string required: - - topologyKey + - name type: object - type: array - type: object - type: object - disableIngress: - type: boolean - host: - type: string - image: - description: Image set in the Deployment pod template. Overrides - the values in the REGISTRY_IMAGE_MEM, REGISTRY_IMAGE_KAFKASQL - and REGISTRY_IMAGE_SQL operator environment variables. - type: string - imagePullSecrets: - description: List of secrets in the same namespace to use for - pulling the Deployment pod image. - items: - description: LocalObjectReference contains enough information - to let you locate the referenced object inside the same namespace. - properties: - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names - TODO: Add other useful fields. apiVersion, kind, uid?' - type: string - type: object - type: array - metadata: - description: Metadata applied to the Deployment pod template. - properties: - annotations: - additionalProperties: - type: string - description: Annotations added to the Deployment pod template. - type: object - labels: - additionalProperties: - type: string - description: Labels added to the Deployment pod template. - type: object - type: object - replicas: - format: int32 - type: integer - tolerations: - 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 + overhead: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + preemptionPolicy: + type: string + priority: + format: int32 + type: integer + priorityClassName: + type: string + readinessGates: + items: + properties: + conditionType: + type: string + required: + - conditionType + type: object + type: array + restartPolicy: + type: string + runtimeClassName: + type: string + schedulerName: + type: string + securityContext: + properties: + fsGroup: + format: int64 + type: integer + fsGroupChangePolicy: + type: string + runAsGroup: + format: int64 + type: integer + runAsNonRoot: + type: boolean + runAsUser: + format: int64 + type: integer + seLinuxOptions: + properties: + level: + type: string + role: + type: string + type: + type: string + user: + type: string + type: object + seccompProfile: + properties: + localhostProfile: + type: string + type: + type: string + required: + - type + type: object + supplementalGroups: + items: + format: int64 + type: integer + type: array + sysctls: + items: + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + properties: + gmsaCredentialSpec: + type: string + gmsaCredentialSpecName: + type: string + hostProcess: + type: boolean + runAsUserName: + type: string + type: object + type: object + serviceAccount: + type: string + serviceAccountName: + type: string + setHostnameAsFQDN: + type: boolean + shareProcessNamespace: + type: boolean + subdomain: + type: string + terminationGracePeriodSeconds: + format: int64 + type: integer + tolerations: + items: + properties: + effect: + type: string + key: + type: string + operator: + type: string + tolerationSeconds: + format: int64 + type: integer + value: + type: string + type: object + type: array + topologySpreadConstraints: + items: + properties: + labelSelector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + maxSkew: + format: int32 + type: integer + topologyKey: + type: string + whenUnsatisfiable: + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + volumes: + items: + properties: + awsElasticBlockStore: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + azureDisk: + properties: + cachingMode: + type: string + diskName: + type: string + diskURI: + type: string + fsType: + type: string + kind: + type: string + readOnly: + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + properties: + readOnly: + type: boolean + secretName: + type: string + shareName: + type: string + required: + - secretName + - shareName + type: object + cephfs: + properties: + monitors: + items: + type: string + type: array + path: + type: string + readOnly: + type: boolean + secretFile: + type: string + secretRef: + properties: + name: + type: string + type: object + user: + type: string + required: + - monitors + type: object + cinder: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + volumeID: + type: string + required: + - volumeID + type: object + configMap: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + name: + type: string + optional: + type: boolean + type: object + csi: + properties: + driver: + type: string + fsType: + type: string + nodePublishSecretRef: + properties: + name: + type: string + type: object + readOnly: + type: boolean + volumeAttributes: + additionalProperties: + type: string + type: object + required: + - driver + type: object + downwardAPI: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + required: + - path + type: object + type: array + type: object + emptyDir: + properties: + medium: + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + properties: + volumeClaimTemplate: + properties: + metadata: + type: object + spec: + properties: + accessModes: + items: + type: string + type: array + dataSource: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + dataSourceRef: + properties: + apiGroup: + type: string + kind: + type: string + name: + type: string + required: + - kind + - name + type: object + resources: + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + type: object + selector: + properties: + matchExpressions: + items: + properties: + key: + type: string + operator: + type: string + values: + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + type: object + type: object + storageClassName: + type: string + volumeMode: + type: string + volumeName: + type: string + type: object + required: + - spec + type: object + type: object + fc: + properties: + fsType: + type: string + lun: + format: int32 + type: integer + readOnly: + type: boolean + targetWWNs: + items: + type: string + type: array + wwids: + items: + type: string + type: array + type: object + flexVolume: + properties: + driver: + type: string + fsType: + type: string + options: + additionalProperties: + type: string + type: object + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + required: + - driver + type: object + flocker: + properties: + datasetName: + type: string + datasetUUID: + type: string + type: object + gcePersistentDisk: + properties: + fsType: + type: string + partition: + format: int32 + type: integer + pdName: + type: string + readOnly: + type: boolean + required: + - pdName + type: object + gitRepo: + properties: + directory: + type: string + repository: + type: string + revision: + type: string + required: + - repository + type: object + glusterfs: + properties: + endpoints: + type: string + path: + type: string + readOnly: + type: boolean + required: + - endpoints + - path + type: object + hostPath: + properties: + path: + type: string + type: + type: string + required: + - path + type: object + iscsi: + properties: + chapAuthDiscovery: + type: boolean + chapAuthSession: + type: boolean + fsType: + type: string + initiatorName: + type: string + iqn: + type: string + iscsiInterface: + type: string + lun: + format: int32 + type: integer + portals: + items: + type: string + type: array + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + targetPortal: + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + type: string + nfs: + properties: + path: + type: string + readOnly: + type: boolean + server: + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + properties: + claimName: + type: string + readOnly: + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + properties: + fsType: + type: string + pdID: + type: string + required: + - pdID + type: object + portworxVolume: + properties: + fsType: + type: string + readOnly: + type: boolean + volumeID: + type: string + required: + - volumeID + type: object + projected: + properties: + defaultMode: + format: int32 + type: integer + sources: + items: + properties: + configMap: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + name: + type: string + optional: + type: boolean + type: object + downwardAPI: + properties: + items: + items: + properties: + fieldRef: + properties: + apiVersion: + type: string + fieldPath: + type: string + required: + - fieldPath + type: object + mode: + format: int32 + type: integer + path: + type: string + resourceFieldRef: + properties: + containerName: + type: string + divisor: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + type: string + required: + - resource + type: object + required: + - path + type: object + type: array + type: object + secret: + properties: + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + name: + type: string + optional: + type: boolean + type: object + serviceAccountToken: + properties: + audience: + type: string + expirationSeconds: + format: int64 + type: integer + path: + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + properties: + group: + type: string + readOnly: + type: boolean + registry: + type: string + tenant: + type: string + user: + type: string + volume: + type: string + required: + - registry + - volume + type: object + rbd: + properties: + fsType: + type: string + image: + type: string + keyring: + type: string + monitors: + items: + type: string + type: array + pool: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + user: + type: string + required: + - image + - monitors + type: object + scaleIO: + properties: + fsType: + type: string + gateway: + type: string + protectionDomain: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + sslEnabled: + type: boolean + storageMode: + type: string + storagePool: + type: string + system: + type: string + volumeName: + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + properties: + defaultMode: + format: int32 + type: integer + items: + items: + properties: + key: + type: string + mode: + format: int32 + type: integer + path: + type: string + required: + - key + - path + type: object + type: array + optional: + type: boolean + secretName: + type: string + type: object + storageos: + properties: + fsType: + type: string + readOnly: + type: boolean + secretRef: + properties: + name: + type: string + type: object + volumeName: + type: string + volumeNamespace: + type: string + type: object + vsphereVolume: + properties: + fsType: + type: string + storagePolicyID: + type: string + storagePolicyName: + type: string + volumePath: + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + type: object type: object - type: array - type: object - type: object - status: - properties: - conditions: - description: List of status conditions. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - type FooStatus struct{ // Represents the observations of a foo's - current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 + replicas: + format: int32 type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type + tolerations: + 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 type: object - type: array - info: - description: Information about the deployed application. - properties: - host: - type: string - type: object - managedResources: - description: List of resources managed by this operator. - items: + type: object + status: + properties: + conditions: + description: List of status conditions. + items: + description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + info: + description: Information about the deployed application. properties: - kind: - type: string - name: - type: string - namespace: + host: type: string type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} + managedResources: + description: List of resources managed by this operator. + items: + properties: + kind: + type: string + name: + type: string + namespace: + type: string + type: object + type: array + type: object + type: object + served: true + storage: true + subresources: + status: {} status: acceptedNames: kind: "" diff --git a/controllers/apicurioregistry_controller.go b/controllers/apicurioregistry_controller.go index 7bd97a58..da1d138c 100644 --- a/controllers/apicurioregistry_controller.go +++ b/controllers/apicurioregistry_controller.go @@ -223,7 +223,8 @@ func (this *ApicurioRegistryReconciler) createNewLoop(appName c.Name, appNamespa result.AddControlFunction(cf.NewDeploymentCF(ctx, loopServices)) //deployment modifiers - result.AddControlFunction(cf.NewPodSpecCF(ctx, loopServices)) + result.AddControlFunction(cf.NewUpgradeCF(ctx, loopServices)) + result.AddControlFunction(cf.NewPodTemplateSpecCF(ctx, loopServices)) result.AddControlFunction(cf.NewAffinityCF(ctx)) result.AddControlFunction(cf.NewTolerationCF(ctx)) result.AddControlFunction(cf.NewAnnotationsCF(ctx)) diff --git a/controllers/cf/cf_annotations.go b/controllers/cf/cf_annotations.go index f0da4fe1..95414361 100644 --- a/controllers/cf/cf_annotations.go +++ b/controllers/cf/cf_annotations.go @@ -69,7 +69,7 @@ func (this *AnnotationsCF) Respond() { // Patch the resource this.deploymentEntry.ApplyPatch(func(value interface{}) interface{} { deployment := value.(*apps.Deployment).DeepCopy() - common.LabelsUpdate(deployment.Spec.Template.Annotations, this.targetAnnotations) + common.LabelsUpdate(&deployment.Spec.Template.Annotations, this.targetAnnotations) return deployment }) } diff --git a/controllers/cf/cf_env_apply.go b/controllers/cf/cf_env_apply.go index 5d9a5634..d7a834b8 100644 --- a/controllers/cf/cf_env_apply.go +++ b/controllers/cf/cf_env_apply.go @@ -4,6 +4,7 @@ import ( "github.com/Apicurio/apicurio-registry-operator/controllers/loop" "github.com/Apicurio/apicurio-registry-operator/controllers/loop/context" "github.com/Apicurio/apicurio-registry-operator/controllers/svc/env" + "github.com/Apicurio/apicurio-registry-operator/controllers/svc/factory" "github.com/Apicurio/apicurio-registry-operator/controllers/svc/resources" "go.uber.org/zap" apps "k8s.io/api/apps/v1" @@ -61,7 +62,7 @@ func (this *EnvApplyCF) Sense() { deployment := this.deploymentEntry.GetValue().(*apps.Deployment) for i, c := range deployment.Spec.Template.Spec.Containers { - if c.Name == this.ctx.GetAppName().Str() { + if c.Name == factory.REGISTRY_CONTAINER_NAME { prevName := "" // To maintain ordering in case of interpolation // Copy variables in the cache deleted := make(map[string]bool, 0) @@ -116,7 +117,7 @@ func (this *EnvApplyCF) Respond() { this.deploymentEntry.ApplyPatch(func(value interface{}) interface{} { deployment := value.(*apps.Deployment).DeepCopy() for i, c := range deployment.Spec.Template.Spec.Containers { - if c.Name == this.ctx.GetAppName().Str() { + if c.Name == factory.REGISTRY_CONTAINER_NAME { deployment.Spec.Template.Spec.Containers[i].Env = this.svcEnvCache.GetSorted() } } // TODO report a problem if not found? diff --git a/controllers/cf/cf_https.go b/controllers/cf/cf_https.go index c6b04672..770aa38d 100644 --- a/controllers/cf/cf_https.go +++ b/controllers/cf/cf_https.go @@ -8,6 +8,7 @@ import ( "github.com/Apicurio/apicurio-registry-operator/controllers/loop/context" "github.com/Apicurio/apicurio-registry-operator/controllers/loop/services" "github.com/Apicurio/apicurio-registry-operator/controllers/svc/env" + "github.com/Apicurio/apicurio-registry-operator/controllers/svc/factory" "github.com/Apicurio/apicurio-registry-operator/controllers/svc/resources" "go.uber.org/zap" apps "k8s.io/api/apps/v1" @@ -140,6 +141,7 @@ func (this *HttpsCF) Sense() { this.containerHttpPortExists = false if entry, exists := this.svcResourceCache.Get(resources.RC_KEY_DEPLOYMENT); exists { deployment := entry.GetValue().(*apps.Deployment) + container := common.GetContainerByName(deployment.Spec.Template.Spec.Containers, factory.REGISTRY_CONTAINER_NAME) if this.targetSecretName != "" { // Volume @@ -150,7 +152,7 @@ func (this *HttpsCF) Sense() { } } // Volume mount - for _, mount := range deployment.Spec.Template.Spec.Containers[0].VolumeMounts { + for _, mount := range container.VolumeMounts { if mount.Name == this.targetSecretName { this.secretVolumeMountExists = true break @@ -158,7 +160,7 @@ func (this *HttpsCF) Sense() { } } // Container port - for _, port := range deployment.Spec.Template.Spec.Containers[0].Ports { + for _, port := range container.Ports { if port.ContainerPort == HttpsPort { this.containerHttpsPortExists = true } @@ -232,15 +234,16 @@ func (this *HttpsCF) Respond() { if entry, exists := this.svcResourceCache.Get(resources.RC_KEY_DEPLOYMENT); exists { entry.ApplyPatch(func(value interface{}) interface{} { deployment := value.(*apps.Deployment).DeepCopy() - - apicurioContainer := &deployment.Spec.Template.Spec.Containers[0] + apicurioContainer := common.GetContainerByName(deployment.Spec.Template.Spec.Containers, factory.REGISTRY_CONTAINER_NAME) httpsPort := &core.ContainerPort{ ContainerPort: HttpsPort, + Protocol: core.ProtocolTCP, } httpPort := &core.ContainerPort{ ContainerPort: HttpPort, + Protocol: core.ProtocolTCP, } if this.httpsEnabled && !this.secretVolumeExists { @@ -248,7 +251,7 @@ func (this *HttpsCF) Respond() { if this.previousSecretName != "" { common.RemoveVolumeFromDeployment(deployment, NewSecretVolume(this.previousSecretName)) } - common.SetVolumeInDeployment(this.log, deployment, NewSecretVolume(this.targetSecretName)) + common.SetVolumeInDeployment(deployment, NewSecretVolume(this.targetSecretName)) this.log.Debugw("added secret volume") } if !this.httpsEnabled && this.secretVolumeExists { @@ -268,7 +271,7 @@ func (this *HttpsCF) Respond() { this.log.Debugw("removed secret volume mount") } if this.httpsEnabled && !this.containerHttpsPortExists { - common.AddPortToContainer(apicurioContainer, httpsPort) + common.AddContainerPort(&apicurioContainer.Ports, httpsPort) this.log.Debugw("added container HTTPS port") } if !this.httpsEnabled && this.containerHttpsPortExists { @@ -277,7 +280,7 @@ func (this *HttpsCF) Respond() { } // HTTP port if (!this.httpsEnabled || this.httpEnabled) && !this.containerHttpPortExists { - common.AddPortToContainer(apicurioContainer, httpPort) + common.AddContainerPort(&apicurioContainer.Ports, httpPort) this.log.Debugw("added container HTTP port") } if this.httpsEnabled && !this.httpEnabled && this.containerHttpPortExists { diff --git a/controllers/cf/cf_image.go b/controllers/cf/cf_image.go index ecd43348..6f9fbb8c 100644 --- a/controllers/cf/cf_image.go +++ b/controllers/cf/cf_image.go @@ -1,6 +1,7 @@ package cf import ( + "github.com/Apicurio/apicurio-registry-operator/controllers/svc/factory" "go.uber.org/zap" "os" @@ -67,7 +68,7 @@ func (this *ImageCF) Sense() { this.existingImage = "" if this.deploymentExists { for i, c := range deploymentEntry.GetValue().(*apps.Deployment).Spec.Template.Spec.Containers { - if c.Name == this.ctx.GetAppName().Str() { + if c.Name == factory.REGISTRY_CONTAINER_NAME { this.existingImage = deploymentEntry.GetValue().(*apps.Deployment).Spec.Template.Spec.Containers[i].Image } } // TODO report a problem if not found? @@ -99,9 +100,8 @@ func (this *ImageCF) Sense() { this.persistenceError = true this.log.Warnw( "The operand image is not selected. " + - "Set the 'spec.configuration.persistence' property in your 'apicurioregistry' resource " + - "to select the appropriate Service Registry image, or set the 'spec.deployment.image' " + - "property to use a specific image.") + "Set the spec.configuration.persistence property to select an appropriate Apicurio Registry image, " + + "or set the spec.deployment.image property to use a custom image.") } } @@ -131,7 +131,7 @@ func (this *ImageCF) Respond() { this.deploymentEntry.ApplyPatch(func(value interface{}) interface{} { deployment := value.(*apps.Deployment).DeepCopy() for i, c := range deployment.Spec.Template.Spec.Containers { - if c.Name == this.ctx.GetAppName().Str() { + if c.Name == factory.REGISTRY_CONTAINER_NAME { deployment.Spec.Template.Spec.Containers[i].Image = this.targetImage } } // TODO report a problem if not found? diff --git a/controllers/cf/cf_imagepullpolicy.go b/controllers/cf/cf_imagepullpolicy.go index 31348f40..e1f082b8 100644 --- a/controllers/cf/cf_imagepullpolicy.go +++ b/controllers/cf/cf_imagepullpolicy.go @@ -1,6 +1,7 @@ package cf import ( + "github.com/Apicurio/apicurio-registry-operator/controllers/svc/factory" "go.uber.org/zap" "os" @@ -52,7 +53,7 @@ func (this *ImagePullPolicyCF) Sense() { // Observation #2 // Get the existing pod ImagePullPolicy for i, c := range this.deploymentEntry.GetValue().(*apps.Deployment).Spec.Template.Spec.Containers { - if c.Name == this.ctx.GetAppName().Str() { + if c.Name == factory.REGISTRY_CONTAINER_NAME { this.existingImagePullPolicy = this.deploymentEntry.GetValue().(*apps.Deployment).Spec.Template.Spec.Containers[i].ImagePullPolicy } } @@ -93,7 +94,7 @@ func (this *ImagePullPolicyCF) Respond() { this.deploymentEntry.ApplyPatch(func(value interface{}) interface{} { deployment := value.(*apps.Deployment).DeepCopy() for i, c := range deployment.Spec.Template.Spec.Containers { - if c.Name == this.ctx.GetAppName().Str() { + if c.Name == factory.REGISTRY_CONTAINER_NAME { deployment.Spec.Template.Spec.Containers[i].ImagePullPolicy = this.targetImagePullPolicy } } diff --git a/controllers/cf/cf_labels.go b/controllers/cf/cf_labels.go index a59fcc62..84418823 100644 --- a/controllers/cf/cf_labels.go +++ b/controllers/cf/cf_labels.go @@ -124,7 +124,6 @@ func (this *LabelsCF) Compare() bool { this.updatePdbV1beta1 = this.pdbV1beta1IsCached && !common.LabelsEqual(this.pdbV1beta1Labels, this.caLabels) this.updatePdbV1 = this.pdbV1IsCached && !common.LabelsEqual(this.pdbV1Labels, this.caLabels) this.updateNetworkPolicy = this.networkPolicyIsCached && !common.LabelsEqual(this.networkPolicyLabels, this.caLabels) - // TODO Add network policy labels return this.updateDeployment || this.updateDeploymentPod || @@ -141,7 +140,7 @@ func (this *LabelsCF) Respond() { if this.updateDeployment { this.deploymentEntry.ApplyPatch(func(value interface{}) interface{} { deployment := value.(*apps.Deployment).DeepCopy() - common.LabelsUpdate(deployment.Labels, this.caLabels) + common.LabelsUpdate(&deployment.Labels, this.caLabels) return deployment }) } @@ -150,7 +149,7 @@ func (this *LabelsCF) Respond() { if this.updateDeploymentPod { this.deploymentEntry.ApplyPatch(func(value interface{}) interface{} { deployment := value.(*apps.Deployment).DeepCopy() - common.LabelsUpdate(deployment.Spec.Template.Labels, this.targetDeploymentPodLabels) + common.LabelsUpdate(&deployment.Spec.Template.Labels, this.targetDeploymentPodLabels) return deployment }) } @@ -159,7 +158,7 @@ func (this *LabelsCF) Respond() { if this.updateService { this.serviceEntry.ApplyPatch(func(value interface{}) interface{} { service := value.(*core.Service).DeepCopy() - common.LabelsUpdate(service.Labels, this.caLabels) + common.LabelsUpdate(&service.Labels, this.caLabels) return service }) } @@ -168,7 +167,7 @@ func (this *LabelsCF) Respond() { if this.updateIngress { this.ingressEntry.ApplyPatch(func(value interface{}) interface{} { ingress := value.(*networking.Ingress).DeepCopy() - common.LabelsUpdate(ingress.Labels, this.caLabels) + common.LabelsUpdate(&ingress.Labels, this.caLabels) return ingress }) } @@ -177,14 +176,14 @@ func (this *LabelsCF) Respond() { if this.updatePdbV1beta1 { this.pdbV1beta1Entry.ApplyPatch(func(value interface{}) interface{} { pdb := value.(*policy_v1beta1.PodDisruptionBudget).DeepCopy() - common.LabelsUpdate(pdb.Labels, this.caLabels) + common.LabelsUpdate(&pdb.Labels, this.caLabels) return pdb }) } if this.updatePdbV1 { this.pdbV1Entry.ApplyPatch(func(value interface{}) interface{} { pdb := value.(*policy_v1.PodDisruptionBudget).DeepCopy() - common.LabelsUpdate(pdb.Labels, this.caLabels) + common.LabelsUpdate(&pdb.Labels, this.caLabels) return pdb }) } @@ -193,7 +192,7 @@ func (this *LabelsCF) Respond() { if this.updateNetworkPolicy { this.networkPolicyEntry.ApplyPatch(func(value interface{}) interface{} { policy := value.(*networking.NetworkPolicy).DeepCopy() - common.LabelsUpdate(policy.Labels, this.caLabels) + common.LabelsUpdate(&policy.Labels, this.caLabels) return policy }) } @@ -212,7 +211,7 @@ func (this *LabelsCF) GetCommonApplicationLabels() map[string]string { func (this *LabelsCF) GetTargetDeploymentPodLabels() map[string]string { targetDeploymentPodLabels := make(map[string]string) - common.LabelsUpdate(targetDeploymentPodLabels, this.GetCommonApplicationLabels()) - common.LabelsUpdate(targetDeploymentPodLabels, this.additionalDeploymentPodLabels) + common.LabelsUpdate(&targetDeploymentPodLabels, this.GetCommonApplicationLabels()) + common.LabelsUpdate(&targetDeploymentPodLabels, this.additionalDeploymentPodLabels) return targetDeploymentPodLabels } diff --git a/controllers/cf/cf_pod_spec.go b/controllers/cf/cf_pod_spec.go deleted file mode 100644 index 0de3952b..00000000 --- a/controllers/cf/cf_pod_spec.go +++ /dev/null @@ -1,318 +0,0 @@ -package cf - -import ( - "encoding/json" - ar "github.com/Apicurio/apicurio-registry-operator/api/v1" - "github.com/Apicurio/apicurio-registry-operator/controllers/common" - "github.com/Apicurio/apicurio-registry-operator/controllers/loop" - "github.com/Apicurio/apicurio-registry-operator/controllers/loop/context" - "github.com/Apicurio/apicurio-registry-operator/controllers/loop/services" - "github.com/Apicurio/apicurio-registry-operator/controllers/svc/resources" - "go.uber.org/zap" - apps "k8s.io/api/apps/v1" - core "k8s.io/api/core/v1" - "reflect" -) - -var _ loop.ControlFunction = &PodSpecCF{} - -type PodSpecCF struct { - ctx context.LoopContext - log *zap.SugaredLogger - svcResourceCache resources.ResourceCache - services services.LoopServices - - previousBasePodSpec *ar.ApicurioRegistrySpecDeploymentPodSpecPreview - basePodSpec *ar.ApicurioRegistrySpecDeploymentPodSpecPreview - valid bool - targetPodSpec *core.PodSpec -} - -func NewPodSpecCF(ctx context.LoopContext, services services.LoopServices) loop.ControlFunction { - res := &PodSpecCF{ - ctx: ctx, - svcResourceCache: ctx.GetResourceCache(), - services: services, - } - res.log = ctx.GetLog().Sugar().With("cf", res.Describe()) - return res -} - -func (this *PodSpecCF) Describe() string { - return "PodSpecCF" -} - -func (this *PodSpecCF) Sense() { - this.valid = false - - if entry, exists := this.svcResourceCache.Get(resources.RC_KEY_SPEC); exists { - - this.basePodSpec = &entry.GetValue().(*ar.ApicurioRegistry).Spec.Deployment.PodSpecPreview - this.basePodSpec = this.basePodSpec.DeepCopy() // Defensive copy so we don't update the spec - - if deploymentEntry, deploymentExists := this.svcResourceCache.Get(resources.RC_KEY_DEPLOYMENT); deploymentExists { - currentPodSpec := &deploymentEntry.GetValue().(*apps.Deployment).Spec.Template.Spec - currentPodSpec = currentPodSpec.DeepCopy() // TODO? - factoryPodSpec := this.services.GetKubeFactory().CreateDeployment().Spec.Template.Spec // TODO Cache this? - targetPodSpec, err := SanitizeBasePodSpec(this.log, this.basePodSpec, currentPodSpec, &factoryPodSpec) - if err != nil { - if err.isConfigError { - this.log.Errorw("PodSpec field in spec.deployment.podSpecPreview is invalid", "error", err) - this.services.GetConditionManager().GetConfigurationErrorCondition(). - TransitionInvalid(err.Error(), "spec.deployment.podSpecPreview") - // No need to transition to not ready, since we can just with the previous config - this.ctx.SetRequeueDelaySec(10) - } else { - this.log.Errorw("Conversion error", "error", err.conversionError) - } - } else { - - this.targetPodSpec, err = ConvertToPodSpec(targetPodSpec) - if err != nil { - this.log.Errorw("Conversion error", "error", err.conversionError) - } else { - this.valid = true - } - } - } - } -} - -func (this *PodSpecCF) Compare() bool { - if this.previousBasePodSpec != nil { // common.LogNillable does not work TODO find out why - this.log.Debugw("Obsevation #1", "this.previousBasePodSpec", this.previousBasePodSpec) - } else { - this.log.Debugw("Obsevation #1", "this.previousBasePodSpec", "") - } - this.log.Debugw("Obsevation #2", "this.basePodSpec", this.basePodSpec) - this.log.Debugw("Obsevation #3", "this.targetPodSpec", this.targetPodSpec) - return this.valid && - // We're only comparing changes to the podSpecPreview, not the real pod spec, - // so we do not overwrite changes by the other CFs, which would cause a loop panic - (this.previousBasePodSpec == nil || !reflect.DeepEqual(this.basePodSpec, this.previousBasePodSpec)) -} - -func (this *PodSpecCF) Respond() { - - if entry, exists := this.svcResourceCache.Get(resources.RC_KEY_DEPLOYMENT); exists { - entry.ApplyPatch(func(value interface{}) interface{} { - deployment := value.(*apps.Deployment).DeepCopy() - - deployment.Spec.Template.Spec = *this.targetPodSpec - - this.previousBasePodSpec = this.basePodSpec - - return deployment - }) - } -} - -func (this *PodSpecCF) Cleanup() bool { - // No cleanup - return true -} - -/* -Not allowed: - -- affinity [alternative exists] -- containers[*]. [only a single container without a name] - - containers.args [reserved] - - containers.command [reserved] - - containers.env [alternative exists] - - containers.image [reserved] - - containers.imagePullPolicy [alternative exists] - - containers.name [reserved] - - containers.ports [reserved] - - containers.workingDir [reserved] -- ephemeralContainers [reserved] -- imagePullSecrets [alternative exists] -- initContainers [reserved] -- tolerations [alternative exists] - -Rules: - -If you are setting a value of a field in the podSpec or podSpec.containers[0], -this value must be valid as a whole. - -For example, when setting the initialDelaySeconds field of a readiness probe, you must also provide the probe handler. - -The operator may still modify the values you provided, -but it will not add required sub-fields or fix an invalid value. -*/ -func SanitizeBasePodSpec(log *zap.SugaredLogger, base *ar.ApicurioRegistrySpecDeploymentPodSpecPreview, current *core.PodSpec, factory *core.PodSpec) (*ar.ApicurioRegistrySpecDeploymentPodSpecPreview, *SanitizeError) { - // We are using values from *current* with fields (values): - // - that the user cannot change - // - or are empty by default - // - or there is a CF that handles them - // We are using values from *factory* with fields (values): - // - that are not empty by default, so empty fields in the base podSpec do not remove default values - // - and there is not and existing CF that handles them - // Otherwise we just pass the base values along, relying on CFs to override things - - base = base.DeepCopy() // Defensive copy TODO is this needed? - current = current.DeepCopy() // Defensive copy TODO is this needed? - // affinity - if base.Affinity != nil { - return nil, NewConfigError("affinity") - } - base.Affinity = current.Affinity - // containers[*] - if len(base.Containers) > 1 { - return nil, NewConfigError("field containers must contain at most one item") - - } else if len(base.Containers) == 1 { - baseContainer := &base.Containers[0] - // We have only a single container at the moment, - // TODO but in the future we should use the name field. - currentContainer := current.Containers[0] - factoryContainer := factory.Containers[0] - - // containers[*].args - if len(baseContainer.Args) > 0 { - return nil, NewConfigError("containers[0].args") - } - baseContainer.Args = currentContainer.Args - // containers[*].command - if len(baseContainer.Command) > 0 { - return nil, NewConfigError("containers[0].command") - } - baseContainer.Command = currentContainer.Command - // containers[*].env - if len(baseContainer.Env) > 0 { - return nil, NewConfigError("containers[0].env") - } - baseContainer.Env = currentContainer.Env - // containers[*].image - if baseContainer.Image != "" { - return nil, NewConfigError("containers[0].image") - } - baseContainer.Image = currentContainer.Image - // containers[*].imagePullPolicy - if baseContainer.ImagePullPolicy != "" { - return nil, NewConfigError("containers[0].imagePullPolicy") - } - baseContainer.ImagePullPolicy = currentContainer.ImagePullPolicy - // containers[*].livenessProbe - if baseContainer.LivenessProbe == nil { - baseContainer.LivenessProbe = factoryContainer.LivenessProbe - } - // containers[*].name - if baseContainer.Name != "" { - return nil, NewConfigError("containers[0].name") - } - baseContainer.Name = factoryContainer.Name - // containers[*].ports - if len(baseContainer.Ports) > 0 { - return nil, NewConfigError("containers[0].ports") - } - baseContainer.Ports = currentContainer.Ports - // containers[*].readinessProbe - if baseContainer.ReadinessProbe == nil { - baseContainer.ReadinessProbe = factoryContainer.ReadinessProbe - } - // containers[*].resources - if len(baseContainer.Resources.Limits) == 0 && - len(baseContainer.Resources.Requests) == 0 { - baseContainer.Resources = factoryContainer.Resources - } - // containers[*].workingDir - if baseContainer.WorkingDir != "" { - return nil, NewConfigError("containers[0].workingDir") - } - baseContainer.WorkingDir = currentContainer.WorkingDir - } else { - base.Containers = make([]ar.ApicurioRegistrySpecDeploymentPodSpecPreviewContainer, len(factory.Containers)) - for i, c := range factory.Containers { - cc, err := ConvertFromContainer(&c) - if err != nil { - return nil, err - } - base.Containers[i] = *cc - } - } - // ephemeralContainers - if len(base.EphemeralContainers) > 0 { - return nil, NewConfigError("ephemeralContainers") - } - base.EphemeralContainers = current.EphemeralContainers - // imagePullSecrets - if len(base.ImagePullSecrets) > 0 { - return nil, NewConfigError("imagePullSecrets") - } - base.ImagePullSecrets = current.ImagePullSecrets - // initContainers - if len(base.InitContainers) > 0 { - return nil, NewConfigError("initContainers") - } - base.InitContainers = current.InitContainers - // terminationGracePeriodSeconds - if base.TerminationGracePeriodSeconds == nil { - base.TerminationGracePeriodSeconds = factory.TerminationGracePeriodSeconds - } - // tolerations - if len(base.Tolerations) > 0 { - return nil, NewConfigError("tolerations") - } - base.Tolerations = current.Tolerations - // volumes - for _, v := range factory.Volumes { - common.SetVolume(log, &base.Volumes, &v) - } - return base, nil -} - -type SanitizeError struct { - isConfigError bool - conversionError error - message string -} - -func (this *SanitizeError) Error() string { - return this.message -} - -func NewConfigError(field string) *SanitizeError { - return &SanitizeError{ - isConfigError: true, - conversionError: nil, - message: "field " + field + " is reserved and must not be defined", - } -} - -func NewConvertError(err error) *SanitizeError { - return &SanitizeError{ - isConfigError: false, - conversionError: err, - message: err.Error(), - } -} - -// Do a magic using JSON to conver these values. -// They MUST have the equivalent field names. -// Remember, we are only doing this because we don't have ommitempty tags in PodSpec. -func ConvertToPodSpec(source *ar.ApicurioRegistrySpecDeploymentPodSpecPreview) (*core.PodSpec, *SanitizeError) { - data, err := json.Marshal(source) - if err != nil { - return nil, NewConvertError(err) - } - out := &core.PodSpec{} - err = json.Unmarshal(data, out) - if err != nil { - return nil, NewConvertError(err) - } - return out, nil -} - -func ConvertFromContainer(source *core.Container) (*ar.ApicurioRegistrySpecDeploymentPodSpecPreviewContainer, *SanitizeError) { - data, err := json.Marshal(source) - if err != nil { - return nil, NewConvertError(err) - } - out := &ar.ApicurioRegistrySpecDeploymentPodSpecPreviewContainer{} - err = json.Unmarshal(data, out) - if err != nil { - return nil, NewConvertError(err) - } - return out, nil -} diff --git a/controllers/cf/cf_pod_template_spec.go b/controllers/cf/cf_pod_template_spec.go new file mode 100644 index 00000000..e1eccf23 --- /dev/null +++ b/controllers/cf/cf_pod_template_spec.go @@ -0,0 +1,266 @@ +package cf + +import ( + "encoding/json" + "errors" + ar "github.com/Apicurio/apicurio-registry-operator/api/v1" + "github.com/Apicurio/apicurio-registry-operator/controllers/common" + "github.com/Apicurio/apicurio-registry-operator/controllers/loop" + "github.com/Apicurio/apicurio-registry-operator/controllers/loop/context" + "github.com/Apicurio/apicurio-registry-operator/controllers/loop/services" + f "github.com/Apicurio/apicurio-registry-operator/controllers/svc/factory" + "github.com/Apicurio/apicurio-registry-operator/controllers/svc/resources" + "go.uber.org/zap" + apps "k8s.io/api/apps/v1" + core "k8s.io/api/core/v1" + "reflect" +) + +var _ loop.ControlFunction = &PodTemplateSpecCF{} + +type PodTemplateSpecCF struct { + ctx context.LoopContext + log *zap.SugaredLogger + svcResourceCache resources.ResourceCache + services services.LoopServices + + previousBasePodTemplateSpec *ar.ApicurioRegistryPodTemplateSpec + basePodTemplateSpec *ar.ApicurioRegistryPodTemplateSpec + valid bool + targetPodTemplateSpec *core.PodTemplateSpec +} + +func NewPodTemplateSpecCF(ctx context.LoopContext, services services.LoopServices) loop.ControlFunction { + res := &PodTemplateSpecCF{ + ctx: ctx, + svcResourceCache: ctx.GetResourceCache(), + services: services, + } + res.log = ctx.GetLog().Sugar().With("cf", res.Describe()) + return res +} + +func (this *PodTemplateSpecCF) Describe() string { + return "PodTemplateSpecCF" +} + +func (this *PodTemplateSpecCF) Sense() { + this.valid = false + + if entry, exists := this.svcResourceCache.Get(resources.RC_KEY_SPEC); exists { + + this.basePodTemplateSpec = &entry.GetValue().(*ar.ApicurioRegistry).Spec.Deployment.PodTemplateSpecPreview + this.basePodTemplateSpec = this.basePodTemplateSpec.DeepCopy() // Defensive copy so we don't update the spec + + if deploymentEntry, deploymentExists := this.svcResourceCache.Get(resources.RC_KEY_DEPLOYMENT); deploymentExists { + currentPodSpec := &deploymentEntry.GetValue().(*apps.Deployment).Spec.Template + currentPodSpec = currentPodSpec.DeepCopy() + factoryPodSpec := this.services.GetKubeFactory().CreateDeployment().Spec.Template + targetPodSpec, err := SanitizeBasePodSpec(this.log, this.basePodTemplateSpec, currentPodSpec, &factoryPodSpec) + if err == nil { + this.targetPodTemplateSpec, err = ConvertToPodTemplateSpec(targetPodSpec) + if err == nil { + this.valid = true + } else { + this.log.Errorw("an error has occurred when processing spec.deployment.podTemplateSpecPreview field", "error", err) + } + } else { + this.log.Errorw("an error has occurred when processing spec.deployment.podTemplateSpecPreview field", "error", err) + this.services.GetConditionManager().GetConfigurationErrorCondition(). + TransitionInvalid(err.Error(), "spec.deployment.podTemplateSpecPreview") + // No need to transition to not ready, since we can just with the previous config + this.ctx.SetRequeueDelaySec(10) + } + } + } +} + +func (this *PodTemplateSpecCF) Compare() bool { + if this.previousBasePodTemplateSpec != nil { // common.LogNillable does not work TODO find out why + this.log.Debugw("Obsevation #1", "this.previousBasePodTemplateSpec", this.previousBasePodTemplateSpec) + } else { + this.log.Debugw("Obsevation #1", "this.previousBasePodTemplateSpec", "") + } + this.log.Debugw("Obsevation #2", "this.basePodTemplateSpec", this.basePodTemplateSpec) + this.log.Debugw("Obsevation #3", "this.targetPodTemplateSpec", this.targetPodTemplateSpec) + return this.valid && + // We're only comparing changes to the podSpecPreview, not the real pod spec, + // so we do not overwrite changes by the other CFs, which would cause a loop panic + (this.previousBasePodTemplateSpec == nil || !reflect.DeepEqual(this.basePodTemplateSpec, this.previousBasePodTemplateSpec)) +} + +func (this *PodTemplateSpecCF) Respond() { + + if entry, exists := this.svcResourceCache.Get(resources.RC_KEY_DEPLOYMENT); exists { + entry.ApplyPatch(func(value interface{}) interface{} { + deployment := value.(*apps.Deployment).DeepCopy() + + deployment.Spec.Template = *this.targetPodTemplateSpec + + this.previousBasePodTemplateSpec = this.basePodTemplateSpec + + return deployment + }) + } +} + +func (this *PodTemplateSpecCF) Cleanup() bool { + // No cleanup + return true +} + +/* +Reserved: + +- metadata + - metadata.annotations [alternative exists] + - metadata.labels [alternative exists] +- spec + - spec.affinity [alternative exists] + - spec.containers[*] + - spec.containers[name = "registry"].env [alternative exists] + - spec.containers[name = "registry"].image [alternative exists] + - spec.containers[name = "registry"].imagePullPolicy [alternative exists] + - spec.imagePullSecrets [alternative exists] + - spec.tolerations [alternative exists] +*/ +func SanitizeBasePodSpec(log *zap.SugaredLogger, base *ar.ApicurioRegistryPodTemplateSpec, current *core.PodTemplateSpec, + factory *core.PodTemplateSpec) (*ar.ApicurioRegistryPodTemplateSpec, error) { + // We are using values from *current* with fields (values): + // - that the user cannot change + // - or are empty by default + // - or there is a CF that handles them + // We are using values from *factory* with fields (values): + // - that are not empty by default, so empty fields in the base podSpec do not remove default values + // - and there is not and existing CF that handles them + // Otherwise we just pass the base values along, relying on CFs to override things + + base = base.DeepCopy() // Defensive copy TODO is this needed? + current = current.DeepCopy() // Defensive copy TODO is this needed? + + // metadata.annotations + if base.Metadata.Annotations != nil { + return nil, newReservedFieldError("metadata.annotations") + } + base.Metadata.Annotations = current.ObjectMeta.Annotations + + // metadata.labels + if base.Metadata.Labels != nil { + return nil, newReservedFieldError("metadata.labels") + } + base.Metadata.Labels = current.ObjectMeta.Labels + + // spec.affinity + if base.Spec.Affinity != nil { + return nil, newReservedFieldError("spec.affinity") + } + base.Spec.Affinity = current.Spec.Affinity + + // spec.containers[*] + + baseContainer := common.GetContainerByName(base.Spec.Containers, f.REGISTRY_CONTAINER_NAME) + if len(base.Spec.Containers) > 0 && baseContainer == nil { + log.Warnw("container named " + f.REGISTRY_CONTAINER_NAME + " is not defined " + + "in spec.deployment.podTemplateSpecPreview.spec.containers. Make sure this is intended.") + } + currentContainer := common.GetContainerByName(current.Spec.Containers, f.REGISTRY_CONTAINER_NAME) + if currentContainer == nil { + panic("could not find current registry container") + } + factoryContainer := common.GetContainerByName(factory.Spec.Containers, f.REGISTRY_CONTAINER_NAME) + if factoryContainer == nil { + panic("could not find factory registry container") + } + + if len(base.Spec.Containers) > 0 && baseContainer != nil { + + // spec.containers[name = "registry"].env + if baseContainer.Env != nil || len(baseContainer.Env) != 0 { + return nil, newReservedFieldError("spec.containers[name = \"registry\"].env") + } + baseContainer.Env = currentContainer.Env + + // spec.containers[name = "registry"].image + if baseContainer.Image != "" { + return nil, newReservedFieldError("spec.containers[name = \"registry\"].image") + } + baseContainer.Image = currentContainer.Image + + // spec.containers[name = "registry"].imagePullPolicy + if baseContainer.ImagePullPolicy != "" { + return nil, newReservedFieldError("spec.containers[name = \"registry\"].imagePullPolicy") + } + baseContainer.ImagePullPolicy = currentContainer.ImagePullPolicy + + // (Factory) spec.containers[name = "registry"].livenessProbe + if baseContainer.LivenessProbe == nil { + baseContainer.LivenessProbe = factoryContainer.LivenessProbe + } + + // (Factory) spec.containers[name = "registry"].readinessProbe + if baseContainer.ReadinessProbe == nil { + baseContainer.ReadinessProbe = factoryContainer.ReadinessProbe + } + + // (Factory) spec.containers[name = "registry"].resources + if len(baseContainer.Resources.Limits) == 0 && + len(baseContainer.Resources.Requests) == 0 { + baseContainer.Resources = factoryContainer.Resources + } + + // (Factory) spec.volumeMounts + for _, v := range factoryContainer.VolumeMounts { + common.SetVolumeMount(&baseContainer.VolumeMounts, &v) + } + + } else { + base.Spec.Containers = make([]core.Container, len(factory.Spec.Containers)) + for i, c := range factory.Spec.Containers { + base.Spec.Containers[i] = c + } + } + + // spec.imagePullSecrets + if len(base.Spec.ImagePullSecrets) > 0 { + return nil, newReservedFieldError("spec.imagePullSecrets") + } + base.Spec.ImagePullSecrets = current.Spec.ImagePullSecrets + + // (Factory) spec.terminationGracePeriodSeconds + if base.Spec.TerminationGracePeriodSeconds == nil { + base.Spec.TerminationGracePeriodSeconds = factory.Spec.TerminationGracePeriodSeconds + } + + // spec.tolerations + if len(base.Spec.Tolerations) > 0 { + return nil, newReservedFieldError("spec.tolerations") + } + base.Spec.Tolerations = current.Spec.Tolerations + + // (Factory) spec.volumes + for _, v := range factory.Spec.Volumes { + common.SetVolume(&base.Spec.Volumes, &v) + } + + return base, nil +} + +func newReservedFieldError(field string) error { + return errors.New("field " + field + " is reserved and must not be defined") +} + +// Do a magic using JSON to conver these values. +// They MUST have the equivalent field names. +// We are only doing this because we don't have some ommitempty tags in PodSpec. +func ConvertToPodTemplateSpec(source *ar.ApicurioRegistryPodTemplateSpec) (*core.PodTemplateSpec, error) { + data, err := json.Marshal(source) + if err != nil { + return nil, errors.New("failed to convert between ApicurioRegistryPodTemplateSpec and PodTemplateSpec: " + err.Error()) + } + out := &core.PodTemplateSpec{} + err = json.Unmarshal(data, out) + if err != nil { + return nil, errors.New("failed to convert between ApicurioRegistryPodTemplateSpec and PodTemplateSpec: " + err.Error()) + } + return out, nil +} diff --git a/controllers/cf/cf_upgrade.go b/controllers/cf/cf_upgrade.go new file mode 100644 index 00000000..ba653da6 --- /dev/null +++ b/controllers/cf/cf_upgrade.go @@ -0,0 +1,83 @@ +package cf + +import ( + "github.com/Apicurio/apicurio-registry-operator/controllers/common" + "github.com/Apicurio/apicurio-registry-operator/controllers/loop" + "github.com/Apicurio/apicurio-registry-operator/controllers/loop/context" + "github.com/Apicurio/apicurio-registry-operator/controllers/loop/services" + "github.com/Apicurio/apicurio-registry-operator/controllers/svc/factory" + "github.com/Apicurio/apicurio-registry-operator/controllers/svc/resources" + "go.uber.org/zap" + apps "k8s.io/api/apps/v1" +) + +var _ loop.ControlFunction = &UpgradeCF{} + +type UpgradeCF struct { + ctx context.LoopContext + log *zap.SugaredLogger + svcResourceCache resources.ResourceCache + + containerNameUpgradeNeeded bool + containerNameUpgradeDone bool +} + +func NewUpgradeCF(ctx context.LoopContext, _ services.LoopServices) loop.ControlFunction { + res := &UpgradeCF{ + ctx: ctx, + svcResourceCache: ctx.GetResourceCache(), + } + res.log = ctx.GetLog().Sugar().With("cf", res.Describe()) + return res +} + +func (this *UpgradeCF) Describe() string { + return "UpgradeCF" +} + +func (this *UpgradeCF) Sense() { + + // Ensure that the registry container in Deployment is named correctly + // This will ensure that the previous deployment is properly managed by this operator version + // Observation #1 + // Get the cached Deployment (if it exists and/or the value) + this.containerNameUpgradeNeeded = false + if entry, exists := this.svcResourceCache.Get(resources.RC_KEY_DEPLOYMENT); exists { + containers := entry.GetValue().(*apps.Deployment).Spec.Template.Spec.Containers + oldContainer := common.GetContainerByName(containers, this.ctx.GetAppName().Str()) + newContainer := common.GetContainerByName(containers, factory.REGISTRY_CONTAINER_NAME) + if oldContainer != nil { + if newContainer != nil { + this.log.Warnw("cannot upgrade: both containers named " + oldContainer.Name + " and " + newContainer.Name + + " found in the Deployment") + } else { + this.containerNameUpgradeNeeded = true + } + } + } +} + +func (this *UpgradeCF) Compare() bool { + return this.containerNameUpgradeNeeded && !this.containerNameUpgradeDone +} + +func (this *UpgradeCF) Respond() { + + if entry, exists := this.svcResourceCache.Get(resources.RC_KEY_DEPLOYMENT); exists { + if this.containerNameUpgradeNeeded { + entry.ApplyPatch(func(value interface{}) interface{} { + deployment := value.(*apps.Deployment).DeepCopy() + oldContainer := common.GetContainerByName(deployment.Spec.Template.Spec.Containers, this.ctx.GetAppName().Str()) + oldContainer.Name = factory.REGISTRY_CONTAINER_NAME + return deployment + }) + this.containerNameUpgradeDone = true + this.log.Infow("upgrade successful: renamed container name") + } + } +} + +func (this *UpgradeCF) Cleanup() bool { + // No cleanup + return true +} diff --git a/controllers/cf/env_test.go b/controllers/cf/env_test.go index 2f8df3de..1436722f 100644 --- a/controllers/cf/env_test.go +++ b/controllers/cf/env_test.go @@ -7,6 +7,7 @@ import ( loop_impl "github.com/Apicurio/apicurio-registry-operator/controllers/loop/impl" services2 "github.com/Apicurio/apicurio-registry-operator/controllers/loop/services" "github.com/Apicurio/apicurio-registry-operator/controllers/svc/env" + "github.com/Apicurio/apicurio-registry-operator/controllers/svc/factory" "github.com/Apicurio/apicurio-registry-operator/controllers/svc/resources" apps "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" @@ -134,7 +135,7 @@ func TestEnvOrdering(t *testing.T) { Spec: corev1.PodSpec{ Containers: []corev1.Container{ { - Name: ctx.GetAppName().Str(), + Name: factory.REGISTRY_CONTAINER_NAME, Env: []corev1.EnvVar{ { Name: "DEPLOYMENT_VAR_1_NAME", @@ -246,7 +247,7 @@ func TestEnvPriority(t *testing.T) { Spec: corev1.PodSpec{ Containers: []corev1.Container{ { - Name: ctx.GetAppName().Str(), + Name: factory.REGISTRY_CONTAINER_NAME, Env: []corev1.EnvVar{ { Name: "VAR_1_NAME", diff --git a/controllers/cf/kafkasql/cf_kafkasql_security_scram.go b/controllers/cf/kafkasql/cf_kafkasql_security_scram.go index e420eba7..b3afeb11 100644 --- a/controllers/cf/kafkasql/cf_kafkasql_security_scram.go +++ b/controllers/cf/kafkasql/cf_kafkasql_security_scram.go @@ -5,6 +5,7 @@ import ( "github.com/Apicurio/apicurio-registry-operator/controllers/loop" "github.com/Apicurio/apicurio-registry-operator/controllers/loop/context" "github.com/Apicurio/apicurio-registry-operator/controllers/svc/env" + "github.com/Apicurio/apicurio-registry-operator/controllers/svc/factory" "github.com/Apicurio/apicurio-registry-operator/controllers/svc/resources" apps "k8s.io/api/apps/v1" core "k8s.io/api/core/v1" @@ -212,7 +213,7 @@ func (this *KafkasqlSecurityScramCF) AddSecretMountPatch(deploymentEntry resourc deploymentEntry.ApplyPatch(func(value interface{}) interface{} { deployment := value.(*apps.Deployment).DeepCopy() for ci, c := range deployment.Spec.Template.Spec.Containers { - if c.Name == this.ctx.GetAppName().Str() { + if c.Name == factory.REGISTRY_CONTAINER_NAME { mount := core.VolumeMount{ Name: volumeName, ReadOnly: true, diff --git a/controllers/cf/kafkasql/cf_kafkasql_security_tls.go b/controllers/cf/kafkasql/cf_kafkasql_security_tls.go index 9ffb3498..357c835a 100644 --- a/controllers/cf/kafkasql/cf_kafkasql_security_tls.go +++ b/controllers/cf/kafkasql/cf_kafkasql_security_tls.go @@ -5,6 +5,7 @@ import ( "github.com/Apicurio/apicurio-registry-operator/controllers/loop" "github.com/Apicurio/apicurio-registry-operator/controllers/loop/context" "github.com/Apicurio/apicurio-registry-operator/controllers/svc/env" + "github.com/Apicurio/apicurio-registry-operator/controllers/svc/factory" "github.com/Apicurio/apicurio-registry-operator/controllers/svc/resources" apps "k8s.io/api/apps/v1" core "k8s.io/api/core/v1" @@ -190,7 +191,7 @@ func (this *KafkasqlSecurityTLSCF) AddSecretMountPatch(deploymentEntry resources deploymentEntry.ApplyPatch(func(value interface{}) interface{} { deployment := value.(*apps.Deployment).DeepCopy() for ci, c := range deployment.Spec.Template.Spec.Containers { - if c.Name == this.ctx.GetAppName().Str() { + if c.Name == factory.REGISTRY_CONTAINER_NAME { mount := core.VolumeMount{ Name: volumeName, ReadOnly: true, diff --git a/controllers/common/util.go b/controllers/common/util.go index 16fb9dc1..b17d111a 100644 --- a/controllers/common/util.go +++ b/controllers/common/util.go @@ -73,10 +73,6 @@ func AssertEquals(t *testing.T, expected interface{}, actual interface{}) { } } -func First(first interface{}, _ interface{}) interface{} { - return first -} - func FindIndex(haystack []interface{}, needle interface{}) (int, error) { for i, v := range haystack { if reflect.DeepEqual(v, needle) { @@ -105,11 +101,11 @@ func AssertSliceContains(t *testing.T, haystack []interface{}, needle interface{ } // TODO Refactor -func SetVolumeInDeployment(log *zap.SugaredLogger, deployment *apps.Deployment, volume *core.Volume) { - SetVolume(log, &deployment.Spec.Template.Spec.Volumes, volume) +func SetVolumeInDeployment(deployment *apps.Deployment, volume *core.Volume) { + SetVolume(&deployment.Spec.Template.Spec.Volumes, volume) } -func SetVolume(log *zap.SugaredLogger, volumes *[]core.Volume, volume *core.Volume) { +func SetVolume(volumes *[]core.Volume, volume *core.Volume) { volumeAlreadyExists := false // Modify volume if it exists, otherwise append as a new volume @@ -125,6 +121,21 @@ func SetVolume(log *zap.SugaredLogger, volumes *[]core.Volume, volume *core.Volu } } +func SetVolumeMount(volumeMounts *[]core.VolumeMount, volumeMount *core.VolumeMount) { + alreadyExists := false + // Modify if it exists, otherwise append + for i, v := range *volumeMounts { + if v.Name == volumeMount.Name { + alreadyExists = true + (*volumeMounts)[i] = *volumeMount + break + } + } + if !alreadyExists { + *volumeMounts = append(*volumeMounts, *volumeMount) + } +} + func RemoveVolumeFromDeployment(deployment *apps.Deployment, volume *core.Volume) { deploymentVolumes := &deployment.Spec.Template.Spec.Volumes @@ -169,51 +180,16 @@ func RemoveVolumeMountFromContainer(container *core.Container, volumeMount *core } } -func AddEnvVarToContainer(container *core.Container, envVar *core.EnvVar) { - - envVars := &container.Env - varAlreadyExists := false - - // Modify envVar if it exists, otherwise append as a new envVar - for i, variable := range *envVars { - if variable.Name == envVar.Name { - varAlreadyExists = true - (*envVars)[i] = *envVar - break - } - } - if !varAlreadyExists { - *envVars = append(*envVars, *envVar) - } -} - -func RemoveEnvVarFromContainer(container *core.Container, envVar *core.EnvVar) { - - envVars := &container.Env - - // Remove envVar from container - for i, variable := range *envVars { - if variable.Name == envVar.Name { - *envVars = append((*envVars)[:i], (*envVars)[i+1:]...) - break - } - } -} - -func AddPortToContainer(container *core.Container, port *core.ContainerPort) { - - ports := &container.Ports - portAlreadyExists := false - - // Modify containerPort if it exists, otherwise append as a new containerPort +func AddContainerPort(ports *[]core.ContainerPort, port *core.ContainerPort) { + exists := false for i, p := range *ports { if p.ContainerPort == port.ContainerPort { - portAlreadyExists = true + exists = true (*ports)[i] = *port break } } - if !portAlreadyExists { + if !exists { *ports = append(*ports, *port) } } @@ -335,11 +311,23 @@ func LabelsEqual(target map[string]string, source map[string]string) bool { return true } -func LabelsUpdate(target map[string]string, source map[string]string) { +func LabelsUpdate(target *map[string]string, source map[string]string) { + if *target == nil { + *target = make(map[string]string) + } for sourceKey, sourceValue := range source { - targetValue, targetExists := target[sourceKey] + targetValue, targetExists := (*target)[sourceKey] if !targetExists || sourceValue != targetValue { - target[sourceKey] = sourceValue + (*target)[sourceKey] = sourceValue + } + } +} + +func GetContainerByName(containers []core.Container, name string) *core.Container { + for i, c := range containers { + if c.Name == name { + return &containers[i] } } + return nil } diff --git a/controllers/svc/factory/factory_kube.go b/controllers/svc/factory/factory_kube.go index a0eb12ff..7469f29f 100644 --- a/controllers/svc/factory/factory_kube.go +++ b/controllers/svc/factory/factory_kube.go @@ -23,6 +23,8 @@ func NewKubeFactory(ctx context.LoopContext) *KubeFactory { } } +const REGISTRY_CONTAINER_NAME = "registry" + const ENV_REGISTRY_VERSION = "REGISTRY_VERSION" const ENV_OPERATOR_NAME = "OPERATOR_NAME" @@ -82,13 +84,10 @@ func (this *KubeFactory) CreateDeployment() *apps.Deployment { Replicas: &replicas, Selector: &meta.LabelSelector{MatchLabels: this.GetSelectorLabels()}, Template: core.PodTemplateSpec{ - ObjectMeta: meta.ObjectMeta{ - Labels: this.GetLabels(), - }, Spec: core.PodSpec{ Containers: []core.Container{ { - Name: this.ctx.GetAppName().Str(), + Name: REGISTRY_CONTAINER_NAME, Resources: core.ResourceRequirements{ Limits: core.ResourceList{ core.ResourceCPU: resource.MustParse("1"),