diff --git a/api/condition_types.go b/api/condition_types.go index 6d948e8f9..3f13f15a5 100644 --- a/api/condition_types.go +++ b/api/condition_types.go @@ -15,6 +15,8 @@ package api import ( + "fmt" + v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -102,3 +104,17 @@ func (c *Condition) GetMessage() string { } return c.Message } + +func (c *Condition) String() string { + if c == nil { + return "" + } + str := fmt.Sprintf("Condition %s status is %s", c.Type, c.Status) + if len(c.Reason) > 0 { + str += fmt.Sprintf(". [Reason] %s", c.Reason) + } + if len(c.Message) > 0 { + str += fmt.Sprintf(". [Message] %s", c.Message) + } + return str +} diff --git a/api/status_types.go b/api/status_types.go index 765e90492..dde98dee0 100644 --- a/api/status_types.go +++ b/api/status_types.go @@ -54,6 +54,14 @@ func (s *Status) GetCondition(t ConditionType) *Condition { return nil } +func (s *Status) String() string { + str := "" + for _, c := range s.Conditions { + str += c.String() + "\n" + } + return str +} + func (s *Status) setConditions(c Conditions) { s.Conditions = c } diff --git a/api/v1alpha08/sonataflowplatform_build_types.go b/api/v1alpha08/sonataflowplatform_build_types.go new file mode 100644 index 000000000..94652810f --- /dev/null +++ b/api/v1alpha08/sonataflowplatform_build_types.go @@ -0,0 +1,102 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// 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. + +package v1alpha08 + +import ( + "strconv" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Describes the general build specification for this platform. Specific for build scenarios. +type BuildPlatformSpec struct { + // Describes a build template for building workflows. Base for the internal SonataFlowBuild resource. + Template BuildTemplate `json:"template,omitempty"` + // Describes the platform configuration for building workflows. + Config BuildPlatformConfig `json:"config,omitempty"` +} + +// Describes the configuration for building in the given platform +type BuildPlatformConfig struct { + // a base image that can be used as base layer for all images. + // It can be useful if you want to provide some custom base image with further utility software + BaseImage string `json:"baseImage,omitempty"` + // how much time to wait before time out the build process + Timeout *metav1.Duration `json:"timeout,omitempty"` + // BuildStrategy to use to build workflows in the platform. + // Usually, the operator elect the strategy based on the platform. + // Note that this field might be read only in certain scenarios. + BuildStrategy BuildStrategy `json:"strategy,omitempty"` + // BuildStrategyOptions additional options to add to the build strategy. + // See https://sonataflow.org/serverlessworkflow/main/cloud/operator/build-and-deploy-workflows.html + BuildStrategyOptions map[string]string `json:"strategyOptions,omitempty"` + // Registry the registry where to publish the built image + Registry RegistrySpec `json:"registry,omitempty"` +} + +// GetTimeout returns the specified duration or a default one +func (b *BuildPlatformConfig) GetTimeout() metav1.Duration { + if b.Timeout == nil { + return metav1.Duration{} + } + return *b.Timeout +} + +// IsStrategyOptionEnabled return whether the BuildStrategyOptions is enabled or not +func (b *BuildPlatformConfig) IsStrategyOptionEnabled(option string) bool { + if enabled, ok := b.BuildStrategyOptions[option]; ok { + res, err := strconv.ParseBool(enabled) + if err != nil { + return false + } + return res + } + return false +} + +func (b *BuildPlatformConfig) IsStrategyOptionEmpty(option string) bool { + if v, ok := b.BuildStrategyOptions[option]; ok { + return len(v) == 0 + } + return false +} + +// RegistrySpec provides the configuration for the container registry +type RegistrySpec struct { + // if the container registry is insecure (ie, http only) + Insecure bool `json:"insecure,omitempty"` + // the URI to access + Address string `json:"address,omitempty"` + // the secret where credentials are stored + Secret string `json:"secret,omitempty"` + // the configmap which stores the Certificate Authority + CA string `json:"ca,omitempty"` + // the registry organization + Organization string `json:"organization,omitempty"` +} + +type BuildStrategy string + +const ( + // OperatorBuildStrategy uses the operator builder to perform the workflow build + // E.g. on Minikube or Kubernetes the container-builder strategies + OperatorBuildStrategy BuildStrategy = "operator" + // PlatformBuildStrategy uses the cluster to perform the build. + // E.g. on OpenShift, BuildConfig. + PlatformBuildStrategy BuildStrategy = "platform" + + // In the future we can have "custom" which will delegate the build to an external actor provided by the administrator + // See https://issues.redhat.com/browse/KOGITO-9084 +) diff --git a/api/v1alpha08/sonataflowplatform_devmode_types.go b/api/v1alpha08/sonataflowplatform_devmode_types.go new file mode 100644 index 000000000..971fbb356 --- /dev/null +++ b/api/v1alpha08/sonataflowplatform_devmode_types.go @@ -0,0 +1,21 @@ +// Copyright 2023 Red Hat, Inc. and/or its affiliates +// +// 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. + +package v1alpha08 + +// DevModePlatformSpec describes the devmode configuration for the given platform. +type DevModePlatformSpec struct { + // Base image to run the Workflow in dev mode instead of the operator's default. + BaseImage string `json:"baseImage,omitempty"` +} diff --git a/api/v1alpha08/sonataflowplatform_types.go b/api/v1alpha08/sonataflowplatform_types.go index a43a94fff..c79172a8e 100644 --- a/api/v1alpha08/sonataflowplatform_types.go +++ b/api/v1alpha08/sonataflowplatform_types.go @@ -15,37 +15,24 @@ package v1alpha08 import ( - "strconv" - - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -// ConfigurationSpecType is used to define the enum values of the supported types for ConfigurationSpec -type ConfigurationSpecType string -const ( - // PropertyConfigurationSpec ... - PropertyConfigurationSpec ConfigurationSpecType = "property" - // ConfigMapConfigurationSpec ... - ConfigMapConfigurationSpec ConfigurationSpecType = "configmap" - // SecretConfigurationSpec ... - SecretConfigurationSpec ConfigurationSpecType = "secret" + "github.com/kiegroup/kogito-serverless-operator/api" ) -// ConfigurationSpec represents a generic configuration specification -type ConfigurationSpec struct { - // Type represents the type of configuration, ie: property, configmap, secret, ... - Type ConfigurationSpecType `json:"type"` - // Value a reference to the object for this configuration (syntax may vary depending on the `Type`) - Value corev1.ObjectReference `json:"value"` -} - const ( // SonataFlowPlatformKind is the Kind name of the SonataFlowPlatform CR SonataFlowPlatformKind string = "SonataFlowPlatform" ) +// SonataFlowPlatformSpec defines the desired state of SonataFlowPlatform +type SonataFlowPlatformSpec struct { + // Attributes for building workflows in the target platform + Build BuildPlatformSpec `json:"build,omitempty"` + // Attributes for running workflows in devmode (immutable, no build required) + DevMode DevModePlatformSpec `json:"devMode,omitempty"` +} + // PlatformCluster is the kind of orchestration cluster the platform is installed into // +kubebuilder:validation:Enum=kubernetes;openshift type PlatformCluster string @@ -57,146 +44,58 @@ const ( PlatformClusterKubernetes PlatformCluster = "kubernetes" ) -// RegistrySpec provides the configuration for the container registry -type RegistrySpec struct { - // if the container registry is insecure (ie, http only) - Insecure bool `json:"insecure,omitempty"` - // the URI to access - Address string `json:"address,omitempty"` - // the secret where credentials are stored - Secret string `json:"secret,omitempty"` - // the configmap which stores the Certificate Authority - CA string `json:"ca,omitempty"` - // the registry organization - Organization string `json:"organization,omitempty"` -} - -type BuildStrategy string - const ( - // OperatorBuildStrategy uses the operator builder to perform the workflow build - // E.g. on Minikube or Kubernetes the container-builder strategies - OperatorBuildStrategy BuildStrategy = "operator" - // PlatformBuildStrategy uses the cluster to perform the build. - // E.g. on OpenShift, BuildConfig. - PlatformBuildStrategy BuildStrategy = "platform" - - // In the future we can have "custom" which will delegate the build to an external actor provided by the administrator - // See https://issues.redhat.com/browse/KOGITO-9084 + PlatformCreatingReason = "Creating" + PlatformWarmingReason = "Warming" + PlatformFailureReason = "Failure" + PlatformDuplicatedReason = "Duplicated" ) -type BuildPlatformTemplate struct { - // a base image that can be used as base layer for all images. - // It can be useful if you want to provide some custom base image with further utility software - BaseImage string `json:"baseImage,omitempty"` - // how much time to wait before time out the build process - Timeout *metav1.Duration `json:"timeout,omitempty"` - // BuildStrategy to use to build workflows in the platform. - // Usually, the operator elect the strategy based on the platform. - // Note that this field might be read only in certain scenarios. - BuildStrategy BuildStrategy `json:"buildStrategy,omitempty"` - // TODO: add a link to the documentation where the user can find more info about this field - // BuildStrategyOptions additional options to add to the build strategy. - BuildStrategyOptions map[string]string `json:"buildStrategyOptions,omitempty"` - // Registry the registry where to publish the built image - Registry RegistrySpec `json:"registry,omitempty"` +// SonataFlowPlatformStatus defines the observed state of SonataFlowPlatform +type SonataFlowPlatformStatus struct { + api.Status `json:",inline"` + // Cluster what kind of cluster you're running (ie, plain Kubernetes or OpenShift) + Cluster PlatformCluster `json:"cluster,omitempty"` + // Version the operator version controlling this Platform + Version string `json:"version,omitempty"` + // Info generic information related to the build + Info map[string]string `json:"info,omitempty"` } -// GetTimeout returns the specified duration or a default one -func (b *BuildPlatformTemplate) GetTimeout() metav1.Duration { - if b.Timeout == nil { - return metav1.Duration{} - } - return *b.Timeout +func (in *SonataFlowPlatformStatus) GetTopLevelConditionType() api.ConditionType { + return api.SucceedConditionType } -// IsOptionEnabled return whether the BuildStrategyOptions is enabled or not -func (b *BuildPlatformTemplate) IsOptionEnabled(option string) bool { - if enabled, ok := b.BuildStrategyOptions[option]; ok { - res, err := strconv.ParseBool(enabled) - if err != nil { - return false - } - return res - } - return false +func (in *SonataFlowPlatformStatus) IsReady() bool { + return in.GetTopLevelCondition().IsTrue() } -func (b *BuildPlatformTemplate) IsOptionEmpty(option string) bool { - if v, ok := b.BuildStrategyOptions[option]; ok { - return len(v) == 0 - } - return false +func (in *SonataFlowPlatformStatus) GetTopLevelCondition() *api.Condition { + return in.GetCondition(in.GetTopLevelConditionType()) } -// SonataFlowPlatformSpec defines the desired state of SonataFlowPlatform -type SonataFlowPlatformSpec struct { - // BuildTemplate specify how to build the Workflow. It's used as a template for the SonataFlowBuild - BuildTemplate BuildTemplate `json:"build,omitempty"` - // BuildPlatform specify how is the platform where we want to build the Workflow - BuildPlatform BuildPlatformTemplate `json:"platform,omitempty"` - // Configuration list of configuration properties to be attached to all the Workflow built from this Platform - Configuration ConfigurationSpec `json:"configuration,omitempty"` - // DevBaseImage Base image to run the Workflow in dev mode instead of the operator's default. - // Optional, used for the dev profile only - DevBaseImage string `json:"devBaseImage,omitempty"` +func (in *SonataFlowPlatformStatus) Manager() api.ConditionsManager { + return api.NewConditionManager(in, api.SucceedConditionType) } -// PlatformPhase is the phase of a Platform -type PlatformPhase string +func (in *SonataFlowPlatformStatus) IsCreating() bool { + cond := in.GetTopLevelCondition() + return cond.IsFalse() && cond.Reason == PlatformCreatingReason +} -const ( - // PlatformPhaseNone when the SonataFlowPlatform does not exist - PlatformPhaseNone PlatformPhase = "" - // PlatformPhaseCreating when the SonataFlowPlatform is under creation process - PlatformPhaseCreating PlatformPhase = "Creating" - // PlatformPhaseWarming when the SonataFlowPlatform is warming (ie, creating Kaniko cache) - PlatformPhaseWarming PlatformPhase = "Warming" - // PlatformPhaseReady when the SonataFlowPlatform is ready - PlatformPhaseReady PlatformPhase = "Ready" - // PlatformPhaseError when the SonataFlowPlatform had some error (see Conditions) - PlatformPhaseError PlatformPhase = "Error" - // PlatformPhaseDuplicate when the SonataFlowPlatform is duplicated - PlatformPhaseDuplicate PlatformPhase = "Duplicate" -) +func (in *SonataFlowPlatformStatus) IsWarming() bool { + cond := in.GetTopLevelCondition() + return cond.IsFalse() && cond.Reason == PlatformWarmingReason +} -// PlatformConditionType defines the type of condition -type PlatformConditionType string - -// PlatformCondition describes the state of a resource at a certain point. -type PlatformCondition struct { - // TODO: the Type can't be Kubernetes or OpenShift, but the actual condition like "Ready". See the Conditions implementation in the workflow. - // TODO: also, we already have the `Cluster` field for that matter. - // TODO: see https://issues.redhat.com/browse/KOGITO-9218 - - // Type of platform condition (i.e. Kubernetes, OpenShift). - Type PlatformConditionType `json:"type"` - // Status of the condition, one of True, False, Unknown. - Status corev1.ConditionStatus `json:"status"` - // The last time this condition was updated. - LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"` - // Last time the condition transitioned from one status to another. - LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"` - // The reason for the condition's last transition. - Reason string `json:"reason,omitempty"` - // A human-readable message indicating details about the transition. - Message string `json:"message,omitempty"` +func (in *SonataFlowPlatformStatus) IsDuplicated() bool { + cond := in.GetTopLevelCondition() + return cond.IsFalse() && cond.Reason == PlatformDuplicatedReason } -// SonataFlowPlatformStatus defines the observed state of SonataFlowPlatform -type SonataFlowPlatformStatus struct { - // Cluster what kind of cluster you're running (ie, plain Kubernetes or OpenShift) - Cluster PlatformCluster `json:"cluster,omitempty"` - // ObservedGeneration is the most recent generation observed for this Platform. - ObservedGeneration int64 `json:"observedGeneration,omitempty"` - // Phase defines in what phase the Platform is found - Phase PlatformPhase `json:"phase,omitempty"` - // Conditions which are the conditions met (particularly useful when in ERROR phase) - Conditions []PlatformCondition `json:"conditions,omitempty"` - // Version the operator version controlling this Platform - Version string `json:"version,omitempty"` - // Info generic information related to the build - Info map[string]string `json:"info,omitempty"` +func (in *SonataFlowPlatformStatus) IsFailure() bool { + cond := in.GetTopLevelCondition() + return cond.IsFalse() && cond.Reason == PlatformFailureReason } // SonataFlowPlatform is the descriptor for the workflow platform infrastructure. @@ -206,8 +105,8 @@ type SonataFlowPlatformStatus struct { // +kubebuilder:subresource:status // +kubebuilder:resource:shortName={"sfp", "sfplatform", "sfplatforms"} // +kubebuilder:printcolumn:name="Cluster",type=string,JSONPath=`.status.cluster` -// +kubebuilder:printcolumn:name="Phase",type=string,JSONPath=`.status.phase` -// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.phase=='Ready'` +// +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.conditions[?(@.type=='Succeed')].status` +// +kubebuilder:printcolumn:name="Reason",type=string,JSONPath=`.status.conditions[?(@.type=='Succeed')].reason` type SonataFlowPlatform struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty"` diff --git a/api/v1alpha08/sonataflowplatform_types_support.go b/api/v1alpha08/sonataflowplatform_types_support.go index d89528637..c6adac741 100644 --- a/api/v1alpha08/sonataflowplatform_types_support.go +++ b/api/v1alpha08/sonataflowplatform_types_support.go @@ -15,7 +15,6 @@ package v1alpha08 import ( - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -28,137 +27,3 @@ func NewSonataFlowPlatformList() SonataFlowPlatformList { }, } } - -// NewSonataFlowPlatform returns the basic Platform definition -func NewSonataFlowPlatform(namespace string, name string) SonataFlowPlatform { - return SonataFlowPlatform{ - TypeMeta: metav1.TypeMeta{ - APIVersion: GroupVersion.String(), - Kind: SonataFlowPlatformKind, - }, - ObjectMeta: metav1.ObjectMeta{ - Namespace: namespace, - Name: name, - }, - } -} - -// GetCondition returns the condition with the provided type. -func (in *SonataFlowPlatformStatus) GetCondition(condType PlatformConditionType) *PlatformCondition { - for i := range in.Conditions { - c := in.Conditions[i] - if c.Type == condType { - return &c - } - } - return nil -} - -// SetErrorCondition sets the condition error for the given platform -func (in *SonataFlowPlatformStatus) SetErrorCondition(condType PlatformConditionType, reason string, err error) { - in.SetConditions(PlatformCondition{ - Type: condType, - Status: corev1.ConditionFalse, - LastUpdateTime: metav1.Now(), - LastTransitionTime: metav1.Now(), - Reason: reason, - Message: err.Error(), - }) -} - -// SetConditions updates the resource to include the provided conditions. -// -// If a condition that we are about to add already exists and has the same status and -// reason then we are not going to update. -func (in *SonataFlowPlatformStatus) SetConditions(conditions ...PlatformCondition) { - for _, condition := range conditions { - if condition.LastUpdateTime.IsZero() { - condition.LastUpdateTime = metav1.Now() - } - if condition.LastTransitionTime.IsZero() { - condition.LastTransitionTime = metav1.Now() - } - - currentCond := in.GetCondition(condition.Type) - - if currentCond != nil && currentCond.Status == condition.Status && currentCond.Reason == condition.Reason { - return - } - // Do not update lastTransitionTime if the status of the condition doesn't change. - if currentCond != nil && currentCond.Status == condition.Status { - condition.LastTransitionTime = currentCond.LastTransitionTime - } - - in.RemoveCondition(condition.Type) - in.Conditions = append(in.Conditions, condition) - } -} - -// RemoveCondition removes the resource condition with the provided type. -func (in *SonataFlowPlatformStatus) RemoveCondition(condType PlatformConditionType) { - newConditions := in.Conditions[:0] - for _, c := range in.Conditions { - if c.Type != condType { - newConditions = append(newConditions, c) - } - } - - in.Conditions = newConditions -} - -const ( - // ServiceTypeUser service user type label marker - ServiceTypeUser = "user" -) - -// +kubebuilder:object:generate=false -// ResourceCondition is a common type for all conditions -type ResourceCondition interface { - GetType() string - GetStatus() corev1.ConditionStatus - GetLastUpdateTime() metav1.Time - GetLastTransitionTime() metav1.Time - GetReason() string - GetMessage() string -} - -var _ ResourceCondition = PlatformCondition{} - -// GetConditions -- -func (in *SonataFlowPlatformStatus) GetConditions() []ResourceCondition { - res := make([]ResourceCondition, 0, len(in.Conditions)) - for _, c := range in.Conditions { - res = append(res, c) - } - return res -} - -// GetType -- -func (c PlatformCondition) GetType() string { - return string(c.Type) -} - -// GetStatus -- -func (c PlatformCondition) GetStatus() corev1.ConditionStatus { - return c.Status -} - -// GetLastUpdateTime -- -func (c PlatformCondition) GetLastUpdateTime() metav1.Time { - return c.LastUpdateTime -} - -// GetLastTransitionTime -- -func (c PlatformCondition) GetLastTransitionTime() metav1.Time { - return c.LastTransitionTime -} - -// GetReason -- -func (c PlatformCondition) GetReason() string { - return c.Reason -} - -// GetMessage -- -func (c PlatformCondition) GetMessage() string { - return c.Message -} diff --git a/api/v1alpha08/zz_generated.deepcopy.go b/api/v1alpha08/zz_generated.deepcopy.go index d44f21520..99985b0e2 100644 --- a/api/v1alpha08/zz_generated.deepcopy.go +++ b/api/v1alpha08/zz_generated.deepcopy.go @@ -27,7 +27,7 @@ import ( ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *BuildPlatformTemplate) DeepCopyInto(out *BuildPlatformTemplate) { +func (in *BuildPlatformConfig) DeepCopyInto(out *BuildPlatformConfig) { *out = *in if in.Timeout != nil { in, out := &in.Timeout, &out.Timeout @@ -44,12 +44,29 @@ func (in *BuildPlatformTemplate) DeepCopyInto(out *BuildPlatformTemplate) { out.Registry = in.Registry } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildPlatformTemplate. -func (in *BuildPlatformTemplate) DeepCopy() *BuildPlatformTemplate { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildPlatformConfig. +func (in *BuildPlatformConfig) DeepCopy() *BuildPlatformConfig { if in == nil { return nil } - out := new(BuildPlatformTemplate) + out := new(BuildPlatformConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *BuildPlatformSpec) DeepCopyInto(out *BuildPlatformSpec) { + *out = *in + in.Template.DeepCopyInto(&out.Template) + in.Config.DeepCopyInto(&out.Config) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BuildPlatformSpec. +func (in *BuildPlatformSpec) DeepCopy() *BuildPlatformSpec { + if in == nil { + return nil + } + out := new(BuildPlatformSpec) in.DeepCopyInto(out) return out } @@ -93,17 +110,16 @@ func (in *ConfigMapWorkflowResource) DeepCopy() *ConfigMapWorkflowResource { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) { +func (in *DevModePlatformSpec) DeepCopyInto(out *DevModePlatformSpec) { *out = *in - out.Value = in.Value } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigurationSpec. -func (in *ConfigurationSpec) DeepCopy() *ConfigurationSpec { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DevModePlatformSpec. +func (in *DevModePlatformSpec) DeepCopy() *DevModePlatformSpec { if in == nil { return nil } - out := new(ConfigurationSpec) + out := new(DevModePlatformSpec) in.DeepCopyInto(out) return out } @@ -200,23 +216,6 @@ func (in *Flow) DeepCopy() *Flow { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PlatformCondition) DeepCopyInto(out *PlatformCondition) { - *out = *in - in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) - in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlatformCondition. -func (in *PlatformCondition) DeepCopy() *PlatformCondition { - if in == nil { - return nil - } - out := new(PlatformCondition) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RegistrySpec) DeepCopyInto(out *RegistrySpec) { *out = *in @@ -444,9 +443,8 @@ func (in *SonataFlowPlatformList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SonataFlowPlatformSpec) DeepCopyInto(out *SonataFlowPlatformSpec) { *out = *in - in.BuildTemplate.DeepCopyInto(&out.BuildTemplate) - in.BuildPlatform.DeepCopyInto(&out.BuildPlatform) - out.Configuration = in.Configuration + in.Build.DeepCopyInto(&out.Build) + out.DevMode = in.DevMode } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowPlatformSpec. @@ -462,13 +460,7 @@ func (in *SonataFlowPlatformSpec) DeepCopy() *SonataFlowPlatformSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SonataFlowPlatformStatus) DeepCopyInto(out *SonataFlowPlatformStatus) { *out = *in - if in.Conditions != nil { - in, out := &in.Conditions, &out.Conditions - *out = make([]PlatformCondition, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } + in.Status.DeepCopyInto(&out.Status) if in.Info != nil { in, out := &in.Info, &out.Info *out = make(map[string]string, len(*in)) diff --git a/bundle/manifests/sonataflow-operator.clusterserviceversion.yaml b/bundle/manifests/sonataflow-operator.clusterserviceversion.yaml index c6660a26b..c86effaf0 100644 --- a/bundle/manifests/sonataflow-operator.clusterserviceversion.yaml +++ b/bundle/manifests/sonataflow-operator.clusterserviceversion.yaml @@ -83,10 +83,12 @@ metadata: "name": "sonataflow-platform" }, "spec": { - "platform": { - "registry": { - "address": "quay.io/kiegroup", - "secret": "regcred" + "build": { + "config": { + "registry": { + "address": "quay.io/kiegroup", + "secret": "regcred" + } } } } diff --git a/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml b/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml index a9ddbc7ae..5d417a84b 100644 --- a/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml +++ b/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml @@ -22,12 +22,12 @@ spec: - jsonPath: .status.cluster name: Cluster type: string - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.phase=='Ready' + - jsonPath: .status.conditions[?(@.type=='Succeed')].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=='Succeed')].reason + name: Reason + type: string name: v1alpha08 schema: openAPIV3Schema: @@ -50,172 +50,132 @@ spec: description: SonataFlowPlatformSpec defines the desired state of SonataFlowPlatform properties: build: - description: BuildTemplate specify how to build the Workflow. It's - used as a template for the SonataFlowBuild + description: Attributes for building workflows in the target platform properties: - arguments: - description: Arguments lists the command line arguments to send - to the builder - items: - type: string - type: array - resources: - description: Resources optional compute resource requirements - for the builder + config: + description: Describes the platform configuration for building + workflows. properties: - claims: - description: "Claims lists the names of resources, defined - in spec.resourceClaims, that are used by this container. - \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable. It can only be - set for containers." - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: Name must match the name of one entry in - pod.spec.resourceClaims of the Pod where this field - is used. It makes that resource available inside a - container. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - 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 - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + baseImage: + description: a base image that can be used as base layer for + all images. It can be useful if you want to provide some + custom base image with further utility software + type: string + registry: + description: Registry the registry where to publish the built + image + properties: + address: + description: the URI to access + type: string + ca: + description: the configmap which stores the Certificate + Authority + type: string + insecure: + description: if the container registry is insecure (ie, + http only) + type: boolean + organization: + description: the registry organization + type: string + secret: + description: the secret where credentials are stored + type: string type: object - requests: + strategy: + description: BuildStrategy to use to build workflows in the + platform. Usually, the operator elect the strategy based + on the platform. Note that this field might be read only + in certain scenarios. + type: string + strategyOptions: 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 - description: 'Requests describes the minimum amount of compute - resources required. If Requests is omitted for a container, - it defaults to Limits if that is explicitly specified, otherwise - to an implementation-defined value. Requests cannot exceed - Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: string + description: BuildStrategyOptions additional options to add + to the build strategy. See https://sonataflow.org/serverlessworkflow/main/cloud/operator/build-and-deploy-workflows.html type: object + timeout: + description: how much time to wait before time out the build + process + type: string type: object - timeout: - description: Timeout defines the Build maximum execution duration. - The Build deadline is set to the Build start time plus the Timeout - duration. If the Build deadline is exceeded, the Build context - is canceled, and its phase set to BuildPhaseFailed. - format: duration - type: string - type: object - configuration: - description: Configuration list of configuration properties to be - attached to all the Workflow built from this Platform - properties: - type: - description: 'Type represents the type of configuration, ie: property, - configmap, secret, ...' - type: string - value: - description: Value a reference to the object for this configuration - (syntax may vary depending on the `Type`) + template: + description: Describes a build template for building workflows. + Base for the internal SonataFlowBuild resource. properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: 'If referring to a piece of an object instead - of an entire object, this string should contain a valid - JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within - a pod, this would take on a value like: "spec.containers{name}" - (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" - (container with index 2 in this pod). This syntax is chosen - only to have some well-defined way of referencing a part - of an object. TODO: this design is not final and this field - is subject to change in the future.' - type: string - kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' - type: string - resourceVersion: - description: 'Specific resourceVersion to which this reference - is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' - type: string - uid: - description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + arguments: + description: Arguments lists the command line arguments to + send to the builder + items: + type: string + type: array + resources: + description: Resources optional compute resource requirements + for the builder + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. \n This field + is immutable. It can only be set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry + in pod.spec.resourceClaims of the Pod where this + field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + 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 + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + 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 + description: 'Requests describes the minimum amount of + compute resources required. If Requests is omitted for + a container, it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined value. + Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + timeout: + description: Timeout defines the Build maximum execution duration. + The Build deadline is set to the Build start time plus the + Timeout duration. If the Build deadline is exceeded, the + Build context is canceled, and its phase set to BuildPhaseFailed. + format: duration type: string type: object - x-kubernetes-map-type: atomic - required: - - type - - value type: object - devBaseImage: - description: DevBaseImage Base image to run the Workflow in dev mode - instead of the operator's default. Optional, used for the dev profile - only - type: string - platform: - description: BuildPlatform specify how is the platform where we want - to build the Workflow + devMode: + description: Attributes for running workflows in devmode (immutable, + no build required) properties: baseImage: - description: a base image that can be used as base layer for all - images. It can be useful if you want to provide some custom - base image with further utility software - type: string - buildStrategy: - description: BuildStrategy to use to build workflows in the platform. - Usually, the operator elect the strategy based on the platform. - Note that this field might be read only in certain scenarios. - type: string - buildStrategyOptions: - additionalProperties: - type: string - description: 'TODO: add a link to the documentation where the - user can find more info about this field BuildStrategyOptions - additional options to add to the build strategy.' - type: object - registry: - description: Registry the registry where to publish the built - image - properties: - address: - description: the URI to access - type: string - ca: - description: the configmap which stores the Certificate Authority - type: string - insecure: - description: if the container registry is insecure (ie, http - only) - type: boolean - organization: - description: the registry organization - type: string - secret: - description: the secret where credentials are stored - type: string - type: object - timeout: - description: how much time to wait before time out the build process + description: Base image to run the Workflow in dev mode instead + of the operator's default. type: string type: object type: object @@ -230,17 +190,12 @@ spec: - openshift type: string conditions: - description: Conditions which are the conditions met (particularly - useful when in ERROR phase) + description: The latest available observations of a resource's current + state. items: - description: PlatformCondition describes the state of a resource - at a certain point. + description: Condition describes the common structure for conditions + in our types properties: - lastTransitionTime: - description: Last time the condition transitioned from one status - to another. - format: date-time - type: string lastUpdateTime: description: The last time this condition was updated. format: date-time @@ -256,7 +211,7 @@ spec: description: Status of the condition, one of True, False, Unknown. type: string type: - description: Type of platform condition (i.e. Kubernetes, OpenShift). + description: Type condition for the given object type: string required: - status @@ -269,13 +224,9 @@ spec: description: Info generic information related to the build type: object observedGeneration: - description: ObservedGeneration is the most recent generation observed - for this Platform. + description: The generation observed by the deployment controller. format: int64 type: integer - phase: - description: Phase defines in what phase the Platform is found - type: string version: description: Version the operator version controlling this Platform type: string diff --git a/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml b/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml index 805fed80a..a13e8727f 100644 --- a/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml +++ b/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml @@ -23,12 +23,12 @@ spec: - jsonPath: .status.cluster name: Cluster type: string - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.phase=='Ready' + - jsonPath: .status.conditions[?(@.type=='Succeed')].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=='Succeed')].reason + name: Reason + type: string name: v1alpha08 schema: openAPIV3Schema: @@ -51,172 +51,132 @@ spec: description: SonataFlowPlatformSpec defines the desired state of SonataFlowPlatform properties: build: - description: BuildTemplate specify how to build the Workflow. It's - used as a template for the SonataFlowBuild + description: Attributes for building workflows in the target platform properties: - arguments: - description: Arguments lists the command line arguments to send - to the builder - items: - type: string - type: array - resources: - description: Resources optional compute resource requirements - for the builder + config: + description: Describes the platform configuration for building + workflows. properties: - claims: - description: "Claims lists the names of resources, defined - in spec.resourceClaims, that are used by this container. - \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable. It can only be - set for containers." - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: Name must match the name of one entry in - pod.spec.resourceClaims of the Pod where this field - is used. It makes that resource available inside a - container. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - 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 - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + baseImage: + description: a base image that can be used as base layer for + all images. It can be useful if you want to provide some + custom base image with further utility software + type: string + registry: + description: Registry the registry where to publish the built + image + properties: + address: + description: the URI to access + type: string + ca: + description: the configmap which stores the Certificate + Authority + type: string + insecure: + description: if the container registry is insecure (ie, + http only) + type: boolean + organization: + description: the registry organization + type: string + secret: + description: the secret where credentials are stored + type: string type: object - requests: + strategy: + description: BuildStrategy to use to build workflows in the + platform. Usually, the operator elect the strategy based + on the platform. Note that this field might be read only + in certain scenarios. + type: string + strategyOptions: 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 - description: 'Requests describes the minimum amount of compute - resources required. If Requests is omitted for a container, - it defaults to Limits if that is explicitly specified, otherwise - to an implementation-defined value. Requests cannot exceed - Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: string + description: BuildStrategyOptions additional options to add + to the build strategy. See https://sonataflow.org/serverlessworkflow/main/cloud/operator/build-and-deploy-workflows.html type: object + timeout: + description: how much time to wait before time out the build + process + type: string type: object - timeout: - description: Timeout defines the Build maximum execution duration. - The Build deadline is set to the Build start time plus the Timeout - duration. If the Build deadline is exceeded, the Build context - is canceled, and its phase set to BuildPhaseFailed. - format: duration - type: string - type: object - configuration: - description: Configuration list of configuration properties to be - attached to all the Workflow built from this Platform - properties: - type: - description: 'Type represents the type of configuration, ie: property, - configmap, secret, ...' - type: string - value: - description: Value a reference to the object for this configuration - (syntax may vary depending on the `Type`) + template: + description: Describes a build template for building workflows. + Base for the internal SonataFlowBuild resource. properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: 'If referring to a piece of an object instead - of an entire object, this string should contain a valid - JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within - a pod, this would take on a value like: "spec.containers{name}" - (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" - (container with index 2 in this pod). This syntax is chosen - only to have some well-defined way of referencing a part - of an object. TODO: this design is not final and this field - is subject to change in the future.' - type: string - kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' - type: string - resourceVersion: - description: 'Specific resourceVersion to which this reference - is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' - type: string - uid: - description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + arguments: + description: Arguments lists the command line arguments to + send to the builder + items: + type: string + type: array + resources: + description: Resources optional compute resource requirements + for the builder + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. \n This field + is immutable. It can only be set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry + in pod.spec.resourceClaims of the Pod where this + field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + 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 + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + 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 + description: 'Requests describes the minimum amount of + compute resources required. If Requests is omitted for + a container, it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined value. + Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + timeout: + description: Timeout defines the Build maximum execution duration. + The Build deadline is set to the Build start time plus the + Timeout duration. If the Build deadline is exceeded, the + Build context is canceled, and its phase set to BuildPhaseFailed. + format: duration type: string type: object - x-kubernetes-map-type: atomic - required: - - type - - value type: object - devBaseImage: - description: DevBaseImage Base image to run the Workflow in dev mode - instead of the operator's default. Optional, used for the dev profile - only - type: string - platform: - description: BuildPlatform specify how is the platform where we want - to build the Workflow + devMode: + description: Attributes for running workflows in devmode (immutable, + no build required) properties: baseImage: - description: a base image that can be used as base layer for all - images. It can be useful if you want to provide some custom - base image with further utility software - type: string - buildStrategy: - description: BuildStrategy to use to build workflows in the platform. - Usually, the operator elect the strategy based on the platform. - Note that this field might be read only in certain scenarios. - type: string - buildStrategyOptions: - additionalProperties: - type: string - description: 'TODO: add a link to the documentation where the - user can find more info about this field BuildStrategyOptions - additional options to add to the build strategy.' - type: object - registry: - description: Registry the registry where to publish the built - image - properties: - address: - description: the URI to access - type: string - ca: - description: the configmap which stores the Certificate Authority - type: string - insecure: - description: if the container registry is insecure (ie, http - only) - type: boolean - organization: - description: the registry organization - type: string - secret: - description: the secret where credentials are stored - type: string - type: object - timeout: - description: how much time to wait before time out the build process + description: Base image to run the Workflow in dev mode instead + of the operator's default. type: string type: object type: object @@ -231,17 +191,12 @@ spec: - openshift type: string conditions: - description: Conditions which are the conditions met (particularly - useful when in ERROR phase) + description: The latest available observations of a resource's current + state. items: - description: PlatformCondition describes the state of a resource - at a certain point. + description: Condition describes the common structure for conditions + in our types properties: - lastTransitionTime: - description: Last time the condition transitioned from one status - to another. - format: date-time - type: string lastUpdateTime: description: The last time this condition was updated. format: date-time @@ -257,7 +212,7 @@ spec: description: Status of the condition, one of True, False, Unknown. type: string type: - description: Type of platform condition (i.e. Kubernetes, OpenShift). + description: Type condition for the given object type: string required: - status @@ -270,13 +225,9 @@ spec: description: Info generic information related to the build type: object observedGeneration: - description: ObservedGeneration is the most recent generation observed - for this Platform. + description: The generation observed by the deployment controller. format: int64 type: integer - phase: - description: Phase defines in what phase the Platform is found - type: string version: description: Version the operator version controlling this Platform type: string diff --git a/config/samples/sonataflow.org_v1alpha08_sonataflowplatform.yaml b/config/samples/sonataflow.org_v1alpha08_sonataflowplatform.yaml index 7b6069e42..cc5b3cbb9 100644 --- a/config/samples/sonataflow.org_v1alpha08_sonataflowplatform.yaml +++ b/config/samples/sonataflow.org_v1alpha08_sonataflowplatform.yaml @@ -3,7 +3,8 @@ kind: SonataFlowPlatform metadata: name: sonataflow-platform spec: - platform: - registry: - address: quay.io/kiegroup - secret: regcred + build: + config: + registry: + address: quay.io/kiegroup + secret: regcred diff --git a/controllers/builder/config.go b/controllers/builder/config.go index 7fbafb9e8..65f59e91b 100644 --- a/controllers/builder/config.go +++ b/controllers/builder/config.go @@ -25,7 +25,6 @@ import ( "k8s.io/apimachinery/pkg/types" "sigs.k8s.io/controller-runtime/pkg/client" - operatorapi "github.com/kiegroup/kogito-serverless-operator/api/v1alpha08" "github.com/kiegroup/kogito-serverless-operator/container-builder/util/log" ) @@ -35,24 +34,8 @@ const ( ConfigMapName = "sonataflow-operator-builder-config" configKeyDefaultExtension = "DEFAULT_WORKFLOW_EXTENSION" configKeyDefaultBuilderResourceName = "DEFAULT_BUILDER_RESOURCE_NAME" - configKeyBuildNamespace = "build-namespace" - configKeyRegistrySecret = "registry-secret" - configKeyRegistryAddress = "registry-address" ) -func NewCustomConfig(platform operatorapi.SonataFlowPlatform) (map[string]string, error) { - customConfig := make(map[string]string) - if platform.Namespace == "" { - return nil, fmt.Errorf("unable to retrieve the namespace from platform %s", platform.Name) - } - customConfig[configKeyBuildNamespace] = platform.Namespace - // Registry Secret and Address are not required, the inner builder will use minikube inner registry if available - // TODO: we should review - customConfig[configKeyRegistrySecret] = platform.Spec.BuildPlatform.Registry.Secret - customConfig[configKeyRegistryAddress] = platform.Spec.BuildPlatform.Registry.Address - return customConfig, nil -} - // GetCommonConfigMap retrieves the config map with the builder common configuration information func GetCommonConfigMap(client client.Client, fallbackNS string) (*corev1.ConfigMap, error) { namespace, found := os.LookupEnv(envVarPodNamespaceName) diff --git a/controllers/builder/containerbuilder.go b/controllers/builder/containerbuilder.go index ef1fc7010..d3f8f8e2e 100644 --- a/controllers/builder/containerbuilder.go +++ b/controllers/builder/containerbuilder.go @@ -102,8 +102,8 @@ func (c *containerBuilderManager) getImageBuilderForKaniko(workflowID string, im ib.WithPodMiddleName(workflowID) ib.WithInsecureRegistry(false) ib.WithImageNameTag(imageNameTag) - ib.WithSecret(c.platform.Spec.BuildPlatform.Registry.Secret) - ib.WithRegistryAddress(c.platform.Spec.BuildPlatform.Registry.Address) + ib.WithSecret(c.platform.Spec.Build.Config.Registry.Secret) + ib.WithRegistryAddress(c.platform.Spec.Build.Config.Registry.Address) ib.WithCache(task.Cache) ib.WithResources(task.Resources) ib.WithAdditionalFlags(task.AdditionalFlags) diff --git a/controllers/builder/kogitoserverlessbuild_manager.go b/controllers/builder/kogitoserverlessbuild_manager.go index 5b15e5fb9..88eba14ca 100644 --- a/controllers/builder/kogitoserverlessbuild_manager.go +++ b/controllers/builder/kogitoserverlessbuild_manager.go @@ -49,7 +49,7 @@ func (k *sonataFlowBuildManager) GetOrCreateBuild(workflow *operatorapi.SonataFl if plat, err = platform.GetActivePlatform(k.ctx, k.client, workflow.Namespace); err != nil { return nil, err } - buildInstance.Spec.BuildTemplate = plat.Spec.BuildTemplate + buildInstance.Spec.BuildTemplate = plat.Spec.Build.Template if err = controllerutil.SetControllerReference(workflow, buildInstance, k.client.Scheme()); err != nil { return nil, err } diff --git a/controllers/platform/create.go b/controllers/platform/create.go index 9749834ff..e1afd9d3a 100644 --- a/controllers/platform/create.go +++ b/controllers/platform/create.go @@ -17,6 +17,7 @@ package platform import ( "context" + "github.com/kiegroup/kogito-serverless-operator/api" v08 "github.com/kiegroup/kogito-serverless-operator/api/v1alpha08" ) @@ -34,12 +35,12 @@ func (action *createAction) Name() string { } func (action *createAction) CanHandle(platform *v08.SonataFlowPlatform) bool { - return platform.Status.Phase == v08.PlatformPhaseCreating + return platform.Status.IsCreating() } func (action *createAction) Handle(ctx context.Context, platform *v08.SonataFlowPlatform) (*v08.SonataFlowPlatform, error) { //TODO: Perform the actions needed for the Platform creation - platform.Status.Phase = v08.PlatformPhaseReady + platform.Status.Manager().MarkTrue(api.SucceedConditionType) return platform, nil } diff --git a/controllers/platform/defaults.go b/controllers/platform/defaults.go index e9a69af4e..417997476 100644 --- a/controllers/platform/defaults.go +++ b/controllers/platform/defaults.go @@ -30,11 +30,11 @@ func ConfigureDefaults(ctx context.Context, c client.Client, p *operatorapi.Sona // update missing fields in the resource if p.Status.Cluster == "" || utils.IsOpenShift() { p.Status.Cluster = operatorapi.PlatformClusterOpenShift - p.Spec.BuildPlatform.BuildStrategy = operatorapi.PlatformBuildStrategy + p.Spec.Build.Config.BuildStrategy = operatorapi.PlatformBuildStrategy } if p.Status.Cluster == "" || !utils.IsOpenShift() { p.Status.Cluster = operatorapi.PlatformClusterKubernetes - p.Spec.BuildPlatform.BuildStrategy = operatorapi.OperatorBuildStrategy + p.Spec.Build.Config.BuildStrategy = operatorapi.OperatorBuildStrategy } err := SetPlatformDefaults(p, verbose) @@ -47,8 +47,8 @@ func ConfigureDefaults(ctx context.Context, c client.Client, p *operatorapi.Sona return err } - if verbose && p.Spec.BuildPlatform.Timeout.Duration != 0 { - log.Log.Infof("Maven Timeout set to %s", p.Spec.BuildPlatform.Timeout.Duration) + if verbose && p.Spec.Build.Config.Timeout.Duration != 0 { + log.Log.Infof("Maven Timeout set to %s", p.Spec.Build.Config.Timeout.Duration) } updatePlatform(ctx, c, p) diff --git a/controllers/platform/initialize.go b/controllers/platform/initialize.go index a4dc08f9c..0d24f7dc1 100644 --- a/controllers/platform/initialize.go +++ b/controllers/platform/initialize.go @@ -22,6 +22,8 @@ import ( "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "github.com/kiegroup/kogito-serverless-operator/api" + "github.com/kiegroup/kogito-serverless-operator/api/metadata" "github.com/kiegroup/kogito-serverless-operator/container-builder/client" @@ -48,7 +50,7 @@ func (action *initializeAction) Name() string { } func (action *initializeAction) CanHandle(platform *operatorapi.SonataFlowPlatform) bool { - return platform.Status.Phase == "" || platform.Status.Phase == operatorapi.PlatformPhaseDuplicate + return platform.Status.GetTopLevelCondition().IsUnknown() || platform.Status.IsDuplicated() } func (action *initializeAction) Handle(ctx context.Context, platform *operatorapi.SonataFlowPlatform) (*operatorapi.SonataFlowPlatform, error) { @@ -58,10 +60,9 @@ func (action *initializeAction) Handle(ctx context.Context, platform *operatorap } if duplicate { // another platform already present in the namespace - if platform.Status.Phase != operatorapi.PlatformPhaseDuplicate { + if !platform.Status.IsDuplicated() { plat := platform.DeepCopy() - plat.Status.Phase = operatorapi.PlatformPhaseDuplicate - + plat.Status.Manager().MarkFalse(api.SucceedConditionType, operatorapi.PlatformDuplicatedReason, "") return plat, nil } @@ -72,7 +73,7 @@ func (action *initializeAction) Handle(ctx context.Context, platform *operatorap return nil, err } // nolint: staticcheck - if platform.Spec.BuildPlatform.BuildStrategy == operatorapi.OperatorBuildStrategy { + if platform.Spec.Build.Config.BuildStrategy == operatorapi.OperatorBuildStrategy { //If KanikoCache is enabled if IsKanikoCacheEnabled(platform) { // Create the persistent volume claim used by the Kaniko cache @@ -87,13 +88,13 @@ func (action *initializeAction) Handle(ctx context.Context, platform *operatorap if err != nil { return nil, err } - platform.Status.Phase = operatorapi.PlatformPhaseWarming + platform.Status.Manager().MarkFalse(api.SucceedConditionType, operatorapi.PlatformWarmingReason, "") } else { // Skip the warmer pod creation - platform.Status.Phase = operatorapi.PlatformPhaseCreating + platform.Status.Manager().MarkFalse(api.SucceedConditionType, operatorapi.PlatformCreatingReason, "") } } else { - platform.Status.Phase = operatorapi.PlatformPhaseCreating + platform.Status.Manager().MarkFalse(api.SucceedConditionType, operatorapi.PlatformCreatingReason, "") } platform.Status.Version = metadata.SpecVersion @@ -109,7 +110,7 @@ func createPersistentVolumeClaim(ctx context.Context, client client.Client, plat } // nolint: staticcheck pvcName := defaultKanikoCachePVCName - if persistentVolumeClaim, found := platform.Spec.BuildPlatform.BuildStrategyOptions[kanikoPVCName]; found { + if persistentVolumeClaim, found := platform.Spec.Build.Config.BuildStrategyOptions[kanikoPVCName]; found { pvcName = persistentVolumeClaim } diff --git a/controllers/platform/kaniko_cache.go b/controllers/platform/kaniko_cache.go index 4c8a04c78..dd396860a 100644 --- a/controllers/platform/kaniko_cache.go +++ b/controllers/platform/kaniko_cache.go @@ -37,7 +37,7 @@ const kanikoBuildCacheEnabled = "KanikoBuildCacheEnabled" const kanikoDefaultWarmerImageName = "gcr.io/kaniko-project/warmer" func IsKanikoCacheEnabled(platform *v08.SonataFlowPlatform) bool { - return platform.Spec.BuildPlatform.IsOptionEnabled(kanikoBuildCacheEnabled) + return platform.Spec.Build.Config.IsStrategyOptionEnabled(kanikoBuildCacheEnabled) } func createKanikoCacheWarmerPod(ctx context.Context, client client.Client, platform *v08.SonataFlowPlatform) error { @@ -49,12 +49,12 @@ func createKanikoCacheWarmerPod(ctx context.Context, client client.Client, platf // - https://kubernetes.io/docs/concepts/storage/volumes/#local // nolint: staticcheck pvcName := defaultKanikoCachePVCName - if persistentVolumeClaim, found := platform.Spec.BuildPlatform.BuildStrategyOptions[kanikoPVCName]; found { + if persistentVolumeClaim, found := platform.Spec.Build.Config.BuildStrategyOptions[kanikoPVCName]; found { pvcName = persistentVolumeClaim } var warmerImage string - if image, found := platform.Spec.BuildPlatform.BuildStrategyOptions[kanikoWarmerImage]; found { + if image, found := platform.Spec.Build.Config.BuildStrategyOptions[kanikoWarmerImage]; found { warmerImage = image } else { warmerImage = fmt.Sprintf("%s:v%s", kanikoDefaultWarmerImageName, defaults.KanikoVersion) @@ -80,7 +80,7 @@ func createKanikoCacheWarmerPod(ctx context.Context, client client.Client, platf Args: []string{ "--force", "--cache-dir=" + kanikoCacheDir, - "--image=" + platform.Spec.BuildPlatform.BaseImage, + "--image=" + platform.Spec.Build.Config.BaseImage, }, VolumeMounts: []corev1.VolumeMount{ { diff --git a/controllers/platform/monitor.go b/controllers/platform/monitor.go index 4ac7ad6bb..cc7064be4 100644 --- a/controllers/platform/monitor.go +++ b/controllers/platform/monitor.go @@ -35,7 +35,7 @@ func (action *monitorAction) Name() string { } func (action *monitorAction) CanHandle(platform *operatorapi.SonataFlowPlatform) bool { - return platform.Status.Phase == operatorapi.PlatformPhaseReady + return platform.Status.IsReady() } func (action *monitorAction) Handle(ctx context.Context, platform *operatorapi.SonataFlowPlatform) (*operatorapi.SonataFlowPlatform, error) { diff --git a/controllers/platform/platform.go b/controllers/platform/platform.go index bde459773..32f84ee8a 100644 --- a/controllers/platform/platform.go +++ b/controllers/platform/platform.go @@ -172,7 +172,7 @@ func ListAllPlatforms(ctx context.Context, c ctrl.Reader, namespace string) (*op // IsActive determines if the given platform is being used. func IsActive(p *operatorapi.SonataFlowPlatform) bool { - return p.Status.Phase != "" && p.Status.Phase != operatorapi.PlatformPhaseDuplicate + return !p.Status.IsDuplicated() } // IsSecondary determines if the given platform is marked as secondary. diff --git a/controllers/platform/platformutils.go b/controllers/platform/platformutils.go index d230c8620..986a37346 100644 --- a/controllers/platform/platformutils.go +++ b/controllers/platform/platformutils.go @@ -42,64 +42,63 @@ var builderDockerfileFromRE = regexp.MustCompile(`FROM (.*) AS builder`) type ResourceCustomizer func(object ctrl.Object) ctrl.Object func ConfigureRegistry(ctx context.Context, c client.Client, p *operatorapi.SonataFlowPlatform, verbose bool) error { - //@TODO Add a notification on the status about this registry value ignored when https://issues.redhat.com/browse/KOGITO-9218 will be implemented - if p.Spec.BuildPlatform.BuildStrategy == operatorapi.PlatformBuildStrategy && p.Status.Cluster == operatorapi.PlatformClusterOpenShift { - p.Spec.BuildPlatform.Registry = operatorapi.RegistrySpec{} - log.Info("Platform registry not set and ignored on openshift cluster") + if p.Spec.Build.Config.BuildStrategy == operatorapi.PlatformBuildStrategy && p.Status.Cluster == operatorapi.PlatformClusterOpenShift { + p.Spec.Build.Config.Registry = operatorapi.RegistrySpec{} + log.Debug("Platform registry not set and ignored on openshift cluster") return nil } - if p.Spec.BuildPlatform.Registry.Address == "" && p.Status.Cluster == operatorapi.PlatformClusterKubernetes { + if p.Spec.Build.Config.Registry.Address == "" && p.Status.Cluster == operatorapi.PlatformClusterKubernetes { // try KEP-1755 address, err := GetRegistryAddress(ctx, c) if err != nil && verbose { log.Error(err, "Cannot find a registry where to push images via KEP-1755") } else if err == nil && address != nil { - p.Spec.BuildPlatform.Registry.Address = *address + p.Spec.Build.Config.Registry.Address = *address } } - log.Debugf("Final Registry Address: %s", p.Spec.BuildPlatform.Registry.Address) + log.Debugf("Final Registry Address: %s", p.Spec.Build.Config.Registry.Address) return nil } func SetPlatformDefaults(p *operatorapi.SonataFlowPlatform, verbose bool) error { - if p.Spec.BuildPlatform.BuildStrategyOptions == nil { + if p.Spec.Build.Config.BuildStrategyOptions == nil { log.Debugf("SonataFlow Platform [%s]: setting publish strategy options", p.Namespace) - p.Spec.BuildPlatform.BuildStrategyOptions = map[string]string{} + p.Spec.Build.Config.BuildStrategyOptions = map[string]string{} } - if p.Spec.BuildPlatform.GetTimeout().Duration != 0 { - d := p.Spec.BuildPlatform.GetTimeout().Duration.Truncate(time.Second) + if p.Spec.Build.Config.GetTimeout().Duration != 0 { + d := p.Spec.Build.Config.GetTimeout().Duration.Truncate(time.Second) - if verbose && p.Spec.BuildPlatform.Timeout.Duration != d { - log.Log.Infof("ContainerBuild timeout minimum unit is sec (configured: %s, truncated: %s)", p.Spec.BuildPlatform.GetTimeout().Duration, d) + if verbose && p.Spec.Build.Config.Timeout.Duration != d { + log.Log.Infof("ContainerBuild timeout minimum unit is sec (configured: %s, truncated: %s)", p.Spec.Build.Config.GetTimeout().Duration, d) } log.Debugf("SonataFlow Platform [%s]: setting build timeout", p.Namespace) - p.Spec.BuildPlatform.Timeout = &metav1.Duration{ + p.Spec.Build.Config.Timeout = &metav1.Duration{ Duration: d, } } else { log.Debugf("SonataFlow Platform [%s]: setting default build timeout to 5 minutes", p.Namespace) - p.Spec.BuildPlatform.Timeout = &metav1.Duration{ + p.Spec.Build.Config.Timeout = &metav1.Duration{ Duration: 5 * time.Minute, } } - if p.Spec.BuildPlatform.IsOptionEnabled(kanikoBuildCacheEnabled) { - p.Spec.BuildPlatform.BuildStrategyOptions[kanikoPVCName] = p.Name - if len(p.Spec.BuildPlatform.BaseImage) == 0 { - p.Spec.BuildPlatform.BaseImage = workflowdef.GetDefaultWorkflowBuilderImageTag() + if p.Spec.Build.Config.IsStrategyOptionEnabled(kanikoBuildCacheEnabled) { + p.Spec.Build.Config.BuildStrategyOptions[kanikoPVCName] = p.Name + if len(p.Spec.Build.Config.BaseImage) == 0 { + p.Spec.Build.Config.BaseImage = workflowdef.GetDefaultWorkflowBuilderImageTag() } } - if p.Spec.BuildPlatform.BuildStrategy == operatorapi.OperatorBuildStrategy && !p.Spec.BuildPlatform.IsOptionEnabled(kanikoBuildCacheEnabled) { + if p.Spec.Build.Config.BuildStrategy == operatorapi.OperatorBuildStrategy && !p.Spec.Build.Config.IsStrategyOptionEnabled(kanikoBuildCacheEnabled) { // Default to disabling Kaniko cache warmer // Using the cache warmer pod seems unreliable with the current Kaniko version // and requires relying on a persistent volume. defaultKanikoBuildCache := "false" - p.Spec.BuildPlatform.BuildStrategyOptions[kanikoBuildCacheEnabled] = defaultKanikoBuildCache + p.Spec.Build.Config.BuildStrategyOptions[kanikoBuildCacheEnabled] = defaultKanikoBuildCache if verbose { log.Log.Infof("Kaniko cache set to %s", defaultKanikoBuildCache) } @@ -108,8 +107,8 @@ func SetPlatformDefaults(p *operatorapi.SonataFlowPlatform, verbose bool) error setStatusAdditionalInfo(p) if verbose { - log.Log.Infof("BaseImage set to %s", p.Spec.BuildPlatform.BaseImage) - log.Log.Infof("Timeout set to %s", p.Spec.BuildPlatform.GetTimeout()) + log.Log.Infof("BaseImage set to %s", p.Spec.Build.Config.BaseImage) + log.Log.Infof("Timeout set to %s", p.Spec.Build.Config.GetTimeout()) } return nil } @@ -118,7 +117,7 @@ func setStatusAdditionalInfo(platform *operatorapi.SonataFlowPlatform) { platform.Status.Info = make(map[string]string) log.Debugf("SonataFlow Platform [%s]: setting build publish strategy", platform.Namespace) - if platform.Spec.BuildPlatform.BuildStrategy == operatorapi.OperatorBuildStrategy { + if platform.Spec.Build.Config.BuildStrategy == operatorapi.OperatorBuildStrategy { platform.Status.Info["kanikoVersion"] = defaults.KanikoVersion } log.Debugf("SonataFlow [%s]: setting status info", platform.Namespace) @@ -148,9 +147,9 @@ func GetRegistryAddress(ctx context.Context, c client.Client) (*string, error) { } func GetCustomizedDockerfile(dockerfile string, platform operatorapi.SonataFlowPlatform) string { - if platform.Spec.BuildPlatform.BaseImage != "" { + if platform.Spec.Build.Config.BaseImage != "" { res := builderDockerfileFromRE.FindAllStringSubmatch(dockerfile, 1) - dockerfile = strings.Replace(dockerfile, strings.Trim(res[0][1], " "), platform.Spec.BuildPlatform.BaseImage, 1) + dockerfile = strings.Replace(dockerfile, strings.Trim(res[0][1], " "), platform.Spec.Build.Config.BaseImage, 1) } return dockerfile } diff --git a/controllers/platform/platformutils_test.go b/controllers/platform/platformutils_test.go index 1bff3a2df..d0fcd851c 100644 --- a/controllers/platform/platformutils_test.go +++ b/controllers/platform/platformutils_test.go @@ -38,7 +38,7 @@ func TestSonataFlowBuildController(t *testing.T) { assert.True(t, foundDefault) // 2 - Let's try to override using the productized image - platform.Spec.BuildPlatform.BaseImage = "registry.access.redhat.com/openshift-serverless-1-tech-preview/logic-swf-builder-rhel8" + platform.Spec.Build.Config.BaseImage = "registry.access.redhat.com/openshift-serverless-1-tech-preview/logic-swf-builder-rhel8" resProductized := GetCustomizedDockerfile(dockerfile, *platform) foundProductized, err := regexp.MatchString("FROM registry.access.redhat.com/openshift-serverless-1-tech-preview/logic-swf-builder-rhel8 AS builder", resProductized) assert.NoError(t, err) diff --git a/controllers/platform/warm.go b/controllers/platform/warm.go index f7786502e..8489dcf69 100644 --- a/controllers/platform/warm.go +++ b/controllers/platform/warm.go @@ -23,6 +23,8 @@ import ( "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/kiegroup/kogito-serverless-operator/api" + operatorapi "github.com/kiegroup/kogito-serverless-operator/api/v1alpha08" ) @@ -42,7 +44,7 @@ func (action *warmAction) Name() string { } func (action *warmAction) CanHandle(platform *operatorapi.SonataFlowPlatform) bool { - return platform.Status.Phase == operatorapi.PlatformPhaseWarming + return platform.Status.IsWarming() } func (action *warmAction) Handle(ctx context.Context, platform *operatorapi.SonataFlowPlatform) (*operatorapi.SonataFlowPlatform, error) { @@ -65,8 +67,7 @@ func (action *warmAction) Handle(ctx context.Context, platform *operatorapi.Sona switch pod.Status.Phase { case corev1.PodSucceeded: - action.Logger.Info("Kaniko cache successfully warmed up") - platform.Status.Phase = operatorapi.PlatformPhaseCreating + platform.Status.Manager().MarkFalse(api.SucceedConditionType, operatorapi.PlatformWarmingReason, "Kaniko cache successfully warmed up") return platform, nil case corev1.PodFailed: return nil, errors.New("failed to warm up Kaniko cache") diff --git a/controllers/profiles/reconciler_dev.go b/controllers/profiles/reconciler_dev.go index d702fd523..6d29a1dd4 100644 --- a/controllers/profiles/reconciler_dev.go +++ b/controllers/profiles/reconciler_dev.go @@ -186,8 +186,8 @@ func (e *ensureRunningDevWorkflowReconciliationState) Do(ctx context.Context, wo devBaseContainerImage := workflowdef.GetDefaultWorkflowDevModeImageTag() pl, errPl := platform.GetActivePlatform(ctx, e.client, workflow.Namespace) // check if the Platform available - if errPl == nil && len(pl.Spec.DevBaseImage) > 0 { - devBaseContainerImage = pl.Spec.DevBaseImage + if errPl == nil && len(pl.Spec.DevMode.BaseImage) > 0 { + devBaseContainerImage = pl.Spec.DevMode.BaseImage } deployment, _, err := e.ensurers.deployment.ensure(ctx, workflow, diff --git a/controllers/profiles/reconciler_prod.go b/controllers/profiles/reconciler_prod.go index 80d0ab54e..a3639d109 100644 --- a/controllers/profiles/reconciler_prod.go +++ b/controllers/profiles/reconciler_prod.go @@ -215,8 +215,8 @@ func (h *deployWorkflowReconciliationState) Do(ctx context.Context, workflow *op // didn't change, business as usual image := workflowdef.GetWorkflowAppImageNameTag(workflow) - if len(pl.Spec.BuildPlatform.Registry.Address) > 0 { - image = pl.Spec.BuildPlatform.Registry.Address + "/" + image + if len(pl.Spec.Build.Config.Registry.Address) > 0 { + image = pl.Spec.Build.Config.Registry.Address + "/" + image } return h.handleObjects(ctx, workflow, image) } diff --git a/controllers/sonataflow_controller.go b/controllers/sonataflow_controller.go index edfc47298..6241ad542 100644 --- a/controllers/sonataflow_controller.go +++ b/controllers/sonataflow_controller.go @@ -96,7 +96,7 @@ func (r *SonataFlowReconciler) Reconcile(ctx context.Context, req ctrl.Request) func platformEnqueueRequestsFromMapFunc(c client.Client, p *operatorapi.SonataFlowPlatform) []reconcile.Request { var requests []reconcile.Request - if p.Status.Phase == operatorapi.PlatformPhaseReady { + if p.Status.IsReady() { list := &operatorapi.SonataFlowList{} // Do global search in case of global operator (it may be using a global platform) @@ -135,12 +135,12 @@ func (r *SonataFlowReconciler) SetupWithManager(mgr ctrl.Manager) error { Owns(&corev1.ConfigMap{}). Owns(&operatorapi.SonataFlowBuild{}). Watches(&operatorapi.SonataFlowPlatform{}, handler.EnqueueRequestsFromMapFunc(func(c context.Context, a client.Object) []reconcile.Request { - platform, ok := a.(*operatorapi.SonataFlowPlatform) + plat, ok := a.(*operatorapi.SonataFlowPlatform) if !ok { log.Error(fmt.Errorf("type assertion failed: %v", a), "Failed to retrieve workflow list") return []reconcile.Request{} } - return platformEnqueueRequestsFromMapFunc(mgr.GetClient(), platform) + return platformEnqueueRequestsFromMapFunc(mgr.GetClient(), plat) })). Complete(r) } diff --git a/controllers/sonataflowplatform_controller.go b/controllers/sonataflowplatform_controller.go index ff634bb45..8d8a6c1e3 100644 --- a/controllers/sonataflowplatform_controller.go +++ b/controllers/sonataflowplatform_controller.go @@ -27,6 +27,8 @@ import ( "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/reconcile" + "github.com/kiegroup/kogito-serverless-operator/api" + clientr "github.com/kiegroup/kogito-serverless-operator/container-builder/client" klog "github.com/kiegroup/kogito-serverless-operator/container-builder/util/log" @@ -90,6 +92,8 @@ func (r *SonataFlowPlatformReconciler) Reconcile(ctx context.Context, req reconc return reconcile.Result{}, err } + instance.Status.Manager().InitializeConditions() + // Only process resources assigned to the operator if !platform.IsOperatorHandlerConsideringLock(ctx, r.Reader, req.Namespace, &instance) { logger.Info("Ignoring request because resource is not assigned to current operator") @@ -102,8 +106,6 @@ func (r *SonataFlowPlatformReconciler) Reconcile(ctx context.Context, req reconc platform.NewMonitorAction(), } - var targetPhase operatorapi.PlatformPhase - var err error target := instance.DeepCopy() @@ -115,13 +117,15 @@ func (r *SonataFlowPlatformReconciler) Reconcile(ctx context.Context, req reconc a.InjectLogger(targetLog) if a.CanHandle(target) { - targetLog.Info("Invoking action", "Name", a.Name()) - - phaseFrom := target.Status.Phase + targetLog.Debug("Invoking action", "Name", a.Name()) target, err = a.Handle(ctx, target) if err != nil { - r.Recorder.Event(&instance, corev1.EventTypeNormal, "Updated", fmt.Sprintf("Updated platform phase to %s", instance.Status.Phase)) + target.Status.Manager().MarkFalse(api.SucceedConditionType, operatorapi.PlatformFailureReason, err.Error()) + if err := r.Client.Status().Patch(ctx, target, ctrl.MergeFrom(&instance)); err != nil { + return reconcile.Result{}, err + } + r.Recorder.Event(&instance, corev1.EventTypeWarning, "Failed", fmt.Sprintf("Failed to update SonataFlowPlaform: %s", err)) return reconcile.Result{}, err } @@ -129,34 +133,24 @@ func (r *SonataFlowPlatformReconciler) Reconcile(ctx context.Context, req reconc target.Status.ObservedGeneration = instance.Generation if err := r.Client.Status().Patch(ctx, target, ctrl.MergeFrom(&instance)); err != nil { - r.Recorder.Event(&instance, corev1.EventTypeNormal, "Status Updated", fmt.Sprintf("Updated platform phase to %s", instance.Status.Phase)) + r.Recorder.Event(&instance, corev1.EventTypeNormal, "Status Updated", fmt.Sprintf("Updated platform condition %s", instance.Status.GetTopLevelCondition())) return reconcile.Result{}, err } if err := r.Client.Update(ctx, target); err != nil { - r.Recorder.Event(&instance, corev1.EventTypeNormal, "Spec Updated", fmt.Sprintf("Updated platform phase to %s", instance.Status.Phase)) + r.Recorder.Event(&instance, corev1.EventTypeNormal, "Spec Updated", fmt.Sprintf("Updated platform condition to %s", instance.Status.GetTopLevelCondition())) return reconcile.Result{}, err } - - targetPhase = target.Status.Phase - - if targetPhase != phaseFrom { - logger.Info( - "state transition", - "phase-from", phaseFrom, - "phase-to", target.Status.Phase, - ) - } } // handle one action at time so the resource // is always at its latest state - r.Recorder.Event(&instance, corev1.EventTypeNormal, "Updated", fmt.Sprintf("Updated platform phase to %s", instance.Status.Phase)) + r.Recorder.Event(&instance, corev1.EventTypeNormal, "Updated", fmt.Sprintf("Updated platform condition to %s", instance.Status.GetTopLevelCondition())) break } } - if targetPhase == operatorapi.PlatformPhaseReady { + if target.Status.IsReady() { return reconcile.Result{}, nil } diff --git a/controllers/sonataflowplatform_controller_test.go b/controllers/sonataflowplatform_controller_test.go index af0c31666..8c2d6cdea 100644 --- a/controllers/sonataflowplatform_controller_test.go +++ b/controllers/sonataflowplatform_controller_test.go @@ -55,11 +55,11 @@ func TestSonataFlowPlatformController(t *testing.T) { assert.NoError(t, cl.Get(context.TODO(), types.NamespacedName{Name: ksp.Name, Namespace: ksp.Namespace}, ksp)) // Perform some checks on the created CR - assert.Equal(t, "quay.io/kiegroup", ksp.Spec.BuildPlatform.Registry.Address) - assert.Equal(t, "regcred", ksp.Spec.BuildPlatform.Registry.Secret) - assert.Equal(t, v1alpha08.OperatorBuildStrategy, ksp.Spec.BuildPlatform.BuildStrategy) + assert.Equal(t, "quay.io/kiegroup", ksp.Spec.Build.Config.Registry.Address) + assert.Equal(t, "regcred", ksp.Spec.Build.Config.Registry.Secret) + assert.Equal(t, v1alpha08.OperatorBuildStrategy, ksp.Spec.Build.Config.BuildStrategy) assert.Equal(t, v1alpha08.PlatformClusterKubernetes, ksp.Status.Cluster) - assert.Equal(t, v1alpha08.PlatformPhaseCreating, ksp.Status.Phase) + assert.Equal(t, v1alpha08.PlatformCreatingReason, ksp.Status.GetTopLevelCondition().Reason) }) } diff --git a/operator.yaml b/operator.yaml index 0f001ef53..9854f1b4e 100644 --- a/operator.yaml +++ b/operator.yaml @@ -165,12 +165,12 @@ spec: - jsonPath: .status.cluster name: Cluster type: string - - jsonPath: .status.phase - name: Phase - type: string - - jsonPath: .status.phase=='Ready' + - jsonPath: .status.conditions[?(@.type=='Succeed')].status name: Ready type: string + - jsonPath: .status.conditions[?(@.type=='Succeed')].reason + name: Reason + type: string name: v1alpha08 schema: openAPIV3Schema: @@ -193,172 +193,132 @@ spec: description: SonataFlowPlatformSpec defines the desired state of SonataFlowPlatform properties: build: - description: BuildTemplate specify how to build the Workflow. It's - used as a template for the SonataFlowBuild + description: Attributes for building workflows in the target platform properties: - arguments: - description: Arguments lists the command line arguments to send - to the builder - items: - type: string - type: array - resources: - description: Resources optional compute resource requirements - for the builder + config: + description: Describes the platform configuration for building + workflows. properties: - claims: - description: "Claims lists the names of resources, defined - in spec.resourceClaims, that are used by this container. - \n This is an alpha field and requires enabling the DynamicResourceAllocation - feature gate. \n This field is immutable. It can only be - set for containers." - items: - description: ResourceClaim references one entry in PodSpec.ResourceClaims. - properties: - name: - description: Name must match the name of one entry in - pod.spec.resourceClaims of the Pod where this field - is used. It makes that resource available inside a - container. - type: string - required: - - name - type: object - type: array - x-kubernetes-list-map-keys: - - name - x-kubernetes-list-type: map - 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 - description: 'Limits describes the maximum amount of compute - resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + baseImage: + description: a base image that can be used as base layer for + all images. It can be useful if you want to provide some + custom base image with further utility software + type: string + registry: + description: Registry the registry where to publish the built + image + properties: + address: + description: the URI to access + type: string + ca: + description: the configmap which stores the Certificate + Authority + type: string + insecure: + description: if the container registry is insecure (ie, + http only) + type: boolean + organization: + description: the registry organization + type: string + secret: + description: the secret where credentials are stored + type: string type: object - requests: + strategy: + description: BuildStrategy to use to build workflows in the + platform. Usually, the operator elect the strategy based + on the platform. Note that this field might be read only + in certain scenarios. + type: string + strategyOptions: 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 - description: 'Requests describes the minimum amount of compute - resources required. If Requests is omitted for a container, - it defaults to Limits if that is explicitly specified, otherwise - to an implementation-defined value. Requests cannot exceed - Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: string + description: BuildStrategyOptions additional options to add + to the build strategy. See https://sonataflow.org/serverlessworkflow/main/cloud/operator/build-and-deploy-workflows.html type: object + timeout: + description: how much time to wait before time out the build + process + type: string type: object - timeout: - description: Timeout defines the Build maximum execution duration. - The Build deadline is set to the Build start time plus the Timeout - duration. If the Build deadline is exceeded, the Build context - is canceled, and its phase set to BuildPhaseFailed. - format: duration - type: string - type: object - configuration: - description: Configuration list of configuration properties to be - attached to all the Workflow built from this Platform - properties: - type: - description: 'Type represents the type of configuration, ie: property, - configmap, secret, ...' - type: string - value: - description: Value a reference to the object for this configuration - (syntax may vary depending on the `Type`) + template: + description: Describes a build template for building workflows. + Base for the internal SonataFlowBuild resource. properties: - apiVersion: - description: API version of the referent. - type: string - fieldPath: - description: 'If referring to a piece of an object instead - of an entire object, this string should contain a valid - JSON/Go field access statement, such as desiredState.manifest.containers[2]. - For example, if the object reference is to a container within - a pod, this would take on a value like: "spec.containers{name}" - (where "name" refers to the name of the container that triggered - the event) or if no container name is specified "spec.containers[2]" - (container with index 2 in this pod). This syntax is chosen - only to have some well-defined way of referencing a part - of an object. TODO: this design is not final and this field - is subject to change in the future.' - type: string - kind: - description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - name: - description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' - type: string - namespace: - description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/' - type: string - resourceVersion: - description: 'Specific resourceVersion to which this reference - is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency' - type: string - uid: - description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids' + arguments: + description: Arguments lists the command line arguments to + send to the builder + items: + type: string + type: array + resources: + description: Resources optional compute resource requirements + for the builder + properties: + claims: + description: "Claims lists the names of resources, defined + in spec.resourceClaims, that are used by this container. + \n This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. \n This field + is immutable. It can only be set for containers." + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name of one entry + in pod.spec.resourceClaims of the Pod where this + field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + 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 + description: 'Limits describes the maximum amount of compute + resources allowed. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + 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 + description: 'Requests describes the minimum amount of + compute resources required. If Requests is omitted for + a container, it defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined value. + Requests cannot exceed Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + timeout: + description: Timeout defines the Build maximum execution duration. + The Build deadline is set to the Build start time plus the + Timeout duration. If the Build deadline is exceeded, the + Build context is canceled, and its phase set to BuildPhaseFailed. + format: duration type: string type: object - x-kubernetes-map-type: atomic - required: - - type - - value type: object - devBaseImage: - description: DevBaseImage Base image to run the Workflow in dev mode - instead of the operator's default. Optional, used for the dev profile - only - type: string - platform: - description: BuildPlatform specify how is the platform where we want - to build the Workflow + devMode: + description: Attributes for running workflows in devmode (immutable, + no build required) properties: baseImage: - description: a base image that can be used as base layer for all - images. It can be useful if you want to provide some custom - base image with further utility software - type: string - buildStrategy: - description: BuildStrategy to use to build workflows in the platform. - Usually, the operator elect the strategy based on the platform. - Note that this field might be read only in certain scenarios. - type: string - buildStrategyOptions: - additionalProperties: - type: string - description: 'TODO: add a link to the documentation where the - user can find more info about this field BuildStrategyOptions - additional options to add to the build strategy.' - type: object - registry: - description: Registry the registry where to publish the built - image - properties: - address: - description: the URI to access - type: string - ca: - description: the configmap which stores the Certificate Authority - type: string - insecure: - description: if the container registry is insecure (ie, http - only) - type: boolean - organization: - description: the registry organization - type: string - secret: - description: the secret where credentials are stored - type: string - type: object - timeout: - description: how much time to wait before time out the build process + description: Base image to run the Workflow in dev mode instead + of the operator's default. type: string type: object type: object @@ -373,17 +333,12 @@ spec: - openshift type: string conditions: - description: Conditions which are the conditions met (particularly - useful when in ERROR phase) + description: The latest available observations of a resource's current + state. items: - description: PlatformCondition describes the state of a resource - at a certain point. + description: Condition describes the common structure for conditions + in our types properties: - lastTransitionTime: - description: Last time the condition transitioned from one status - to another. - format: date-time - type: string lastUpdateTime: description: The last time this condition was updated. format: date-time @@ -399,7 +354,7 @@ spec: description: Status of the condition, one of True, False, Unknown. type: string type: - description: Type of platform condition (i.e. Kubernetes, OpenShift). + description: Type condition for the given object type: string required: - status @@ -412,13 +367,9 @@ spec: description: Info generic information related to the build type: object observedGeneration: - description: ObservedGeneration is the most recent generation observed - for this Platform. + description: The generation observed by the deployment controller. format: int64 type: integer - phase: - description: Phase defines in what phase the Platform is found - type: string version: description: Version the operator version controlling this Platform type: string diff --git a/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform_openshift.yaml b/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform_openshift.yaml index af37fe431..74a371704 100644 --- a/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform_openshift.yaml +++ b/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform_openshift.yaml @@ -17,5 +17,6 @@ kind: SonataFlowPlatform metadata: name: sonataflow-platform spec: - platform: - buildStrategy: platform \ No newline at end of file + build: + config: + strategy: platform \ No newline at end of file diff --git a/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform_withCache_minikube.yaml b/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform_withCache_minikube.yaml index 15149e2ba..f1226091a 100644 --- a/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform_withCache_minikube.yaml +++ b/test/testdata/sonataflow.org_v1alpha08_sonataflowplatform_withCache_minikube.yaml @@ -17,7 +17,8 @@ kind: SonataFlowPlatform metadata: name: sonataflow-platform spec: - platform: - baseImage: quay.io/kiegroup/kogito-swf-builder-nightly:latest - buildStrategyOptions: - KanikoBuildCacheEnabled: "true" + build: + config: + baseImage: quay.io/kiegroup/kogito-swf-builder-nightly:latest + strategyOptions: + KanikoBuildCacheEnabled: "true" diff --git a/test/yaml.go b/test/yaml.go index 044fea116..1c54cbb25 100644 --- a/test/yaml.go +++ b/test/yaml.go @@ -22,6 +22,8 @@ import ( "github.com/davecgh/go-spew/spew" + "github.com/kiegroup/kogito-serverless-operator/api" + corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/yaml" @@ -83,12 +85,13 @@ func GetSonataFlowPlatform(path string) *operatorapi.SonataFlowPlatform { panic(err) } log.Debugf("Successfully read KSP #%v ", ksp) + ksp.Status.Manager().InitializeConditions() return ksp } func GetSonataFlowPlatformInReadyPhase(path string, namespace string) *operatorapi.SonataFlowPlatform { ksp := GetSonataFlowPlatform(path) - ksp.Status.Phase = operatorapi.PlatformPhaseReady + ksp.Status.Manager().MarkTrue(api.SucceedConditionType) ksp.Namespace = namespace return ksp } @@ -179,16 +182,16 @@ func GetBasePlatformInReadyPhase(namespace string) *operatorapi.SonataFlowPlatfo func GetBasePlatformWithBaseImageInReadyPhase(namespace string) *operatorapi.SonataFlowPlatform { platform := GetBasePlatform() platform.Namespace = namespace - platform.Status.Phase = operatorapi.PlatformPhaseReady - platform.Spec.BuildPlatform.BaseImage = "quay.io/customx/custom-swf-builder:24.8.17" + platform.Status.Manager().MarkTrue(api.SucceedConditionType) + platform.Spec.Build.Config.BaseImage = "quay.io/customx/custom-swf-builder:24.8.17" return platform } func GetBasePlatformWithDevBaseImageInReadyPhase(namespace string) *operatorapi.SonataFlowPlatform { platform := GetBasePlatform() platform.Namespace = namespace - platform.Status.Phase = operatorapi.PlatformPhaseReady - platform.Spec.DevBaseImage = "quay.io/customgroup/custom-swf-builder-nightly:42.43.7" + platform.Status.Manager().MarkTrue(api.SucceedConditionType) + platform.Spec.DevMode.BaseImage = "quay.io/customgroup/custom-swf-builder-nightly:42.43.7" return platform } @@ -197,7 +200,9 @@ func GetBasePlatform() *operatorapi.SonataFlowPlatform { if ok { return GetSonataFlowPlatform(GetPathForSamples(file) + sonataFlowPlatformYamlCR) } else { - return &operatorapi.SonataFlowPlatform{} + ksp := &operatorapi.SonataFlowPlatform{} + ksp.Status.Manager().InitializeConditions() + return ksp } }