From 387657e7b69396503ab4fc59fbc6cc444e947989 Mon Sep 17 00:00:00 2001 From: Bogdan Kanivets Date: Thu, 1 Jun 2023 10:53:41 -0700 Subject: [PATCH] server: add fields to migrate from 3.5 to 3.4 Signed-off-by: Bogdan Kanivets --- etcdutl/etcdutl/migrate_command.go | 4 ++-- server/storage/schema/schema.go | 11 +++++++++++ server/storage/schema/schema_test.go | 10 ++++------ tests/e2e/utl_migrate_test.go | 23 +++++++++++++++++++++++ 4 files changed, 40 insertions(+), 8 deletions(-) diff --git a/etcdutl/etcdutl/migrate_command.go b/etcdutl/etcdutl/migrate_command.go index 521cf8ba80c8..4fc7f4644bfb 100644 --- a/etcdutl/etcdutl/migrate_command.go +++ b/etcdutl/etcdutl/migrate_command.go @@ -87,8 +87,8 @@ func (o *migrateOptions) Config() (*migrateConfig, error) { if err != nil { return nil, fmt.Errorf("failed to parse target version: %v", err) } - if c.targetVersion.LessThan(version.V3_5) { - return nil, fmt.Errorf(`target version %q not supported. Minimal "3.5"`, storageVersionToString(c.targetVersion)) + if c.targetVersion.LessThan(version.V3_4) { + return nil, fmt.Errorf(`target version %q not supported. Minimal "3.4"`, storageVersionToString(c.targetVersion)) } dbPath := datadir.ToBackendFileName(o.dataDir) diff --git a/server/storage/schema/schema.go b/server/storage/schema/schema.go index e2e7fe7e5667..e9f661146013 100644 --- a/server/storage/schema/schema.go +++ b/server/storage/schema/schema.go @@ -131,8 +131,19 @@ var ( version.V3_6: { addNewField(Meta, MetaStorageVersionName, emptyStorageVersion), }, + version.V3_5: { + // 'migrate' command from v3.4 to v3.5 isn't supported and will fail with `missing confstate information` + // these fields are added for v3.5 -> v3.4 downgrade only + // + // note about emptyValue: + // even if these fields are used for upgrade, it's safe to set emptyValue + // UnsafeReadConsistentIndex and UnsafeConfStateFromBackend checks for zero-length values + addNewField(Meta, MetaTermKeyName, emptyValue), + addNewField(Meta, MetaConfStateName, emptyValue), + }, } // emptyStorageVersion is used for v3.6 Step for the first time, in all other version StoragetVersion should be set by migrator. // Adding a addNewField for StorageVersion we can reuse logic to remove it when downgrading to v3.5 emptyStorageVersion = []byte("") + emptyValue = []byte("") ) diff --git a/server/storage/schema/schema_test.go b/server/storage/schema/schema_test.go index 6b0024ba7476..4fba3960e3b6 100644 --- a/server/storage/schema/schema_test.go +++ b/server/storage/schema/schema_test.go @@ -192,12 +192,10 @@ func TestMigrate(t *testing.T) { expectErrorMsg: "cannot downgrade storage, WAL contains newer entries", }, { - name: "Downgrading v3.5 to v3.4 is not supported as schema was introduced in v3.6", - version: version.V3_5, - targetVersion: version.V3_4, - expectVersion: nil, - expectError: true, - expectErrorMsg: `cannot create migration plan: version "3.5.0" is not supported`, + name: "Downgrading v3.5 to v3.4 is supported", + version: version.V3_5, + targetVersion: version.V3_4, + expectVersion: nil, }, } for _, tc := range tcs { diff --git a/tests/e2e/utl_migrate_test.go b/tests/e2e/utl_migrate_test.go index 1513d34b4e1b..df25f335f24f 100644 --- a/tests/e2e/utl_migrate_test.go +++ b/tests/e2e/utl_migrate_test.go @@ -34,6 +34,11 @@ import ( "go.etcd.io/etcd/tests/v3/framework/e2e" ) +type bucketKey struct { + bucket backend.Bucket + key []byte +} + func TestEtctlutlMigrate(t *testing.T) { lastReleaseBinary := e2e.BinPath.EtcdLastRelease @@ -45,6 +50,8 @@ func TestEtctlutlMigrate(t *testing.T) { expectLogsSubString string expectStorageVersion *semver.Version + + expectNonFoundKeys []bucketKey }{ { name: "Invalid target version string", @@ -70,6 +77,16 @@ func TestEtctlutlMigrate(t *testing.T) { expectLogsSubString: `Error: wrong target version format, expected "X.Y", got "3.6.0"`, expectStorageVersion: &version.V3_6, }, + { + name: "Downgrade v3.5 to v3.4 should work", + clusterVersion: e2e.LastVersion, + targetVersion: "3.4", + expectLogsSubString: "updated storage version\t" + `{"new-storage-version": "3.4.0"}`, + expectNonFoundKeys: []bucketKey{ + {bucket: schema.Meta, key: schema.MetaTermKeyName}, + {bucket: schema.Meta, key: schema.MetaConfStateName}, + }, + }, { name: "Migrate v3.5 to v3.5 is no-op", clusterVersion: e2e.LastVersion, @@ -170,6 +187,12 @@ func TestEtctlutlMigrate(t *testing.T) { ver := schema.ReadStorageVersion(be.ReadTx()) assert.Equal(t, tc.expectStorageVersion, ver) + + for _, bk := range tc.expectNonFoundKeys { + _, vs := be.ReadTx().UnsafeRange(bk.bucket, bk.key, nil, 0) + assert.Zero(t, len(vs)) + } + }) } }