Loading configuration/configuration.go +67 −1 Original line number Diff line number Diff line Loading @@ -399,10 +399,67 @@ type DatabaseMetrics struct { LeaseDuration time.Duration `yaml:"leaseduration,omitempty"` } // DatabaseEnabled is an enum allowing the user to set various policies for // the registry database enabling behavior. type DatabaseEnabled int const ( // DatabaseEnabledFalse the database is explicitly disabled. DatabaseEnabledFalse DatabaseEnabled = iota // DatabaseEnabledTrue the database is explicitly enabled. DatabaseEnabledTrue // DatabaseEnabledPrefer the database remains enabled if already enabled OR // there is no data detected in the container registry (fresh install). DatabaseEnabledPrefer ) var databaseEnabledStrings = map[DatabaseEnabled]string{ DatabaseEnabledFalse: "false", DatabaseEnabledTrue: "true", DatabaseEnabledPrefer: "prefer", } var stringToDatabaseEnabled = map[string]DatabaseEnabled{ "false": DatabaseEnabledFalse, "true": DatabaseEnabledTrue, "prefer": DatabaseEnabledPrefer, } func (d *DatabaseEnabled) UnmarshalYAML(unmarshal func(any) error) error { var s string if err := unmarshal(&s); err == nil { if enum, ok := stringToDatabaseEnabled[s]; ok { *d = enum return nil } } // Convert bools to enums for backwards compatibility. var b bool if err := unmarshal(&b); err == nil { if b { *d = DatabaseEnabledTrue return nil } *d = DatabaseEnabledFalse return nil } return fmt.Errorf("invalid database.enabled value: %q, valid values: false, true, prefer", s) } func (d DatabaseEnabled) String() string { return databaseEnabledStrings[d] } func (d DatabaseEnabled) MarshalYAML() (any, error) { return d.String(), nil } // Database is the configuration for the registry's metadata database type Database struct { // Enabled can be used to enable or bypass the metadata database Enabled bool `yaml:"enabled"` Enabled DatabaseEnabled `yaml:"enabled"` // Host is the database server hostname Host string `yaml:"host"` // Port is the database server port Loading Loading @@ -452,6 +509,15 @@ type Database struct { Metrics DatabaseMetrics `yaml:"metrics,omitempty"` } // IsEnabled returns true if the database is in prefer mode or explicitly enabled. func (d Database) IsEnabled() bool { return d.Enabled != DatabaseEnabledFalse } func (d Database) IsPrefer() bool { return d.Enabled == DatabaseEnabledPrefer } // BackgroundMigrations represents the configuration for the asynchronous batched background migrations in the registry. type BackgroundMigrations struct { // Enabled can be used to enable or bypass the asynchronous batched background migration process Loading configuration/configuration_test.go +47 −4 Original line number Diff line number Diff line Loading @@ -55,7 +55,7 @@ var configStruct = Configuration{ }, }, Database: Database{ Enabled: true, Enabled: DatabaseEnabledTrue, Host: "localhost", Port: 5432, User: "postgres", Loading Loading @@ -333,7 +333,7 @@ func (s *ConfigSuite) TestParseSimple() { func (s *ConfigSuite) TestParseInmemory() { s.expectedConfig.Storage = Storage{"inmemory": Parameters{}} s.expectedConfig.Database = Database{ Enabled: true, Enabled: DatabaseEnabledTrue, BackgroundMigrations: BackgroundMigrations{ Enabled: true, MaxJobRetries: 1, Loading Loading @@ -720,7 +720,7 @@ storage: inmemory // TestParseWithDifferentEnvDatabase validates that environment variables properly override database parameters func (s *ConfigSuite) TestParseWithDifferentEnvDatabase() { expected := Database{ Enabled: true, Enabled: DatabaseEnabledTrue, Host: "127.0.0.1", Port: 1234, User: "user", Loading @@ -743,7 +743,7 @@ func (s *ConfigSuite) TestParseWithDifferentEnvDatabase() { } s.expectedConfig.Database = expected err := os.Setenv("REGISTRY_DATABASE_DISABLE", strconv.FormatBool(expected.Enabled)) err := os.Setenv("REGISTRY_DATABASE_DISABLE", strconv.FormatBool(expected.IsEnabled())) require.NoError(s.T(), err) err = os.Setenv("REGISTRY_DATABASE_HOST", expected.Host) require.NoError(s.T(), err) Loading Loading @@ -3242,3 +3242,46 @@ database: testParameter(t, yml, "REGISTRY_DATABASE_METRICS_LEASEDURATION", tt, validator) } func TestParseDatabaseEnabled(t *testing.T) { yml := ` version: 0.1 storage: inmemory database: enabled: %s ` tt := []parameterTest{ { name: "string true", value: "true", want: DatabaseEnabledTrue, }, { name: "string false", value: "false", want: DatabaseEnabledFalse, }, { name: "prefer", value: "prefer", want: DatabaseEnabledPrefer, }, { name: "typo", value: "perfer", wantErr: true, err: fmt.Sprintf("invalid database.enabled value: %q, valid values: false, true, prefer", "perfer"), }, { name: "default", value: "", want: DatabaseEnabledFalse, }, } validator := func(t *testing.T, want any, got *Configuration) { require.Equal(t, want, got.Database.Enabled) } testParameter(t, yml, "REGISTRY_DATABASE_ENABLED", tt, validator) } registry/cli_test.go +1 −1 Original line number Diff line number Diff line Loading @@ -919,7 +919,7 @@ func generateDBConfig(t *testing.T, dbHost string, dbPort int, dbUser, dbPasswor config := configuration.Configuration{ Version: "0.1", Database: configuration.Database{ Enabled: true, Enabled: configuration.DatabaseEnabledTrue, Host: dbHost, Port: dbPort, User: dbUser, Loading registry/handlers/api_conformance_test.go +4 −4 Original line number Diff line number Diff line Loading @@ -613,7 +613,7 @@ func baseURLAuth(t *testing.T, opts ...configOpt) { } // The v1 API base route returns 404s if the database is not enabled. if env.config.Database.Enabled { if env.config.Database.IsEnabled() { gitLabV1Base, err := env.builder.BuildGitlabV1BaseURL() require.NoError(t, err) Loading Loading @@ -650,7 +650,7 @@ func baseURLAuth(t *testing.T, opts ...configOpt) { if test.wantExtFeatures { require.Equal(t, version.ExtFeatures, resp.Header.Get("Gitlab-Container-Registry-Features")) require.Equal(t, strconv.FormatBool(env.config.Database.Enabled), resp.Header.Get("Gitlab-Container-Registry-Database-Enabled")) require.Equal(t, strconv.FormatBool(env.config.Database.IsEnabled()), resp.Header.Get("Gitlab-Container-Registry-Database-Enabled")) } else { require.Empty(t, resp.Header.Get("Gitlab-Container-Registry-Features")) } Loading Loading @@ -707,7 +707,7 @@ func baseURLPrefix(t *testing.T, opts ...configOpt) { defer resp.Body.Close() // The V1 API base route returns 404s if the database is not enabled. if env.config.Database.Enabled { if env.config.Database.IsEnabled() { require.Equal(t, http.StatusOK, resp.StatusCode) require.Equal(t, "application/json", resp.Header.Get("Content-Type")) require.Equal(t, "2", resp.Header.Get("Content-Length")) Loading Loading @@ -3108,7 +3108,7 @@ func tagsGet(t *testing.T, opts ...configOpt) { for _, test := range tt { t.Run(test.name, func(t *testing.T) { if !test.runWithoutDBEnabled && !env.config.Database.Enabled { if !test.runWithoutDBEnabled && !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } Loading registry/handlers/api_integration_test.go +11 −11 Original line number Diff line number Diff line Loading @@ -63,12 +63,12 @@ func TestBlobAPI_Get_BlobNotInDatabase(t *testing.T) { env := newTestEnv(t) defer env.Shutdown() if !env.config.Database.Enabled { if !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } // Disable the database so writes only go to the filesytem. env.config.Database.Enabled = false env.config.Database.Enabled = configuration.DatabaseEnabledFalse // create repository with a layer args := makeBlobArgs(t) Loading @@ -76,7 +76,7 @@ func TestBlobAPI_Get_BlobNotInDatabase(t *testing.T) { blobURL := pushLayer(t, env.builder, args.imageName, args.layerDigest, uploadURLBase, args.layerFile) // Enable the database again so that reads first check the database. env.config.Database.Enabled = true env.config.Database.Enabled = configuration.DatabaseEnabledTrue // fetch layer res, err := http.Get(blobURL) Loading Loading @@ -836,7 +836,7 @@ func TestManifestAPI_Put_Schema2LayersNotAssociatedWithRepositoryButArePresentIn tagName := "schema2missinglayerstag" repoPath := "schema2/missinglayers" if !env.config.Database.Enabled { if !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } Loading Loading @@ -875,13 +875,13 @@ func TestManifestAPI_Put_Schema2LayersNotAssociatedWithRepositoryButArePresentIn pushLayer(t, env.builder, fakeRepoRef, dgst, uploadURLBase, bytes.NewReader(layerBytes)) // Disable the database so writes only go to the filesytem. env.config.Database.Enabled = false env.config.Database.Enabled = configuration.DatabaseEnabledFalse uploadURLBase, _ = startPushLayer(t, env, repoRef) pushLayer(t, env.builder, repoRef, dgst, uploadURLBase, bytes.NewReader(layerBytes)) // Enable the database again so that reads first check the database. env.config.Database.Enabled = true env.config.Database.Enabled = configuration.DatabaseEnabledTrue testManifest.Layers[i] = distribution.Descriptor{ Digest: dgst, Loading Loading @@ -1091,7 +1091,7 @@ func TestManifestAPI_Get_Schema1(t *testing.T) { defer env.Shutdown() // Seed manifest in database directly since schema1 manifests are unpushable. if env.config.Database.Enabled { if env.config.Database.IsEnabled() { repositoryStore := datastore.NewRepositoryStore(env.db.Primary()) dbRepo, err := repositoryStore.CreateByPath(env.ctx, preseededSchema1RepoPath) require.NoError(t, err) Loading Loading @@ -1206,7 +1206,7 @@ func TestManifestAPI_Delete_ManifestReferencedByList(t *testing.T) { env := newTestEnv(t, withDelete) defer env.Shutdown() if !env.config.Database.Enabled { if !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } Loading @@ -1233,7 +1233,7 @@ func TestManifestAPI_Put_DatabaseEnabled_InvalidConfigMediaType(t *testing.T) { env := newTestEnv(t) defer env.Shutdown() if !env.config.Database.Enabled { if !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } Loading Loading @@ -2050,7 +2050,7 @@ func TestManifestAPI_Get_Config(t *testing.T) { defer env.Shutdown() // disable the database so writes only go to the filesystem env.config.Database.Enabled = false env.config.Database.Enabled = configuration.DatabaseEnabledFalse // create repository with a manifest repo, err := reference.WithName("foo/bar") Loading Loading @@ -3102,7 +3102,7 @@ func TestManifestAPI_Put_ImmutableTags(t *testing.T) { env := newTestEnv(t) t.Cleanup(env.Shutdown) if !env.config.Database.Enabled { if !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } Loading Loading
configuration/configuration.go +67 −1 Original line number Diff line number Diff line Loading @@ -399,10 +399,67 @@ type DatabaseMetrics struct { LeaseDuration time.Duration `yaml:"leaseduration,omitempty"` } // DatabaseEnabled is an enum allowing the user to set various policies for // the registry database enabling behavior. type DatabaseEnabled int const ( // DatabaseEnabledFalse the database is explicitly disabled. DatabaseEnabledFalse DatabaseEnabled = iota // DatabaseEnabledTrue the database is explicitly enabled. DatabaseEnabledTrue // DatabaseEnabledPrefer the database remains enabled if already enabled OR // there is no data detected in the container registry (fresh install). DatabaseEnabledPrefer ) var databaseEnabledStrings = map[DatabaseEnabled]string{ DatabaseEnabledFalse: "false", DatabaseEnabledTrue: "true", DatabaseEnabledPrefer: "prefer", } var stringToDatabaseEnabled = map[string]DatabaseEnabled{ "false": DatabaseEnabledFalse, "true": DatabaseEnabledTrue, "prefer": DatabaseEnabledPrefer, } func (d *DatabaseEnabled) UnmarshalYAML(unmarshal func(any) error) error { var s string if err := unmarshal(&s); err == nil { if enum, ok := stringToDatabaseEnabled[s]; ok { *d = enum return nil } } // Convert bools to enums for backwards compatibility. var b bool if err := unmarshal(&b); err == nil { if b { *d = DatabaseEnabledTrue return nil } *d = DatabaseEnabledFalse return nil } return fmt.Errorf("invalid database.enabled value: %q, valid values: false, true, prefer", s) } func (d DatabaseEnabled) String() string { return databaseEnabledStrings[d] } func (d DatabaseEnabled) MarshalYAML() (any, error) { return d.String(), nil } // Database is the configuration for the registry's metadata database type Database struct { // Enabled can be used to enable or bypass the metadata database Enabled bool `yaml:"enabled"` Enabled DatabaseEnabled `yaml:"enabled"` // Host is the database server hostname Host string `yaml:"host"` // Port is the database server port Loading Loading @@ -452,6 +509,15 @@ type Database struct { Metrics DatabaseMetrics `yaml:"metrics,omitempty"` } // IsEnabled returns true if the database is in prefer mode or explicitly enabled. func (d Database) IsEnabled() bool { return d.Enabled != DatabaseEnabledFalse } func (d Database) IsPrefer() bool { return d.Enabled == DatabaseEnabledPrefer } // BackgroundMigrations represents the configuration for the asynchronous batched background migrations in the registry. type BackgroundMigrations struct { // Enabled can be used to enable or bypass the asynchronous batched background migration process Loading
configuration/configuration_test.go +47 −4 Original line number Diff line number Diff line Loading @@ -55,7 +55,7 @@ var configStruct = Configuration{ }, }, Database: Database{ Enabled: true, Enabled: DatabaseEnabledTrue, Host: "localhost", Port: 5432, User: "postgres", Loading Loading @@ -333,7 +333,7 @@ func (s *ConfigSuite) TestParseSimple() { func (s *ConfigSuite) TestParseInmemory() { s.expectedConfig.Storage = Storage{"inmemory": Parameters{}} s.expectedConfig.Database = Database{ Enabled: true, Enabled: DatabaseEnabledTrue, BackgroundMigrations: BackgroundMigrations{ Enabled: true, MaxJobRetries: 1, Loading Loading @@ -720,7 +720,7 @@ storage: inmemory // TestParseWithDifferentEnvDatabase validates that environment variables properly override database parameters func (s *ConfigSuite) TestParseWithDifferentEnvDatabase() { expected := Database{ Enabled: true, Enabled: DatabaseEnabledTrue, Host: "127.0.0.1", Port: 1234, User: "user", Loading @@ -743,7 +743,7 @@ func (s *ConfigSuite) TestParseWithDifferentEnvDatabase() { } s.expectedConfig.Database = expected err := os.Setenv("REGISTRY_DATABASE_DISABLE", strconv.FormatBool(expected.Enabled)) err := os.Setenv("REGISTRY_DATABASE_DISABLE", strconv.FormatBool(expected.IsEnabled())) require.NoError(s.T(), err) err = os.Setenv("REGISTRY_DATABASE_HOST", expected.Host) require.NoError(s.T(), err) Loading Loading @@ -3242,3 +3242,46 @@ database: testParameter(t, yml, "REGISTRY_DATABASE_METRICS_LEASEDURATION", tt, validator) } func TestParseDatabaseEnabled(t *testing.T) { yml := ` version: 0.1 storage: inmemory database: enabled: %s ` tt := []parameterTest{ { name: "string true", value: "true", want: DatabaseEnabledTrue, }, { name: "string false", value: "false", want: DatabaseEnabledFalse, }, { name: "prefer", value: "prefer", want: DatabaseEnabledPrefer, }, { name: "typo", value: "perfer", wantErr: true, err: fmt.Sprintf("invalid database.enabled value: %q, valid values: false, true, prefer", "perfer"), }, { name: "default", value: "", want: DatabaseEnabledFalse, }, } validator := func(t *testing.T, want any, got *Configuration) { require.Equal(t, want, got.Database.Enabled) } testParameter(t, yml, "REGISTRY_DATABASE_ENABLED", tt, validator) }
registry/cli_test.go +1 −1 Original line number Diff line number Diff line Loading @@ -919,7 +919,7 @@ func generateDBConfig(t *testing.T, dbHost string, dbPort int, dbUser, dbPasswor config := configuration.Configuration{ Version: "0.1", Database: configuration.Database{ Enabled: true, Enabled: configuration.DatabaseEnabledTrue, Host: dbHost, Port: dbPort, User: dbUser, Loading
registry/handlers/api_conformance_test.go +4 −4 Original line number Diff line number Diff line Loading @@ -613,7 +613,7 @@ func baseURLAuth(t *testing.T, opts ...configOpt) { } // The v1 API base route returns 404s if the database is not enabled. if env.config.Database.Enabled { if env.config.Database.IsEnabled() { gitLabV1Base, err := env.builder.BuildGitlabV1BaseURL() require.NoError(t, err) Loading Loading @@ -650,7 +650,7 @@ func baseURLAuth(t *testing.T, opts ...configOpt) { if test.wantExtFeatures { require.Equal(t, version.ExtFeatures, resp.Header.Get("Gitlab-Container-Registry-Features")) require.Equal(t, strconv.FormatBool(env.config.Database.Enabled), resp.Header.Get("Gitlab-Container-Registry-Database-Enabled")) require.Equal(t, strconv.FormatBool(env.config.Database.IsEnabled()), resp.Header.Get("Gitlab-Container-Registry-Database-Enabled")) } else { require.Empty(t, resp.Header.Get("Gitlab-Container-Registry-Features")) } Loading Loading @@ -707,7 +707,7 @@ func baseURLPrefix(t *testing.T, opts ...configOpt) { defer resp.Body.Close() // The V1 API base route returns 404s if the database is not enabled. if env.config.Database.Enabled { if env.config.Database.IsEnabled() { require.Equal(t, http.StatusOK, resp.StatusCode) require.Equal(t, "application/json", resp.Header.Get("Content-Type")) require.Equal(t, "2", resp.Header.Get("Content-Length")) Loading Loading @@ -3108,7 +3108,7 @@ func tagsGet(t *testing.T, opts ...configOpt) { for _, test := range tt { t.Run(test.name, func(t *testing.T) { if !test.runWithoutDBEnabled && !env.config.Database.Enabled { if !test.runWithoutDBEnabled && !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } Loading
registry/handlers/api_integration_test.go +11 −11 Original line number Diff line number Diff line Loading @@ -63,12 +63,12 @@ func TestBlobAPI_Get_BlobNotInDatabase(t *testing.T) { env := newTestEnv(t) defer env.Shutdown() if !env.config.Database.Enabled { if !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } // Disable the database so writes only go to the filesytem. env.config.Database.Enabled = false env.config.Database.Enabled = configuration.DatabaseEnabledFalse // create repository with a layer args := makeBlobArgs(t) Loading @@ -76,7 +76,7 @@ func TestBlobAPI_Get_BlobNotInDatabase(t *testing.T) { blobURL := pushLayer(t, env.builder, args.imageName, args.layerDigest, uploadURLBase, args.layerFile) // Enable the database again so that reads first check the database. env.config.Database.Enabled = true env.config.Database.Enabled = configuration.DatabaseEnabledTrue // fetch layer res, err := http.Get(blobURL) Loading Loading @@ -836,7 +836,7 @@ func TestManifestAPI_Put_Schema2LayersNotAssociatedWithRepositoryButArePresentIn tagName := "schema2missinglayerstag" repoPath := "schema2/missinglayers" if !env.config.Database.Enabled { if !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } Loading Loading @@ -875,13 +875,13 @@ func TestManifestAPI_Put_Schema2LayersNotAssociatedWithRepositoryButArePresentIn pushLayer(t, env.builder, fakeRepoRef, dgst, uploadURLBase, bytes.NewReader(layerBytes)) // Disable the database so writes only go to the filesytem. env.config.Database.Enabled = false env.config.Database.Enabled = configuration.DatabaseEnabledFalse uploadURLBase, _ = startPushLayer(t, env, repoRef) pushLayer(t, env.builder, repoRef, dgst, uploadURLBase, bytes.NewReader(layerBytes)) // Enable the database again so that reads first check the database. env.config.Database.Enabled = true env.config.Database.Enabled = configuration.DatabaseEnabledTrue testManifest.Layers[i] = distribution.Descriptor{ Digest: dgst, Loading Loading @@ -1091,7 +1091,7 @@ func TestManifestAPI_Get_Schema1(t *testing.T) { defer env.Shutdown() // Seed manifest in database directly since schema1 manifests are unpushable. if env.config.Database.Enabled { if env.config.Database.IsEnabled() { repositoryStore := datastore.NewRepositoryStore(env.db.Primary()) dbRepo, err := repositoryStore.CreateByPath(env.ctx, preseededSchema1RepoPath) require.NoError(t, err) Loading Loading @@ -1206,7 +1206,7 @@ func TestManifestAPI_Delete_ManifestReferencedByList(t *testing.T) { env := newTestEnv(t, withDelete) defer env.Shutdown() if !env.config.Database.Enabled { if !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } Loading @@ -1233,7 +1233,7 @@ func TestManifestAPI_Put_DatabaseEnabled_InvalidConfigMediaType(t *testing.T) { env := newTestEnv(t) defer env.Shutdown() if !env.config.Database.Enabled { if !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } Loading Loading @@ -2050,7 +2050,7 @@ func TestManifestAPI_Get_Config(t *testing.T) { defer env.Shutdown() // disable the database so writes only go to the filesystem env.config.Database.Enabled = false env.config.Database.Enabled = configuration.DatabaseEnabledFalse // create repository with a manifest repo, err := reference.WithName("foo/bar") Loading Loading @@ -3102,7 +3102,7 @@ func TestManifestAPI_Put_ImmutableTags(t *testing.T) { env := newTestEnv(t) t.Cleanup(env.Shutdown) if !env.config.Database.Enabled { if !env.config.Database.IsEnabled() { t.Skip("skipping test because the metadata database is not enabled") } Loading