etcdserver/cluster_util.go
func decideClusterVersion(lg *zap.Logger, vers map[string]*version.Versions) *semver.Version {
	var cv *semver.Version
	lv := semver.Must(semver.NewVersion(version.Version))

	for mid, ver := range vers {
		if ver == nil {
			return nil
		}
		v, err := semver.NewVersion(ver.Server)
		if err != nil {
			if lg != nil {
				lg.Warn(
					"failed to parse server version of remote member",
					zap.String("remote-member-id", mid),
					zap.String("remote-member-version", ver.Server),
					zap.Error(err),
				)
			} else {
				plog.Errorf("cannot understand the version of member %s (%v)", mid, err)
			}
			return nil
		}
		if lv.LessThan(*v) {
			if lg != nil {
				lg.Warn(
					"leader found higher-versioned member",
					zap.String("local-member-version", lv.String()),
					zap.String("remote-member-id", mid),
					zap.String("remote-member-version", ver.Server),
				)
			} else {
				plog.Warningf("the local etcd version %s is not up-to-date", lv.String())
				plog.Warningf("member %s has a higher version %s", mid, ver.Server)
			}
		}
		if cv == nil {
			cv = v
		} else if v.LessThan(*cv) {
			cv = v
		}
	}
	return cv
}
func decideClusterVersion(lg *zap.Logger, vers map[string]*version.Versions) *semver.Version {
	var cv *semver.Version
	lv := semver.Must(semver.NewVersion(version.Version))

	for mid, ver := range vers {
		if ver == nil {
			return nil
		}
		v, err := semver.NewVersion(ver.Server)
		if err != nil {
			if lg != nil {
				lg.Warn(
					"failed to parse server version of remote member",
					zap.String("remote-member-id", mid),
					zap.String("remote-member-version", ver.Server),
					zap.Error(err),
				)
			} else {
				plog.Errorf("cannot understand the version of member %s (%v)", mid, err)
			}
			return nil
		}
		if lv.LessThan(*v) {
			if lg != nil {
				lg.Warn(
					"leader found higher-versioned member",
					zap.String("local-member-version", lv.String()),
					zap.String("remote-member-id", mid),
					zap.String("remote-member-version", ver.Server),
				)
			} else {
				plog.Warningf("the local etcd version %s is not up-to-date", lv.String())
				plog.Warningf("member %s has a higher version %s", mid, ver.Server)
			}
		}
		if cv == nil {
			cv = v
		} else if v.LessThan(*cv) {
			cv = v
		}
	}
	return cv
}
// decideClusterVersion decides the cluster version based on the versions map.
// The returned version is the min server version in the map, or nil if the min
// version in unknown.