diff --git a/api/v1/runtimecomponent_types.go b/api/v1/runtimecomponent_types.go index 9850daa60..f1063104c 100644 --- a/api/v1/runtimecomponent_types.go +++ b/api/v1/runtimecomponent_types.go @@ -177,15 +177,15 @@ type RuntimeComponentServiceAccount struct { type RuntimeComponentProbes struct { // Periodic probe of container liveness. Container will be restarted if the probe fails. // +operator-sdk:csv:customresourcedefinitions:order=3,type=spec,displayName="Liveness Probe" - Liveness *corev1.Probe `json:"liveness,omitempty"` + Liveness *common.BaseComponentProbe `json:"liveness,omitempty"` // Periodic probe of container service readiness. Container will be removed from service endpoints if the probe fails. // +operator-sdk:csv:customresourcedefinitions:order=2,type=spec,displayName="Readiness Probe" - Readiness *corev1.Probe `json:"readiness,omitempty"` + Readiness *common.BaseComponentProbe `json:"readiness,omitempty"` // Probe to determine successful initialization. If specified, other probes are not executed until this completes successfully. // +operator-sdk:csv:customresourcedefinitions:order=1,type=spec,displayName="Startup Probe" - Startup *corev1.Probe `json:"startup,omitempty"` + Startup *common.BaseComponentProbe `json:"startup,omitempty"` } // Configure pods to run on particular Nodes. @@ -544,32 +544,32 @@ func (cr *RuntimeComponent) GetProbes() common.BaseComponentProbes { } // GetLivenessProbe returns liveness probe -func (p *RuntimeComponentProbes) GetLivenessProbe() *corev1.Probe { +func (p *RuntimeComponentProbes) GetLivenessProbe() *common.BaseComponentProbe { return p.Liveness } // GetReadinessProbe returns readiness probe -func (p *RuntimeComponentProbes) GetReadinessProbe() *corev1.Probe { +func (p *RuntimeComponentProbes) GetReadinessProbe() *common.BaseComponentProbe { return p.Readiness } // GetStartupProbe returns startup probe -func (p *RuntimeComponentProbes) GetStartupProbe() *corev1.Probe { +func (p *RuntimeComponentProbes) GetStartupProbe() *common.BaseComponentProbe { return p.Startup } // GetDefaultLivenessProbe returns default values for liveness probe -func (p *RuntimeComponentProbes) GetDefaultLivenessProbe(ba common.BaseComponent) *corev1.Probe { +func (p *RuntimeComponentProbes) GetDefaultLivenessProbe(ba common.BaseComponent) *common.BaseComponentProbe { return common.GetDefaultMicroProfileLivenessProbe(ba) } // GetDefaultReadinessProbe returns default values for readiness probe -func (p *RuntimeComponentProbes) GetDefaultReadinessProbe(ba common.BaseComponent) *corev1.Probe { +func (p *RuntimeComponentProbes) GetDefaultReadinessProbe(ba common.BaseComponent) *common.BaseComponentProbe { return common.GetDefaultMicroProfileReadinessProbe(ba) } // GetDefaultStartupProbe returns default values for startup probe -func (p *RuntimeComponentProbes) GetDefaultStartupProbe(ba common.BaseComponent) *corev1.Probe { +func (p *RuntimeComponentProbes) GetDefaultStartupProbe(ba common.BaseComponent) *common.BaseComponentProbe { return common.GetDefaultMicroProfileStartupProbe(ba) } diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 8c2f73819..52794d704 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -301,17 +301,17 @@ func (in *RuntimeComponentProbes) DeepCopyInto(out *RuntimeComponentProbes) { *out = *in if in.Liveness != nil { in, out := &in.Liveness, &out.Liveness - *out = new(corev1.Probe) + *out = new(common.BaseComponentProbe) (*in).DeepCopyInto(*out) } if in.Readiness != nil { in, out := &in.Readiness, &out.Readiness - *out = new(corev1.Probe) + *out = new(common.BaseComponentProbe) (*in).DeepCopyInto(*out) } if in.Startup != nil { in, out := &in.Startup, &out.Startup - *out = new(corev1.Probe) + *out = new(common.BaseComponentProbe) (*in).DeepCopyInto(*out) } } diff --git a/api/v1beta2/runtimecomponent_types.go b/api/v1beta2/runtimecomponent_types.go index f18249215..7ab0c0116 100644 --- a/api/v1beta2/runtimecomponent_types.go +++ b/api/v1beta2/runtimecomponent_types.go @@ -19,7 +19,7 @@ package v1beta2 import ( "time" - "github.com/application-stacks/runtime-component-operator/common" + common "github.com/application-stacks/runtime-component-operator/common_v1beta2" routev1 "github.com/openshift/api/route/v1" prometheusv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" appsv1 "k8s.io/api/apps/v1" diff --git a/bundle/manifests/rc.app.stacks_runtimecomponents.yaml b/bundle/manifests/rc.app.stacks_runtimecomponents.yaml index 6d3f573c9..906083e8d 100644 --- a/bundle/manifests/rc.app.stacks_runtimecomponents.yaml +++ b/bundle/manifests/rc.app.stacks_runtimecomponents.yaml @@ -3144,8 +3144,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started @@ -3295,8 +3293,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started @@ -3447,8 +3443,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started diff --git a/bundle/manifests/runtime-component.clusterserviceversion.yaml b/bundle/manifests/runtime-component.clusterserviceversion.yaml index 0a9cae7b4..9c266038b 100644 --- a/bundle/manifests/runtime-component.clusterserviceversion.yaml +++ b/bundle/manifests/runtime-component.clusterserviceversion.yaml @@ -71,7 +71,7 @@ metadata: categories: Application Runtime certified: "true" containerImage: icr.io/appcafe/runtime-component-operator:daily - createdAt: "2024-05-07T20:25:49Z" + createdAt: "2024-05-16T14:08:31Z" description: Deploys any runtime component with dynamic and auto-tuning configuration olm.skipRange: '>=0.8.0 <1.3.2' operators.openshift.io/infrastructure-features: '["disconnected"]' diff --git a/common/common.go b/common/common.go index a8f750e37..9d790ec89 100644 --- a/common/common.go +++ b/common/common.go @@ -1,17 +1,17 @@ package common import ( - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/util/intstr" ) // GetDefaultMicroProfileStartupProbe returns the default values for MicroProfile Health-based startup probe. -func GetDefaultMicroProfileStartupProbe(ba BaseComponent) *corev1.Probe { - return &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ +func GetDefaultMicroProfileStartupProbe(ba BaseComponent) *BaseComponentProbe { + port := intstr.FromInt(int(ba.GetService().GetPort())) + return &BaseComponentProbe{ + BaseComponentProbeHandler: BaseComponentProbeHandler{ + HTTPGet: &OptionalHTTPGetAction{ Path: "/health/started", - Port: intstr.FromInt(int(ba.GetService().GetPort())), + Port: &port, Scheme: "HTTPS", }, }, @@ -22,12 +22,13 @@ func GetDefaultMicroProfileStartupProbe(ba BaseComponent) *corev1.Probe { } // GetDefaultMicroProfileReadinessProbe returns the default values for MicroProfile Health-based readiness probe. -func GetDefaultMicroProfileReadinessProbe(ba BaseComponent) *corev1.Probe { - return &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ +func GetDefaultMicroProfileReadinessProbe(ba BaseComponent) *BaseComponentProbe { + port := intstr.FromInt(int(ba.GetService().GetPort())) + return &BaseComponentProbe{ + BaseComponentProbeHandler: BaseComponentProbeHandler{ + HTTPGet: &OptionalHTTPGetAction{ Path: "/health/ready", - Port: intstr.FromInt(int(ba.GetService().GetPort())), + Port: &port, Scheme: "HTTPS", }, }, @@ -39,12 +40,13 @@ func GetDefaultMicroProfileReadinessProbe(ba BaseComponent) *corev1.Probe { } // GetDefaultMicroProfileLivenessProbe returns the default values for MicroProfile Health-based liveness probe. -func GetDefaultMicroProfileLivenessProbe(ba BaseComponent) *corev1.Probe { - return &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{ +func GetDefaultMicroProfileLivenessProbe(ba BaseComponent) *BaseComponentProbe { + port := intstr.FromInt(int(ba.GetService().GetPort())) + return &BaseComponentProbe{ + BaseComponentProbeHandler: BaseComponentProbeHandler{ + HTTPGet: &OptionalHTTPGetAction{ Path: "/health/live", - Port: intstr.FromInt(int(ba.GetService().GetPort())), + Port: &port, Scheme: "HTTPS", }, }, diff --git a/common/types.go b/common/types.go index 7c8c141c0..8725013bd 100644 --- a/common/types.go +++ b/common/types.go @@ -7,6 +7,7 @@ import ( corev1 "k8s.io/api/core/v1" networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" ) // StatusConditionType ... @@ -177,15 +178,99 @@ type BaseComponentStatefulSet interface { GetAnnotations() map[string]string } +// This struct is taken from the Probe specification in https://github.com/kubernetes/api/blob/v0.24.2/core/v1/types.go +// +kubebuilder:object:generate=true +type BaseComponentProbe struct { + // The action taken to determine the health of a container + BaseComponentProbeHandler `json:",inline"` + // Number of seconds after the container has started before liveness probes are initiated. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + // +optional + InitialDelaySeconds int32 `json:"initialDelaySeconds,omitempty"` + // Number of seconds after which the probe times out. + // Defaults to 1 second. Minimum value is 1. + // More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + // +optional + TimeoutSeconds int32 `json:"timeoutSeconds,omitempty"` + // How often (in seconds) to perform the probe. + // Default to 10 seconds. Minimum value is 1. + // +optional + PeriodSeconds int32 `json:"periodSeconds,omitempty"` + // Minimum consecutive successes for the probe to be considered successful after having failed. + // Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + // +optional + SuccessThreshold int32 `json:"successThreshold,omitempty"` + // Minimum consecutive failures for the probe to be considered failed after having succeeded. + // Defaults to 3. Minimum value is 1. + // +optional + FailureThreshold int32 `json:"failureThreshold,omitempty"` + // Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + // The grace period is the duration in seconds after the processes running in the pod are sent + // a termination signal and the time when the processes are forcibly halted with a kill signal. + // Set this value longer than the expected cleanup time for your process. + // If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + // value overrides the value provided by the pod spec. + // Value must be non-negative integer. The value zero indicates stop immediately via + // the kill signal (no opportunity to shut down). + // This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + // Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + // +optional + TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` +} + +// This struct is taken from the ProbeHandler specification in https://github.com/kubernetes/api/blob/v0.24.2/core/v1/types.go +// +kubebuilder:object:generate=true +type BaseComponentProbeHandler struct { + // Exec specifies the action to take. + // +optional + Exec *corev1.ExecAction `json:"exec,omitempty"` + // HTTPGet specifies the http request to perform. + // +optional + HTTPGet *OptionalHTTPGetAction `json:"httpGet,omitempty"` + // TCPSocket specifies an action involving a TCP port. + // +optional + TCPSocket *corev1.TCPSocketAction `json:"tcpSocket,omitempty"` + + // GRPC specifies an action involving a GRPC port. + // This is a beta field and requires enabling GRPCContainerProbe feature gate. + // +featureGate=GRPCContainerProbe + // +optional + GRPC *corev1.GRPCAction `json:"grpc,omitempty"` +} + +// This struct is based upon the HTTPGetAction specification in https://github.com/kubernetes/api/blob/v0.24.2/core/v1/types.go +// +kubebuilder:object:generate=true +type OptionalHTTPGetAction struct { + // Path to access on the HTTP server. + // +optional + Path string `json:"path,omitempty"` + // Name or number of the port to access on the container. + // Number must be in the range 1 to 65535. + // Name must be an IANA_SVC_NAME. + // +optional + Port *intstr.IntOrString `json:"port,omitempty"` + // Host name to connect to, defaults to the pod IP. You probably want to set + // "Host" in httpHeaders instead. + // +optional + Host string `json:"host,omitempty"` + // Scheme to use for connecting to the host. + // Defaults to HTTP. + // +optional + Scheme corev1.URIScheme `json:"scheme,omitempty"` + // Custom headers to set in the request. HTTP allows repeated headers. + // +optional + HTTPHeaders []corev1.HTTPHeader `json:"httpHeaders,omitempty"` +} + // BaseComponentProbes describes the probes for application container type BaseComponentProbes interface { - GetLivenessProbe() *corev1.Probe - GetReadinessProbe() *corev1.Probe - GetStartupProbe() *corev1.Probe + GetLivenessProbe() *BaseComponentProbe + GetReadinessProbe() *BaseComponentProbe + GetStartupProbe() *BaseComponentProbe - GetDefaultLivenessProbe(ba BaseComponent) *corev1.Probe - GetDefaultReadinessProbe(ba BaseComponent) *corev1.Probe - GetDefaultStartupProbe(ba BaseComponent) *corev1.Probe + GetDefaultLivenessProbe(ba BaseComponent) *BaseComponentProbe + GetDefaultReadinessProbe(ba BaseComponent) *BaseComponentProbe + GetDefaultStartupProbe(ba BaseComponent) *BaseComponentProbe } type BaseComponentServiceAccount interface { diff --git a/common/zz_generated.deepcopy.go b/common/zz_generated.deepcopy.go new file mode 100644 index 000000000..88bed28ba --- /dev/null +++ b/common/zz_generated.deepcopy.go @@ -0,0 +1,108 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* + + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package common + +import ( + "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/util/intstr" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseComponentProbe) DeepCopyInto(out *BaseComponentProbe) { + *out = *in + in.BaseComponentProbeHandler.DeepCopyInto(&out.BaseComponentProbeHandler) + if in.TerminationGracePeriodSeconds != nil { + in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds + *out = new(int64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseComponentProbe. +func (in *BaseComponentProbe) DeepCopy() *BaseComponentProbe { + if in == nil { + return nil + } + out := new(BaseComponentProbe) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BaseComponentProbeHandler) DeepCopyInto(out *BaseComponentProbeHandler) { + *out = *in + if in.Exec != nil { + in, out := &in.Exec, &out.Exec + *out = new(v1.ExecAction) + (*in).DeepCopyInto(*out) + } + if in.HTTPGet != nil { + in, out := &in.HTTPGet, &out.HTTPGet + *out = new(OptionalHTTPGetAction) + (*in).DeepCopyInto(*out) + } + if in.TCPSocket != nil { + in, out := &in.TCPSocket, &out.TCPSocket + *out = new(v1.TCPSocketAction) + **out = **in + } + if in.GRPC != nil { + in, out := &in.GRPC, &out.GRPC + *out = new(v1.GRPCAction) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BaseComponentProbeHandler. +func (in *BaseComponentProbeHandler) DeepCopy() *BaseComponentProbeHandler { + if in == nil { + return nil + } + out := new(BaseComponentProbeHandler) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OptionalHTTPGetAction) DeepCopyInto(out *OptionalHTTPGetAction) { + *out = *in + if in.Port != nil { + in, out := &in.Port, &out.Port + *out = new(intstr.IntOrString) + **out = **in + } + if in.HTTPHeaders != nil { + in, out := &in.HTTPHeaders, &out.HTTPHeaders + *out = make([]v1.HTTPHeader, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OptionalHTTPGetAction. +func (in *OptionalHTTPGetAction) DeepCopy() *OptionalHTTPGetAction { + if in == nil { + return nil + } + out := new(OptionalHTTPGetAction) + in.DeepCopyInto(out) + return out +} diff --git a/common_v1beta2/types.go b/common_v1beta2/types.go new file mode 100644 index 000000000..f397dc1cf --- /dev/null +++ b/common_v1beta2/types.go @@ -0,0 +1,236 @@ +package common_v1beta2 + +import ( + routev1 "github.com/openshift/api/route/v1" + prometheusv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" + appsv1 "k8s.io/api/apps/v1" + corev1 "k8s.io/api/core/v1" + networkingv1 "k8s.io/api/networking/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// StatusConditionType ... +type StatusConditionType string + +// StatusEndpointScope ... +type StatusEndpointScope string + +type StatusReferences map[string]string + +const ( + StatusReferenceCertSecretName = "svcCertSecretName" + StatusReferencePullSecretName = "saPullSecretName" + StatusReferenceSAResourceVersion = "saResourceVersion" + StatusReferenceRouteHost = "routeHost" +) + +// StatusCondition ... +type StatusCondition interface { + GetLastTransitionTime() *metav1.Time + SetLastTransitionTime(*metav1.Time) + + GetReason() string + SetReason(string) + + GetMessage() string + SetMessage(string) + + GetStatus() corev1.ConditionStatus + SetStatus(corev1.ConditionStatus) + + GetType() StatusConditionType + SetType(StatusConditionType) + + SetConditionFields(string, string, corev1.ConditionStatus) StatusCondition +} + +// StatusEndpoint ... +type StatusEndpoint interface { + GetEndpointName() string + SetEndpointName(string) + + GetEndpointScope() StatusEndpointScope + SetEndpointScope(StatusEndpointScope) + + GetEndpointType() string + SetEndpointType(string) + + GetEndpointUri() string + SetEndpointUri(string) + + SetStatusEndpointFields(StatusEndpointScope, string, string) StatusEndpoint +} + +// BaseComponentStatus returns base appplication status +type BaseComponentStatus interface { + GetConditions() []StatusCondition + GetCondition(StatusConditionType) StatusCondition + SetCondition(StatusCondition) + UnsetCondition(StatusCondition) + NewCondition(StatusConditionType) StatusCondition + + GetStatusEndpoint(string) StatusEndpoint + SetStatusEndpoint(StatusEndpoint) + NewStatusEndpoint(string) StatusEndpoint + RemoveStatusEndpoint(string) + + GetImageReference() string + SetImageReference(string) + + GetBinding() *corev1.LocalObjectReference + SetBinding(*corev1.LocalObjectReference) + + GetReferences() StatusReferences + SetReferences(StatusReferences) + SetReference(string, string) +} + +const ( + // Status Condition Types + StatusConditionTypeReconciled StatusConditionType = "Reconciled" + StatusConditionTypeResourcesReady StatusConditionType = "ResourcesReady" + StatusConditionTypeReady StatusConditionType = "Ready" + StatusConditionTypeWarning StatusConditionType = "Warning" + + // Status Condition Type Messages + StatusConditionTypeReadyMessage string = "Application is reconciled and resources are ready." + + // Status Endpoint Scopes + StatusEndpointScopeExternal StatusEndpointScope = "External" + StatusEndpointScopeInternal StatusEndpointScope = "Internal" +) + +// BaseComponentAutoscaling represents basic HPA configuration +type BaseComponentAutoscaling interface { + GetMinReplicas() *int32 + GetMaxReplicas() int32 + GetTargetCPUUtilizationPercentage() *int32 +} + +// BaseComponentStorage represents basic PVC configuration +type BaseComponentStorage interface { + GetSize() string + GetClassName() string + GetMountPath() string + GetVolumeClaimTemplate() *corev1.PersistentVolumeClaim +} + +// BaseComponentService represents basic service configuration +type BaseComponentService interface { + GetPort() int32 + GetTargetPort() *int32 + GetPortName() string + GetType() *corev1.ServiceType + GetNodePort() *int32 + GetPorts() []corev1.ServicePort + GetAnnotations() map[string]string + GetCertificateSecretRef() *string + GetCertificate() BaseComponentCertificate + GetBindable() *bool +} +type BaseComponentCertificate interface { + GetAnnotations() map[string]string +} + +// BaseComponentNetworkPolicy represents a basic network policy configuration +type BaseComponentNetworkPolicy interface { + GetNamespaceLabels() map[string]string + GetFromLabels() map[string]string +} + +// BaseComponentMonitoring represents basic service monitoring configuration +type BaseComponentMonitoring interface { + GetLabels() map[string]string + GetEndpoints() []prometheusv1.Endpoint +} + +// BaseComponentRoute represents route configuration +type BaseComponentRoute interface { + GetTermination() *routev1.TLSTerminationType + GetInsecureEdgeTerminationPolicy() *routev1.InsecureEdgeTerminationPolicyType + GetAnnotations() map[string]string + GetHost() string + GetPath() string + GetPathType() networkingv1.PathType + GetCertificateSecretRef() *string +} + +// BaseComponentAffinity describes deployment and pod affinity +type BaseComponentAffinity interface { + GetNodeAffinity() *corev1.NodeAffinity + GetPodAffinity() *corev1.PodAffinity + GetPodAntiAffinity() *corev1.PodAntiAffinity + GetArchitecture() []string + GetNodeAffinityLabels() map[string]string +} + +// BaseComponentDeployment describes deployment +type BaseComponentDeployment interface { + GetDeploymentUpdateStrategy() *appsv1.DeploymentStrategy + GetAnnotations() map[string]string +} + +// BaseComponentStatefulSet describes deployment +type BaseComponentStatefulSet interface { + GetStatefulSetUpdateStrategy() *appsv1.StatefulSetUpdateStrategy + GetStorage() BaseComponentStorage + GetAnnotations() map[string]string +} + +// BaseComponentProbes describes the probes for application container +type BaseComponentProbes interface { + GetLivenessProbe() *corev1.Probe + GetReadinessProbe() *corev1.Probe + GetStartupProbe() *corev1.Probe + + GetDefaultLivenessProbe(ba BaseComponent) *corev1.Probe + GetDefaultReadinessProbe(ba BaseComponent) *corev1.Probe + GetDefaultStartupProbe(ba BaseComponent) *corev1.Probe +} + +type BaseComponentServiceAccount interface { + GetMountToken() *bool + GetName() *string +} + +type BaseComponentTopologySpreadConstraints interface { + GetConstraints() *[]corev1.TopologySpreadConstraint + GetDisableOperatorDefaults() *bool +} + +// BaseComponent represents basic kubernetes application +type BaseComponent interface { + GetApplicationImage() string + GetPullPolicy() *corev1.PullPolicy + GetPullSecret() *string + GetServiceAccountName() *string + GetServiceAccount() BaseComponentServiceAccount + GetReplicas() *int32 + GetProbes() BaseComponentProbes + GetVolumes() []corev1.Volume + GetVolumeMounts() []corev1.VolumeMount + GetResourceConstraints() *corev1.ResourceRequirements + GetExpose() *bool + GetEnv() []corev1.EnvVar + GetEnvFrom() []corev1.EnvFromSource + GetCreateKnativeService() *bool + GetAutoscaling() BaseComponentAutoscaling + GetService() BaseComponentService + GetNetworkPolicy() BaseComponentNetworkPolicy + GetDeployment() BaseComponentDeployment + GetStatefulSet() BaseComponentStatefulSet + GetApplicationVersion() string + GetApplicationName() string + GetMonitoring() BaseComponentMonitoring + GetLabels() map[string]string + GetAnnotations() map[string]string + GetStatus() BaseComponentStatus + GetInitContainers() []corev1.Container + GetSidecarContainers() []corev1.Container + GetGroupName() string + GetRoute() BaseComponentRoute + GetAffinity() BaseComponentAffinity + GetTopologySpreadConstraints() BaseComponentTopologySpreadConstraints + GetSecurityContext() *corev1.SecurityContext + GetManageTLS() *bool +} diff --git a/config/crd/bases/rc.app.stacks_runtimecomponents.yaml b/config/crd/bases/rc.app.stacks_runtimecomponents.yaml index ee3e256c1..52f8fd009 100644 --- a/config/crd/bases/rc.app.stacks_runtimecomponents.yaml +++ b/config/crd/bases/rc.app.stacks_runtimecomponents.yaml @@ -3140,8 +3140,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started @@ -3291,8 +3289,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started @@ -3443,8 +3439,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started diff --git a/internal/deploy/kubectl/runtime-component-crd.yaml b/internal/deploy/kubectl/runtime-component-crd.yaml index 6e24a893e..149fce52f 100644 --- a/internal/deploy/kubectl/runtime-component-crd.yaml +++ b/internal/deploy/kubectl/runtime-component-crd.yaml @@ -3143,8 +3143,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started @@ -3294,8 +3292,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started @@ -3446,8 +3442,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started diff --git a/internal/deploy/kustomize/daily/base/runtime-component-crd.yaml b/internal/deploy/kustomize/daily/base/runtime-component-crd.yaml index 6e24a893e..149fce52f 100644 --- a/internal/deploy/kustomize/daily/base/runtime-component-crd.yaml +++ b/internal/deploy/kustomize/daily/base/runtime-component-crd.yaml @@ -3143,8 +3143,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started @@ -3294,8 +3292,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started @@ -3446,8 +3442,6 @@ spec: description: Scheme to use for connecting to the host. Defaults to HTTP. type: string - required: - - port type: object initialDelaySeconds: description: 'Number of seconds after the container has started diff --git a/utils/utils.go b/utils/utils.go index ebe216b62..62ad0f558 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -293,39 +293,123 @@ func CustomizeProbes(container *corev1.Container, ba common.BaseComponent) { container.StartupProbe = customizeProbe(probesConfig.GetStartupProbe(), probesConfig.GetDefaultStartupProbe, ba) } -func customizeProbe(config *corev1.Probe, defaultProbeCallback func(ba common.BaseComponent) *corev1.Probe, ba common.BaseComponent) *corev1.Probe { +func customizeProbe(config *common.BaseComponentProbe, getDefaultProbeCallback func(ba common.BaseComponent) *common.BaseComponentProbe, ba common.BaseComponent) *corev1.Probe { // Probe not defined -- set probe to nil if config == nil { return nil } - // Probe handler is defined in config so use probe as is - if config.ProbeHandler != (corev1.ProbeHandler{}) { - return config + // Always use MicroProfile default values for the probe + return ConvertToCoreProbe(ba, customizeProbeDefaults(config, getDefaultProbeCallback(ba))) +} + +func createHTTPGetActionFromOptionalHTTPGetAction(ba common.BaseComponent, optionalHTTPGetAction *common.OptionalHTTPGetAction) *corev1.HTTPGetAction { + httpGetAction := &corev1.HTTPGetAction{} + if optionalHTTPGetAction != nil { + if len(optionalHTTPGetAction.Host) > 0 { + httpGetAction.Host = optionalHTTPGetAction.Host + } + if len(optionalHTTPGetAction.Path) > 0 { + httpGetAction.Path = optionalHTTPGetAction.Path + } + if len(optionalHTTPGetAction.HTTPHeaders) > 0 { + httpGetAction.HTTPHeaders = optionalHTTPGetAction.HTTPHeaders + } + + if optionalHTTPGetAction.Port != nil { + httpGetAction.Port = *optionalHTTPGetAction.Port + } else if ba.GetService().GetPort() > 0 { + httpGetAction.Port = intstr.FromInt(int(ba.GetService().GetPort())) + } else { + // Can't create HTTPGetAction without a port specified, so return nil. + return nil + } + + if optionalHTTPGetAction.Scheme != "" { + httpGetAction.Scheme = optionalHTTPGetAction.Scheme + } else if httpGetAction.Port.IntValue() == int(ba.GetService().GetPort()) { + // If .spec.service.port matches the configured probe port, set the scheme based on the .spec.manageTLS flag + if ba.GetManageTLS() == nil || *ba.GetManageTLS() { + httpGetAction.Scheme = corev1.URISchemeHTTPS + } else { + httpGetAction.Scheme = corev1.URISchemeHTTP + } + } else { + // Otherwise, use the Kubernetes default scheme + httpGetAction.Scheme = corev1.URISchemeHTTP + } } + return httpGetAction +} - // Probe handler is not defined so use default values for the probe if values not set in probe config - return customizeProbeDefaults(config, defaultProbeCallback(ba)) +func ConvertToCoreProbe(ba common.BaseComponent, baseProbe *common.BaseComponentProbe) *corev1.Probe { + probe := &corev1.Probe{} + if baseProbe != nil { + if baseProbe.BaseComponentProbeHandler.Exec != nil { + probe.ProbeHandler.Exec = baseProbe.BaseComponentProbeHandler.Exec + } + probe.ProbeHandler.HTTPGet = createHTTPGetActionFromOptionalHTTPGetAction(ba, baseProbe.BaseComponentProbeHandler.HTTPGet) + if baseProbe.BaseComponentProbeHandler.TCPSocket != nil { + probe.ProbeHandler.TCPSocket = baseProbe.BaseComponentProbeHandler.TCPSocket + } + if baseProbe.BaseComponentProbeHandler.GRPC != nil { + probe.ProbeHandler.GRPC = baseProbe.BaseComponentProbeHandler.GRPC + } + probe.InitialDelaySeconds = baseProbe.InitialDelaySeconds + probe.TimeoutSeconds = baseProbe.TimeoutSeconds + probe.PeriodSeconds = baseProbe.PeriodSeconds + probe.SuccessThreshold = baseProbe.SuccessThreshold + probe.FailureThreshold = baseProbe.FailureThreshold + probe.TerminationGracePeriodSeconds = baseProbe.TerminationGracePeriodSeconds + } + return probe } -func customizeProbeDefaults(config *corev1.Probe, defaultProbe *corev1.Probe) *corev1.Probe { +func customizeProbeDefaults(config *common.BaseComponentProbe, defaultProbe *common.BaseComponentProbe) *common.BaseComponentProbe { probe := defaultProbe - if config.InitialDelaySeconds != 0 { - probe.InitialDelaySeconds = config.InitialDelaySeconds - } - if config.TimeoutSeconds != 0 { - probe.TimeoutSeconds = config.TimeoutSeconds - } - if config.PeriodSeconds != 0 { - probe.PeriodSeconds = config.PeriodSeconds - } - if config.SuccessThreshold != 0 { - probe.SuccessThreshold = config.SuccessThreshold - } - if config.FailureThreshold != 0 { - probe.FailureThreshold = config.FailureThreshold + if config != nil { + if config.BaseComponentProbeHandler.Exec != nil { + probe.BaseComponentProbeHandler.Exec = config.BaseComponentProbeHandler.Exec + } + if config.BaseComponentProbeHandler.HTTPGet != nil { + if config.BaseComponentProbeHandler.HTTPGet.Path != "" && config.BaseComponentProbeHandler.HTTPGet.Path != "/" { + probe.BaseComponentProbeHandler.HTTPGet.Path = config.BaseComponentProbeHandler.HTTPGet.Path + } + if config.BaseComponentProbeHandler.HTTPGet.Host != "" { + probe.BaseComponentProbeHandler.HTTPGet.Host = config.BaseComponentProbeHandler.HTTPGet.Host + } + if config.BaseComponentProbeHandler.HTTPGet.Port != nil { + probe.BaseComponentProbeHandler.HTTPGet.Port = config.BaseComponentProbeHandler.HTTPGet.Port + } + if config.BaseComponentProbeHandler.HTTPGet.Scheme != "" { + probe.BaseComponentProbeHandler.HTTPGet.Scheme = config.BaseComponentProbeHandler.HTTPGet.Scheme + } + if len(config.BaseComponentProbeHandler.HTTPGet.HTTPHeaders) > 0 { + probe.BaseComponentProbeHandler.HTTPGet.HTTPHeaders = config.BaseComponentProbeHandler.HTTPGet.HTTPHeaders + } + } + if config.BaseComponentProbeHandler.TCPSocket != nil { + probe.BaseComponentProbeHandler.TCPSocket = config.BaseComponentProbeHandler.TCPSocket + } + if config.BaseComponentProbeHandler.GRPC != nil { + probe.BaseComponentProbeHandler.GRPC = config.BaseComponentProbeHandler.GRPC + } + if config.InitialDelaySeconds != 0 { + probe.InitialDelaySeconds = config.InitialDelaySeconds + } + if config.TimeoutSeconds != 0 { + probe.TimeoutSeconds = config.TimeoutSeconds + } + if config.PeriodSeconds != 0 { + probe.PeriodSeconds = config.PeriodSeconds + } + if config.SuccessThreshold != 0 { + probe.SuccessThreshold = config.SuccessThreshold + } + if config.FailureThreshold != 0 { + probe.FailureThreshold = config.FailureThreshold + } } - return probe } diff --git a/utils/utils_test.go b/utils/utils_test.go index edd0a0cf2..0756a8a01 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -1,13 +1,14 @@ package utils import ( - appstacksv1 "github.com/application-stacks/runtime-component-operator/api/v1" "os" "reflect" "strconv" "testing" + appstacksv1 "github.com/application-stacks/runtime-component-operator/api/v1" "github.com/application-stacks/runtime-component-operator/common" + routev1 "github.com/openshift/api/route/v1" prometheusv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" appsv1 "k8s.io/api/apps/v1" @@ -55,21 +56,21 @@ var ( TypeMeta: metav1.TypeMeta{Kind: "StatefulSet"}} storage = appstacksv1.RuntimeComponentStorage{Size: "10Mi", MountPath: "/mnt/data", VolumeClaimTemplate: volumeCT} arch = []string{"ppc64le"} - readinessProbe = &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{}, + readinessProbe = &common.BaseComponentProbe{ + BaseComponentProbeHandler: common.BaseComponentProbeHandler{ + HTTPGet: &common.OptionalHTTPGetAction{}, TCPSocket: &corev1.TCPSocketAction{}, }, } - livenessProbe = &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{}, + livenessProbe = &common.BaseComponentProbe{ + BaseComponentProbeHandler: common.BaseComponentProbeHandler{ + HTTPGet: &common.OptionalHTTPGetAction{}, TCPSocket: &corev1.TCPSocketAction{}, }, } - startupProbe = &corev1.Probe{ - ProbeHandler: corev1.ProbeHandler{ - HTTPGet: &corev1.HTTPGetAction{}, + startupProbe = &common.BaseComponentProbe{ + BaseComponentProbeHandler: common.BaseComponentProbeHandler{ + HTTPGet: &common.OptionalHTTPGetAction{}, TCPSocket: &corev1.TCPSocketAction{}, }, }