...

Source file src/go.etcd.io/etcd/server/v3/etcdserver/api/membership/downgrade.go

Documentation: go.etcd.io/etcd/server/v3/etcdserver/api/membership

     1  // Copyright 2020 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package membership
    16  
    17  import (
    18  	"github.com/coreos/go-semver/semver"
    19  	"go.etcd.io/etcd/api/v3/version"
    20  	"go.uber.org/zap"
    21  )
    22  
    23  type DowngradeInfo struct {
    24  	// TargetVersion is the target downgrade version, if the cluster is not under downgrading,
    25  	// the targetVersion will be an empty string
    26  	TargetVersion string `json:"target-version"`
    27  	// Enabled indicates whether the cluster is enabled to downgrade
    28  	Enabled bool `json:"enabled"`
    29  }
    30  
    31  func (d *DowngradeInfo) GetTargetVersion() *semver.Version {
    32  	return semver.Must(semver.NewVersion(d.TargetVersion))
    33  }
    34  
    35  // isValidDowngrade verifies whether the cluster can be downgraded from verFrom to verTo
    36  func isValidDowngrade(verFrom *semver.Version, verTo *semver.Version) bool {
    37  	return verTo.Equal(*AllowedDowngradeVersion(verFrom))
    38  }
    39  
    40  // mustDetectDowngrade will detect unexpected downgrade when the local server is recovered.
    41  func mustDetectDowngrade(lg *zap.Logger, cv *semver.Version, d *DowngradeInfo) {
    42  	lv := semver.Must(semver.NewVersion(version.Version))
    43  	// only keep major.minor version for comparison against cluster version
    44  	lv = &semver.Version{Major: lv.Major, Minor: lv.Minor}
    45  
    46  	// if the cluster enables downgrade, check local version against downgrade target version.
    47  	if d != nil && d.Enabled && d.TargetVersion != "" {
    48  		if lv.Equal(*d.GetTargetVersion()) {
    49  			if cv != nil {
    50  				lg.Info(
    51  					"cluster is downgrading to target version",
    52  					zap.String("target-cluster-version", d.TargetVersion),
    53  					zap.String("determined-cluster-version", version.Cluster(cv.String())),
    54  					zap.String("current-server-version", version.Version),
    55  				)
    56  			}
    57  			return
    58  		}
    59  		lg.Fatal(
    60  			"invalid downgrade; server version is not allowed to join when downgrade is enabled",
    61  			zap.String("current-server-version", version.Version),
    62  			zap.String("target-cluster-version", d.TargetVersion),
    63  		)
    64  	}
    65  
    66  	// if the cluster disables downgrade, check local version against determined cluster version.
    67  	// the validation passes when local version is not less than cluster version
    68  	if cv != nil && lv.LessThan(*cv) {
    69  		lg.Fatal(
    70  			"invalid downgrade; server version is lower than determined cluster version",
    71  			zap.String("current-server-version", version.Version),
    72  			zap.String("determined-cluster-version", version.Cluster(cv.String())),
    73  		)
    74  	}
    75  }
    76  
    77  func AllowedDowngradeVersion(ver *semver.Version) *semver.Version {
    78  	// Todo: handle the case that downgrading from higher major version(e.g. downgrade from v4.0 to v3.x)
    79  	return &semver.Version{Major: ver.Major, Minor: ver.Minor - 1}
    80  }
    81  

View as plain text