@@ -31,9 +31,13 @@ import (
3131 "github.com/coreos/go-semver/semver"
3232 "go.uber.org/zap"
3333
34+ "go.etcd.io/etcd/api/v3/version"
3435 "go.etcd.io/etcd/client/pkg/v3/fileutil"
3536 "go.etcd.io/etcd/pkg/v3/expect"
3637 "go.etcd.io/etcd/pkg/v3/proxy"
38+ "go.etcd.io/etcd/server/v3/storage/backend"
39+ "go.etcd.io/etcd/server/v3/storage/datadir"
40+ "go.etcd.io/etcd/server/v3/storage/schema"
3741 "go.etcd.io/etcd/tests/v3/framework/config"
3842)
3943
@@ -60,6 +64,8 @@ type EtcdProcess interface {
6064 LazyFS () * LazyFS
6165 Logs () LogsExpect
6266 Kill () error
67+ // VerifySchemaVersion verifies the db file schema version is compatible with the binary after the process is closed.
68+ VerifySchemaVersion (lg * zap.Logger ) error
6369}
6470
6571type LogsExpect interface {
@@ -253,6 +259,34 @@ func (ep *EtcdServerProcess) Close() error {
253259 return nil
254260}
255261
262+ func (ep * EtcdServerProcess ) VerifySchemaVersion (lg * zap.Logger ) error {
263+ dbPath := datadir .ToBackendFileName (ep .cfg .DataDirPath )
264+ be := backend .NewDefaultBackend (lg , dbPath )
265+ defer be .Close ()
266+ ver , err := schema .UnsafeDetectSchemaVersion (lg , be .BatchTx ())
267+ if err != nil {
268+ return err
269+ }
270+ maxStorageVersion := version .V3_6
271+ if ep .cfg .ExecPath == BinPath .EtcdLastRelease {
272+ maxStorageVersion = version .V3_5
273+ }
274+ // in a mix version cluster, the storage version would be set to the cluster version,
275+ // which could be lower than the server version by 1 minor version.
276+ if ! ver .LessThan (maxStorageVersion ) && ! ver .Equal (maxStorageVersion ) {
277+ return fmt .Errorf ("expect backend schema version to be <= %s, but got %s" , maxStorageVersion .String (), ver .String ())
278+ }
279+ // check new fields introduced in V3_6 do not exist in V3_5 data file.
280+ // V3_6 contains all the fields in V3_5, so no need to check for V3_6 servers.
281+ if maxStorageVersion == version .V3_5 {
282+ _ , vs := be .BatchTx ().UnsafeRange (schema .Meta , schema .MetaStorageVersionName , nil , 1 )
283+ if len (vs ) != 0 {
284+ return fmt .Errorf ("expect storageVersion not exist in the meta bucket, but got %s" , string (vs [0 ]))
285+ }
286+ }
287+ return nil
288+ }
289+
256290func (ep * EtcdServerProcess ) waitReady (ctx context.Context ) error {
257291 defer close (ep .donec )
258292 return WaitReadyExpectProc (ctx , ep .proc , EtcdServerReadyLines )
0 commit comments