diff --git a/api/v1alpha08/sonataflow_persistence_types.go b/api/v1alpha08/sonataflow_persistence_types.go index 53a5b15e5..fda28888c 100644 --- a/api/v1alpha08/sonataflow_persistence_types.go +++ b/api/v1alpha08/sonataflow_persistence_types.go @@ -14,6 +14,14 @@ package v1alpha08 +type DBMigrationStrategyType string + +const ( + DBMigrationStrategyService DBMigrationStrategyType = "service" + DBMigrationStrategyJob DBMigrationStrategyType = "job" + DBMigrationStrategyNone DBMigrationStrategyType = "none" +) + // PlatformPersistenceOptionsSpec configures the DataBase in the platform spec. This specification can // be used by workflows and platform services when they don't provide one of their own. // +optional @@ -51,10 +59,13 @@ type PersistenceOptionsSpec struct { // +optional PostgreSQL *PersistencePostgreSQL `json:"postgresql,omitempty"` - // Whether to migrate database on service startup? + // DB Migration approach for service? + // job: use job based approach + // service: service itself shall migrate the db + // none: no db migration needed // +optional - // +default: false - MigrateDBOnStartUp bool `json:"migrateDBOnStartUp"` + // +kubebuilder:default:=service + DBMigrationStrategy string `json:"dbMigrationStrategy,omitempty"` } // PersistencePostgreSQL configure postgresql connection for service(s). diff --git a/api/v1alpha08/sonataflowplatform_types.go b/api/v1alpha08/sonataflowplatform_types.go index e1a009e75..91f23d14f 100644 --- a/api/v1alpha08/sonataflowplatform_types.go +++ b/api/v1alpha08/sonataflowplatform_types.go @@ -92,6 +92,31 @@ const ( PlatformDuplicatedReason = "Duplicated" ) +type DBMigrationStatus string + +const ( + DBMigrationStatusStarted DBMigrationStatus = "Started" + DBMigrationStatusInProgress DBMigrationStatus = "In-Progress" + DBMigrationStatusSucceeded DBMigrationStatus = "Succeeded" + DBMigrationStatusFailed DBMigrationStatus = "Failed" + + MessageDBMigrationStatusStarted string = "Started the database migrations for the services" + MessageDBMigrationStatusInProgress string = "The database migrations for the services are in-progress" + MessageDBMigrationStatusSucceeded string = "The database migrations for the services are successful" + MessageDBMigrationStatusFailed string = "The database migrations for the services have failed" + + ReasonDBMigrationStatusStarted string = "Started by SonataFlow operator" + ReasonDBMigrationStatusInProgress string = "The database migration job is in-progress" + ReasonDBMigrationStatusSucceeded string = "The database migration job completed as expected" + ReasonDBMigrationStatusFailed string = "The database may be unreachable, invalid credentials supplied or flyway migration failed. Please check logs for further details." +) + +type SonataFlowPlatformDBMigrationPhase struct { + Status DBMigrationStatus `json:"dbMigrationStatus,omitempty"` + Message string `json:"message,omitempty"` + Reason string `json:"reason,omitempty"` +} + // SonataFlowPlatformStatus defines the observed state of SonataFlowPlatform // +k8s:openapi-gen=true type SonataFlowPlatformStatus struct { @@ -111,6 +136,8 @@ type SonataFlowPlatformStatus struct { // Triggers list of triggers created for the SonataFlowPlatform //+operator-sdk:csv:customresourcedefinitions:type=status,displayName="triggers" Triggers []SonataFlowPlatformTriggerRef `json:"triggers,omitempty"` + //+operator-sdk:csv:customresourcedefinitions:type=status,displayName="dbMigrationStatus" + SonataFlowPlatformDBMigrationPhase *SonataFlowPlatformDBMigrationPhase `json:"sonataFlowPlatformDBMigrationPhase,omitempty"` } // SonataFlowPlatformTriggerRef defines a trigger created for the SonataFlowPlatform. diff --git a/api/v1alpha08/zz_generated.deepcopy.go b/api/v1alpha08/zz_generated.deepcopy.go index b5a16a466..925067cc3 100644 --- a/api/v1alpha08/zz_generated.deepcopy.go +++ b/api/v1alpha08/zz_generated.deepcopy.go @@ -1217,6 +1217,21 @@ func (in *SonataFlowPlatform) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SonataFlowPlatformDBMigrationPhase) DeepCopyInto(out *SonataFlowPlatformDBMigrationPhase) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowPlatformDBMigrationPhase. +func (in *SonataFlowPlatformDBMigrationPhase) DeepCopy() *SonataFlowPlatformDBMigrationPhase { + if in == nil { + return nil + } + out := new(SonataFlowPlatformDBMigrationPhase) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SonataFlowPlatformList) DeepCopyInto(out *SonataFlowPlatformList) { *out = *in @@ -1322,6 +1337,11 @@ func (in *SonataFlowPlatformStatus) DeepCopyInto(out *SonataFlowPlatformStatus) *out = make([]SonataFlowPlatformTriggerRef, len(*in)) copy(*out, *in) } + if in.SonataFlowPlatformDBMigrationPhase != nil { + in, out := &in.SonataFlowPlatformDBMigrationPhase, &out.SonataFlowPlatformDBMigrationPhase + *out = new(SonataFlowPlatformDBMigrationPhase) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SonataFlowPlatformStatus. diff --git a/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml b/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml index 6f83ab0ae..b4542fb30 100644 --- a/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml +++ b/bundle/manifests/sonataflow.org_sonataflowplatforms.yaml @@ -665,9 +665,14 @@ spec: by default. maxProperties: 2 properties: - migrateDBOnStartUp: - description: Whether to migrate database on service startup? - type: boolean + dbMigrationStrategy: + default: service + description: |- + DB Migration approach for service? + job: use job based approach + service: service itself shall migrate the db + none: no db migration needed + type: string postgresql: description: Connect configured services to a postgresql database. @@ -8709,9 +8714,14 @@ spec: by default. maxProperties: 2 properties: - migrateDBOnStartUp: - description: Whether to migrate database on service startup? - type: boolean + dbMigrationStrategy: + default: service + description: |- + DB Migration approach for service? + job: use job based approach + service: service itself shall migrate the db + none: no db migration needed + type: string postgresql: description: Connect configured services to a postgresql database. @@ -16886,6 +16896,15 @@ spec: description: The generation observed by the deployment controller. format: int64 type: integer + sonataFlowPlatformDBMigrationPhase: + properties: + dbMigrationStatus: + type: string + message: + type: string + reason: + type: string + type: object triggers: description: Triggers list of triggers created for the SonataFlowPlatform items: diff --git a/bundle/manifests/sonataflow.org_sonataflows.yaml b/bundle/manifests/sonataflow.org_sonataflows.yaml index b98be2399..afa82c7af 100644 --- a/bundle/manifests/sonataflow.org_sonataflows.yaml +++ b/bundle/manifests/sonataflow.org_sonataflows.yaml @@ -1997,9 +1997,14 @@ spec: for the workflow maxProperties: 2 properties: - migrateDBOnStartUp: - description: Whether to migrate database on service startup? - type: boolean + dbMigrationStrategy: + default: service + description: |- + DB Migration approach for service? + job: use job based approach + service: service itself shall migrate the db + none: no db migration needed + type: string postgresql: description: Connect configured services to a postgresql database. maxProperties: 2 diff --git a/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml b/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml index 762533cb7..69f5651f4 100644 --- a/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml +++ b/config/crd/bases/sonataflow.org_sonataflowplatforms.yaml @@ -665,9 +665,14 @@ spec: by default. maxProperties: 2 properties: - migrateDBOnStartUp: - description: Whether to migrate database on service startup? - type: boolean + dbMigrationStrategy: + default: service + description: |- + DB Migration approach for service? + job: use job based approach + service: service itself shall migrate the db + none: no db migration needed + type: string postgresql: description: Connect configured services to a postgresql database. @@ -8709,9 +8714,14 @@ spec: by default. maxProperties: 2 properties: - migrateDBOnStartUp: - description: Whether to migrate database on service startup? - type: boolean + dbMigrationStrategy: + default: service + description: |- + DB Migration approach for service? + job: use job based approach + service: service itself shall migrate the db + none: no db migration needed + type: string postgresql: description: Connect configured services to a postgresql database. @@ -16886,6 +16896,15 @@ spec: description: The generation observed by the deployment controller. format: int64 type: integer + sonataFlowPlatformDBMigrationPhase: + properties: + dbMigrationStatus: + type: string + message: + type: string + reason: + type: string + type: object triggers: description: Triggers list of triggers created for the SonataFlowPlatform items: diff --git a/config/crd/bases/sonataflow.org_sonataflows.yaml b/config/crd/bases/sonataflow.org_sonataflows.yaml index 6acf20104..2112b8586 100644 --- a/config/crd/bases/sonataflow.org_sonataflows.yaml +++ b/config/crd/bases/sonataflow.org_sonataflows.yaml @@ -1997,9 +1997,14 @@ spec: for the workflow maxProperties: 2 properties: - migrateDBOnStartUp: - description: Whether to migrate database on service startup? - type: boolean + dbMigrationStrategy: + default: service + description: |- + DB Migration approach for service? + job: use job based approach + service: service itself shall migrate the db + none: no db migration needed + type: string postgresql: description: Connect configured services to a postgresql database. maxProperties: 2 diff --git a/config/manifests/bases/sonataflow-operator.clusterserviceversion.yaml b/config/manifests/bases/sonataflow-operator.clusterserviceversion.yaml index 71a0e9411..4c88d685c 100644 --- a/config/manifests/bases/sonataflow-operator.clusterserviceversion.yaml +++ b/config/manifests/bases/sonataflow-operator.clusterserviceversion.yaml @@ -164,6 +164,8 @@ spec: - description: Info generic information related to the Platform displayName: info path: info + - displayName: dbMigrationStatus + path: sonataFlowPlatformDBMigrationPhase - description: Triggers list of triggers created for the SonataFlowPlatform displayName: triggers path: triggers diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 66e33fa72..167f61955 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -4,6 +4,18 @@ kind: ClusterRole metadata: name: manager-role rules: +- apiGroups: + - batch + resources: + - jobs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - sonataflow.org resources: diff --git a/images/tools/sonataflow-db-migrator/build-container-image.sh b/images/tools/sonataflow-db-migrator/build-container-image.sh index 53a2fbdd9..64c4cf45a 100755 --- a/images/tools/sonataflow-db-migrator/build-container-image.sh +++ b/images/tools/sonataflow-db-migrator/build-container-image.sh @@ -33,7 +33,7 @@ cleanup () { # Script variables with default values. These values will be updated by hack/bump-version.sh, don't change it. OPERATOR_VERSION=999.0.0 # comes from version.go DDL_VERSION=10.0.999-SNAPSHOT -DDL_FILE=kogito-ddl-10.0.999-20240806.011718-23-db-scripts.zip +DDL_FILE=kogito-ddl-10.0.999-20241002.021447-65-db-scripts.zip DDL_BASE_URL=https://repository.apache.org/content/groups/snapshots/org/kie/kogito/kogito-ddl CEKIT_BUILDER=podman diff --git a/internal/controller/platform/dbMigratorJob.go b/internal/controller/platform/dbMigratorJob.go new file mode 100644 index 000000000..d6ddafb9b --- /dev/null +++ b/internal/controller/platform/dbMigratorJob.go @@ -0,0 +1,278 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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 platform + +import ( + "context" + "errors" + "strconv" + "strings" + + operatorapi "github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08" + "github.com/apache/incubator-kie-kogito-serverless-operator/container-builder/client" + "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/platform/services" + "github.com/apache/incubator-kie-kogito-serverless-operator/log" + batchv1 "k8s.io/api/batch/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog/v2" + "k8s.io/utils/pointer" +) + +type QuarkusDataSource struct { + JdbcUrl string + Username string + Password string + Schema string +} + +type DBMigratorJob struct { + MigrateDBDataIndex bool + DataIndexDataSource *QuarkusDataSource + MigrateDBJobsService bool + JobsServiceDataSource *QuarkusDataSource +} + +const ( + dbMigrationJobName = "sonataflow-db-migrator-job" + dbMigrationContainerName = "db-migration-container" + dbMigratorToolImage = "quay.io/rhkp/incubator-kie-kogito-service-db-migration-postgresql:latest" + dbMigrationCmd = "./migration.sh" +) + +type DBMigrationJobCfg struct { + JobName string + ContainerName string + ToolImageName string + MigrationCmd string +} + +func getDBSchemaName(persistencePostgreSQL *operatorapi.PersistencePostgreSQL, defaultSchemaName string) string { + jdbcURL := persistencePostgreSQL.JdbcUrl + + if len(jdbcURL) == 0 { + if persistencePostgreSQL.ServiceRef != nil && len(persistencePostgreSQL.ServiceRef.DatabaseSchema) > 0 { + return persistencePostgreSQL.ServiceRef.DatabaseSchema + } + } else { + _, a, found := strings.Cut(jdbcURL, "currentSchema=") + + if found { + if strings.Contains(a, "&") { + b, _, found := strings.Cut(a, "&") + if found { + return b + } + } else { + return a + } + } + } + return defaultSchemaName +} + +func getNewQuarkusDataSource(jdbcURL string, userName string, password string, schema string) *QuarkusDataSource { + return &QuarkusDataSource{ + JdbcUrl: jdbcURL, + Username: userName, + Password: password, + Schema: schema, + } +} + +func getQuarkusDataSourceFromPersistence(ctx context.Context, platform *operatorapi.SonataFlowPlatform, persistence *operatorapi.PersistenceOptionsSpec, defaultSchemaName string) *QuarkusDataSource { + quarkusDataSource := getNewQuarkusDataSource("", "", "", "") + if persistence != nil && persistence.PostgreSQL != nil { + quarkusDataSource.JdbcUrl = persistence.PostgreSQL.JdbcUrl + quarkusDataSource.Username, _ = services.GetSecretKeyValueString(ctx, persistence.PostgreSQL.SecretRef.Name, persistence.PostgreSQL.SecretRef.UserKey, platform.Namespace) + quarkusDataSource.Password, _ = services.GetSecretKeyValueString(ctx, persistence.PostgreSQL.SecretRef.Name, persistence.PostgreSQL.SecretRef.PasswordKey, platform.Namespace) + quarkusDataSource.Schema = getDBSchemaName(persistence.PostgreSQL, defaultSchemaName) + } + return quarkusDataSource +} + +func NewDBMigratorJobData(ctx context.Context, client client.Client, platform *operatorapi.SonataFlowPlatform, pshDI services.PlatformServiceHandler, pshJS services.PlatformServiceHandler) *DBMigratorJob { + + diJobsBasedDBMigration := false + jsJobsBasedDBMigration := false + + if pshDI.IsPersistenceEnabledtInSpec() { + diJobsBasedDBMigration = services.IsJobsBasedDBMigration(platform.Spec.Services.DataIndex.Persistence) + } + if pshJS.IsPersistenceEnabledtInSpec() { + jsJobsBasedDBMigration = services.IsJobsBasedDBMigration(platform.Spec.Services.JobService.Persistence) + } + + if (pshDI.IsServiceSetInSpec() && diJobsBasedDBMigration) || (pshJS.IsServiceSetInSpec() && jsJobsBasedDBMigration) { + quarkusDataSourceDataIndex := getNewQuarkusDataSource("", "", "", "") + quarkusDataSourceJobService := getNewQuarkusDataSource("", "", "", "") + + if diJobsBasedDBMigration { + quarkusDataSourceDataIndex = getQuarkusDataSourceFromPersistence(ctx, platform, platform.Spec.Services.DataIndex.Persistence, "defaultDi") + } + + if jsJobsBasedDBMigration { + quarkusDataSourceJobService = getQuarkusDataSourceFromPersistence(ctx, platform, platform.Spec.Services.JobService.Persistence, "defaultJs") + } + + return &DBMigratorJob{ + MigrateDBDataIndex: diJobsBasedDBMigration, + DataIndexDataSource: quarkusDataSourceDataIndex, + MigrateDBJobsService: jsJobsBasedDBMigration, + JobsServiceDataSource: quarkusDataSourceJobService, + } + } + return nil +} + +func (dbmj DBMigratorJob) CreateJobDBMigration(platform *operatorapi.SonataFlowPlatform) *batchv1.Job { + dbMigrationJobCfg := getDBMigrationJobCfg() + job := &batchv1.Job{ + ObjectMeta: metav1.ObjectMeta{ + Name: dbMigrationJobCfg.JobName, + Namespace: platform.Namespace, + }, + Spec: batchv1.JobSpec{ + Template: corev1.PodTemplateSpec{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: dbMigrationJobCfg.ContainerName, + Image: dbMigrationJobCfg.ToolImageName, + Env: []corev1.EnvVar{ + { + Name: "MIGRATE_DB_DATAINDEX", + Value: strconv.FormatBool(dbmj.MigrateDBDataIndex), + }, + { + Name: "QUARKUS_DATASOURCE_DATAINDEX_JDBC_URL", + Value: dbmj.DataIndexDataSource.JdbcUrl, + }, + { + Name: "QUARKUS_DATASOURCE_DATAINDEX_USERNAME", + Value: dbmj.DataIndexDataSource.Username, + }, + { + Name: "QUARKUS_DATASOURCE_DATAINDEX_PASSWORD", + Value: dbmj.DataIndexDataSource.Password, + }, + { + Name: "QUARKUS_FLYWAY_DATAINDEX_SCHEMAS", + Value: dbmj.DataIndexDataSource.Schema, + }, + { + Name: "MIGRATE_DB_JOBSSERVICE", + Value: strconv.FormatBool(dbmj.MigrateDBJobsService), + }, + { + Name: "QUARKUS_DATASOURCE_JOBSSERVICE_JDBC_URL", + Value: dbmj.JobsServiceDataSource.JdbcUrl, + }, + { + Name: "QUARKUS_DATASOURCE_JOBSSERVICE_USERNAME", + Value: dbmj.JobsServiceDataSource.Username, + }, + { + Name: "QUARKUS_DATASOURCE_JOBSSERVICE_PASSWORD", + Value: dbmj.JobsServiceDataSource.Password, + }, + { + Name: "QUARKUS_FLYWAY_JOBSSERVICE_SCHEMAS", + Value: dbmj.JobsServiceDataSource.Schema, + }, + }, + Command: []string{ + dbMigrationJobCfg.MigrationCmd, + }, + }, + }, + RestartPolicy: "Never", + }, + }, + BackoffLimit: pointer.Int32(0), + }, + } + return job +} + +// GetDBMigrationJobStatus Returns db migration job status +func (dbmj DBMigratorJob) GetDBMigrationJobStatus(ctx context.Context, client client.Client, platform *operatorapi.SonataFlowPlatform) (*batchv1.JobStatus, error) { + job, err := client.BatchV1().Jobs(platform.Namespace).Get(ctx, dbMigrationJobName, metav1.GetOptions{}) + if err != nil { + klog.V(log.E).InfoS("Error getting DB migrator job while monitoring completion: ", "error", err) + return nil, err + } + return &job.Status, nil +} + +// NewSonataFlowPlatformDBMigrationPhase Returns a new DB migration phase for SonataFlowPlatform +func NewSonataFlowPlatformDBMigrationPhase(status operatorapi.DBMigrationStatus, message string, reason string) *operatorapi.SonataFlowPlatformDBMigrationPhase { + return &operatorapi.SonataFlowPlatformDBMigrationPhase{ + Status: status, + Message: message, + Reason: reason, + } +} + +// UpdateSonataFlowPlatformDBMigrationPhase Updates a given SonataFlowPlatformDBMigrationPhase with the supplied values +func UpdateSonataFlowPlatformDBMigrationPhase(dbMigrationStatus *operatorapi.SonataFlowPlatformDBMigrationPhase, status operatorapi.DBMigrationStatus, message string, reason string) *operatorapi.SonataFlowPlatformDBMigrationPhase { + if dbMigrationStatus != nil { + dbMigrationStatus.Status = status + dbMigrationStatus.Message = message + dbMigrationStatus.Reason = reason + return dbMigrationStatus + } + return nil +} + +func getDBMigrationJobCfg() *DBMigrationJobCfg { + return &DBMigrationJobCfg{ + JobName: dbMigrationJobName, + ContainerName: dbMigrationContainerName, + ToolImageName: dbMigratorToolImage, + MigrationCmd: dbMigrationCmd, + } +} + +// ReconcileDBMigrationJob Check the status of running DB migration job and return status +func (dbmj DBMigratorJob) ReconcileDBMigrationJob(ctx context.Context, client client.Client, platform *operatorapi.SonataFlowPlatform) (*batchv1.JobStatus, error) { + platform.Status.SonataFlowPlatformDBMigrationPhase = NewSonataFlowPlatformDBMigrationPhase(operatorapi.DBMigrationStatusStarted, operatorapi.MessageDBMigrationStatusStarted, operatorapi.ReasonDBMigrationStatusStarted) + + dbMigratorJobStatus, err := dbmj.GetDBMigrationJobStatus(ctx, client, platform) + if err != nil { + return nil, err + } + + klog.V(log.I).InfoS("Db migration job status: ", "active", dbMigratorJobStatus.Active, "ready", dbMigratorJobStatus.Ready, "failed", dbMigratorJobStatus.Failed, "success", dbMigratorJobStatus.Succeeded, "CompletedIndexes", dbMigratorJobStatus.CompletedIndexes, "terminatedPods", dbMigratorJobStatus.UncountedTerminatedPods) + + if dbMigratorJobStatus.Failed == 1 { + platform.Status.SonataFlowPlatformDBMigrationPhase = UpdateSonataFlowPlatformDBMigrationPhase(platform.Status.SonataFlowPlatformDBMigrationPhase, operatorapi.DBMigrationStatusFailed, operatorapi.MessageDBMigrationStatusFailed, operatorapi.ReasonDBMigrationStatusFailed) + klog.V(log.I).InfoS("DB migration job failed") + return dbMigratorJobStatus, errors.New("DB migration job failed") + } else if dbMigratorJobStatus.Succeeded == 1 { + platform.Status.SonataFlowPlatformDBMigrationPhase = UpdateSonataFlowPlatformDBMigrationPhase(platform.Status.SonataFlowPlatformDBMigrationPhase, operatorapi.DBMigrationStatusSucceeded, operatorapi.MessageDBMigrationStatusSucceeded, operatorapi.ReasonDBMigrationStatusSucceeded) + klog.V(log.I).InfoS("DB migration job succeeded") + } else { + // DB migration is still running + platform.Status.SonataFlowPlatformDBMigrationPhase = UpdateSonataFlowPlatformDBMigrationPhase(platform.Status.SonataFlowPlatformDBMigrationPhase, operatorapi.DBMigrationStatusInProgress, operatorapi.MessageDBMigrationStatusInProgress, operatorapi.ReasonDBMigrationStatusInProgress) + } + + return dbMigratorJobStatus, nil +} diff --git a/internal/controller/platform/k8s.go b/internal/controller/platform/k8s.go index 9433f5a85..4379ea9d2 100644 --- a/internal/controller/platform/k8s.go +++ b/internal/controller/platform/k8s.go @@ -21,6 +21,7 @@ package platform import ( "context" + "errors" "fmt" "k8s.io/klog/v2" @@ -61,6 +62,64 @@ func (action *serviceAction) CanHandle(platform *operatorapi.SonataFlowPlatform) return platform.Status.IsReady() } +func (action *serviceAction) createOrUpdateDBMigrationJob(ctx context.Context, client client.Client, platform *operatorapi.SonataFlowPlatform, pshDI services.PlatformServiceHandler, pshJS services.PlatformServiceHandler) (*DBMigratorJob, error) { + dbMigratorJob := NewDBMigratorJobData(ctx, action.client, platform, pshDI, pshJS) + + // Invoke DB Migration only if both or either DI/JS services are requested, in addition to DBMigrationStrategyJob + if dbMigratorJob != nil { + klog.V(log.I).InfoS("Starting DB Migration Job: ") + + job := dbMigratorJob.CreateJobDBMigration(platform) + if op, err := controllerutil.CreateOrUpdate(ctx, client, job, func() error { + return nil + }); err != nil { + return dbMigratorJob, err + } else { + klog.V(log.I).InfoS("DB Migration Job successfully created on cluster", "operation", op) + } + } + return dbMigratorJob, nil +} + +func (action *serviceAction) handleDBMigrationJob(ctx context.Context, platform *operatorapi.SonataFlowPlatform, psDI services.PlatformServiceHandler, psJS services.PlatformServiceHandler) (*operatorapi.SonataFlowPlatform, error) { + + dbMigratorJob, err := action.createOrUpdateDBMigrationJob(ctx, action.client, platform, psDI, psJS) + if err != nil { + return nil, err + } + if dbMigratorJob != nil { + klog.V(log.E).InfoS("Created DB migration job") + dbMigratorJobStatus, err := dbMigratorJob.ReconcileDBMigrationJob(ctx, action.client, platform) + if err != nil { + return nil, err + } + if dbMigratorJobStatus.Failed == 1 { + return nil, errors.New("DB migration job failed") + } else if dbMigratorJobStatus.Succeeded == 1 { + return platform, nil + } else { + // DB migration is still running + return nil, nil + } + } + + return platform, nil +} + +func (action *serviceAction) isJobsBasedDBMigration(platform *operatorapi.SonataFlowPlatform, pshDI services.PlatformServiceHandler, pshJS services.PlatformServiceHandler) bool { + diJobsBasedDBMigration := false + jsJobsBasedDBMigration := false + + if pshDI.IsPersistenceEnabledtInSpec() { + diJobsBasedDBMigration = services.IsJobsBasedDBMigration(platform.Spec.Services.DataIndex.Persistence) + } + if pshJS.IsPersistenceEnabledtInSpec() { + jsJobsBasedDBMigration = services.IsJobsBasedDBMigration(platform.Spec.Services.JobService.Persistence) + } + + return (pshDI.IsServiceSetInSpec() && diJobsBasedDBMigration) || (pshJS.IsServiceSetInSpec() && jsJobsBasedDBMigration) +} + func (action *serviceAction) Handle(ctx context.Context, platform *operatorapi.SonataFlowPlatform) (*operatorapi.SonataFlowPlatform, error) { // Refresh applied configuration if err := CreateOrUpdateWithDefaults(ctx, platform, false); err != nil { @@ -68,13 +127,21 @@ func (action *serviceAction) Handle(ctx context.Context, platform *operatorapi.S } psDI := services.NewDataIndexHandler(platform) + psJS := services.NewJobServiceHandler(platform) + + if action.isJobsBasedDBMigration(platform, psDI, psJS) { + p, err := action.handleDBMigrationJob(ctx, platform, psDI, psJS) + if p == nil { + return nil, err + } + } + if psDI.IsServiceSetInSpec() { if err := createOrUpdateServiceComponents(ctx, action.client, platform, psDI); err != nil { return nil, err } } - psJS := services.NewJobServiceHandler(platform) if psJS.IsServiceSetInSpec() { if err := createOrUpdateServiceComponents(ctx, action.client, platform, psJS); err != nil { return nil, err diff --git a/internal/controller/platform/services/secrets.go b/internal/controller/platform/services/secrets.go new file mode 100644 index 000000000..c0b727e99 --- /dev/null +++ b/internal/controller/platform/services/secrets.go @@ -0,0 +1,40 @@ +// Copyright 2024 Apache Software Foundation (ASF) +// +// 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 services + +import ( + "context" + + "github.com/apache/incubator-kie-kogito-serverless-operator/log" + "github.com/apache/incubator-kie-kogito-serverless-operator/utils" + corev1 "k8s.io/api/core/v1" + "k8s.io/klog/v2" + ctrl "sigs.k8s.io/controller-runtime/pkg/client" +) + +func GetSecretKeyValueString(ctx context.Context, secretName string, secretKey string, nameSpace string) (string, error) { + secret := corev1.Secret{} + err := utils.GetClient().Get(ctx, ctrl.ObjectKey{Namespace: nameSpace, Name: secretName}, &secret) + if err != nil { + panic(err.Error()) + } + + if err != nil { + klog.V(log.E).InfoS("Error extracting secret: ", "namespace", nameSpace, "error", err) + return "", err + } + + return string(secret.Data[secretKey]), nil +} diff --git a/internal/controller/platform/services/services.go b/internal/controller/platform/services/services.go index 20673b75b..4a5b56fe9 100644 --- a/internal/controller/platform/services/services.go +++ b/internal/controller/platform/services/services.go @@ -21,6 +21,7 @@ package services import ( "fmt" + "strconv" "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/cfg" "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/knative" @@ -40,6 +41,7 @@ import ( "knative.dev/pkg/tracker" "sigs.k8s.io/controller-runtime/pkg/client" + "github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08" operatorapi "github.com/apache/incubator-kie-kogito-serverless-operator/api/v1alpha08" "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/profiles/common/constants" "github.com/apache/incubator-kie-kogito-serverless-operator/internal/controller/profiles/common/persistence" @@ -89,6 +91,8 @@ type PlatformServiceHandler interface { IsServiceSetInSpec() bool // IsServiceEnabledInSpec returns true if the service is enabled in the spec. IsServiceEnabledInSpec() bool + // IsPersistenceEnabledtInSpec returns true if the service has persistence set in the spec. + IsPersistenceEnabledtInSpec() bool // GetLocalServiceBaseUrl returns the base url of the local service GetLocalServiceBaseUrl() string // GetServiceBaseUrl returns the base url of the service, based on whether using local or cluster-scoped service. @@ -105,12 +109,20 @@ type PlatformServiceHandler interface { // Check if K_SINK has injected for Job Service. No Op for Data Index CheckKSinkInjected() (bool, error) + + // Returns whether job based, service based or no DB migration is needed + GetDBMigrationStrategy() operatorapi.DBMigrationStrategyType } type DataIndexHandler struct { platform *operatorapi.SonataFlowPlatform } +// GetDBMigrationStrategy returns DB migration approach +func (d *DataIndexHandler) GetDBMigrationStrategy() operatorapi.DBMigrationStrategyType { + return GetDBMigrationStrategy(d.platform.Spec.Services.DataIndex.Persistence) +} + func NewDataIndexHandler(platform *operatorapi.SonataFlowPlatform) PlatformServiceHandler { return &DataIndexHandler{platform: platform} } @@ -167,6 +179,10 @@ func (d *DataIndexHandler) IsServiceEnabledInSpec() bool { return isDataIndexEnabled(d.platform) } +func (d DataIndexHandler) IsPersistenceEnabledtInSpec() bool { + return d.IsServiceSetInSpec() && d.platform.Spec.Services.DataIndex.Persistence != nil +} + func (d *DataIndexHandler) isServiceEnabledInStatus() bool { return d.platform != nil && d.platform.Status.ClusterPlatformRef != nil && d.platform.Status.ClusterPlatformRef.Services != nil && d.platform.Status.ClusterPlatformRef.Services.DataIndexRef != nil && @@ -226,18 +242,51 @@ func (d *DataIndexHandler) hasPostgreSQLConfigured() bool { (d.platform.Spec.Persistence != nil && d.platform.Spec.Persistence.PostgreSQL != nil)) } +func GetDBMigrationStrategy(persistence *operatorapi.PersistenceOptionsSpec) operatorapi.DBMigrationStrategyType { + dbMigrationStrategy := operatorapi.DBMigrationStrategyNone + + if persistence != nil { + return operatorapi.DBMigrationStrategyType(persistence.DBMigrationStrategy) + } + + return dbMigrationStrategy +} + +func IsServiceBasedDBMigration(persistence *operatorapi.PersistenceOptionsSpec) bool { + dbMigrationStrategy := GetDBMigrationStrategy(persistence) + return dbMigrationStrategy == operatorapi.DBMigrationStrategyService +} + +func IsJobsBasedDBMigration(persistence *operatorapi.PersistenceOptionsSpec) bool { + dbMigrationStrategy := GetDBMigrationStrategy(persistence) + return dbMigrationStrategy == operatorapi.DBMigrationStrategyJob +} + +func IsNoDBMigration(persistence *operatorapi.PersistenceOptionsSpec) bool { + dbMigrationStrategy := GetDBMigrationStrategy(persistence) + return dbMigrationStrategy == operatorapi.DBMigrationStrategyNone || dbMigrationStrategy == "" +} + +func isDBMigrationStrategyService(persistence *v1alpha08.PersistenceOptionsSpec) string { + dbMigrationStrategyService := "true" + if persistence != nil { + dbMigrationStrategyService = strconv.FormatBool(IsServiceBasedDBMigration(persistence)) + } + + return dbMigrationStrategyService +} + func (d *DataIndexHandler) ConfigurePersistence(containerSpec *corev1.Container) *corev1.Container { if d.hasPostgreSQLConfigured() { p := persistence.RetrievePostgreSQLConfiguration(d.platform.Spec.Services.DataIndex.Persistence, d.platform.Spec.Persistence, d.GetServiceName()) c := containerSpec.DeepCopy() c.Image = d.GetServiceImageName(constants.PersistenceTypePostgreSQL) c.Env = append(c.Env, persistence.ConfigurePostgreSQLEnv(p.PostgreSQL, d.GetServiceName(), d.platform.Namespace)...) - // TODO upcoming work as part of the DB Migrator incorporation should continue where - // assignments like -> migrateDBOnStart := strconv.FormatBool(d.platform.Spec.Services.DataIndex.Persistence.MigrateDBOnStartUp) introduces nil pointer references, - // since Services, and services Persistence are optional references. + + dbMigrationStrategyService := isDBMigrationStrategyService(d.platform.Spec.Services.DataIndex.Persistence) // specific to DataIndex - c.Env = append(c.Env, corev1.EnvVar{Name: quarkusHibernateORMDatabaseGeneration, Value: "update"}, corev1.EnvVar{Name: quarkusFlywayMigrateAtStart, Value: "true"}) + c.Env = append(c.Env, corev1.EnvVar{Name: quarkusHibernateORMDatabaseGeneration, Value: "update"}, corev1.EnvVar{Name: quarkusFlywayMigrateAtStart, Value: dbMigrationStrategyService}) return c } return containerSpec @@ -280,6 +329,11 @@ type JobServiceHandler struct { platform *operatorapi.SonataFlowPlatform } +// GetDBMigrationStrategy returns db migration approach otherwise +func (j *JobServiceHandler) GetDBMigrationStrategy() operatorapi.DBMigrationStrategyType { + return GetDBMigrationStrategy(j.platform.Spec.Services.JobService.Persistence) +} + func NewJobServiceHandler(platform *operatorapi.SonataFlowPlatform) PlatformServiceHandler { return &JobServiceHandler{platform: platform} } @@ -340,6 +394,10 @@ func (j *JobServiceHandler) IsServiceEnabledInSpec() bool { return isJobServiceEnabled(j.platform) } +func (j JobServiceHandler) IsPersistenceEnabledtInSpec() bool { + return j.IsServiceSetInSpec() && j.platform.Spec.Services.JobService.Persistence != nil +} + func (j *JobServiceHandler) isServiceEnabledInStatus() bool { return j.platform != nil && j.platform.Status.ClusterPlatformRef != nil && j.platform.Status.ClusterPlatformRef.Services != nil && j.platform.Status.ClusterPlatformRef.Services.JobServiceRef != nil && @@ -403,12 +461,11 @@ func (j *JobServiceHandler) ConfigurePersistence(containerSpec *corev1.Container c.Image = j.GetServiceImageName(constants.PersistenceTypePostgreSQL) p := persistence.RetrievePostgreSQLConfiguration(j.platform.Spec.Services.JobService.Persistence, j.platform.Spec.Persistence, j.GetServiceName()) c.Env = append(c.Env, persistence.ConfigurePostgreSQLEnv(p.PostgreSQL, j.GetServiceName(), j.platform.Namespace)...) - // TODO upcoming work as part of the DB Migrator incorporation should continue where - // assignments like -> migrateDBOnStart := strconv.FormatBool(j.platform.Spec.Services.JobService.Persistence.MigrateDBOnStartUp) introduces nil pointer references, - // since Services, and services Persistence are optional references. + + dbMigrationStrategyService := isDBMigrationStrategyService(j.platform.Spec.Services.JobService.Persistence) // Specific to Job Service - c.Env = append(c.Env, corev1.EnvVar{Name: "QUARKUS_FLYWAY_MIGRATE_AT_START", Value: "true"}) + c.Env = append(c.Env, corev1.EnvVar{Name: "QUARKUS_FLYWAY_MIGRATE_AT_START", Value: dbMigrationStrategyService}) c.Env = append(c.Env, corev1.EnvVar{Name: "KOGITO_JOBS_SERVICE_LOADJOBERRORSTRATEGY", Value: "FAIL_SERVICE"}) return c } diff --git a/internal/controller/sonataflowplatform_controller.go b/internal/controller/sonataflowplatform_controller.go index 75f3d1c5e..6840f8b17 100644 --- a/internal/controller/sonataflowplatform_controller.go +++ b/internal/controller/sonataflowplatform_controller.go @@ -69,6 +69,7 @@ type SonataFlowPlatformReconciler struct { //+kubebuilder:rbac:groups=sonataflow.org,resources=sonataflowplatforms,verbs=get;list;watch;create;update;patch;delete //+kubebuilder:rbac:groups=sonataflow.org,resources=sonataflowplatforms/status,verbs=get;update;patch //+kubebuilder:rbac:groups=sonataflow.org,resources=sonataflowplatforms/finalizers,verbs=update +//+kubebuilder:rbac:groups=batch,resources=jobs,verbs=get;list;watch;create;update;patch;delete // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. diff --git a/internal/controller/sonataflowplatform_controller_test.go b/internal/controller/sonataflowplatform_controller_test.go index db567769b..73130f747 100644 --- a/internal/controller/sonataflowplatform_controller_test.go +++ b/internal/controller/sonataflowplatform_controller_test.go @@ -277,14 +277,14 @@ func TestSonataFlowPlatformController(t *testing.T) { DataIndex: &v1alpha08.DataIndexServiceSpec{ ServiceSpec: v1alpha08.ServiceSpec{ Persistence: &v1alpha08.PersistenceOptionsSpec{ - MigrateDBOnStartUp: false, + DBMigrationStrategy: "none", }, }, }, JobService: &v1alpha08.JobServiceServiceSpec{ ServiceSpec: v1alpha08.ServiceSpec{ Persistence: &v1alpha08.PersistenceOptionsSpec{ - MigrateDBOnStartUp: false, + DBMigrationStrategy: "none", }, }, }, diff --git a/operator.yaml b/operator.yaml index 85d949106..0d620df44 100644 --- a/operator.yaml +++ b/operator.yaml @@ -1199,9 +1199,14 @@ spec: by default. maxProperties: 2 properties: - migrateDBOnStartUp: - description: Whether to migrate database on service startup? - type: boolean + dbMigrationStrategy: + default: service + description: |- + DB Migration approach for service? + job: use job based approach + service: service itself shall migrate the db + none: no db migration needed + type: string postgresql: description: Connect configured services to a postgresql database. @@ -9243,9 +9248,14 @@ spec: by default. maxProperties: 2 properties: - migrateDBOnStartUp: - description: Whether to migrate database on service startup? - type: boolean + dbMigrationStrategy: + default: service + description: |- + DB Migration approach for service? + job: use job based approach + service: service itself shall migrate the db + none: no db migration needed + type: string postgresql: description: Connect configured services to a postgresql database. @@ -17420,6 +17430,15 @@ spec: description: The generation observed by the deployment controller. format: int64 type: integer + sonataFlowPlatformDBMigrationPhase: + properties: + dbMigrationStatus: + type: string + message: + type: string + reason: + type: string + type: object triggers: description: Triggers list of triggers created for the SonataFlowPlatform items: @@ -19445,9 +19464,14 @@ spec: for the workflow maxProperties: 2 properties: - migrateDBOnStartUp: - description: Whether to migrate database on service startup? - type: boolean + dbMigrationStrategy: + default: service + description: |- + DB Migration approach for service? + job: use job based approach + service: service itself shall migrate the db + none: no db migration needed + type: string postgresql: description: Connect configured services to a postgresql database. maxProperties: 2 @@ -27783,6 +27807,18 @@ kind: ClusterRole metadata: name: sonataflow-operator-manager-role rules: +- apiGroups: + - batch + resources: + - jobs + verbs: + - create + - delete + - get + - list + - patch + - update + - watch - apiGroups: - sonataflow.org resources: diff --git a/test/e2e/platform_test.go b/test/e2e/platform_test.go index 6e75934db..2f0cc8695 100644 --- a/test/e2e/platform_test.go +++ b/test/e2e/platform_test.go @@ -74,6 +74,46 @@ var _ = Describe("Platform Use Cases :: ", Label("platform"), Ordered, func() { } } }) + + var _ = Describe("Db migration :: ", Ordered, func() { + + Describe("ensure service based db migration", func() { + projectDir, _ := utils.GetProjectDir() + It("should successfully deploy the SonataFlowPlatform with data index and jobs service", func() { + By("Deploy the CR") + var manifests []byte + EventuallyWithOffset(1, func() error { + var err error + cmd := exec.Command("kubectl", "kustomize", filepath.Join(projectDir, + "test/testdata/platform/persistence/service_based_db_migration")) + manifests, err = utils.Run(cmd) + return err + }, time.Minute, time.Second).Should(Succeed()) + cmd := exec.Command("kubectl", "create", "-n", targetNamespace, "-f", "-") + cmd.Stdin = bytes.NewBuffer(manifests) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + + By("Wait for SonatatFlowPlatform CR to complete deployment") + // wait for service deployments to be ready + EventuallyWithOffset(1, func() error { + cmd = exec.Command("kubectl", "wait", "pod", "-n", targetNamespace, "-l", "app.kubernetes.io/name in (jobs-service,data-index-service)", "--for", "condition=Ready", "--timeout=5s") + _, err = utils.Run(cmd) + return err + }, 10*time.Minute, 5).Should(Succeed()) + + By("Evaluate status of all service's health endpoint") + cmd = exec.Command("kubectl", "get", "pod", "-l", "app.kubernetes.io/name in (jobs-service,data-index-service)", "-n", targetNamespace, "-ojsonpath={.items[*].metadata.name}") + output, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + for _, pn := range strings.Split(string(output), " ") { + verifyHealthStatusInPod(pn, targetNamespace) + } + }) + }) + + }) + var _ = Context("with platform services", func() { DescribeTable("when creating a simple workflow", func(testcaseDir string, profile metadata.ProfileType, persistenceType string) { @@ -183,6 +223,60 @@ var _ = Describe("Platform Use Cases :: ", Label("platform"), Ordered, func() { }, Entry("and both Job Service and Data Index using the persistence from platform CR", test.GetPathFromE2EDirectory("platform", "persistence", "generic_from_platform_cr")), Entry("and both Job Service and Data Index using the one defined in each service, discarding the one from the platform CR", test.GetPathFromE2EDirectory("platform", "persistence", "overwritten_by_services")), + Entry("Job Service and Data Index come up with service based db migration", test.GetPathFromE2EDirectory("platform", "persistence", "service_based_db_migration")), + ) + + DescribeTable("when deploying a SonataFlowPlatform CR with PostgreSQL Persistence and using Job based DB migration", func(testcaseDir string) { + By("Deploy the Postgres DB") + var manifests []byte + EventuallyWithOffset(1, func() error { + var err error + cmd := exec.Command("kubectl", "kustomize", testcaseDir+"/pg-service") + manifests, err = utils.Run(cmd) + return err + }, time.Minute, time.Second).Should(Succeed()) + cmd := exec.Command("kubectl", "create", "-n", targetNamespace, "-f", "-") + cmd.Stdin = bytes.NewBuffer(manifests) + _, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + + By("Wait for Postgres DB to come alive") + // wait for service deployments to be ready + EventuallyWithOffset(1, func() error { + cmd = exec.Command("kubectl", "wait", "pod", "-n", targetNamespace, "-l", "app.kubernetes.io/name in (postgres)", "--for", "condition=Ready", "--timeout=5s") + _, err = utils.Run(cmd) + return err + }, 5*time.Minute, 5).Should(Succeed()) + + By("Deploy the CR") + EventuallyWithOffset(1, func() error { + var err error + cmd := exec.Command("kubectl", "kustomize", testcaseDir+"/sonataflow-platform") + manifests, err = utils.Run(cmd) + return err + }, time.Minute, time.Second).Should(Succeed()) + cmd = exec.Command("kubectl", "create", "-n", targetNamespace, "-f", "-") + cmd.Stdin = bytes.NewBuffer(manifests) + _, err = utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + + By("Wait for SonatatFlowPlatform CR to complete deployment") + // wait for service deployments to be ready + EventuallyWithOffset(1, func() error { + cmd = exec.Command("kubectl", "wait", "pod", "-n", targetNamespace, "-l", "app.kubernetes.io/name in (jobs-service,data-index-service)", "--for", "condition=Ready", "--timeout=5s") + _, err = utils.Run(cmd) + return err + }, 10*time.Minute, 5).Should(Succeed()) + + By("Evaluate status of all service's health endpoint") + cmd = exec.Command("kubectl", "get", "pod", "-l", "app.kubernetes.io/name in (jobs-service,data-index-service)", "-n", targetNamespace, "-ojsonpath={.items[*].metadata.name}") + output, err := utils.Run(cmd) + Expect(err).NotTo(HaveOccurred()) + for _, pn := range strings.Split(string(output), " ") { + verifyHealthStatusInPod(pn, targetNamespace) + } + }, + Entry("Job Service and Data Index come up with job based db migration", test.GetPathFromE2EDirectory("platform", "persistence", "job_based_db_migration")), ) DescribeTable("when deploying a SonataFlowPlatform CR with brokers", func(testcaseDir string) { diff --git a/test/e2e/testdata/platform/persistence/generic_from_platform_cr/02-sonataflow_platform.yaml b/test/e2e/testdata/platform/persistence/generic_from_platform_cr/02-sonataflow_platform.yaml index cce1782e6..b14e53e2b 100644 --- a/test/e2e/testdata/platform/persistence/generic_from_platform_cr/02-sonataflow_platform.yaml +++ b/test/e2e/testdata/platform/persistence/generic_from_platform_cr/02-sonataflow_platform.yaml @@ -31,7 +31,7 @@ spec: dataIndex: enabled: false persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service podTemplate: initContainers: - name: init-postgres @@ -41,7 +41,7 @@ spec: jobService: enabled: false persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service podTemplate: initContainers: - name: init-postgres diff --git a/test/e2e/testdata/platform/persistence/job_based_db_migration/pg-service/01-postgres.yaml b/test/e2e/testdata/platform/persistence/job_based_db_migration/pg-service/01-postgres.yaml new file mode 100644 index 000000000..cf9313e61 --- /dev/null +++ b/test/e2e/testdata/platform/persistence/job_based_db_migration/pg-service/01-postgres.yaml @@ -0,0 +1,85 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: postgres + template: + metadata: + labels: + app.kubernetes.io/name: postgres + spec: + containers: + - name: postgres + image: postgres:13.2-alpine + imagePullPolicy: 'IfNotPresent' + ports: + - containerPort: 5432 + volumeMounts: + - name: storage + mountPath: /var/lib/postgresql/data + envFrom: + - secretRef: + name: postgres-secrets + readinessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + livenessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + resources: + limits: + memory: "256Mi" + cpu: "500m" + volumes: + - name: storage + persistentVolumeClaim: + claimName: postgres-pvc +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + selector: + app.kubernetes.io/name: postgres + ports: + - port: 5432 \ No newline at end of file diff --git a/test/e2e/testdata/platform/persistence/job_based_db_migration/pg-service/kustomization.yaml b/test/e2e/testdata/platform/persistence/job_based_db_migration/pg-service/kustomization.yaml new file mode 100644 index 000000000..54c58ff9c --- /dev/null +++ b/test/e2e/testdata/platform/persistence/job_based_db_migration/pg-service/kustomization.yaml @@ -0,0 +1,30 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. + +resources: +- 01-postgres.yaml + +generatorOptions: + disableNameSuffixHash: true + +secretGenerator: + - name: postgres-secrets + literals: + - POSTGRES_USER=sonataflow + - POSTGRES_PASSWORD=sonataflow + - POSTGRES_DATABASE=sonataflow + - PGDATA=/var/lib/pgsql/data/userdata + +sortOptions: + order: fifo diff --git a/test/e2e/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/01-sonataflow_platform.yaml b/test/e2e/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/01-sonataflow_platform.yaml new file mode 100644 index 000000000..7ef030055 --- /dev/null +++ b/test/e2e/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/01-sonataflow_platform.yaml @@ -0,0 +1,43 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlowPlatform +metadata: + name: sonataflow-platform +spec: + build: + config: + strategyOptions: + KanikoBuildCacheEnabled: "true" + services: + dataIndex: + enabled: true + persistence: + dbMigrationStrategy: job + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=data-index-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD + jobService: + enabled: true + persistence: + dbMigrationStrategy: job + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=jobs-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD \ No newline at end of file diff --git a/test/e2e/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/kustomization.yaml b/test/e2e/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/kustomization.yaml new file mode 100644 index 000000000..ef19095a0 --- /dev/null +++ b/test/e2e/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/kustomization.yaml @@ -0,0 +1,19 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. + +resources: +- 01-sonataflow_platform.yaml + +generatorOptions: + disableNameSuffixHash: true \ No newline at end of file diff --git a/test/e2e/testdata/platform/persistence/overwritten_by_services/02-sonataflow_platform.yaml b/test/e2e/testdata/platform/persistence/overwritten_by_services/02-sonataflow_platform.yaml index 14b0cef9b..60c671eef 100644 --- a/test/e2e/testdata/platform/persistence/overwritten_by_services/02-sonataflow_platform.yaml +++ b/test/e2e/testdata/platform/persistence/overwritten_by_services/02-sonataflow_platform.yaml @@ -35,7 +35,7 @@ spec: dataIndex: enabled: false persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service postgresql: jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=data-index-service secretRef: @@ -51,7 +51,7 @@ spec: jobService: enabled: false persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service postgresql: jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=jobs-service secretRef: diff --git a/test/e2e/testdata/platform/persistence/service_based_db_migration/01-postgres.yaml b/test/e2e/testdata/platform/persistence/service_based_db_migration/01-postgres.yaml new file mode 100644 index 000000000..cf9313e61 --- /dev/null +++ b/test/e2e/testdata/platform/persistence/service_based_db_migration/01-postgres.yaml @@ -0,0 +1,85 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: postgres + template: + metadata: + labels: + app.kubernetes.io/name: postgres + spec: + containers: + - name: postgres + image: postgres:13.2-alpine + imagePullPolicy: 'IfNotPresent' + ports: + - containerPort: 5432 + volumeMounts: + - name: storage + mountPath: /var/lib/postgresql/data + envFrom: + - secretRef: + name: postgres-secrets + readinessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + livenessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + resources: + limits: + memory: "256Mi" + cpu: "500m" + volumes: + - name: storage + persistentVolumeClaim: + claimName: postgres-pvc +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + selector: + app.kubernetes.io/name: postgres + ports: + - port: 5432 \ No newline at end of file diff --git a/test/e2e/testdata/platform/persistence/service_based_db_migration/02-sonataflow_platform.yaml b/test/e2e/testdata/platform/persistence/service_based_db_migration/02-sonataflow_platform.yaml new file mode 100644 index 000000000..990ef7685 --- /dev/null +++ b/test/e2e/testdata/platform/persistence/service_based_db_migration/02-sonataflow_platform.yaml @@ -0,0 +1,56 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlowPlatform +metadata: + name: sonataflow-platform +spec: + build: + config: + strategyOptions: + KanikoBuildCacheEnabled: "true" + services: + # jobBasedDbMigration: false + dataIndex: + enabled: true + persistence: + dbMigrationStrategy: service + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=data-index-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD + podTemplate: + initContainers: + - name: init-postgres + image: registry.access.redhat.com/ubi9/ubi-micro:latest + imagePullPolicy: IfNotPresent + command: [ 'sh', '-c', 'until (echo 1 > /dev/tcp/postgres.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local/5432) >/dev/null 2>&1; do echo "Waiting for postgres server"; sleep 3; done;' ] + jobService: + enabled: true + persistence: + dbMigrationStrategy: service + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=jobs-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD + podTemplate: + initContainers: + - name: init-postgres + image: registry.access.redhat.com/ubi9/ubi-micro:latest + imagePullPolicy: IfNotPresent + command: [ 'sh', '-c', 'until (echo 1 > /dev/tcp/postgres.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local/5432) >/dev/null 2>&1; do echo "Waiting for postgres server"; sleep 3; done;' ] \ No newline at end of file diff --git a/test/e2e/testdata/platform/persistence/service_based_db_migration/kustomization.yaml b/test/e2e/testdata/platform/persistence/service_based_db_migration/kustomization.yaml new file mode 100644 index 000000000..064f65818 --- /dev/null +++ b/test/e2e/testdata/platform/persistence/service_based_db_migration/kustomization.yaml @@ -0,0 +1,31 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. + +resources: +- 01-postgres.yaml +- 02-sonataflow_platform.yaml + +generatorOptions: + disableNameSuffixHash: true + +secretGenerator: + - name: postgres-secrets + literals: + - POSTGRES_USER=sonataflow + - POSTGRES_PASSWORD=sonataflow + - POSTGRES_DATABASE=sonataflow + - PGDATA=/var/lib/pgsql/data/userdata + +sortOptions: + order: fifo diff --git a/test/e2e/testdata/platform/services/dev/postgreSQL/02-sonataflow_platform.yaml b/test/e2e/testdata/platform/services/dev/postgreSQL/02-sonataflow_platform.yaml index 27daa5c4f..1b4504105 100644 --- a/test/e2e/testdata/platform/services/dev/postgreSQL/02-sonataflow_platform.yaml +++ b/test/e2e/testdata/platform/services/dev/postgreSQL/02-sonataflow_platform.yaml @@ -26,7 +26,7 @@ spec: dataIndex: enabled: false persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service postgresql: jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=data-index-service secretRef: @@ -42,7 +42,7 @@ spec: jobService: enabled: false persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service postgresql: jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=jobs-service secretRef: diff --git a/test/e2e/testdata/platform/services/gitops/knative/platform-level-broker/02-sonataflow_platform.yaml b/test/e2e/testdata/platform/services/gitops/knative/platform-level-broker/02-sonataflow_platform.yaml index ca791c9b6..919cdd929 100644 --- a/test/e2e/testdata/platform/services/gitops/knative/platform-level-broker/02-sonataflow_platform.yaml +++ b/test/e2e/testdata/platform/services/gitops/knative/platform-level-broker/02-sonataflow_platform.yaml @@ -32,7 +32,7 @@ spec: dataIndex: enabled: true persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service postgresql: jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=data-index-service secretRef: @@ -55,7 +55,7 @@ spec: jobService: enabled: true persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service postgresql: jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=jobs-service secretRef: diff --git a/test/e2e/testdata/platform/services/gitops/knative/service-level-broker/02-sonataflow_platform.yaml b/test/e2e/testdata/platform/services/gitops/knative/service-level-broker/02-sonataflow_platform.yaml index 1bb215d8b..aaefb7416 100644 --- a/test/e2e/testdata/platform/services/gitops/knative/service-level-broker/02-sonataflow_platform.yaml +++ b/test/e2e/testdata/platform/services/gitops/knative/service-level-broker/02-sonataflow_platform.yaml @@ -36,7 +36,7 @@ spec: kind: Broker name: di-source persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service postgresql: jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=data-index-service secretRef: @@ -69,7 +69,7 @@ spec: kind: Broker name: js-sink persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service postgresql: jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=jobs-service secretRef: diff --git a/test/e2e/testdata/platform/services/gitops/postgreSQL/02-sonataflow_platform.yaml b/test/e2e/testdata/platform/services/gitops/postgreSQL/02-sonataflow_platform.yaml index f33dbf82a..d8e60866a 100644 --- a/test/e2e/testdata/platform/services/gitops/postgreSQL/02-sonataflow_platform.yaml +++ b/test/e2e/testdata/platform/services/gitops/postgreSQL/02-sonataflow_platform.yaml @@ -31,7 +31,7 @@ spec: dataIndex: enabled: true persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service postgresql: jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=data-index-service secretRef: @@ -54,7 +54,7 @@ spec: jobService: enabled: true persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service postgresql: jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=jobs-service secretRef: diff --git a/test/e2e/testdata/workflows/persistence/from_platform_with_di_and_js_services/02-sonataflow_platform.yaml b/test/e2e/testdata/workflows/persistence/from_platform_with_di_and_js_services/02-sonataflow_platform.yaml index aa5ec69b5..5d424a244 100644 --- a/test/e2e/testdata/workflows/persistence/from_platform_with_di_and_js_services/02-sonataflow_platform.yaml +++ b/test/e2e/testdata/workflows/persistence/from_platform_with_di_and_js_services/02-sonataflow_platform.yaml @@ -41,7 +41,7 @@ spec: dataIndex: enabled: true persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service podTemplate: initContainers: - name: init-postgres @@ -51,7 +51,7 @@ spec: jobService: enabled: true persistence: - migrateDBOnStartUp: true + dbMigrationStrategy: service podTemplate: initContainers: - name: init-postgres diff --git a/test/e2e/testdata/workflows/persistence/from_platform_with_no_persistence_required/03-sonataflow_callbackstatetimeouts-no-persistence.sw.yaml b/test/e2e/testdata/workflows/persistence/from_platform_with_no_persistence_required/03-sonataflow_callbackstatetimeouts-no-persistence.sw.yaml index 98bb7d5c4..1c65a4e3a 100644 --- a/test/e2e/testdata/workflows/persistence/from_platform_with_no_persistence_required/03-sonataflow_callbackstatetimeouts-no-persistence.sw.yaml +++ b/test/e2e/testdata/workflows/persistence/from_platform_with_no_persistence_required/03-sonataflow_callbackstatetimeouts-no-persistence.sw.yaml @@ -22,7 +22,7 @@ metadata: sonataflow.org/profile: gitops spec: persistence: { - migrateDBOnStartUp: true + dbMigrationStrategy: service } podTemplate: replicas: 0 diff --git a/test/testdata/platform/persistence/job_based_db_migration/pg-service/01-postgres.yaml b/test/testdata/platform/persistence/job_based_db_migration/pg-service/01-postgres.yaml new file mode 100644 index 000000000..c2905c927 --- /dev/null +++ b/test/testdata/platform/persistence/job_based_db_migration/pg-service/01-postgres.yaml @@ -0,0 +1,85 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: postgres + template: + metadata: + labels: + app.kubernetes.io/name: postgres + spec: + containers: + - name: postgres + image: postgres:13.2-alpine + imagePullPolicy: 'IfNotPresent' + ports: + - containerPort: 5432 + volumeMounts: + - name: storage + mountPath: /var/lib/postgresql/data + envFrom: + - secretRef: + name: postgres-secrets + readinessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + livenessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + resources: + limits: + memory: "256Mi" + cpu: "500m" + volumes: + - name: storage + persistentVolumeClaim: + claimName: postgres-pvc +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + selector: + app.kubernetes.io/name: postgres + ports: + - port: 5432 diff --git a/test/testdata/platform/persistence/job_based_db_migration/pg-service/kustomization.yaml b/test/testdata/platform/persistence/job_based_db_migration/pg-service/kustomization.yaml new file mode 100644 index 000000000..d4d4e50d3 --- /dev/null +++ b/test/testdata/platform/persistence/job_based_db_migration/pg-service/kustomization.yaml @@ -0,0 +1,31 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. + +resources: +- 01-postgres.yaml + +generatorOptions: + disableNameSuffixHash: true + +secretGenerator: + - name: postgres-secrets + literals: + - POSTGRES_USER=sonataflow + - POSTGRES_PASSWORD=sonataflow + - POSTGRES_DATABASE=sonataflow + - PGDATA=/var/lib/pgsql/data/userdata + +sortOptions: + order: fifo + diff --git a/test/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/01-sonataflow_platform.yaml b/test/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/01-sonataflow_platform.yaml new file mode 100644 index 000000000..7ef030055 --- /dev/null +++ b/test/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/01-sonataflow_platform.yaml @@ -0,0 +1,43 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlowPlatform +metadata: + name: sonataflow-platform +spec: + build: + config: + strategyOptions: + KanikoBuildCacheEnabled: "true" + services: + dataIndex: + enabled: true + persistence: + dbMigrationStrategy: job + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=data-index-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD + jobService: + enabled: true + persistence: + dbMigrationStrategy: job + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=jobs-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD \ No newline at end of file diff --git a/test/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/kustomization.yaml b/test/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/kustomization.yaml new file mode 100644 index 000000000..ef19095a0 --- /dev/null +++ b/test/testdata/platform/persistence/job_based_db_migration/sonataflow-platform/kustomization.yaml @@ -0,0 +1,19 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. + +resources: +- 01-sonataflow_platform.yaml + +generatorOptions: + disableNameSuffixHash: true \ No newline at end of file diff --git a/test/testdata/platform/persistence/service_based_db_migration/01-postgres.yaml b/test/testdata/platform/persistence/service_based_db_migration/01-postgres.yaml new file mode 100644 index 000000000..c2905c927 --- /dev/null +++ b/test/testdata/platform/persistence/service_based_db_migration/01-postgres.yaml @@ -0,0 +1,85 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres-pvc +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: postgres + template: + metadata: + labels: + app.kubernetes.io/name: postgres + spec: + containers: + - name: postgres + image: postgres:13.2-alpine + imagePullPolicy: 'IfNotPresent' + ports: + - containerPort: 5432 + volumeMounts: + - name: storage + mountPath: /var/lib/postgresql/data + envFrom: + - secretRef: + name: postgres-secrets + readinessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + livenessProbe: + exec: + command: ["pg_isready"] + initialDelaySeconds: 15 + timeoutSeconds: 2 + resources: + limits: + memory: "256Mi" + cpu: "500m" + volumes: + - name: storage + persistentVolumeClaim: + claimName: postgres-pvc +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/name: postgres + name: postgres +spec: + selector: + app.kubernetes.io/name: postgres + ports: + - port: 5432 diff --git a/test/testdata/platform/persistence/service_based_db_migration/02-sonataflow_platform.yaml b/test/testdata/platform/persistence/service_based_db_migration/02-sonataflow_platform.yaml new file mode 100644 index 000000000..f9098f025 --- /dev/null +++ b/test/testdata/platform/persistence/service_based_db_migration/02-sonataflow_platform.yaml @@ -0,0 +1,53 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. +apiVersion: sonataflow.org/v1alpha08 +kind: SonataFlowPlatform +metadata: + name: sonataflow-platform +spec: + build: + config: + strategyOptions: + KanikoBuildCacheEnabled: "true" + services: + dataIndex: + enabled: true + persistence: + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=data-index-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD + podTemplate: + initContainers: + - name: init-postgres + image: registry.access.redhat.com/ubi9/ubi-micro:latest + imagePullPolicy: IfNotPresent + command: [ 'sh', '-c', 'until (echo 1 > /dev/tcp/postgres.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local/5432) >/dev/null 2>&1; do echo "Waiting for postgres server"; sleep 3; done;' ] + jobService: + enabled: true + persistence: + postgresql: + jdbcUrl: jdbc:postgresql://postgres:5432/sonataflow?currentSchema=jobs-service + secretRef: + name: postgres-secrets + userKey: POSTGRES_USER + passwordKey: POSTGRES_PASSWORD + podTemplate: + initContainers: + - name: init-postgres + image: registry.access.redhat.com/ubi9/ubi-micro:latest + imagePullPolicy: IfNotPresent + command: [ 'sh', '-c', 'until (echo 1 > /dev/tcp/postgres.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local/5432) >/dev/null 2>&1; do echo "Waiting for postgres server"; sleep 3; done;' ] diff --git a/test/testdata/platform/persistence/service_based_db_migration/kustomization.yaml b/test/testdata/platform/persistence/service_based_db_migration/kustomization.yaml new file mode 100644 index 000000000..d3fd127c7 --- /dev/null +++ b/test/testdata/platform/persistence/service_based_db_migration/kustomization.yaml @@ -0,0 +1,32 @@ +# Copyright 2024 Apache Software Foundation (ASF) +# +# 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. + +resources: +- 01-postgres.yaml +- 02-sonataflow_platform.yaml + +generatorOptions: + disableNameSuffixHash: true + +secretGenerator: + - name: postgres-secrets + literals: + - POSTGRES_USER=sonataflow + - POSTGRES_PASSWORD=sonataflow + - POSTGRES_DATABASE=sonataflow + - PGDATA=/var/lib/pgsql/data/userdata + +sortOptions: + order: fifo +