From 944fd442b45c487423f74c27e2d319cc4eeb7857 Mon Sep 17 00:00:00 2001 From: Bryttanie <28575816+xbhouse@users.noreply.github.com> Date: Thu, 16 Jan 2025 13:27:56 -0500 Subject: [PATCH] HMS-5056: add layered RH repos with feature name (#941) * HMS-5056: add layered RH repos with feature name * store feature_name in db * add index --- configs/config.yaml.example | 1 + db/migrations.latest | 2 +- ..._add_feature_name_to_repo_configs.down.sql | 6 ++ ...07_add_feature_name_to_repo_configs.up.sql | 8 ++ deployments/deployment.yaml | 4 + pkg/config/config.go | 8 +- pkg/dao/interfaces.go | 2 +- pkg/dao/repository_configs.go | 5 +- pkg/dao/repository_configs_mock.go | 82 ++++++++++--------- pkg/dao/repository_configs_test.go | 4 +- pkg/external_repos/redhat_repos.go | 8 +- pkg/external_repos/redhat_repos.json | 82 +++++++++++++++---- pkg/models/repository_configuration.go | 1 + 13 files changed, 149 insertions(+), 64 deletions(-) create mode 100644 db/migrations/20250115112007_add_feature_name_to_repo_configs.down.sql create mode 100644 db/migrations/20250115112007_add_feature_name_to_repo_configs.up.sql diff --git a/configs/config.yaml.example b/configs/config.yaml.example index 6ed5571c9..b77950899 100644 --- a/configs/config.yaml.example +++ b/configs/config.yaml.example @@ -62,6 +62,7 @@ options: enable_notifications: true template_event_topic: "platform.content-sources.template" snapshot_retain_days_limit: 365 + feature_filter: ["RHEL-OS-x86_64"] metrics: path: "/metrics" port: 9000 diff --git a/db/migrations.latest b/db/migrations.latest index d33ce6d06..9135ca16a 100644 --- a/db/migrations.latest +++ b/db/migrations.latest @@ -1 +1 @@ -20241203143614 +20250115112007 diff --git a/db/migrations/20250115112007_add_feature_name_to_repo_configs.down.sql b/db/migrations/20250115112007_add_feature_name_to_repo_configs.down.sql new file mode 100644 index 000000000..657600350 --- /dev/null +++ b/db/migrations/20250115112007_add_feature_name_to_repo_configs.down.sql @@ -0,0 +1,6 @@ +BEGIN; + +DROP INDEX IF EXISTS repo_config_feature_name; +ALTER TABLE repository_configurations DROP COLUMN feature_name; + +COMMIT; \ No newline at end of file diff --git a/db/migrations/20250115112007_add_feature_name_to_repo_configs.up.sql b/db/migrations/20250115112007_add_feature_name_to_repo_configs.up.sql new file mode 100644 index 000000000..3e4af87b9 --- /dev/null +++ b/db/migrations/20250115112007_add_feature_name_to_repo_configs.up.sql @@ -0,0 +1,8 @@ +BEGIN; + +ALTER TABLE repository_configurations + ADD COLUMN IF NOT EXISTS feature_name VARCHAR (255) DEFAULT NULL; + +CREATE INDEX IF NOT EXISTS repo_config_feature_name ON repository_configurations(feature_name); + +COMMIT; \ No newline at end of file diff --git a/deployments/deployment.yaml b/deployments/deployment.yaml index 735e5e32e..df8409a8d 100644 --- a/deployments/deployment.yaml +++ b/deployments/deployment.yaml @@ -134,6 +134,8 @@ objects: value: ${OPTIONS_ENABLE_NOTIFICATIONS} - name: OPTIONS_REPOSITORY_IMPORT_FILTER value: ${OPTIONS_REPOSITORY_IMPORT_FILTER} + - name: OPTIONS_FEATURE_FILTER + value: ${OPTIONS_FEATURE_FILTER} - name: TASKING_WORKER_COUNT value: ${TASKING_WORKER_COUNT} - name: CLIENTS_CANDLEPIN_SERVER @@ -860,3 +862,5 @@ parameters: description: Number of task workers running within a single worker process - name: CLIENTS_CANDLEPIN_SERVER default: '' + - name: OPTIONS_FEATURE_FILTER + description: Comma separated list of features that determine which repos to import diff --git a/pkg/config/config.go b/pkg/config/config.go index e0297319b..3e72d3d74 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -175,8 +175,9 @@ type Options struct { // url (https://servername) to access the api, used to reference gpg keys // Supports partial hostnames (i.e. http://.server.example.com). // If this is encountered (and clowder is used), it will prepend the envName from clowder - ExternalURL string `mapstructure:"external_url"` - SnapshotRetainDaysLimit int `mapstructure:"snapshot_retain_days_limit"` + ExternalURL string `mapstructure:"external_url"` + SnapshotRetainDaysLimit int `mapstructure:"snapshot_retain_days_limit"` + FeatureFilter []string `mapstructure:"feature_filter"` // Used to control which repos are imported based on feature name } type Metrics struct { @@ -197,6 +198,8 @@ const ( DefaultIntrospectApiTimeLimitSec = 30 ) +var featureFilter = [...]string{"RHEL-OS-x86_64"} + var LoadedConfig Configuration func Get() *Configuration { @@ -243,6 +246,7 @@ func setDefaults(v *viper.Viper) { v.SetDefault("options.enable_notifications", false) v.SetDefault("options.template_event_topic", "platform.content-sources.template") v.SetDefault("options.repository_import_filter", "") + v.SetDefault("options.feature_filter", featureFilter) v.SetDefault("options.external_url", "http://pulp.content:8000") v.SetDefault("options.snapshot_retain_days_limit", 365) v.SetDefault("logging.level", "info") diff --git a/pkg/dao/interfaces.go b/pkg/dao/interfaces.go index 6778ea5cf..3bd034d2c 100644 --- a/pkg/dao/interfaces.go +++ b/pkg/dao/interfaces.go @@ -76,7 +76,7 @@ type RepositoryConfigDao interface { InternalOnly_FetchRepoConfigsForRepoUUID(ctx context.Context, uuid string) []api.RepositoryResponse UpdateLastSnapshotTask(ctx context.Context, taskUUID string, orgID string, repoUUID string) error UpdateLastSnapshot(ctx context.Context, orgID string, repoConfigUUID string, snapUUID string) error - InternalOnly_RefreshRedHatRepo(ctx context.Context, request api.RepositoryRequest, label string) (*api.RepositoryResponse, error) + InternalOnly_RefreshRedHatRepo(ctx context.Context, request api.RepositoryRequest, label string, featureName string) (*api.RepositoryResponse, error) FetchWithoutOrgID(ctx context.Context, uuid string) (api.RepositoryResponse, error) BulkExport(ctx context.Context, orgID string, reposToExport api.RepositoryExportRequest) ([]api.RepositoryExportResponse, error) BulkImport(ctx context.Context, reposToImport []api.RepositoryRequest) ([]api.RepositoryImportResponse, []error) diff --git a/pkg/dao/repository_configs.go b/pkg/dao/repository_configs.go index 71b084209..aec9c904e 100644 --- a/pkg/dao/repository_configs.go +++ b/pkg/dao/repository_configs.go @@ -1247,7 +1247,7 @@ func isTimeout(err error) bool { return false } -func (r repositoryConfigDaoImpl) InternalOnly_RefreshRedHatRepo(ctx context.Context, request api.RepositoryRequest, label string) (*api.RepositoryResponse, error) { +func (r repositoryConfigDaoImpl) InternalOnly_RefreshRedHatRepo(ctx context.Context, request api.RepositoryRequest, label string, featureName string) (*api.RepositoryResponse, error) { newRepoConfig := models.RepositoryConfiguration{} newRepo := models.Repository{} @@ -1256,6 +1256,7 @@ func (r repositoryConfigDaoImpl) InternalOnly_RefreshRedHatRepo(ctx context.Cont newRepoConfig.OrgID = config.RedHatOrg newRepoConfig.Label = label + newRepoConfig.FeatureName = featureName newRepo.Origin = config.OriginRedHat newRepo.Public = true // Ensure all RH repos can be searched @@ -1278,7 +1279,7 @@ func (r repositoryConfigDaoImpl) InternalOnly_RefreshRedHatRepo(ctx context.Cont result = r.db.WithContext(ctx).Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "repository_uuid"}, {Name: "org_id"}}, TargetWhere: clause.Where{Exprs: []clause.Expression{clause.Eq{Column: "deleted_at", Value: nil}}}, - DoUpdates: clause.AssignmentColumns([]string{"name", "arch", "versions", "gpg_key", "label"})}). + DoUpdates: clause.AssignmentColumns([]string{"name", "arch", "versions", "gpg_key", "label", "feature_name"})}). Create(&newRepoConfig) if result.Error != nil { return nil, result.Error diff --git a/pkg/dao/repository_configs_mock.go b/pkg/dao/repository_configs_mock.go index 858f68515..e3302f27d 100644 --- a/pkg/dao/repository_configs_mock.go +++ b/pkg/dao/repository_configs_mock.go @@ -6,8 +6,10 @@ import ( context "context" api "github.com/content-services/content-sources-backend/pkg/api" - models "github.com/content-services/content-sources-backend/pkg/models" + mock "github.com/stretchr/testify/mock" + + models "github.com/content-services/content-sources-backend/pkg/models" ) // MockRepositoryConfigDao is an autogenerated mock type for the RepositoryConfigDao type @@ -309,39 +311,9 @@ func (_m *MockRepositoryConfigDao) InternalOnly_ListReposToSnapshot(ctx context. return r0, r1 } -// InternalOnly_ListReposWithOutdatedSnapshots provides a mock function with given fields: ctx, olderThanDays -func (_m *MockRepositoryConfigDao) ListReposWithOutdatedSnapshots(ctx context.Context, olderThanDays int) ([]models.RepositoryConfiguration, error) { - ret := _m.Called(ctx, olderThanDays) - - if len(ret) == 0 { - panic("no return value specified for ListReposWithOutdatedSnapshots") - } - - var r0 []models.RepositoryConfiguration - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, int) ([]models.RepositoryConfiguration, error)); ok { - return rf(ctx, olderThanDays) - } - if rf, ok := ret.Get(0).(func(context.Context, int) []models.RepositoryConfiguration); ok { - r0 = rf(ctx, olderThanDays) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]models.RepositoryConfiguration) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, int) error); ok { - r1 = rf(ctx, olderThanDays) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// InternalOnly_RefreshRedHatRepo provides a mock function with given fields: ctx, request, label -func (_m *MockRepositoryConfigDao) InternalOnly_RefreshRedHatRepo(ctx context.Context, request api.RepositoryRequest, label string) (*api.RepositoryResponse, error) { - ret := _m.Called(ctx, request, label) +// InternalOnly_RefreshRedHatRepo provides a mock function with given fields: ctx, request, label, featureName +func (_m *MockRepositoryConfigDao) InternalOnly_RefreshRedHatRepo(ctx context.Context, request api.RepositoryRequest, label string, featureName string) (*api.RepositoryResponse, error) { + ret := _m.Called(ctx, request, label, featureName) if len(ret) == 0 { panic("no return value specified for InternalOnly_RefreshRedHatRepo") @@ -349,19 +321,19 @@ func (_m *MockRepositoryConfigDao) InternalOnly_RefreshRedHatRepo(ctx context.Co var r0 *api.RepositoryResponse var r1 error - if rf, ok := ret.Get(0).(func(context.Context, api.RepositoryRequest, string) (*api.RepositoryResponse, error)); ok { - return rf(ctx, request, label) + if rf, ok := ret.Get(0).(func(context.Context, api.RepositoryRequest, string, string) (*api.RepositoryResponse, error)); ok { + return rf(ctx, request, label, featureName) } - if rf, ok := ret.Get(0).(func(context.Context, api.RepositoryRequest, string) *api.RepositoryResponse); ok { - r0 = rf(ctx, request, label) + if rf, ok := ret.Get(0).(func(context.Context, api.RepositoryRequest, string, string) *api.RepositoryResponse); ok { + r0 = rf(ctx, request, label, featureName) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*api.RepositoryResponse) } } - if rf, ok := ret.Get(1).(func(context.Context, api.RepositoryRequest, string) error); ok { - r1 = rf(ctx, request, label) + if rf, ok := ret.Get(1).(func(context.Context, api.RepositoryRequest, string, string) error); ok { + r1 = rf(ctx, request, label, featureName) } else { r1 = ret.Error(1) } @@ -404,6 +376,36 @@ func (_m *MockRepositoryConfigDao) List(ctx context.Context, orgID string, pagin return r0, r1, r2 } +// ListReposWithOutdatedSnapshots provides a mock function with given fields: ctx, olderThanDays +func (_m *MockRepositoryConfigDao) ListReposWithOutdatedSnapshots(ctx context.Context, olderThanDays int) ([]models.RepositoryConfiguration, error) { + ret := _m.Called(ctx, olderThanDays) + + if len(ret) == 0 { + panic("no return value specified for ListReposWithOutdatedSnapshots") + } + + var r0 []models.RepositoryConfiguration + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, int) ([]models.RepositoryConfiguration, error)); ok { + return rf(ctx, olderThanDays) + } + if rf, ok := ret.Get(0).(func(context.Context, int) []models.RepositoryConfiguration); ok { + r0 = rf(ctx, olderThanDays) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]models.RepositoryConfiguration) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, int) error); ok { + r1 = rf(ctx, olderThanDays) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // SavePublicRepos provides a mock function with given fields: ctx, urls func (_m *MockRepositoryConfigDao) SavePublicRepos(ctx context.Context, urls []string) error { ret := _m.Called(ctx, urls) diff --git a/pkg/dao/repository_configs_test.go b/pkg/dao/repository_configs_test.go index 6726d8c6a..e4de3de9c 100644 --- a/pkg/dao/repository_configs_test.go +++ b/pkg/dao/repository_configs_test.go @@ -2633,7 +2633,7 @@ func (suite *RepositoryConfigSuite) TestRefreshRedHatRepo() { ContentType: utils.Ptr(config.ContentTypeRpm), Snapshot: utils.Ptr(true), } - response, err := dao.InternalOnly_RefreshRedHatRepo(context.Background(), rhRepo, "another-label") + response, err := dao.InternalOnly_RefreshRedHatRepo(context.Background(), rhRepo, "another-label", "test-feature") assert.NoError(suite.T(), err) assert.NotEmpty(suite.T(), response.UUID) @@ -2644,7 +2644,7 @@ func (suite *RepositoryConfigSuite) TestRefreshRedHatRepo() { // Change the name rhRepo.Name = utils.Ptr("another name") - response, err = dao.InternalOnly_RefreshRedHatRepo(context.Background(), rhRepo, "some-label") + response, err = dao.InternalOnly_RefreshRedHatRepo(context.Background(), rhRepo, "some-label", "test-feature") assert.NoError(suite.T(), err) assert.Equal(suite.T(), *rhRepo.Name, response.Name) diff --git a/pkg/external_repos/redhat_repos.go b/pkg/external_repos/redhat_repos.go index e34a2cfff..f98c0809e 100644 --- a/pkg/external_repos/redhat_repos.go +++ b/pkg/external_repos/redhat_repos.go @@ -27,6 +27,7 @@ type RedHatRepo struct { Selector string `json:"selector"` GpgKey string `json:"gpg_key"` Label string `json:"content_label"` + FeatureName string `json:"feature_name"` } func (rhr RedHatRepo) ToRepositoryRequest() api.RepositoryRequest { @@ -63,7 +64,7 @@ func (rhr *RedHatRepoImporter) LoadAndSave(ctx context.Context) error { } for _, r := range repos { r.GpgKey = gpgKey - _, err = rhr.daoReg.RepositoryConfig.InternalOnly_RefreshRedHatRepo(ctx, r.ToRepositoryRequest(), r.Label) + _, err = rhr.daoReg.RepositoryConfig.InternalOnly_RefreshRedHatRepo(ctx, r.ToRepositoryRequest(), r.Label, r.FeatureName) if err != nil { return err } @@ -96,9 +97,12 @@ func (rhr *RedHatRepoImporter) loadFromFile() ([]RedHatRepo, error) { } filteredRepos := []RedHatRepo{} filter := config.Get().Options.RepositoryImportFilter + features := config.Get().Options.FeatureFilter for _, repo := range repos { if filter == "" || repo.Selector == filter { - filteredRepos = append(filteredRepos, repo) + if utils.Contains(features, repo.FeatureName) { + filteredRepos = append(filteredRepos, repo) + } } } return filteredRepos, nil diff --git a/pkg/external_repos/redhat_repos.json b/pkg/external_repos/redhat_repos.json index 5c33971f4..923473855 100644 --- a/pkg/external_repos/redhat_repos.json +++ b/pkg/external_repos/redhat_repos.json @@ -5,7 +5,8 @@ "content_label": "ansible-2-for-rhel-8-x86_64-rpms", "arch": "x86_64", "distribution_version": "8", - "selector": "small" + "selector": "small", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat Enterprise Linux 8 for x86_64 - AppStream (RPMs)", @@ -13,7 +14,8 @@ "content_label": "rhel-8-for-x86_64-appstream-rpms", "arch": "x86_64", "distribution_version": "8", - "selector": "rhel8" + "selector": "rhel8", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat Enterprise Linux 8 for x86_64 - BaseOS (RPMs)", @@ -21,7 +23,8 @@ "url": "https://cdn.redhat.com/content/dist/rhel8/8/x86_64/baseos/os", "arch": "x86_64", "distribution_version": "8", - "selector": "rhel8" + "selector": "rhel8", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat Enterprise Linux 9 for x86_64 - AppStream (RPMs)", @@ -29,7 +32,8 @@ "url": "https://cdn.redhat.com/content/dist/rhel9/9/x86_64/appstream/os", "arch": "x86_64", "distribution_version": "9", - "selector": "rhel9" + "selector": "rhel9", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat Enterprise Linux 9 for x86_64 - BaseOS (RPMs)", @@ -37,7 +41,8 @@ "url": "https://cdn.redhat.com/content/dist/rhel9/9/x86_64/baseos/os", "arch": "x86_64", "distribution_version": "9", - "selector": "rhel9" + "selector": "rhel9", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat CodeReady Linux Builder for RHEL 9 x86_64 (RPMs)", @@ -45,35 +50,40 @@ "url": "https://cdn.redhat.com/content/dist/rhel9/9/x86_64/codeready-builder/os", "arch": "x86_64", "distribution_version": "9", - "selector":"rhel9" + "selector": "rhel9", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat CodeReady Linux Builder for RHEL 8 x86_64 (RPMs)", "content_label": "codeready-builder-for-rhel-8-x86_64-rpms", "url": "https://cdn.redhat.com/content/dist/rhel8/8/x86_64/codeready-builder/os", "arch": "x86_64", - "distribution_version": "8" + "distribution_version": "8", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat Ansible Engine 2 for RHEL 8 ARM 64 (RPMs)", "url": "https://cdn.redhat.com/content/dist/layered/rhel8/aarch64/ansible/2/os", "content_label": "ansible-2-for-rhel-8-aarch64-rpms", "arch": "aarch64", - "distribution_version": "8" + "distribution_version": "8", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat Enterprise Linux 8 for ARM 64 - AppStream (RPMs)", "url": "https://cdn.redhat.com/content/dist/rhel8/8/aarch64/appstream/os", "content_label": "rhel-8-for-aarch64-appstream-rpms", "arch": "aarch64", - "distribution_version": "8" + "distribution_version": "8", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat Enterprise Linux 8 for ARM 64 - BaseOS (RPMs)", "content_label": "rhel-8-for-aarch64-baseos-rpms", "url": "https://cdn.redhat.com/content/dist/rhel8/8/aarch64/baseos/os", "arch": "aarch64", - "distribution_version": "8" + "distribution_version": "8", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat Enterprise Linux 9 for ARM 64 - AppStream (RPMs)", @@ -81,7 +91,8 @@ "url": "https://cdn.redhat.com/content/dist/rhel9/9/aarch64/appstream/os", "arch": "aarch64", "distribution_version": "9", - "selector": "arm" + "selector": "arm", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat Enterprise Linux 9 for ARM 64 - BaseOS (RPMs)", @@ -89,7 +100,8 @@ "url": "https://cdn.redhat.com/content/dist/rhel9/9/aarch64/baseos/os", "arch": "aarch64", "distribution_version": "9", - "selector": "arm" + "selector": "arm", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat CodeReady Linux Builder for RHEL 9 ARM 64 (RPMs)", @@ -97,13 +109,55 @@ "url": "https://cdn.redhat.com/content/dist/rhel9/9/aarch64/codeready-builder/os", "arch": "aarch64", "distribution_version": "9", - "selector": "arm" + "selector": "arm", + "feature_name": "RHEL-OS-x86_64" }, { "name": "Red Hat CodeReady Linux Builder for RHEL 8 ARM 64 (RPMs)", "content_label": "codeready-builder-for-rhel-8-aarch64-rpms", "url": "https://cdn.redhat.com/content/dist/rhel8/8/aarch64/codeready-builder/os", "arch": "aarch64", - "distribution_version": "8" + "distribution_version": "8", + "feature_name": "RHEL-OS-x86_64" + }, + { + "name": "Red Hat Enterprise Linux 8 for x86_64 - High Availability (RPMs)", + "content_label": "rhel-8-for-x86_64-highavailability-rpms", + "url": "https://cdn.redhat.com/content/dist/rhel8/8/x86_64/highavailability/os", + "arch": "x86_64", + "distribution_version": "8", + "feature_name": "RHEL-HA-x86_64" + }, + { + "name": "Red Hat Enterprise Linux 9 for x86_64 - High Availability (RPMs)", + "content_label": "rhel-9-for-x86_64-highavailability-rpms", + "url": "https://cdn.redhat.com/content/dist/rhel9/9/x86_64/highavailability/os", + "arch": "x86_64", + "distribution_version": "9", + "feature_name": "RHEL-HA-x86_64" + }, + { + "name": "Ironic content for Red Hat OpenShift Container Platform 4.16 for RHEL 9 x86_64 (RPMs)", + "content_label": "rhocp-ironic-4.16-for-rhel-9-x86_64-rpms", + "url": "https://cdn.redhat.com/content/dist/layered/rhel9/x86_64/rhocp-ironic/4.16/os", + "arch": "x86_64", + "distribution_version": "9", + "feature_name": "OPENSHIFT-OCP-x86_64" + }, + { + "name": "Red Hat OpenShift Container Platform 4.16 for RHEL 9 x86_64 (RPMs)", + "content_label": "rhocp-4.16-for-rhel-9-x86_64-rpms", + "url": "https://cdn.redhat.com/content/dist/layered/rhel9/x86_64/rhocp/4.16/os", + "arch": "x86_64", + "distribution_version": "9", + "feature_name": "OPENSHIFT-OCP-x86_64" + }, + { + "name": "Red Hat OpenShift Container Platform 4.16 for RHEL 8 x86_64 (RPMs)", + "content_label": "rhocp-4.16-for-rhel-8-x86_64-rpms", + "url": "https://cdn.redhat.com/content/dist/layered/rhel8/x86_64/rhocp/4.16/os", + "arch": "x86_64", + "distribution_version": "8", + "feature_name": "OPENSHIFT-OCP-x86_64" } ] \ No newline at end of file diff --git a/pkg/models/repository_configuration.go b/pkg/models/repository_configuration.go index 839b171bf..856fc38ec 100644 --- a/pkg/models/repository_configuration.go +++ b/pkg/models/repository_configuration.go @@ -33,6 +33,7 @@ type RepositoryConfiguration struct { LastSnapshot *Snapshot `json:"last_snapshot,omitempty" gorm:"foreignKey:last_snapshot_uuid"` LastSnapshotTaskUUID string `json:"last_snapshot_task_uuid" gorm:"default:null"` LastSnapshotTask *TaskInfo `json:"last_snapshot_task" gorm:"foreignKey:last_snapshot_task_uuid"` + FeatureName string `json:"feature_name" gorm:"default:null"` } // When updating a model with gorm, we want to explicitly update any field that is set to