diff --git a/internal/dinosaur/pkg/api/dbapi/central_request_types.go b/internal/dinosaur/pkg/api/dbapi/central_request_types.go index b641d346f3..b861ccecdb 100644 --- a/internal/dinosaur/pkg/api/dbapi/central_request_types.go +++ b/internal/dinosaur/pkg/api/dbapi/central_request_types.go @@ -75,8 +75,11 @@ type CentralRequest struct { RoutesCreated bool `json:"routes_created"` // Namespace is the namespace of the provisioned central instance. // We store this in the database to ensure that old centrals whose namespace contained "owner-" information will continue to work. - Namespace string `json:"namespace"` - RoutesCreationID string `json:"routes_creation_id"` + + // Secrets stores the encrypted secrets reported for a central tenant + Secrets api.JSON `json:"secrets"` + Namespace string `json:"namespace"` + RoutesCreationID string `json:"routes_creation_id"` // DeletionTimestamp stores the timestamp of the DELETE api call for the resource. DeletionTimestamp *time.Time `json:"deletionTimestamp"` @@ -158,6 +161,16 @@ func (k *CentralRequest) SetRoutes(routes []DataPlaneCentralRoute) error { return nil } +// SetSecrets sets CentralRequest.Secret field by converting secrets to api.JSON +func (k *CentralRequest) SetSecrets(secrets map[string]string) error { + r, err := json.Marshal(secrets) + if err != nil { + return fmt.Errorf("marshalling routes into JSON: %w", err) + } + k.Secrets = r + return nil +} + // GetUIHost returns host for CLI/GUI/API connections func (k *CentralRequest) GetUIHost() string { if k.Host == "" { diff --git a/internal/dinosaur/pkg/api/dbapi/data_plane_central_status.go b/internal/dinosaur/pkg/api/dbapi/data_plane_central_status.go index 81b33976b0..6e7b6b4b5f 100644 --- a/internal/dinosaur/pkg/api/dbapi/data_plane_central_status.go +++ b/internal/dinosaur/pkg/api/dbapi/data_plane_central_status.go @@ -10,6 +10,7 @@ type DataPlaneCentralStatus struct { Conditions []DataPlaneCentralStatusCondition // Going to ignore the rest of fields (like capacity and versions) for now, until when they are needed Routes []DataPlaneCentralRoute + Secrets map[string]string CentralVersion string CentralOperatorVersion string } diff --git a/internal/dinosaur/pkg/migrations/20230616000000_add_acs_operator_version.go b/internal/dinosaur/pkg/migrations/20230616000000_add_acs_operator_version copy.go similarity index 100% rename from internal/dinosaur/pkg/migrations/20230616000000_add_acs_operator_version.go rename to internal/dinosaur/pkg/migrations/20230616000000_add_acs_operator_version copy.go diff --git a/internal/dinosaur/pkg/migrations/20230802000000_add_secrets_field_to_central_request.go.go b/internal/dinosaur/pkg/migrations/20230802000000_add_secrets_field_to_central_request.go.go new file mode 100644 index 0000000000..d8dfd93bd4 --- /dev/null +++ b/internal/dinosaur/pkg/migrations/20230802000000_add_secrets_field_to_central_request.go.go @@ -0,0 +1,63 @@ +package migrations + +// Migrations should NEVER use types from other packages. Types can change +// and then migrations run on a _new_ database will fail or behave unexpectedly. +// Instead of importing types, always re-create the type in the migration, as +// is done here, even though the same type is defined in pkg/api + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "github.com/stackrox/acs-fleet-manager/pkg/api" + "github.com/stackrox/acs-fleet-manager/pkg/db" + "gorm.io/gorm" + + "time" +) + +func addSecretFieldToCentralRequests() *gormigrate.Migration { + type CentralRequest struct { + db.Model + Region string `json:"region"` + ClusterID string `json:"cluster_id" gorm:"index"` + CloudProvider string `json:"cloud_provider"` + MultiAZ bool `json:"multi_az"` + Name string `json:"name" gorm:"index"` + Status string `json:"status" gorm:"index"` + SubscriptionID string `json:"subscription_id"` + Owner string `json:"owner" gorm:"index"` + OwnerAccountID string `json:"owner_account_id"` + OwnerUserID string `json:"owner_user_id"` + Host string `json:"host"` + OrganisationID string `json:"organisation_id" gorm:"index"` + FailedReason string `json:"failed_reason"` + PlacementID string `json:"placement_id"` + DesiredCentralVersion string `json:"desired_central_version"` + ActualCentralVersion string `json:"actual_central_version"` + DesiredCentralOperatorVersion string `json:"desired_central_operator_version"` + ActualCentralOperatorVersion string `json:"actual_central_operator_version"` + CentralUpgrading bool `json:"central_upgrading"` + CentralOperatorUpgrading bool `json:"central_operator_upgrading"` + InstanceType string `json:"instance_type"` + QuotaType string `json:"quota_type"` + Routes api.JSON `json:"routes"` + Secrets api.JSON `json:"secrets"` + RoutesCreated bool `json:"routes_created"` + Namespace string `json:"namespace"` + RoutesCreationID string `json:"routes_creation_id"` + DeletionTimestamp *time.Time `json:"deletionTimestamp"` + Central api.JSON `json:"central"` + Scanner api.JSON `json:"scanner"` + OperatorImage string `json:"operator_image"` + } + migrationID := "20230802000000" + + return &gormigrate.Migration{ + ID: migrationID, + Migrate: func(tx *gorm.DB) error { + return addColumnIfNotExists(tx, &CentralRequest{}, "secrets") + }, + Rollback: func(tx *gorm.DB) error { + return nil + }, + } +} diff --git a/internal/dinosaur/pkg/migrations/migrations.go b/internal/dinosaur/pkg/migrations/migrations.go index 339fd713f8..fff67c8476 100644 --- a/internal/dinosaur/pkg/migrations/migrations.go +++ b/internal/dinosaur/pkg/migrations/migrations.go @@ -2,6 +2,7 @@ package migrations import ( "fmt" + "github.com/go-gormigrate/gormigrate/v2" "github.com/stackrox/acs-fleet-manager/pkg/db" "gorm.io/gorm" @@ -46,6 +47,7 @@ func getMigrations() []*gormigrate.Migration { addForceReconcileToCentralRequest(), addOperatorImageFields(), removeAvailableOperatorField(), + addSecretFieldToCentralRequests(), } } diff --git a/internal/dinosaur/pkg/presenters/data_plane_dinosaur_status.go b/internal/dinosaur/pkg/presenters/data_plane_dinosaur_status.go index 2ed3f1add2..e1b0789f5d 100644 --- a/internal/dinosaur/pkg/presenters/data_plane_dinosaur_status.go +++ b/internal/dinosaur/pkg/presenters/data_plane_dinosaur_status.go @@ -29,10 +29,12 @@ func ConvertDataPlaneDinosaurStatus(status map[string]private.DataPlaneCentralSt }) } } + res = append(res, &dbapi.DataPlaneCentralStatus{ CentralClusterID: k, Conditions: c, Routes: routes, + Secrets: v.Secrets, // pragma: allowlist secret }) } diff --git a/internal/dinosaur/pkg/services/data_plane_dinosaur.go b/internal/dinosaur/pkg/services/data_plane_dinosaur.go index f057259a09..3621278d21 100644 --- a/internal/dinosaur/pkg/services/data_plane_dinosaur.go +++ b/internal/dinosaur/pkg/services/data_plane_dinosaur.go @@ -75,7 +75,7 @@ func (d *dataPlaneCentralService) UpdateDataPlaneCentralService(ctx context.Cont case statusReady: // Only store the routes (and create them) when the Dinosaurs are ready, as by the time they are ready, // the routes should definitely be there. - e = d.persistCentralRoutes(dinosaur, ks, cluster) + e = d.persistCentralValues(dinosaur, ks, cluster) if e == nil { e = d.setCentralClusterReady(dinosaur) } @@ -217,7 +217,23 @@ func (d *dataPlaneCentralService) checkCentralRequestCurrentStatus(centralReques return matchStatus, nil } -func (d *dataPlaneCentralService) persistCentralRoutes(centralRequest *dbapi.CentralRequest, centralStatus *dbapi.DataPlaneCentralStatus, cluster *api.Cluster) *serviceError.ServiceError { +func (d *dataPlaneCentralService) persistCentralValues(centralRequest *dbapi.CentralRequest, centralStatus *dbapi.DataPlaneCentralStatus, cluster *api.Cluster) *serviceError.ServiceError { + if err := d.addRoutesToRequest(centralRequest, centralStatus, cluster); err != nil { + return err + } + + if err := d.addSecretsToRequest(centralRequest, centralStatus, cluster); err != nil { + return err + } + + if err := d.dinosaurService.Update(centralRequest); err != nil { + return serviceError.NewWithCause(err.Code, err, "failed to update routes for central cluster %s", centralRequest.ID) + } + + return nil +} + +func (d *dataPlaneCentralService) addRoutesToRequest(centralRequest *dbapi.CentralRequest, centralStatus *dbapi.DataPlaneCentralStatus, cluster *api.Cluster) *serviceError.ServiceError { if centralRequest.Routes != nil { logger.Logger.V(10).Infof("skip persisting routes for Central %s as they are already stored", centralRequest.ID) return nil @@ -238,9 +254,20 @@ func (d *dataPlaneCentralService) persistCentralRoutes(centralRequest *dbapi.Cen return serviceError.NewWithCause(serviceError.ErrorGeneral, err, "failed to set routes for central %s", centralRequest.ID) } - if err := d.dinosaurService.Update(centralRequest); err != nil { - return serviceError.NewWithCause(err.Code, err, "failed to update routes for central cluster %s", centralRequest.ID) + return nil +} + +func (d *dataPlaneCentralService) addSecretsToRequest(centralRequest *dbapi.CentralRequest, centralStatus *dbapi.DataPlaneCentralStatus, cluster *api.Cluster) *serviceError.ServiceError { + if centralRequest.Secrets != nil { // pragma: allowlist secret + logger.Logger.V(10).Infof("skip persisting secrets for Central %s as they are already stored", centralRequest.ID) + return nil } + logger.Logger.Infof("store secret information for central %s", centralRequest.ID) + + if err := centralRequest.SetSecrets(centralStatus.Secrets); err != nil { + return serviceError.NewWithCause(serviceError.ErrorGeneral, err, "failed to set secrets for central %s", centralRequest.ID) + } + return nil }