mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-12-24 23:19:39 -05:00
cli: use Semver type to represent microservice versions (#2125)
Previously we used strings to pass microservice versions. This invited bugs due to missing input validation.
This commit is contained in:
parent
2d3999440d
commit
1d5a8283e0
@ -33,7 +33,7 @@ func run(issuer atls.Issuer, openDevice vtpm.TPMOpenFunc, fileHandler file.Handl
|
|||||||
) {
|
) {
|
||||||
defer cloudLogger.Close()
|
defer cloudLogger.Close()
|
||||||
|
|
||||||
log.With(zap.String("version", constants.VersionInfo())).Infof("Starting bootstrapper")
|
log.With(zap.String("version", constants.BinaryVersion().String())).Infof("Starting bootstrapper")
|
||||||
cloudLogger.Disclose("bootstrapper started running...")
|
cloudLogger.Disclose("bootstrapper started running...")
|
||||||
|
|
||||||
uuid, err := getDiskUUID()
|
uuid, err := getDiskUUID()
|
||||||
|
@ -157,6 +157,7 @@ go_test(
|
|||||||
"//internal/kms/uri",
|
"//internal/kms/uri",
|
||||||
"//internal/license",
|
"//internal/license",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
"//internal/semver",
|
||||||
"//internal/versions",
|
"//internal/versions",
|
||||||
"//operators/constellation-node-operator/api/v1alpha1",
|
"//operators/constellation-node-operator/api/v1alpha1",
|
||||||
"//verify/verifyproto",
|
"//verify/verifyproto",
|
||||||
|
@ -86,7 +86,7 @@ func (c *createCmd) create(cmd *cobra.Command, creator cloudCreator, fileHandler
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !flags.force {
|
if !flags.force {
|
||||||
if err := validateCLIandConstellationVersionAreEqual(constants.VersionInfo(), conf.Image, conf.MicroserviceVersion); err != nil {
|
if err := validateCLIandConstellationVersionAreEqual(constants.BinaryVersion(), conf.Image, conf.MicroserviceVersion); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -301,7 +301,7 @@ func must(err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// validateCLIandConstellationVersionAreEqual checks if the image and microservice version are equal (down to patch level) to the CLI version.
|
// validateCLIandConstellationVersionAreEqual checks if the image and microservice version are equal (down to patch level) to the CLI version.
|
||||||
func validateCLIandConstellationVersionAreEqual(cliVersion, imageVersion, microserviceVersion string) error {
|
func validateCLIandConstellationVersionAreEqual(cliVersion semver.Semver, imageVersion string, microserviceVersion semver.Semver) error {
|
||||||
parsedImageVersion, err := versionsapi.NewVersionFromShortPath(imageVersion, versionsapi.VersionKindImage)
|
parsedImageVersion, err := versionsapi.NewVersionFromShortPath(imageVersion, versionsapi.VersionKindImage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("parsing image version: %w", err)
|
return fmt.Errorf("parsing image version: %w", err)
|
||||||
@ -312,21 +312,11 @@ func validateCLIandConstellationVersionAreEqual(cliVersion, imageVersion, micros
|
|||||||
return fmt.Errorf("parsing image semantical version: %w", err)
|
return fmt.Errorf("parsing image semantical version: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
semMicro, err := semver.New(microserviceVersion)
|
if !cliVersion.MajorMinorEqual(semImage) {
|
||||||
if err != nil {
|
return fmt.Errorf("image version %q does not match the major and minor version of the cli version %q", semImage.String(), cliVersion.String())
|
||||||
return fmt.Errorf("parsing microservice version: %w", err)
|
|
||||||
}
|
}
|
||||||
|
if cliVersion.Compare(microserviceVersion) != 0 {
|
||||||
semCLI, err := semver.New(cliVersion)
|
return fmt.Errorf("cli version %q does not match microservice version %q", cliVersion.String(), microserviceVersion.String())
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing binary version: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !semCLI.MajorMinorEqual(semImage) {
|
|
||||||
return fmt.Errorf("image version %q does not match the major and minor version of the cli version %q", semImage.String(), semCLI.String())
|
|
||||||
}
|
|
||||||
if semCLI.Compare(semMicro) != 0 {
|
|
||||||
return fmt.Errorf("cli version %q does not match microservice version %q", semCLI.String(), semMicro.String())
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
|
consemver "github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -273,52 +274,52 @@ func TestCheckDirClean(t *testing.T) {
|
|||||||
func TestValidateCLIandConstellationVersionCompatibility(t *testing.T) {
|
func TestValidateCLIandConstellationVersionCompatibility(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
imageVersion string
|
imageVersion string
|
||||||
microServiceVersion string
|
microServiceVersion consemver.Semver
|
||||||
cliVersion string
|
cliVersion consemver.Semver
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
"empty": {
|
"empty": {
|
||||||
imageVersion: "",
|
imageVersion: "",
|
||||||
microServiceVersion: "",
|
microServiceVersion: consemver.Semver{},
|
||||||
cliVersion: "",
|
cliVersion: consemver.Semver{},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"invalid when image < CLI": {
|
"invalid when image < CLI": {
|
||||||
imageVersion: "v2.7.1",
|
imageVersion: "v2.7.1",
|
||||||
microServiceVersion: "v2.8.0",
|
microServiceVersion: consemver.NewFromInt(2, 8, 0, ""),
|
||||||
cliVersion: "v2.8.0",
|
cliVersion: consemver.NewFromInt(2, 8, 0, ""),
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"invalid when microservice < CLI": {
|
"invalid when microservice < CLI": {
|
||||||
imageVersion: "v2.8.0",
|
imageVersion: "v2.8.0",
|
||||||
microServiceVersion: "v2.7.1",
|
microServiceVersion: consemver.NewFromInt(2, 7, 1, ""),
|
||||||
cliVersion: "v2.8.0",
|
cliVersion: consemver.NewFromInt(2, 8, 0, ""),
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
"valid release version": {
|
"valid release version": {
|
||||||
imageVersion: "v2.9.0",
|
imageVersion: "v2.9.0",
|
||||||
microServiceVersion: "v2.9.0",
|
microServiceVersion: consemver.NewFromInt(2, 9, 0, ""),
|
||||||
cliVersion: "2.9.0",
|
cliVersion: consemver.NewFromInt(2, 9, 0, ""),
|
||||||
},
|
},
|
||||||
"valid pre-version": {
|
"valid pre-version": {
|
||||||
imageVersion: "ref/main/stream/nightly/v2.9.0-pre.0.20230626150512-0a36ce61719f",
|
imageVersion: "ref/main/stream/nightly/v2.9.0-pre.0.20230626150512-0a36ce61719f",
|
||||||
microServiceVersion: "v2.9.0-pre.0.20230626150512-0a36ce61719f",
|
microServiceVersion: consemver.NewFromInt(2, 9, 0, "pre.0.20230626150512-0a36ce61719f"),
|
||||||
cliVersion: "2.9.0-pre.0.20230626150512-0a36ce61719f",
|
cliVersion: consemver.NewFromInt(2, 9, 0, "pre.0.20230626150512-0a36ce61719f"),
|
||||||
},
|
},
|
||||||
"image version suffix need not be equal to CLI version": {
|
"image version suffix need not be equal to CLI version": {
|
||||||
imageVersion: "ref/main/stream/nightly/v2.9.0-pre.0.19990626150512-9z36ce61799z",
|
imageVersion: "ref/main/stream/nightly/v2.9.0-pre.0.19990626150512-9z36ce61799z",
|
||||||
microServiceVersion: "v2.9.0-pre.0.20230626150512-0a36ce61719f",
|
microServiceVersion: consemver.NewFromInt(2, 9, 0, "pre.0.20230626150512-0a36ce61719f"),
|
||||||
cliVersion: "2.9.0-pre.0.20230626150512-0a36ce61719f",
|
cliVersion: consemver.NewFromInt(2, 9, 0, "pre.0.20230626150512-0a36ce61719f"),
|
||||||
},
|
},
|
||||||
"image version can have different patch version": {
|
"image version can have different patch version": {
|
||||||
imageVersion: "ref/main/stream/nightly/v2.9.1-pre.0.19990626150512-9z36ce61799z",
|
imageVersion: "ref/main/stream/nightly/v2.9.1-pre.0.19990626150512-9z36ce61799z",
|
||||||
microServiceVersion: "v2.9.0-pre.0.20230626150512-0a36ce61719f",
|
microServiceVersion: consemver.NewFromInt(2, 9, 0, "pre.0.20230626150512-0a36ce61719f"),
|
||||||
cliVersion: "2.9.0-pre.0.20230626150512-0a36ce61719f",
|
cliVersion: consemver.NewFromInt(2, 9, 0, "pre.0.20230626150512-0a36ce61719f"),
|
||||||
},
|
},
|
||||||
"microService version suffix must be equal to CLI version": {
|
"microService version suffix must be equal to CLI version": {
|
||||||
imageVersion: "ref/main/stream/nightly/v2.9.0-pre.0.20230626150512-0a36ce61719f",
|
imageVersion: "ref/main/stream/nightly/v2.9.0-pre.0.20230626150512-0a36ce61719f",
|
||||||
microServiceVersion: "v2.9.0-pre.0.19990626150512-9z36ce61799z",
|
microServiceVersion: consemver.NewFromInt(2, 9, 0, "pre.0.19990626150512-9z36ce61799z"),
|
||||||
cliVersion: "2.9.0-pre.0.20230626150512-0a36ce61719f",
|
cliVersion: consemver.NewFromInt(2, 9, 0, "pre.0.20230626150512-0a36ce61719f"),
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ func (i *initCmd) initialize(cmd *cobra.Command, newDialer func(validator atls.V
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !flags.force {
|
if !flags.force {
|
||||||
if err := validateCLIandConstellationVersionAreEqual(constants.VersionInfo(), conf.Image, conf.MicroserviceVersion); err != nil {
|
if err := validateCLIandConstellationVersionAreEqual(constants.BinaryVersion(), conf.Image, conf.MicroserviceVersion); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -592,7 +592,7 @@ func (m *stubMerger) kubeconfigEnvVar() string {
|
|||||||
func defaultConfigWithExpectedMeasurements(t *testing.T, conf *config.Config, csp cloudprovider.Provider) *config.Config {
|
func defaultConfigWithExpectedMeasurements(t *testing.T, conf *config.Config, csp cloudprovider.Provider) *config.Config {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
conf.Image = "v" + constants.VersionInfo()
|
conf.Image = constants.BinaryVersion().String()
|
||||||
conf.Name = "kubernetes"
|
conf.Name = "kubernetes"
|
||||||
|
|
||||||
switch csp {
|
switch csp {
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
"github.com/edgelesssys/constellation/v2/cli/internal/helm"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||||
|
consemver "github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -117,7 +118,7 @@ func TestStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
helmClient: stubHelmClient{
|
helmClient: stubHelmClient{
|
||||||
serviceVersions: helm.NewServiceVersions("v1.0.0", "v1.0.0", "v1.1.0", "v1.1.0"),
|
serviceVersions: helm.NewServiceVersions(consemver.NewFromInt(1, 0, 0, ""), consemver.NewFromInt(1, 0, 0, ""), consemver.NewFromInt(1, 1, 0, ""), consemver.NewFromInt(1, 1, 0, "")),
|
||||||
},
|
},
|
||||||
nodeVersion: updatev1alpha1.NodeVersion{
|
nodeVersion: updatev1alpha1.NodeVersion{
|
||||||
Spec: updatev1alpha1.NodeVersionSpec{
|
Spec: updatev1alpha1.NodeVersionSpec{
|
||||||
@ -167,7 +168,7 @@ func TestStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
helmClient: stubHelmClient{
|
helmClient: stubHelmClient{
|
||||||
serviceVersions: helm.NewServiceVersions("v1.0.0", "v1.0.0", "v1.1.0", "v1.1.0"),
|
serviceVersions: helm.NewServiceVersions(consemver.NewFromInt(1, 0, 0, ""), consemver.NewFromInt(1, 0, 0, ""), consemver.NewFromInt(1, 1, 0, ""), consemver.NewFromInt(1, 1, 0, "")),
|
||||||
},
|
},
|
||||||
nodeVersion: updatev1alpha1.NodeVersion{
|
nodeVersion: updatev1alpha1.NodeVersion{
|
||||||
Spec: updatev1alpha1.NodeVersionSpec{
|
Spec: updatev1alpha1.NodeVersionSpec{
|
||||||
|
@ -33,7 +33,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/imagefetcher"
|
"github.com/edgelesssys/constellation/v2/internal/imagefetcher"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl"
|
"github.com/edgelesssys/constellation/v2/internal/kubernetes/kubectl"
|
||||||
conSemver "github.com/edgelesssys/constellation/v2/internal/semver"
|
consemver "github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
"github.com/edgelesssys/constellation/v2/internal/sigstore"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||||
"github.com/siderolabs/talos/pkg/machinery/config/encoder"
|
"github.com/siderolabs/talos/pkg/machinery/config/encoder"
|
||||||
@ -93,7 +93,7 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error {
|
|||||||
cosign: sigstore.CosignVerifier{},
|
cosign: sigstore.CosignVerifier{},
|
||||||
rekor: rekor,
|
rekor: rekor,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
cliVersion: compatibility.EnsurePrefixV(constants.VersionInfo()),
|
cliVersion: constants.BinaryVersion(),
|
||||||
log: log,
|
log: log,
|
||||||
versionsapi: versionfetcher,
|
versionsapi: versionfetcher,
|
||||||
},
|
},
|
||||||
@ -202,9 +202,9 @@ func (u *upgradeCheckCmd) upgradeCheck(cmd *cobra.Command, fileHandler file.Hand
|
|||||||
|
|
||||||
// Filter versions to only include upgrades
|
// Filter versions to only include upgrades
|
||||||
newServices := supported.service
|
newServices := supported.service
|
||||||
if err := compatibility.IsValidUpgrade(current.service, supported.service); err != nil {
|
if err := supported.service.IsUpgradeTo(current.service); err != nil {
|
||||||
newServices = ""
|
newServices = consemver.Semver{}
|
||||||
u.log.Debugf("No valid service upgrades are available from %q to %q. The minor version can only drift by 1.\n", current.service, supported.service)
|
u.log.Debugf("No valid service upgrades are available from %q to %q. The minor version can only drift by 1.\n", current.service.String(), supported.service.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
newKubernetes := filterK8sUpgrades(current.k8s, supported.k8s)
|
newKubernetes := filterK8sUpgrades(current.k8s, supported.k8s)
|
||||||
@ -352,8 +352,8 @@ type collector interface {
|
|||||||
newImages(ctx context.Context, version string) ([]versionsapi.Version, error)
|
newImages(ctx context.Context, version string) ([]versionsapi.Version, error)
|
||||||
newMeasurements(ctx context.Context, csp cloudprovider.Provider, attestationVariant variant.Variant, images []versionsapi.Version) (map[string]measurements.M, error)
|
newMeasurements(ctx context.Context, csp cloudprovider.Provider, attestationVariant variant.Variant, images []versionsapi.Version) (map[string]measurements.M, error)
|
||||||
newerVersions(ctx context.Context, allowedVersions []string) ([]versionsapi.Version, error)
|
newerVersions(ctx context.Context, allowedVersions []string) ([]versionsapi.Version, error)
|
||||||
newCLIVersions(ctx context.Context) ([]string, error)
|
newCLIVersions(ctx context.Context) ([]consemver.Semver, error)
|
||||||
filterCompatibleCLIVersions(ctx context.Context, cliPatchVersions []string, currentK8sVersion string) ([]string, error)
|
filterCompatibleCLIVersions(ctx context.Context, cliPatchVersions []consemver.Semver, currentK8sVersion string) ([]consemver.Semver, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type versionCollector struct {
|
type versionCollector struct {
|
||||||
@ -366,7 +366,7 @@ type versionCollector struct {
|
|||||||
rekor rekorVerifier
|
rekor rekorVerifier
|
||||||
flags upgradeCheckFlags
|
flags upgradeCheckFlags
|
||||||
versionsapi versionFetcher
|
versionsapi versionFetcher
|
||||||
cliVersion string
|
cliVersion consemver.Semver
|
||||||
log debugLog
|
log debugLog
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,10 +382,10 @@ func (v *versionCollector) newMeasurements(ctx context.Context, csp cloudprovide
|
|||||||
}
|
}
|
||||||
|
|
||||||
type currentVersionInfo struct {
|
type currentVersionInfo struct {
|
||||||
service string
|
service consemver.Semver
|
||||||
image string
|
image string
|
||||||
k8s string
|
k8s string
|
||||||
cli string
|
cli consemver.Semver
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *versionCollector) currentVersions(ctx context.Context) (currentVersionInfo, error) {
|
func (v *versionCollector) currentVersions(ctx context.Context) (currentVersionInfo, error) {
|
||||||
@ -418,20 +418,18 @@ func (v *versionCollector) currentVersions(ctx context.Context) (currentVersionI
|
|||||||
}
|
}
|
||||||
|
|
||||||
type supportedVersionInfo struct {
|
type supportedVersionInfo struct {
|
||||||
service string
|
service consemver.Semver
|
||||||
image []versionsapi.Version
|
image []versionsapi.Version
|
||||||
k8s []string
|
k8s []string
|
||||||
// CLI versions including those incompatible with the current Kubernetes version.
|
// CLI versions including those incompatible with the current Kubernetes version.
|
||||||
cli []string
|
cli []consemver.Semver
|
||||||
// CLI versions compatible with the current Kubernetes version.
|
// CLI versions compatible with the current Kubernetes version.
|
||||||
compatibleCLI []string
|
compatibleCLI []consemver.Semver
|
||||||
}
|
}
|
||||||
|
|
||||||
// supportedVersions returns slices of supported versions.
|
// supportedVersions returns slices of supported versions.
|
||||||
func (v *versionCollector) supportedVersions(ctx context.Context, version, currentK8sVersion string) (supportedVersionInfo, error) {
|
func (v *versionCollector) supportedVersions(ctx context.Context, version, currentK8sVersion string) (supportedVersionInfo, error) {
|
||||||
k8sVersions := versions.SupportedK8sVersions()
|
k8sVersions := versions.SupportedK8sVersions()
|
||||||
// Each CLI comes with a set of services that have the same version as the CLI.
|
|
||||||
serviceVersion := compatibility.EnsurePrefixV(constants.VersionInfo())
|
|
||||||
|
|
||||||
imageVersions, err := v.newImages(ctx, version)
|
imageVersions, err := v.newImages(ctx, version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -447,7 +445,8 @@ func (v *versionCollector) supportedVersions(ctx context.Context, version, curre
|
|||||||
}
|
}
|
||||||
|
|
||||||
return supportedVersionInfo{
|
return supportedVersionInfo{
|
||||||
service: serviceVersion,
|
// Each CLI comes with a set of services that have the same version as the CLI.
|
||||||
|
service: constants.BinaryVersion(),
|
||||||
image: imageVersions,
|
image: imageVersions,
|
||||||
k8s: k8sVersions,
|
k8s: k8sVersions,
|
||||||
cli: cliVersions,
|
cli: cliVersions,
|
||||||
@ -462,7 +461,7 @@ func (v *versionCollector) newImages(ctx context.Context, version string) ([]ver
|
|||||||
// additionally, we allow updates to the next minor version (e.g. 0.1.0 -> 0.2.0)
|
// additionally, we allow updates to the next minor version (e.g. 0.1.0 -> 0.2.0)
|
||||||
// if the CLI minor version is newer than the cluster minor version
|
// if the CLI minor version is newer than the cluster minor version
|
||||||
currentImageMinorVer := semver.MajorMinor(version)
|
currentImageMinorVer := semver.MajorMinor(version)
|
||||||
currentCLIMinorVer := semver.MajorMinor(v.cliVersion)
|
currentCLIMinorVer := semver.MajorMinor(v.cliVersion.String())
|
||||||
nextImageMinorVer, err := compatibility.NextMinorVersion(currentImageMinorVer)
|
nextImageMinorVer, err := compatibility.NextMinorVersion(currentImageMinorVer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("calculating next image minor version: %w", err)
|
return nil, fmt.Errorf("calculating next image minor version: %w", err)
|
||||||
@ -522,15 +521,15 @@ func (v *versionCollector) newerVersions(ctx context.Context, allowedVersions []
|
|||||||
}
|
}
|
||||||
|
|
||||||
type versionUpgrade struct {
|
type versionUpgrade struct {
|
||||||
newServices string
|
newServices consemver.Semver
|
||||||
newImages map[string]measurements.M
|
newImages map[string]measurements.M
|
||||||
newKubernetes []string
|
newKubernetes []string
|
||||||
newCLI []string
|
newCLI []consemver.Semver
|
||||||
newCompatibleCLI []string
|
newCompatibleCLI []consemver.Semver
|
||||||
currentServices string
|
currentServices consemver.Semver
|
||||||
currentImage string
|
currentImage string
|
||||||
currentKubernetes string
|
currentKubernetes string
|
||||||
currentCLI string
|
currentCLI consemver.Semver
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *versionUpgrade) buildString() (string, error) {
|
func (v *versionUpgrade) buildString() (string, error) {
|
||||||
@ -560,7 +559,7 @@ func (v *versionUpgrade) buildString() (string, error) {
|
|||||||
fmt.Fprintln(&upgradeMsg, "")
|
fmt.Fprintln(&upgradeMsg, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v.newServices != "" {
|
if v.newServices != (consemver.Semver{}) {
|
||||||
upgradeMsg.WriteString(fmt.Sprintf(" Services: %s --> %s\n", v.currentServices, v.newServices))
|
upgradeMsg.WriteString(fmt.Sprintf(" Services: %s --> %s\n", v.currentServices, v.newServices))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,12 +571,12 @@ func (v *versionUpgrade) buildString() (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// no upgrades available
|
// no upgrades available
|
||||||
if v.newServices == "" && len(v.newImages) == 0 {
|
if v.newServices == (consemver.Semver{}) && len(v.newImages) == 0 {
|
||||||
if len(v.newCompatibleCLI) > 0 {
|
if len(v.newCompatibleCLI) > 0 {
|
||||||
result.WriteString(fmt.Sprintf("Newer CLI versions that are compatible with your cluster are: %s\n", strings.Join(v.newCompatibleCLI, " ")))
|
result.WriteString(fmt.Sprintf("Newer CLI versions that are compatible with your cluster are: %s\n", strings.Join(consemver.ToStrings(v.newCompatibleCLI), " ")))
|
||||||
return result.String(), nil
|
return result.String(), nil
|
||||||
} else if len(v.newCLI) > 0 {
|
} else if len(v.newCLI) > 0 {
|
||||||
result.WriteString(fmt.Sprintf("There are newer CLIs available (%s), however, you need to upgrade your cluster's Kubernetes version first.\n", strings.Join(v.newCLI, " ")))
|
result.WriteString(fmt.Sprintf("There are newer CLIs available (%s), however, you need to upgrade your cluster's Kubernetes version first.\n", strings.Join(consemver.ToStrings(v.newCLI), " ")))
|
||||||
return result.String(), nil
|
return result.String(), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -589,7 +588,7 @@ func (v *versionUpgrade) buildString() (string, error) {
|
|||||||
func (v *versionUpgrade) writeConfig(conf *config.Config, fileHandler file.Handler, configPath string) error {
|
func (v *versionUpgrade) writeConfig(conf *config.Config, fileHandler file.Handler, configPath string) error {
|
||||||
// can't sort image map because maps are unsorted. services is only one string, k8s versions are sorted.
|
// can't sort image map because maps are unsorted. services is only one string, k8s versions are sorted.
|
||||||
|
|
||||||
if v.newServices != "" {
|
if v.newServices != (consemver.Semver{}) {
|
||||||
conf.MicroserviceVersion = v.newServices
|
conf.MicroserviceVersion = v.newServices
|
||||||
}
|
}
|
||||||
if len(v.newKubernetes) > 0 {
|
if len(v.newKubernetes) > 0 {
|
||||||
@ -685,16 +684,12 @@ type versionFetcher interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// newCLIVersions returns a list of versions of the CLI which are a valid upgrade.
|
// newCLIVersions returns a list of versions of the CLI which are a valid upgrade.
|
||||||
func (v *versionCollector) newCLIVersions(ctx context.Context) ([]string, error) {
|
func (v *versionCollector) newCLIVersions(ctx context.Context) ([]consemver.Semver, error) {
|
||||||
cliVersion, err := conSemver.New(constants.VersionInfo())
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("parsing current CLI version: %w", err)
|
|
||||||
}
|
|
||||||
list := versionsapi.List{
|
list := versionsapi.List{
|
||||||
Ref: v.flags.ref,
|
Ref: v.flags.ref,
|
||||||
Stream: v.flags.stream,
|
Stream: v.flags.stream,
|
||||||
Granularity: versionsapi.GranularityMajor,
|
Granularity: versionsapi.GranularityMajor,
|
||||||
Base: fmt.Sprintf("v%d", cliVersion.Major),
|
Base: fmt.Sprintf("v%d", constants.BinaryVersion().Major()),
|
||||||
Kind: versionsapi.VersionKindCLI,
|
Kind: versionsapi.VersionKindCLI,
|
||||||
}
|
}
|
||||||
minorList, err := v.versionsapi.FetchVersionList(ctx, list)
|
minorList, err := v.versionsapi.FetchVersionList(ctx, list)
|
||||||
@ -704,7 +699,11 @@ func (v *versionCollector) newCLIVersions(ctx context.Context) ([]string, error)
|
|||||||
|
|
||||||
var patchVersions []string
|
var patchVersions []string
|
||||||
for _, version := range minorList.Versions {
|
for _, version := range minorList.Versions {
|
||||||
if err := compatibility.IsValidUpgrade(v.cliVersion, version); err != nil {
|
target, err := consemver.New(version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing version %s: %w", version, err)
|
||||||
|
}
|
||||||
|
if err := target.IsUpgradeTo(v.cliVersion); err != nil {
|
||||||
v.log.Debugf("Skipping incompatible minor version %q: %s", version, err)
|
v.log.Debugf("Skipping incompatible minor version %q: %s", version, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -722,24 +721,29 @@ func (v *versionCollector) newCLIVersions(ctx context.Context) ([]string, error)
|
|||||||
patchVersions = append(patchVersions, patchList.Versions...)
|
patchVersions = append(patchVersions, patchList.Versions...)
|
||||||
}
|
}
|
||||||
|
|
||||||
semver.Sort(patchVersions)
|
out, err := consemver.NewSlice(patchVersions)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing versions: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
return patchVersions, nil
|
consemver.Sort(out)
|
||||||
|
|
||||||
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// filterCompatibleCLIVersions filters a list of CLI versions which are compatible with the current Kubernetes version.
|
// filterCompatibleCLIVersions filters a list of CLI versions which are compatible with the current Kubernetes version.
|
||||||
func (v *versionCollector) filterCompatibleCLIVersions(ctx context.Context, cliPatchVersions []string, currentK8sVersion string) ([]string, error) {
|
func (v *versionCollector) filterCompatibleCLIVersions(ctx context.Context, cliPatchVersions []consemver.Semver, currentK8sVersion string) ([]consemver.Semver, error) {
|
||||||
// filter out invalid upgrades and versions which are not compatible with the current Kubernetes version
|
// filter out invalid upgrades and versions which are not compatible with the current Kubernetes version
|
||||||
var compatibleVersions []string
|
var compatibleVersions []consemver.Semver
|
||||||
for _, version := range cliPatchVersions {
|
for _, version := range cliPatchVersions {
|
||||||
if err := compatibility.IsValidUpgrade(v.cliVersion, version); err != nil {
|
if err := version.IsUpgradeTo(v.cliVersion); err != nil {
|
||||||
v.log.Debugf("Skipping incompatible patch version %q: %s", version, err)
|
v.log.Debugf("Skipping incompatible patch version %q: %s", version, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
req := versionsapi.CLIInfo{
|
req := versionsapi.CLIInfo{
|
||||||
Ref: v.flags.ref,
|
Ref: v.flags.ref,
|
||||||
Stream: v.flags.stream,
|
Stream: v.flags.stream,
|
||||||
Version: version,
|
Version: version.String(),
|
||||||
}
|
}
|
||||||
info, err := v.versionsapi.FetchCLIInfo(ctx, req)
|
info, err := v.versionsapi.FetchCLIInfo(ctx, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -753,7 +757,7 @@ func (v *versionCollector) filterCompatibleCLIVersions(ctx context.Context, cliP
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
semver.Sort(compatibleVersions)
|
consemver.Sort(compatibleVersions)
|
||||||
|
|
||||||
return compatibleVersions, nil
|
return compatibleVersions, nil
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
|
consemver "github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
@ -40,30 +41,30 @@ func TestBuildString(t *testing.T) {
|
|||||||
}{
|
}{
|
||||||
"update everything": {
|
"update everything": {
|
||||||
upgrade: versionUpgrade{
|
upgrade: versionUpgrade{
|
||||||
newServices: "v2.5.0",
|
newServices: consemver.NewFromInt(2, 5, 0, ""),
|
||||||
newImages: map[string]measurements.M{
|
newImages: map[string]measurements.M{
|
||||||
"v2.5.0": measurements.DefaultsFor(cloudprovider.QEMU, variant.QEMUVTPM{}),
|
"v2.5.0": measurements.DefaultsFor(cloudprovider.QEMU, variant.QEMUVTPM{}),
|
||||||
},
|
},
|
||||||
newKubernetes: []string{"v1.24.12", "v1.25.6"},
|
newKubernetes: []string{"v1.24.12", "v1.25.6"},
|
||||||
newCLI: []string{"v2.5.0", "v2.6.0"},
|
newCLI: []consemver.Semver{consemver.NewFromInt(2, 5, 0, ""), consemver.NewFromInt(2, 6, 0, "")},
|
||||||
currentServices: "v2.4.0",
|
currentServices: consemver.NewFromInt(2, 4, 0, ""),
|
||||||
currentImage: "v2.4.0",
|
currentImage: "v2.4.0",
|
||||||
currentKubernetes: "v1.24.5",
|
currentKubernetes: "v1.24.5",
|
||||||
currentCLI: "v2.4.0",
|
currentCLI: consemver.NewFromInt(2, 4, 0, ""),
|
||||||
},
|
},
|
||||||
expected: "The following updates are available with this CLI:\n Kubernetes: v1.24.5 --> v1.24.12 v1.25.6\n Images:\n v2.4.0 --> v2.5.0\n Includes these measurements:\n 4:\n expected: \"1234123412341234123412341234123412341234123412341234123412341234\"\n warnOnly: false\n 8:\n expected: \"0000000000000000000000000000000000000000000000000000000000000000\"\n warnOnly: false\n 9:\n expected: \"1234123412341234123412341234123412341234123412341234123412341234\"\n warnOnly: false\n 11:\n expected: \"0000000000000000000000000000000000000000000000000000000000000000\"\n warnOnly: false\n 12:\n expected: \"1234123412341234123412341234123412341234123412341234123412341234\"\n warnOnly: false\n 13:\n expected: \"0000000000000000000000000000000000000000000000000000000000000000\"\n warnOnly: false\n 15:\n expected: \"0000000000000000000000000000000000000000000000000000000000000000\"\n warnOnly: false\n \n Services: v2.4.0 --> v2.5.0\n",
|
expected: "The following updates are available with this CLI:\n Kubernetes: v1.24.5 --> v1.24.12 v1.25.6\n Images:\n v2.4.0 --> v2.5.0\n Includes these measurements:\n 4:\n expected: \"1234123412341234123412341234123412341234123412341234123412341234\"\n warnOnly: false\n 8:\n expected: \"0000000000000000000000000000000000000000000000000000000000000000\"\n warnOnly: false\n 9:\n expected: \"1234123412341234123412341234123412341234123412341234123412341234\"\n warnOnly: false\n 11:\n expected: \"0000000000000000000000000000000000000000000000000000000000000000\"\n warnOnly: false\n 12:\n expected: \"1234123412341234123412341234123412341234123412341234123412341234\"\n warnOnly: false\n 13:\n expected: \"0000000000000000000000000000000000000000000000000000000000000000\"\n warnOnly: false\n 15:\n expected: \"0000000000000000000000000000000000000000000000000000000000000000\"\n warnOnly: false\n \n Services: v2.4.0 --> v2.5.0\n",
|
||||||
},
|
},
|
||||||
"cli incompatible with K8s": {
|
"cli incompatible with K8s": {
|
||||||
upgrade: versionUpgrade{
|
upgrade: versionUpgrade{
|
||||||
newCLI: []string{"v2.5.0", "v2.6.0"},
|
newCLI: []consemver.Semver{consemver.NewFromInt(2, 5, 0, ""), consemver.NewFromInt(2, 6, 0, "")},
|
||||||
currentCLI: "v2.4.0",
|
currentCLI: consemver.NewFromInt(2, 4, 0, ""),
|
||||||
},
|
},
|
||||||
expected: "There are newer CLIs available (v2.5.0 v2.6.0), however, you need to upgrade your cluster's Kubernetes version first.\n",
|
expected: "There are newer CLIs available (v2.5.0 v2.6.0), however, you need to upgrade your cluster's Kubernetes version first.\n",
|
||||||
},
|
},
|
||||||
"cli compatible with K8s": {
|
"cli compatible with K8s": {
|
||||||
upgrade: versionUpgrade{
|
upgrade: versionUpgrade{
|
||||||
newCompatibleCLI: []string{"v2.5.0", "v2.6.0"},
|
newCompatibleCLI: []consemver.Semver{consemver.NewFromInt(2, 5, 0, ""), consemver.NewFromInt(2, 6, 0, "")},
|
||||||
currentCLI: "v2.4.0",
|
currentCLI: consemver.NewFromInt(2, 4, 0, ""),
|
||||||
},
|
},
|
||||||
expected: "Newer CLI versions that are compatible with your cluster are: v2.5.0 v2.6.0\n",
|
expected: "Newer CLI versions that are compatible with your cluster are: v2.5.0 v2.6.0\n",
|
||||||
},
|
},
|
||||||
@ -76,14 +77,14 @@ func TestBuildString(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"no upgrades": {
|
"no upgrades": {
|
||||||
upgrade: versionUpgrade{
|
upgrade: versionUpgrade{
|
||||||
newServices: "",
|
newServices: consemver.Semver{},
|
||||||
newImages: map[string]measurements.M{},
|
newImages: map[string]measurements.M{},
|
||||||
newKubernetes: []string{},
|
newKubernetes: []string{},
|
||||||
newCLI: []string{},
|
newCLI: []consemver.Semver{},
|
||||||
currentServices: "v2.5.0",
|
currentServices: consemver.NewFromInt(2, 5, 0, ""),
|
||||||
currentImage: "v2.5.0",
|
currentImage: "v2.5.0",
|
||||||
currentKubernetes: "v1.25.6",
|
currentKubernetes: "v1.25.6",
|
||||||
currentCLI: "v2.5.0",
|
currentCLI: consemver.NewFromInt(2, 5, 0, ""),
|
||||||
},
|
},
|
||||||
expected: "You are up to date.\n",
|
expected: "You are up to date.\n",
|
||||||
},
|
},
|
||||||
@ -227,18 +228,18 @@ func TestUpgradeCheck(t *testing.T) {
|
|||||||
Kind: versionsapi.VersionKindImage,
|
Kind: versionsapi.VersionKindImage,
|
||||||
}
|
}
|
||||||
collector := stubVersionCollector{
|
collector := stubVersionCollector{
|
||||||
supportedServicesVersions: "v2.5.0",
|
supportedServicesVersions: consemver.NewFromInt(2, 5, 0, ""),
|
||||||
supportedImages: []versionsapi.Version{v2_3},
|
supportedImages: []versionsapi.Version{v2_3},
|
||||||
supportedImageVersions: map[string]measurements.M{
|
supportedImageVersions: map[string]measurements.M{
|
||||||
"v2.3.0": measurements.DefaultsFor(cloudprovider.GCP, variant.GCPSEVES{}),
|
"v2.3.0": measurements.DefaultsFor(cloudprovider.GCP, variant.GCPSEVES{}),
|
||||||
},
|
},
|
||||||
supportedK8sVersions: []string{"v1.24.5", "v1.24.12", "v1.25.6"},
|
supportedK8sVersions: []string{"v1.24.5", "v1.24.12", "v1.25.6"},
|
||||||
currentServicesVersions: "v2.4.0",
|
currentServicesVersions: consemver.NewFromInt(2, 4, 0, ""),
|
||||||
currentImageVersion: "v2.4.0",
|
currentImageVersion: "v2.4.0",
|
||||||
currentK8sVersion: "v1.24.5",
|
currentK8sVersion: "v1.24.5",
|
||||||
currentCLIVersion: "v2.4.0",
|
currentCLIVersion: consemver.NewFromInt(2, 4, 0, ""),
|
||||||
images: []versionsapi.Version{v2_5},
|
images: []versionsapi.Version{v2_5},
|
||||||
newCLIVersionsList: []string{"v2.5.0", "v2.6.0"},
|
newCLIVersionsList: []consemver.Semver{consemver.NewFromInt(2, 5, 0, ""), consemver.NewFromInt(2, 6, 0, "")},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
@ -305,18 +306,18 @@ func TestUpgradeCheck(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type stubVersionCollector struct {
|
type stubVersionCollector struct {
|
||||||
supportedServicesVersions string
|
supportedServicesVersions consemver.Semver
|
||||||
supportedImages []versionsapi.Version
|
supportedImages []versionsapi.Version
|
||||||
supportedImageVersions map[string]measurements.M
|
supportedImageVersions map[string]measurements.M
|
||||||
supportedK8sVersions []string
|
supportedK8sVersions []string
|
||||||
supportedCLIVersions []string
|
supportedCLIVersions []consemver.Semver
|
||||||
currentServicesVersions string
|
currentServicesVersions consemver.Semver
|
||||||
currentImageVersion string
|
currentImageVersion string
|
||||||
currentK8sVersion string
|
currentK8sVersion string
|
||||||
currentCLIVersion string
|
currentCLIVersion consemver.Semver
|
||||||
images []versionsapi.Version
|
images []versionsapi.Version
|
||||||
newCLIVersionsList []string
|
newCLIVersionsList []consemver.Semver
|
||||||
newCompatibleCLIVersionsList []string
|
newCompatibleCLIVersionsList []consemver.Semver
|
||||||
someErr error
|
someErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,11 +351,11 @@ func (s *stubVersionCollector) newerVersions(_ context.Context, _ []string) ([]v
|
|||||||
return s.images, nil
|
return s.images, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubVersionCollector) newCLIVersions(_ context.Context) ([]string, error) {
|
func (s *stubVersionCollector) newCLIVersions(_ context.Context) ([]consemver.Semver, error) {
|
||||||
return s.newCLIVersionsList, nil
|
return s.newCLIVersionsList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubVersionCollector) filterCompatibleCLIVersions(_ context.Context, _ []string, _ string) ([]string, error) {
|
func (s *stubVersionCollector) filterCompatibleCLIVersions(_ context.Context, _ []consemver.Semver, _ string) ([]consemver.Semver, error) {
|
||||||
return s.newCompatibleCLIVersionsList, nil
|
return s.newCompatibleCLIVersionsList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +409,7 @@ func TestNewCLIVersions(t *testing.T) {
|
|||||||
}
|
}
|
||||||
verCollector := func(minorList, patchList versionsapi.List, verListErr error) versionCollector {
|
verCollector := func(minorList, patchList versionsapi.List, verListErr error) versionCollector {
|
||||||
return versionCollector{
|
return versionCollector{
|
||||||
cliVersion: "v0.1.0",
|
cliVersion: consemver.NewFromInt(0, 1, 0, ""),
|
||||||
versionsapi: stubVersionFetcher{
|
versionsapi: stubVersionFetcher{
|
||||||
minorList: minorList,
|
minorList: minorList,
|
||||||
patchList: patchList,
|
patchList: patchList,
|
||||||
@ -451,7 +452,7 @@ func TestFilterCompatibleCLIVersions(t *testing.T) {
|
|||||||
someErr := errors.New("some error")
|
someErr := errors.New("some error")
|
||||||
verCollector := func(cliInfoErr error) versionCollector {
|
verCollector := func(cliInfoErr error) versionCollector {
|
||||||
return versionCollector{
|
return versionCollector{
|
||||||
cliVersion: "v0.1.0",
|
cliVersion: consemver.NewFromInt(0, 1, 0, ""),
|
||||||
versionsapi: stubVersionFetcher{
|
versionsapi: stubVersionFetcher{
|
||||||
cliInfoErr: cliInfoErr,
|
cliInfoErr: cliInfoErr,
|
||||||
},
|
},
|
||||||
@ -460,16 +461,16 @@ func TestFilterCompatibleCLIVersions(t *testing.T) {
|
|||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
verCollector versionCollector
|
verCollector versionCollector
|
||||||
cliPatchVersions []string
|
cliPatchVersions []consemver.Semver
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
"works": {
|
"works": {
|
||||||
verCollector: verCollector(nil),
|
verCollector: verCollector(nil),
|
||||||
cliPatchVersions: []string{"v0.1.1"},
|
cliPatchVersions: []consemver.Semver{consemver.NewFromInt(0, 1, 1, "")},
|
||||||
},
|
},
|
||||||
"cli info error": {
|
"cli info error": {
|
||||||
verCollector: verCollector(someErr),
|
verCollector: verCollector(someErr),
|
||||||
cliPatchVersions: []string{"v0.1.1"},
|
cliPatchVersions: []consemver.Semver{consemver.NewFromInt(0, 1, 1, "")},
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ func runVersion(cmd *cobra.Command, _ []string) {
|
|||||||
commit, state, date, goVersion, compiler, platform = parseStamp()
|
commit, state, date, goVersion, compiler, platform = parseStamp()
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Printf("Version:\t%s (%s)\n", constants.VersionInfo(), constants.VersionBuild)
|
cmd.Printf("Version:\t%s (%s)\n", constants.BinaryVersion().String(), constants.VersionBuild)
|
||||||
cmd.Printf("GitCommit:\t%s\n", commit)
|
cmd.Printf("GitCommit:\t%s\n", commit)
|
||||||
cmd.Printf("GitTreeState:\t%s\n", state)
|
cmd.Printf("GitTreeState:\t%s\n", state)
|
||||||
cmd.Printf("BuildDate:\t%s\n", date)
|
cmd.Printf("BuildDate:\t%s\n", date)
|
||||||
|
@ -30,7 +30,7 @@ func TestVersionCmd(t *testing.T) {
|
|||||||
|
|
||||||
s, err := io.ReadAll(b)
|
s, err := io.ReadAll(b)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Contains(string(s), constants.VersionInfo())
|
assert.Contains(string(s), constants.BinaryVersion().String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestParseBuildInfo(t *testing.T) {
|
func TestParseBuildInfo(t *testing.T) {
|
||||||
|
@ -459,6 +459,7 @@ go_test(
|
|||||||
"//internal/deploy/helm",
|
"//internal/deploy/helm",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
"//internal/semver",
|
||||||
"@com_github_pkg_errors//:errors",
|
"@com_github_pkg_errors//:errors",
|
||||||
"@com_github_spf13_afero//:afero",
|
"@com_github_spf13_afero//:afero",
|
||||||
"@com_github_stretchr_testify//assert",
|
"@com_github_stretchr_testify//assert",
|
||||||
|
@ -77,7 +77,7 @@ func NewClient(client crdClient, kubeConfigPath, helmNamespace string, log debug
|
|||||||
return &Client{kubectl: client, fs: fileHandler, actions: actions{config: actionConfig}, log: log}, nil
|
return &Client{kubectl: client, fs: fileHandler, actions: actions{config: actionConfig}, log: log}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) shouldUpgrade(releaseName, newVersion string, force bool) error {
|
func (c *Client) shouldUpgrade(releaseName string, newVersion semver.Semver, force bool) error {
|
||||||
currentVersion, err := c.currentVersion(releaseName)
|
currentVersion, err := c.currentVersion(releaseName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getting version for %s: %w", releaseName, err)
|
return fmt.Errorf("getting version for %s: %w", releaseName, err)
|
||||||
@ -88,14 +88,15 @@ func (c *Client) shouldUpgrade(releaseName, newVersion string, force bool) error
|
|||||||
// This may break for cert-manager or cilium if we decide to upgrade more than one minor version at a time.
|
// This may break for cert-manager or cilium if we decide to upgrade more than one minor version at a time.
|
||||||
// Leaving it as is since it is not clear to me what kind of sanity check we could do.
|
// Leaving it as is since it is not clear to me what kind of sanity check we could do.
|
||||||
if !force {
|
if !force {
|
||||||
if err := compatibility.IsValidUpgrade(currentVersion, newVersion); err != nil {
|
if err := newVersion.IsUpgradeTo(currentVersion); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cliVersion := constants.BinaryVersion()
|
||||||
// at this point we conclude that the release should be upgraded. check that this CLI supports the upgrade.
|
// at this point we conclude that the release should be upgraded. check that this CLI supports the upgrade.
|
||||||
if releaseName == constellationOperatorsInfo.releaseName || releaseName == constellationServicesInfo.releaseName {
|
if releaseName == constellationOperatorsInfo.releaseName || releaseName == constellationServicesInfo.releaseName {
|
||||||
if compatibility.EnsurePrefixV(constants.VersionInfo()) != compatibility.EnsurePrefixV(newVersion) {
|
if cliVersion.Compare(newVersion) != 0 {
|
||||||
return fmt.Errorf("this CLI only supports microservice version %s for upgrading", constants.VersionInfo())
|
return fmt.Errorf("this CLI only supports microservice version %s for upgrading", cliVersion.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.log.Debugf("Upgrading %s from %s to %s", releaseName, currentVersion, newVersion)
|
c.log.Debugf("Upgrading %s from %s to %s", releaseName, currentVersion, newVersion)
|
||||||
@ -118,13 +119,17 @@ func (c *Client) Upgrade(ctx context.Context, config *config.Config, idFile clus
|
|||||||
}
|
}
|
||||||
|
|
||||||
// define target version the chart is upgraded to
|
// define target version the chart is upgraded to
|
||||||
var upgradeVersion string
|
var upgradeVersion semver.Semver
|
||||||
if info == constellationOperatorsInfo || info == constellationServicesInfo {
|
if info == constellationOperatorsInfo || info == constellationServicesInfo {
|
||||||
// ensure that the services chart has the same version as the CLI
|
// ensure that the services chart has the same version as the CLI
|
||||||
updateVersions(chart, compatibility.EnsurePrefixV(constants.VersionInfo()))
|
updateVersions(chart, constants.BinaryVersion())
|
||||||
upgradeVersion = config.MicroserviceVersion
|
upgradeVersion = config.MicroserviceVersion
|
||||||
} else {
|
} else {
|
||||||
upgradeVersion = chart.Metadata.Version
|
chartVersion, err := semver.New(chart.Metadata.Version)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("parsing chart version: %w", err)
|
||||||
|
}
|
||||||
|
upgradeVersion = chartVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
var invalidUpgrade *compatibility.InvalidUpgradeError
|
var invalidUpgrade *compatibility.InvalidUpgradeError
|
||||||
@ -222,49 +227,51 @@ func (c *Client) Versions() (ServiceVersions, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res := ServiceVersions{
|
res := ServiceVersions{
|
||||||
cilium: compatibility.EnsurePrefixV(ciliumVersion),
|
cilium: ciliumVersion,
|
||||||
certManager: compatibility.EnsurePrefixV(certManagerVersion),
|
certManager: certManagerVersion,
|
||||||
constellationOperators: compatibility.EnsurePrefixV(operatorsVersion),
|
constellationOperators: operatorsVersion,
|
||||||
constellationServices: compatibility.EnsurePrefixV(servicesVersion),
|
constellationServices: servicesVersion,
|
||||||
|
awsLBController: awsLBVersion,
|
||||||
}
|
}
|
||||||
if awsLBVersion != "" {
|
if awsLBVersion != (semver.Semver{}) {
|
||||||
res.awsLBController = compatibility.EnsurePrefixV(awsLBVersion)
|
res.awsLBController = awsLBVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// currentVersion returns the version of the currently installed helm release.
|
// currentVersion returns the version of the currently installed helm release.
|
||||||
func (c *Client) currentVersion(release string) (string, error) {
|
func (c *Client) currentVersion(release string) (semver.Semver, error) {
|
||||||
rel, err := c.actions.listAction(release)
|
rel, err := c.actions.listAction(release)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return semver.Semver{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rel) == 0 {
|
if len(rel) == 0 {
|
||||||
return "", errReleaseNotFound
|
return semver.Semver{}, errReleaseNotFound
|
||||||
}
|
}
|
||||||
if len(rel) > 1 {
|
if len(rel) > 1 {
|
||||||
return "", fmt.Errorf("multiple releases found for %s", release)
|
return semver.Semver{}, fmt.Errorf("multiple releases found for %s", release)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rel[0] == nil || rel[0].Chart == nil || rel[0].Chart.Metadata == nil {
|
if rel[0] == nil || rel[0].Chart == nil || rel[0].Chart.Metadata == nil {
|
||||||
return "", fmt.Errorf("received invalid release %s", release)
|
return semver.Semver{}, fmt.Errorf("received invalid release %s", release)
|
||||||
}
|
}
|
||||||
|
|
||||||
return rel[0].Chart.Metadata.Version, nil
|
return semver.New(rel[0].Chart.Metadata.Version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServiceVersions bundles the versions of all services that are part of Constellation.
|
// ServiceVersions bundles the versions of all services that are part of Constellation.
|
||||||
type ServiceVersions struct {
|
type ServiceVersions struct {
|
||||||
cilium string
|
cilium semver.Semver
|
||||||
certManager string
|
certManager semver.Semver
|
||||||
constellationOperators string
|
constellationOperators semver.Semver
|
||||||
constellationServices string
|
constellationServices semver.Semver
|
||||||
awsLBController string
|
awsLBController semver.Semver
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewServiceVersions returns a new ServiceVersions struct.
|
// NewServiceVersions returns a new ServiceVersions struct.
|
||||||
func NewServiceVersions(cilium, certManager, constellationOperators, constellationServices string) ServiceVersions {
|
func NewServiceVersions(cilium, certManager, constellationOperators, constellationServices semver.Semver) ServiceVersions {
|
||||||
return ServiceVersions{
|
return ServiceVersions{
|
||||||
cilium: cilium,
|
cilium: cilium,
|
||||||
certManager: certManager,
|
certManager: certManager,
|
||||||
@ -274,22 +281,22 @@ func NewServiceVersions(cilium, certManager, constellationOperators, constellati
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cilium returns the version of the Cilium release.
|
// Cilium returns the version of the Cilium release.
|
||||||
func (s ServiceVersions) Cilium() string {
|
func (s ServiceVersions) Cilium() semver.Semver {
|
||||||
return s.cilium
|
return s.cilium
|
||||||
}
|
}
|
||||||
|
|
||||||
// CertManager returns the version of the cert-manager release.
|
// CertManager returns the version of the cert-manager release.
|
||||||
func (s ServiceVersions) CertManager() string {
|
func (s ServiceVersions) CertManager() semver.Semver {
|
||||||
return s.certManager
|
return s.certManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConstellationOperators returns the version of the constellation-operators release.
|
// ConstellationOperators returns the version of the constellation-operators release.
|
||||||
func (s ServiceVersions) ConstellationOperators() string {
|
func (s ServiceVersions) ConstellationOperators() semver.Semver {
|
||||||
return s.constellationOperators
|
return s.constellationOperators
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConstellationServices returns the version of the constellation-services release.
|
// ConstellationServices returns the version of the constellation-services release.
|
||||||
func (s ServiceVersions) ConstellationServices() string {
|
func (s ServiceVersions) ConstellationServices() semver.Semver {
|
||||||
return s.constellationServices
|
return s.constellationServices
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,12 +392,8 @@ func (c *Client) applyMigrations(ctx context.Context, releaseName string, values
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("getting %s version: %w", releaseName, err)
|
return fmt.Errorf("getting %s version: %w", releaseName, err)
|
||||||
}
|
}
|
||||||
currentV, err := semver.New(current)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("parsing current version: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if currentV.Major == 2 && currentV.Minor == 8 {
|
if current.Major() == 2 && current.Minor() == 8 {
|
||||||
// Rename/change the following function to implement any necessary migrations.
|
// Rename/change the following function to implement any necessary migrations.
|
||||||
return migrateFrom2_8(ctx, values, conf, c.kubectl)
|
return migrateFrom2_8(ctx, values, conf, c.kubectl)
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"helm.sh/helm/v3/pkg/chart"
|
"helm.sh/helm/v3/pkg/chart"
|
||||||
@ -49,7 +50,9 @@ func TestShouldUpgrade(t *testing.T) {
|
|||||||
|
|
||||||
chart, err := loadChartsDir(helmFS, certManagerInfo.path)
|
chart, err := loadChartsDir(helmFS, certManagerInfo.path)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
err = client.shouldUpgrade(certManagerInfo.releaseName, chart.Metadata.Version, false)
|
chartVersion, err := semver.New(chart.Metadata.Version)
|
||||||
|
require.NoError(err)
|
||||||
|
err = client.shouldUpgrade(certManagerInfo.releaseName, chartVersion, false)
|
||||||
if tc.wantError {
|
if tc.wantError {
|
||||||
tc.assertCorrectError(t, err)
|
tc.assertCorrectError(t, err)
|
||||||
return
|
return
|
||||||
|
@ -25,10 +25,10 @@ import (
|
|||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/cli/internal/helm/imageversion"
|
"github.com/edgelesssys/constellation/v2/cli/internal/helm/imageversion"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/deploy/helm"
|
"github.com/edgelesssys/constellation/v2/internal/deploy/helm"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -175,15 +175,15 @@ func (i *ChartLoader) loadRelease(info chartInfo, helmWaitMode helm.WaitMode) (h
|
|||||||
case certManagerInfo.releaseName:
|
case certManagerInfo.releaseName:
|
||||||
values = i.loadCertManagerValues()
|
values = i.loadCertManagerValues()
|
||||||
case constellationOperatorsInfo.releaseName:
|
case constellationOperatorsInfo.releaseName:
|
||||||
updateVersions(chart, compatibility.EnsurePrefixV(constants.VersionInfo()))
|
updateVersions(chart, constants.BinaryVersion())
|
||||||
values = i.loadOperatorsValues()
|
values = i.loadOperatorsValues()
|
||||||
case constellationServicesInfo.releaseName:
|
case constellationServicesInfo.releaseName:
|
||||||
updateVersions(chart, compatibility.EnsurePrefixV(constants.VersionInfo()))
|
updateVersions(chart, constants.BinaryVersion())
|
||||||
values = i.loadConstellationServicesValues()
|
values = i.loadConstellationServicesValues()
|
||||||
case awsLBControllerInfo.releaseName:
|
case awsLBControllerInfo.releaseName:
|
||||||
values = i.loadAWSLBControllerValues()
|
values = i.loadAWSLBControllerValues()
|
||||||
case csiInfo.releaseName:
|
case csiInfo.releaseName:
|
||||||
updateVersions(chart, compatibility.EnsurePrefixV(constants.VersionInfo()))
|
updateVersions(chart, constants.BinaryVersion())
|
||||||
values = i.loadCSIValues()
|
values = i.loadCSIValues()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,19 +378,19 @@ func extendConstellationServicesValues(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// updateVersions changes all versions of direct dependencies that are set to "0.0.0" to newVersion.
|
// updateVersions changes all versions of direct dependencies that are set to "0.0.0" to newVersion.
|
||||||
func updateVersions(chart *chart.Chart, newVersion string) {
|
func updateVersions(chart *chart.Chart, newVersion semver.Semver) {
|
||||||
chart.Metadata.Version = newVersion
|
chart.Metadata.Version = newVersion.String()
|
||||||
selectedDeps := chart.Metadata.Dependencies
|
selectedDeps := chart.Metadata.Dependencies
|
||||||
for i := range selectedDeps {
|
for i := range selectedDeps {
|
||||||
if selectedDeps[i].Version == "0.0.0" {
|
if selectedDeps[i].Version == "0.0.0" {
|
||||||
selectedDeps[i].Version = newVersion
|
selectedDeps[i].Version = newVersion.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deps := chart.Dependencies()
|
deps := chart.Dependencies()
|
||||||
for i := range deps {
|
for i := range deps {
|
||||||
if deps[i].Metadata.Version == "0.0.0" {
|
if deps[i].Metadata.Version == "0.0.0" {
|
||||||
deps[i].Metadata.Version = newVersion
|
deps[i].Metadata.Version = newVersion.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ func main() {
|
|||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
||||||
log.With(zap.String("version", constants.VersionInfo()), zap.String("cloudProvider", *csp)).
|
log.With(zap.String("version", constants.BinaryVersion().String()), zap.String("cloudProvider", *csp)).
|
||||||
Infof("Starting disk-mapper")
|
Infof("Starting disk-mapper")
|
||||||
|
|
||||||
// set up quote issuer for aTLS connections
|
// set up quote issuer for aTLS connections
|
||||||
|
@ -12,6 +12,7 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/logger",
|
"//internal/logger",
|
||||||
|
"//internal/semver",
|
||||||
"@sh_helm_helm_v3//pkg/action",
|
"@sh_helm_helm_v3//pkg/action",
|
||||||
"@sh_helm_helm_v3//pkg/cli",
|
"@sh_helm_helm_v3//pkg/cli",
|
||||||
],
|
],
|
||||||
|
@ -14,41 +14,42 @@ import (
|
|||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/logger"
|
"github.com/edgelesssys/constellation/v2/internal/logger"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
"helm.sh/helm/v3/pkg/action"
|
"helm.sh/helm/v3/pkg/action"
|
||||||
"helm.sh/helm/v3/pkg/cli"
|
"helm.sh/helm/v3/pkg/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func servicesVersion(t *testing.T) (string, error) {
|
func servicesVersion(t *testing.T) (semver.Semver, error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
log := logger.NewTest(t)
|
log := logger.NewTest(t)
|
||||||
settings := cli.New()
|
settings := cli.New()
|
||||||
settings.KubeConfig = "constellation-admin.conf"
|
settings.KubeConfig = "constellation-admin.conf"
|
||||||
actionConfig := &action.Configuration{}
|
actionConfig := &action.Configuration{}
|
||||||
if err := actionConfig.Init(settings.RESTClientGetter(), constants.HelmNamespace, "secret", log.Infof); err != nil {
|
if err := actionConfig.Init(settings.RESTClientGetter(), constants.HelmNamespace, "secret", log.Infof); err != nil {
|
||||||
return "", fmt.Errorf("initializing config: %w", err)
|
return semver.Semver{}, fmt.Errorf("initializing config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return currentVersion(actionConfig, "constellation-services")
|
return currentVersion(actionConfig, "constellation-services")
|
||||||
}
|
}
|
||||||
|
|
||||||
func currentVersion(cfg *action.Configuration, release string) (string, error) {
|
func currentVersion(cfg *action.Configuration, release string) (semver.Semver, error) {
|
||||||
action := action.NewList(cfg)
|
action := action.NewList(cfg)
|
||||||
action.Filter = release
|
action.Filter = release
|
||||||
rel, err := action.Run()
|
rel, err := action.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return semver.Semver{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(rel) == 0 {
|
if len(rel) == 0 {
|
||||||
return "", fmt.Errorf("release %s not found", release)
|
return semver.Semver{}, fmt.Errorf("release %s not found", release)
|
||||||
}
|
}
|
||||||
if len(rel) > 1 {
|
if len(rel) > 1 {
|
||||||
return "", fmt.Errorf("multiple releases found for %s", release)
|
return semver.Semver{}, fmt.Errorf("multiple releases found for %s", release)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rel[0] == nil || rel[0].Chart == nil || rel[0].Chart.Metadata == nil {
|
if rel[0] == nil || rel[0].Chart == nil || rel[0].Chart.Metadata == nil {
|
||||||
return "", fmt.Errorf("received invalid release %s", release)
|
return semver.Semver{}, fmt.Errorf("received invalid release %s", release)
|
||||||
}
|
}
|
||||||
|
|
||||||
return rel[0].Chart.Metadata.Version, nil
|
return semver.New(rel[0].Chart.Metadata.Version)
|
||||||
}
|
}
|
||||||
|
@ -293,11 +293,13 @@ func writeUpgradeConfig(require *require.Assertions, image string, kubernetes st
|
|||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var microserviceVersion string
|
var microserviceVersion semver.Semver
|
||||||
if microservices == "" {
|
if microservices == "" {
|
||||||
microserviceVersion = defaultConfig.MicroserviceVersion
|
microserviceVersion = defaultConfig.MicroserviceVersion
|
||||||
} else {
|
} else {
|
||||||
microserviceVersion = microservices
|
version, err := semver.New(microservices)
|
||||||
|
require.NoError(err)
|
||||||
|
microserviceVersion = version
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Printf("Setting K8s version: %s\n", kubernetesVersion.String())
|
log.Printf("Setting K8s version: %s\n", kubernetesVersion.String())
|
||||||
@ -330,10 +332,8 @@ func runUpgradeCheck(require *require.Assertions, cli, targetKubernetes string)
|
|||||||
require.Contains(string(stdout), targetKubernetes, fmt.Sprintf("Expected Kubernetes version %s in output.", targetKubernetes))
|
require.Contains(string(stdout), targetKubernetes, fmt.Sprintf("Expected Kubernetes version %s in output.", targetKubernetes))
|
||||||
}
|
}
|
||||||
|
|
||||||
cliVersion, err := semver.New(constants.VersionInfo())
|
|
||||||
require.NoError(err)
|
|
||||||
require.Contains(string(stdout), "Services:")
|
require.Contains(string(stdout), "Services:")
|
||||||
require.Contains(string(stdout), fmt.Sprintf("--> %s", cliVersion.String()))
|
require.Contains(string(stdout), fmt.Sprintf("--> %s", constants.BinaryVersion().String()))
|
||||||
|
|
||||||
log.Println(string(stdout))
|
log.Println(string(stdout))
|
||||||
}
|
}
|
||||||
@ -403,7 +403,7 @@ func testStatusEventuallyWorks(t *testing.T, cli string, timeout time.Duration)
|
|||||||
}, timeout, time.Minute)
|
}, timeout, time.Minute)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testMicroservicesEventuallyHaveVersion(t *testing.T, wantMicroserviceVersion string, timeout time.Duration) {
|
func testMicroservicesEventuallyHaveVersion(t *testing.T, wantMicroserviceVersion semver.Semver, timeout time.Duration) {
|
||||||
require.Eventually(t, func() bool {
|
require.Eventually(t, func() bool {
|
||||||
version, err := servicesVersion(t)
|
version, err := servicesVersion(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -460,7 +460,7 @@ func testNodesEventuallyHaveVersion(t *testing.T, k *kubernetes.Clientset, targe
|
|||||||
type versionContainer struct {
|
type versionContainer struct {
|
||||||
imageRef string
|
imageRef string
|
||||||
kubernetes semver.Semver
|
kubernetes semver.Semver
|
||||||
microservices string
|
microservices semver.Semver
|
||||||
}
|
}
|
||||||
|
|
||||||
// runCommandWithSeparateOutputs runs the given command while separating buffers for
|
// runCommandWithSeparateOutputs runs the given command while separating buffers for
|
||||||
|
@ -29,6 +29,7 @@ go_library(
|
|||||||
"//internal/config/instancetypes",
|
"//internal/config/instancetypes",
|
||||||
"//internal/constants",
|
"//internal/constants",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
|
"//internal/semver",
|
||||||
"//internal/versions",
|
"//internal/versions",
|
||||||
"@com_github_go_playground_locales//en",
|
"@com_github_go_playground_locales//en",
|
||||||
"@com_github_go_playground_universal_translator//:universal-translator",
|
"@com_github_go_playground_universal_translator//:universal-translator",
|
||||||
|
@ -40,10 +40,10 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/measurements"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config/imageversion"
|
"github.com/edgelesssys/constellation/v2/internal/config/imageversion"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ type Config struct {
|
|||||||
Version string `yaml:"version" validate:"eq=v3"`
|
Version string `yaml:"version" validate:"eq=v3"`
|
||||||
// description: |
|
// description: |
|
||||||
// Machine image version used to create Constellation nodes.
|
// Machine image version used to create Constellation nodes.
|
||||||
Image string `yaml:"image" validate:"required,version_compatibility"`
|
Image string `yaml:"image" validate:"required,image_compatibility"`
|
||||||
// description: |
|
// description: |
|
||||||
// Name of the cluster.
|
// Name of the cluster.
|
||||||
Name string `yaml:"name" validate:"valid_name,required"`
|
Name string `yaml:"name" validate:"valid_name,required"`
|
||||||
@ -75,7 +75,7 @@ type Config struct {
|
|||||||
KubernetesVersion string `yaml:"kubernetesVersion" validate:"required,supported_k8s_version"`
|
KubernetesVersion string `yaml:"kubernetesVersion" validate:"required,supported_k8s_version"`
|
||||||
// description: |
|
// description: |
|
||||||
// Microservice version to be installed into the cluster. Defaults to the version of the CLI.
|
// Microservice version to be installed into the cluster. Defaults to the version of the CLI.
|
||||||
MicroserviceVersion string `yaml:"microserviceVersion" validate:"required,version_compatibility"`
|
MicroserviceVersion semver.Semver `yaml:"microserviceVersion" validate:"required"`
|
||||||
// description: |
|
// description: |
|
||||||
// DON'T USE IN PRODUCTION: enable debug mode and use debug images.
|
// DON'T USE IN PRODUCTION: enable debug mode and use debug images.
|
||||||
DebugCluster *bool `yaml:"debugCluster" validate:"required"`
|
DebugCluster *bool `yaml:"debugCluster" validate:"required"`
|
||||||
@ -315,7 +315,7 @@ func Default() *Config {
|
|||||||
Version: Version3,
|
Version: Version3,
|
||||||
Image: defaultImage,
|
Image: defaultImage,
|
||||||
Name: defaultName,
|
Name: defaultName,
|
||||||
MicroserviceVersion: compatibility.EnsurePrefixV(constants.VersionInfo()),
|
MicroserviceVersion: constants.BinaryVersion(),
|
||||||
KubernetesVersion: string(versions.Default),
|
KubernetesVersion: string(versions.Default),
|
||||||
StateDiskSizeGB: 30,
|
StateDiskSizeGB: 30,
|
||||||
DebugCluster: toPtr(false),
|
DebugCluster: toPtr(false),
|
||||||
@ -725,7 +725,7 @@ func (c *Config) Validate(force bool) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := validate.RegisterTranslation("version_compatibility", trans, registerVersionCompatibilityError, translateVersionCompatibilityError); err != nil {
|
if err := validate.RegisterTranslation("image_compatibility", trans, registerImageCompatibilityError, translateImageCompatibilityError); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -750,7 +750,7 @@ func (c *Config) Validate(force bool) error {
|
|||||||
if force {
|
if force {
|
||||||
versionCompatibilityValidator = returnsTrue
|
versionCompatibilityValidator = returnsTrue
|
||||||
}
|
}
|
||||||
if err := validate.RegisterValidation("version_compatibility", versionCompatibilityValidator); err != nil {
|
if err := validate.RegisterValidation("image_compatibility", versionCompatibilityValidator); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -800,6 +800,18 @@ func (c *Config) Validate(force bool) error {
|
|||||||
validate.RegisterStructValidation(validateMeasurement, measurements.Measurement{})
|
validate.RegisterStructValidation(validateMeasurement, measurements.Measurement{})
|
||||||
validate.RegisterStructValidation(validateAttestation, AttestationConfig{})
|
validate.RegisterStructValidation(validateAttestation, AttestationConfig{})
|
||||||
|
|
||||||
|
if !force {
|
||||||
|
// Validating MicroserviceVersion separately is required since it is a custom type.
|
||||||
|
// The validation pkg we use does not allow accessing the field name during struct validation.
|
||||||
|
// Because of this we can't print the offending field name in the error message, resulting in
|
||||||
|
// suboptimal UX. Adding the field name to the struct validation of Semver would make it
|
||||||
|
// impossible to use Semver for other fields.
|
||||||
|
if err := validateMicroserviceVersion(constants.BinaryVersion(), c.MicroserviceVersion); err != nil {
|
||||||
|
msg := "microserviceVersion: " + msgFromCompatibilityError(err, constants.BinaryVersion().String(), c.MicroserviceVersion.String())
|
||||||
|
return &ValidationError{validationErrMsgs: []string{msg}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := validate.Struct(c)
|
err := validate.Struct(c)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -61,7 +61,7 @@ func init() {
|
|||||||
ConfigDoc.Fields[4].Description = "Kubernetes version to be installed into the cluster."
|
ConfigDoc.Fields[4].Description = "Kubernetes version to be installed into the cluster."
|
||||||
ConfigDoc.Fields[4].Comments[encoder.LineComment] = "Kubernetes version to be installed into the cluster."
|
ConfigDoc.Fields[4].Comments[encoder.LineComment] = "Kubernetes version to be installed into the cluster."
|
||||||
ConfigDoc.Fields[5].Name = "microserviceVersion"
|
ConfigDoc.Fields[5].Name = "microserviceVersion"
|
||||||
ConfigDoc.Fields[5].Type = "string"
|
ConfigDoc.Fields[5].Type = "Semver"
|
||||||
ConfigDoc.Fields[5].Note = ""
|
ConfigDoc.Fields[5].Note = ""
|
||||||
ConfigDoc.Fields[5].Description = "Microservice version to be installed into the cluster. Defaults to the version of the CLI."
|
ConfigDoc.Fields[5].Description = "Microservice version to be installed into the cluster. Defaults to the version of the CLI."
|
||||||
ConfigDoc.Fields[5].Comments[encoder.LineComment] = "Microservice version to be installed into the cluster. Defaults to the version of the CLI."
|
ConfigDoc.Fields[5].Comments[encoder.LineComment] = "Microservice version to be installed into the cluster. Defaults to the version of the CLI."
|
||||||
|
@ -140,7 +140,7 @@ func TestNew(t *testing.T) {
|
|||||||
|
|
||||||
func modifyConfigForAzureToPassValidate(c *Config) {
|
func modifyConfigForAzureToPassValidate(c *Config) {
|
||||||
c.RemoveProviderAndAttestationExcept(cloudprovider.Azure)
|
c.RemoveProviderAndAttestationExcept(cloudprovider.Azure)
|
||||||
c.Image = "v" + constants.VersionInfo()
|
c.Image = constants.BinaryVersion().String()
|
||||||
c.Provider.Azure.SubscriptionID = "11111111-1111-1111-1111-111111111111"
|
c.Provider.Azure.SubscriptionID = "11111111-1111-1111-1111-111111111111"
|
||||||
c.Provider.Azure.TenantID = "11111111-1111-1111-1111-111111111111"
|
c.Provider.Azure.TenantID = "11111111-1111-1111-1111-111111111111"
|
||||||
c.Provider.Azure.Location = "westus"
|
c.Provider.Azure.Location = "westus"
|
||||||
@ -308,13 +308,25 @@ func TestValidate(t *testing.T) {
|
|||||||
cnf.Image = ""
|
cnf.Image = ""
|
||||||
ver, err := semver.New(versions.SupportedK8sVersions()[0])
|
ver, err := semver.New(versions.SupportedK8sVersions()[0])
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
ver.Patch = ver.Patch - 1
|
ver = semver.NewFromInt(ver.Major(), ver.Minor(), ver.Patch()-1, "")
|
||||||
cnf.KubernetesVersion = ver.String()
|
cnf.KubernetesVersion = ver.String()
|
||||||
return cnf
|
return cnf
|
||||||
}(),
|
}(),
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
wantErrCount: defaultErrCount,
|
wantErrCount: defaultErrCount,
|
||||||
},
|
},
|
||||||
|
"microservices violate version drift": {
|
||||||
|
cnf: func() *Config {
|
||||||
|
cnf := Default()
|
||||||
|
cnf.Image = ""
|
||||||
|
cliVersion := constants.BinaryVersion()
|
||||||
|
cnf.MicroserviceVersion = semver.NewFromInt(cliVersion.Major()+2, cliVersion.Minor(), cliVersion.Patch(), "")
|
||||||
|
return cnf
|
||||||
|
}(),
|
||||||
|
wantErr: true,
|
||||||
|
// This is a very different value from the other error counts because of the way we are checking MicroserviceVersions.
|
||||||
|
wantErrCount: 1,
|
||||||
|
},
|
||||||
"v0 is one error": {
|
"v0 is one error": {
|
||||||
cnf: func() *Config {
|
cnf: func() *Config {
|
||||||
cnf := Default()
|
cnf := Default()
|
||||||
@ -350,7 +362,7 @@ func TestValidate(t *testing.T) {
|
|||||||
cnf: func() *Config {
|
cnf: func() *Config {
|
||||||
cnf := Default()
|
cnf := Default()
|
||||||
cnf.RemoveProviderAndAttestationExcept(cloudprovider.Azure)
|
cnf.RemoveProviderAndAttestationExcept(cloudprovider.Azure)
|
||||||
cnf.Image = "v" + constants.VersionInfo()
|
cnf.Image = constants.BinaryVersion().String()
|
||||||
az := cnf.Provider.Azure
|
az := cnf.Provider.Azure
|
||||||
az.SubscriptionID = "01234567-0123-0123-0123-0123456789ab"
|
az.SubscriptionID = "01234567-0123-0123-0123-0123456789ab"
|
||||||
az.TenantID = "01234567-0123-0123-0123-0123456789ab"
|
az.TenantID = "01234567-0123-0123-0123-0123456789ab"
|
||||||
@ -411,7 +423,7 @@ func TestValidate(t *testing.T) {
|
|||||||
cnf: func() *Config {
|
cnf: func() *Config {
|
||||||
cnf := Default()
|
cnf := Default()
|
||||||
cnf.RemoveProviderAndAttestationExcept(cloudprovider.GCP)
|
cnf.RemoveProviderAndAttestationExcept(cloudprovider.GCP)
|
||||||
cnf.Image = "v" + constants.VersionInfo()
|
cnf.Image = constants.BinaryVersion().String()
|
||||||
gcp := cnf.Provider.GCP
|
gcp := cnf.Provider.GCP
|
||||||
gcp.Region = "test-region"
|
gcp.Region = "test-region"
|
||||||
gcp.Project = "test-project"
|
gcp.Project = "test-project"
|
||||||
|
@ -11,5 +11,6 @@ go_library(
|
|||||||
"//internal/attestation/variant",
|
"//internal/attestation/variant",
|
||||||
"//internal/config",
|
"//internal/config",
|
||||||
"//internal/file",
|
"//internal/file",
|
||||||
|
"//internal/semver",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -28,11 +29,11 @@ const (
|
|||||||
// Config defines configuration used by CLI.
|
// Config defines configuration used by CLI.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Version string `yaml:"version" validate:"eq=v2"`
|
Version string `yaml:"version" validate:"eq=v2"`
|
||||||
Image string `yaml:"image" validate:"required,version_compatibility"`
|
Image string `yaml:"image" validate:"required,image_compatibility"`
|
||||||
Name string `yaml:"name" validate:"valid_name,required"`
|
Name string `yaml:"name" validate:"valid_name,required"`
|
||||||
StateDiskSizeGB int `yaml:"stateDiskSizeGB" validate:"min=0"`
|
StateDiskSizeGB int `yaml:"stateDiskSizeGB" validate:"min=0"`
|
||||||
KubernetesVersion string `yaml:"kubernetesVersion" validate:"required,supported_k8s_version"`
|
KubernetesVersion string `yaml:"kubernetesVersion" validate:"required,supported_k8s_version"`
|
||||||
MicroserviceVersion string `yaml:"microserviceVersion" validate:"required,version_compatibility"`
|
MicroserviceVersion string `yaml:"microserviceVersion" validate:"required"`
|
||||||
DebugCluster *bool `yaml:"debugCluster" validate:"required"`
|
DebugCluster *bool `yaml:"debugCluster" validate:"required"`
|
||||||
AttestationVariant string `yaml:"attestationVariant,omitempty" validate:"valid_attestation_variant"`
|
AttestationVariant string `yaml:"attestationVariant,omitempty" validate:"valid_attestation_variant"`
|
||||||
Provider ProviderConfig `yaml:"provider" validate:"dive"`
|
Provider ProviderConfig `yaml:"provider" validate:"dive"`
|
||||||
@ -195,6 +196,11 @@ func V2ToV3(path string, fileHandler file.Handler) error {
|
|||||||
return fmt.Errorf("reading config file %s using v2 format: %w", path, err)
|
return fmt.Errorf("reading config file %s using v2 format: %w", path, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
microserviceVersion, err := semver.New(cfgV2.MicroserviceVersion)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("parsing microservice version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
// Migrate to new format
|
// Migrate to new format
|
||||||
var cfgV3 config.Config
|
var cfgV3 config.Config
|
||||||
cfgV3.Version = config.Version3
|
cfgV3.Version = config.Version3
|
||||||
@ -202,7 +208,7 @@ func V2ToV3(path string, fileHandler file.Handler) error {
|
|||||||
cfgV3.Name = cfgV2.Name
|
cfgV3.Name = cfgV2.Name
|
||||||
cfgV3.StateDiskSizeGB = cfgV2.StateDiskSizeGB
|
cfgV3.StateDiskSizeGB = cfgV2.StateDiskSizeGB
|
||||||
cfgV3.KubernetesVersion = cfgV2.KubernetesVersion
|
cfgV3.KubernetesVersion = cfgV2.KubernetesVersion
|
||||||
cfgV3.MicroserviceVersion = cfgV2.MicroserviceVersion
|
cfgV3.MicroserviceVersion = microserviceVersion
|
||||||
cfgV3.DebugCluster = cfgV2.DebugCluster
|
cfgV3.DebugCluster = cfgV2.DebugCluster
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
|
"github.com/edgelesssys/constellation/v2/internal/config/instancetypes"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/constants"
|
||||||
|
consemver "github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
"github.com/edgelesssys/constellation/v2/internal/versions"
|
"github.com/edgelesssys/constellation/v2/internal/versions"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -86,11 +87,11 @@ func translateInvalidK8sVersionError(ut ut.Translator, fe validator.FieldError)
|
|||||||
configured = compatibility.EnsurePrefixV(configured)
|
configured = compatibility.EnsurePrefixV(configured)
|
||||||
switch {
|
switch {
|
||||||
case !semver.IsValid(configured):
|
case !semver.IsValid(configured):
|
||||||
errorMsg = "The configured version is not a valid semantic version"
|
errorMsg = "The configured version is not a valid semantic version\n"
|
||||||
case semver.Compare(configured, minVersion) == -1:
|
case semver.Compare(configured, minVersion) == -1:
|
||||||
errorMsg = fmt.Sprintf("The configured version %s is older than the oldest version supported by this CLI: %s", configured, minVersion)
|
errorMsg = fmt.Sprintf("The configured version %s is older than the oldest version supported by this CLI: %s\n", configured, minVersion)
|
||||||
case semver.Compare(configured, maxVersion) == 1:
|
case semver.Compare(configured, maxVersion) == 1:
|
||||||
errorMsg = fmt.Sprintf("The configured version %s is newer than the newest version supported by this CLI: %s", configured, maxVersion)
|
errorMsg = fmt.Sprintf("The configured version %s is newer than the newest version supported by this CLI: %s\n", configured, maxVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
errorMsg = errorMsg + fmt.Sprintf("Supported versions: %s", strings.Join(validVersionsSorted, " "))
|
errorMsg = errorMsg + fmt.Sprintf("Supported versions: %s", strings.Join(validVersionsSorted, " "))
|
||||||
@ -492,44 +493,21 @@ func K8sVersionFromMajorMinor(version string) string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerVersionCompatibilityError(ut ut.Translator) error {
|
func registerImageCompatibilityError(ut ut.Translator) error {
|
||||||
return ut.Add("version_compatibility", "{0} specifies an invalid version: {1}", true)
|
return ut.Add("image_compatibility", "{0} specifies an invalid version: {1}", true)
|
||||||
}
|
|
||||||
|
|
||||||
func translateVersionCompatibilityError(ut ut.Translator, fe validator.FieldError) string {
|
|
||||||
binaryVersion := constants.VersionInfo()
|
|
||||||
err := validateVersionCompatibilityHelper(binaryVersion, fe.Field(), fe.Value().(string))
|
|
||||||
var msg string
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case errors.Is(err, compatibility.ErrSemVer):
|
|
||||||
msg = fmt.Sprintf("configured version (%s) does not adhere to SemVer syntax", fe.Value().(string))
|
|
||||||
case errors.Is(err, compatibility.ErrMajorMismatch):
|
|
||||||
msg = fmt.Sprintf("the CLI's major version (%s) has to match your configured major version (%s). Use --force to ignore the version mismatch.", constants.VersionInfo(), fe.Value().(string))
|
|
||||||
case errors.Is(err, compatibility.ErrMinorDrift):
|
|
||||||
msg = fmt.Sprintf("the CLI's minor version (%s) and the configured version (%s) are more than one minor version apart. Use --force to ignore the version mismatch.", constants.VersionInfo(), fe.Value().(string))
|
|
||||||
case errors.Is(err, compatibility.ErrOutdatedCLI):
|
|
||||||
msg = fmt.Sprintf("the CLI's version (%s) is older than the configured version (%s). Use --force to ignore the version mismatch.", constants.VersionInfo(), fe.Value().(string))
|
|
||||||
default:
|
|
||||||
msg = err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
t, _ := ut.T("version_compatibility", fe.Field(), msg)
|
|
||||||
|
|
||||||
return t
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that the validated field and the CLI version are not more than one minor version apart.
|
// Check that the validated field and the CLI version are not more than one minor version apart.
|
||||||
func validateVersionCompatibility(fl validator.FieldLevel) bool {
|
func validateVersionCompatibility(fl validator.FieldLevel) bool {
|
||||||
binaryVersion := constants.VersionInfo()
|
binaryVersion := constants.BinaryVersion()
|
||||||
if err := validateVersionCompatibilityHelper(binaryVersion, fl.FieldName(), fl.Field().String()); err != nil {
|
if err := validateImageCompatibilityHelper(binaryVersion, fl.FieldName(), fl.Field().String()); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateVersionCompatibilityHelper(binaryVersion, fieldName, configuredVersion string) error {
|
func validateImageCompatibilityHelper(binaryVersion consemver.Semver, fieldName, configuredVersion string) error {
|
||||||
if fieldName == "image" {
|
if fieldName == "image" {
|
||||||
imageVersion, err := versionsapi.NewVersionFromShortPath(configuredVersion, versionsapi.VersionKindImage)
|
imageVersion, err := versionsapi.NewVersionFromShortPath(configuredVersion, versionsapi.VersionKindImage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -538,15 +516,51 @@ func validateVersionCompatibilityHelper(binaryVersion, fieldName, configuredVers
|
|||||||
configuredVersion = imageVersion.Version
|
configuredVersion = imageVersion.Version
|
||||||
}
|
}
|
||||||
|
|
||||||
if fieldName == "microserviceVersion" {
|
return compatibility.BinaryWith(binaryVersion.String(), configuredVersion)
|
||||||
cliVersion := compatibility.EnsurePrefixV(binaryVersion)
|
}
|
||||||
serviceVersion := compatibility.EnsurePrefixV(configuredVersion)
|
|
||||||
if semver.Compare(cliVersion, serviceVersion) == -1 {
|
func translateImageCompatibilityError(ut ut.Translator, fe validator.FieldError) string {
|
||||||
return fmt.Errorf("the CLI's version (%s) is older than the configured version (%s)", cliVersion, serviceVersion)
|
binaryVersion := constants.BinaryVersion()
|
||||||
}
|
err := validateImageCompatibilityHelper(binaryVersion, fe.Field(), fe.Value().(string))
|
||||||
|
|
||||||
|
msg := msgFromCompatibilityError(err, binaryVersion.String(), fe.Value().(string))
|
||||||
|
|
||||||
|
t, _ := ut.T("image_compatibility", fe.Field(), msg)
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// msgFromCompatibilityError translates compatibility errors into user-facing error messages.
|
||||||
|
func msgFromCompatibilityError(err error, binaryVersion, fieldValue string) string {
|
||||||
|
switch {
|
||||||
|
case errors.Is(err, compatibility.ErrSemVer):
|
||||||
|
return fmt.Sprintf("configured version (%s) does not adhere to SemVer syntax", fieldValue)
|
||||||
|
case errors.Is(err, compatibility.ErrMajorMismatch):
|
||||||
|
return fmt.Sprintf("the CLI's major version (%s) has to match your configured major version (%s). Use --force to ignore the version mismatch.", binaryVersion, fieldValue)
|
||||||
|
case errors.Is(err, compatibility.ErrMinorDrift):
|
||||||
|
return fmt.Sprintf("the CLI's minor version (%s) and the configured version (%s) are more than one minor version apart. Use --force to ignore the version mismatch.", binaryVersion, fieldValue)
|
||||||
|
case errors.Is(err, compatibility.ErrOutdatedCLI):
|
||||||
|
return fmt.Sprintf("the CLI's version (%s) is older than the configured version (%s). Use --force to ignore the version mismatch.", binaryVersion, fieldValue)
|
||||||
|
default:
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateMicroserviceVersion(binaryVersion, version consemver.Semver) error {
|
||||||
|
// Major versions always have to match.
|
||||||
|
if binaryVersion.Major() != version.Major() {
|
||||||
|
return compatibility.ErrMajorMismatch
|
||||||
|
}
|
||||||
|
// Allow newer CLIs (for upgrades), but dissallow newer service versions.
|
||||||
|
if binaryVersion.Compare(version) == -1 {
|
||||||
|
return compatibility.ErrOutdatedCLI
|
||||||
|
}
|
||||||
|
// Abort if minor version drift between CLI and versionA value is greater than 1.
|
||||||
|
if binaryVersion.Minor()-version.Minor() > 1 {
|
||||||
|
return compatibility.ErrMinorDrift
|
||||||
}
|
}
|
||||||
|
|
||||||
return compatibility.BinaryWith(binaryVersion, configuredVersion)
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func returnsTrue(_ validator.FieldLevel) bool {
|
func returnsTrue(_ validator.FieldLevel) bool {
|
||||||
|
@ -9,26 +9,27 @@ package config
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestValidateVersionCompatibilityHelper checks that basic version and image short paths are correctly validated.
|
// TestValidateVersionCompatibilityHelper checks that basic version and image short paths are correctly validated.
|
||||||
func TestValidateVersionCompatibilityHelper(t *testing.T) {
|
func TestValidateVersionCompatibilityHelper(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
cli string
|
cli semver.Semver
|
||||||
target string
|
target string
|
||||||
wantError bool
|
wantError bool
|
||||||
}{
|
}{
|
||||||
"full version works": {
|
"full version works": {
|
||||||
cli: "0.1.0",
|
cli: semver.NewFromInt(0, 1, 0, ""),
|
||||||
target: "v0.0.0",
|
target: "v0.0.0",
|
||||||
},
|
},
|
||||||
"short path works": {
|
"short path works": {
|
||||||
cli: "0.1.0",
|
cli: semver.NewFromInt(0, 1, 0, ""),
|
||||||
target: "ref/main/stream/debug/v0.0.0-pre.0.20230109121528-d24fac00f018",
|
target: "ref/main/stream/debug/v0.0.0-pre.0.20230109121528-d24fac00f018",
|
||||||
},
|
},
|
||||||
"minor version difference > 1": {
|
"minor version difference > 1": {
|
||||||
cli: "0.0.0",
|
cli: semver.NewFromInt(0, 0, 0, ""),
|
||||||
target: "ref/main/stream/debug/v0.2.0-pre.0.20230109121528-d24fac00f018",
|
target: "ref/main/stream/debug/v0.2.0-pre.0.20230109121528-d24fac00f018",
|
||||||
wantError: true,
|
wantError: true,
|
||||||
},
|
},
|
||||||
@ -38,7 +39,43 @@ func TestValidateVersionCompatibilityHelper(t *testing.T) {
|
|||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
err := validateVersionCompatibilityHelper(tc.cli, "image", tc.target)
|
err := validateImageCompatibilityHelper(tc.cli, "image", tc.target)
|
||||||
|
if tc.wantError {
|
||||||
|
assert.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.NoError(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestValidateMicroserviceVersion(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
cli semver.Semver
|
||||||
|
services semver.Semver
|
||||||
|
wantError bool
|
||||||
|
}{
|
||||||
|
"success": {
|
||||||
|
cli: semver.NewFromInt(0, 1, 0, ""),
|
||||||
|
services: semver.NewFromInt(0, 0, 0, ""),
|
||||||
|
},
|
||||||
|
"minor version difference > 1": {
|
||||||
|
cli: semver.NewFromInt(0, 0, 0, ""),
|
||||||
|
services: semver.NewFromInt(0, 2, 0, "pre.0.20230109121528-d24fac00f018"),
|
||||||
|
wantError: true,
|
||||||
|
},
|
||||||
|
"major version difference": {
|
||||||
|
cli: semver.NewFromInt(0, 0, 0, ""),
|
||||||
|
services: semver.NewFromInt(1, 0, 0, ""),
|
||||||
|
wantError: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
err := validateMicroserviceVersion(tc.cli, tc.services)
|
||||||
if tc.wantError {
|
if tc.wantError {
|
||||||
assert.Error(err)
|
assert.Error(err)
|
||||||
return
|
return
|
||||||
|
@ -17,4 +17,5 @@ go_library(
|
|||||||
"timestamp": "{STABLE_STAMP_TIME}",
|
"timestamp": "{STABLE_STAMP_TIME}",
|
||||||
"versionInfo": "{STABLE_STAMP_VERSION}",
|
"versionInfo": "{STABLE_STAMP_VERSION}",
|
||||||
},
|
},
|
||||||
|
deps = ["//internal/semver"],
|
||||||
)
|
)
|
||||||
|
@ -11,7 +11,10 @@ Constants should never be overwritable by command line flags or configuration fi
|
|||||||
package constants
|
package constants
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/internal/semver"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -231,9 +234,15 @@ b92PDCpM7FZAINQF88s1TZS/HmRXYk62UJ4eqPduvUnJmXhNikhLbMi6fw==
|
|||||||
`
|
`
|
||||||
)
|
)
|
||||||
|
|
||||||
// VersionInfo returns the version of a binary.
|
// BinaryVersion returns the version of this Binary.
|
||||||
func VersionInfo() string {
|
func BinaryVersion() semver.Semver {
|
||||||
return versionInfo
|
version, err := semver.New(versionInfo)
|
||||||
|
if err != nil {
|
||||||
|
// This is not user input, unrecoverable, should never happen.
|
||||||
|
panic(fmt.Sprintf("parsing embedded version information: %s", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timestamp returns the commit timestamp of a binary.
|
// Timestamp returns the commit timestamp of a binary.
|
||||||
|
@ -7,7 +7,7 @@ go_library(
|
|||||||
importpath = "github.com/edgelesssys/constellation/v2/internal/semver",
|
importpath = "github.com/edgelesssys/constellation/v2/internal/semver",
|
||||||
visibility = ["//:__subpackages__"],
|
visibility = ["//:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
"//internal/constants",
|
"//internal/compatibility",
|
||||||
"@org_golang_x_mod//semver",
|
"@org_golang_x_mod//semver",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -19,5 +19,6 @@ go_test(
|
|||||||
deps = [
|
deps = [
|
||||||
"@com_github_stretchr_testify//assert",
|
"@com_github_stretchr_testify//assert",
|
||||||
"@com_github_stretchr_testify//require",
|
"@com_github_stretchr_testify//require",
|
||||||
|
"@in_gopkg_yaml_v3//:yaml_v3",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
@ -6,24 +6,37 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
Package semver provides functionality to parse and process semantic versions, as they are used in multiple components of Constellation.
|
Package semver provides functionality to parse and process semantic versions, as they are used in multiple components of Constellation.
|
||||||
|
|
||||||
|
The official [semantic versioning specification] disallows leading "v" prefixes.
|
||||||
|
However, the Constellation config uses the "v" prefix for versions to make version strings more recognizable.
|
||||||
|
This package bridges the gap between Go's semver pkg (doesn't allow "v" prefix) and the Constellation config (requires "v" prefix).
|
||||||
|
|
||||||
|
[semantic versioning specification]: https://semver.org/
|
||||||
*/
|
*/
|
||||||
package semver
|
package semver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/edgelesssys/constellation/v2/internal/constants"
|
"github.com/edgelesssys/constellation/v2/internal/compatibility"
|
||||||
"golang.org/x/mod/semver"
|
"golang.org/x/mod/semver"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Sort sorts a list of semantic version strings using [ByVersion].
|
||||||
|
func Sort(list []Semver) {
|
||||||
|
sort.Sort(byVersion(list))
|
||||||
|
}
|
||||||
|
|
||||||
// Semver represents a semantic version.
|
// Semver represents a semantic version.
|
||||||
type Semver struct {
|
type Semver struct {
|
||||||
Major int
|
major int
|
||||||
Minor int
|
minor int
|
||||||
Patch int
|
patch int
|
||||||
Prerelease string
|
prerelease string
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns a Version from a string.
|
// New returns a Version from a string.
|
||||||
@ -47,18 +60,72 @@ func New(version string) (Semver, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Semver{
|
return Semver{
|
||||||
Major: major,
|
major: major,
|
||||||
Minor: minor,
|
minor: minor,
|
||||||
Patch: patch,
|
patch: patch,
|
||||||
Prerelease: pre,
|
prerelease: pre,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewFromInt constructs a new Semver from three integers and prerelease string: MAJOR.MINOR.PATCH-PRERELEASE.
|
||||||
|
func NewFromInt(major, minor, patch int, prerelease string) Semver {
|
||||||
|
return Semver{
|
||||||
|
major: major,
|
||||||
|
minor: minor,
|
||||||
|
patch: patch,
|
||||||
|
prerelease: prerelease,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewSlice returns a slice of Semver from a slice of strings.
|
||||||
|
func NewSlice(in []string) ([]Semver, error) {
|
||||||
|
var out []Semver
|
||||||
|
for _, version := range in {
|
||||||
|
semVersion, err := New(version)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("parsing version %s: %w", version, err)
|
||||||
|
}
|
||||||
|
out = append(out, semVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToStrings converts a slice of Semver to a slice of strings.
|
||||||
|
func ToStrings(in []Semver) []string {
|
||||||
|
var out []string
|
||||||
|
for _, v := range in {
|
||||||
|
out = append(out, v.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// Major returns the major version of the object.
|
||||||
|
func (v Semver) Major() int {
|
||||||
|
return v.major
|
||||||
|
}
|
||||||
|
|
||||||
|
// Minor returns the minor version of the object.
|
||||||
|
func (v Semver) Minor() int {
|
||||||
|
return v.minor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Patch returns the patch version of the object.
|
||||||
|
func (v Semver) Patch() int {
|
||||||
|
return v.patch
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prerelease returns the prerelease section of the object.
|
||||||
|
func (v Semver) Prerelease() string {
|
||||||
|
return v.prerelease
|
||||||
|
}
|
||||||
|
|
||||||
// String returns the string representation of the version.
|
// String returns the string representation of the version.
|
||||||
func (v Semver) String() string {
|
func (v Semver) String() string {
|
||||||
version := fmt.Sprintf("v%d.%d.%d", v.Major, v.Minor, v.Patch)
|
version := fmt.Sprintf("v%d.%d.%d", v.major, v.minor, v.patch)
|
||||||
if v.Prerelease != "" {
|
if v.prerelease != "" {
|
||||||
return fmt.Sprintf("%s-%s", version, v.Prerelease)
|
return fmt.Sprintf("%s-%s", version, v.prerelease)
|
||||||
}
|
}
|
||||||
return version
|
return version
|
||||||
}
|
}
|
||||||
@ -70,29 +137,51 @@ func (v Semver) Compare(other Semver) int {
|
|||||||
|
|
||||||
// MajorMinorEqual returns if the major and minor version of two versions are equal.
|
// MajorMinorEqual returns if the major and minor version of two versions are equal.
|
||||||
func (v Semver) MajorMinorEqual(other Semver) bool {
|
func (v Semver) MajorMinorEqual(other Semver) bool {
|
||||||
return v.Major == other.Major && v.Minor == other.Minor
|
return v.major == other.major && v.minor == other.minor
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsUpgradeTo returns if a version is an upgrade to another version.
|
// IsUpgradeTo returns if a version is an upgrade to another version.
|
||||||
// It checks if the version of v is greater than the version of other and allows a drift of at most one minor version.
|
// It checks if the version of v is greater than the version of other and allows a drift of at most one minor version.
|
||||||
func (v Semver) IsUpgradeTo(other Semver) bool {
|
func (v Semver) IsUpgradeTo(other Semver) error {
|
||||||
return v.Compare(other) > 0 && v.Major == other.Major && v.Minor-other.Minor <= 1
|
if v.Compare(other) <= 0 {
|
||||||
}
|
return compatibility.NewInvalidUpgradeError(v.String(), other.String(), errors.New("current version newer than or equal to new version"))
|
||||||
|
}
|
||||||
// CompatibleWithBinary returns if a version is compatible version of the current built binary.
|
if v.major != other.major {
|
||||||
// It checks if the version of the binary is equal or greater than the current version and allows a drift of at most one minor version.
|
return compatibility.NewInvalidUpgradeError(v.String(), other.String(), compatibility.ErrMajorMismatch)
|
||||||
func (v Semver) CompatibleWithBinary() bool {
|
|
||||||
binaryVersion, err := New(constants.VersionInfo())
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return v.Compare(binaryVersion) == 0 || binaryVersion.IsUpgradeTo(v)
|
if v.minor-other.minor > 1 {
|
||||||
|
return compatibility.NewInvalidUpgradeError(v.String(), other.String(), compatibility.ErrMinorDrift)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextMinor returns the next minor version in the format "vMAJOR.MINOR".
|
// NextMinor returns the next minor version in the format "vMAJOR.MINOR+1".
|
||||||
func (v Semver) NextMinor() string {
|
func (v Semver) NextMinor() string {
|
||||||
return fmt.Sprintf("v%d.%d", v.Major, v.Minor+1)
|
return fmt.Sprintf("v%d.%d", v.major, v.minor+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalYAML implements the yaml.Marshaller interface.
|
||||||
|
func (v Semver) MarshalYAML() (any, error) {
|
||||||
|
return v.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalYAML implements the yaml.Unmarshaler interface.
|
||||||
|
func (v *Semver) UnmarshalYAML(unmarshal func(any) error) error {
|
||||||
|
var raw string
|
||||||
|
if err := unmarshal(&raw); err != nil {
|
||||||
|
return fmt.Errorf("unmarshalling to string: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := New(raw)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("parsing semantic version: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
*v = version
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON implements the json.Marshaler interface.
|
// MarshalJSON implements the json.Marshaler interface.
|
||||||
@ -115,3 +204,20 @@ func (v *Semver) UnmarshalJSON(data []byte) error {
|
|||||||
*v = version
|
*v = version
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// byVersion implements [sort.Interface] for sorting semantic version strings.
|
||||||
|
// Copied from Go's semver pkg with minimal modification.
|
||||||
|
// https://cs.opensource.google/go/x/mod/+/master:semver/semver.go
|
||||||
|
type byVersion []Semver
|
||||||
|
|
||||||
|
func (vs byVersion) Len() int { return len(vs) }
|
||||||
|
func (vs byVersion) Swap(i, j int) { vs[i], vs[j] = vs[j], vs[i] }
|
||||||
|
func (vs byVersion) Less(i, j int) bool {
|
||||||
|
cmp := vs[i].Compare(vs[j])
|
||||||
|
if cmp != 0 {
|
||||||
|
return cmp < 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// if versions are equal, sort by lexicographic order
|
||||||
|
return vs[i].String() < vs[j].String()
|
||||||
|
}
|
||||||
|
@ -7,20 +7,22 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||||||
package semver
|
package semver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
v1_18_0 = Semver{Major: 1, Minor: 18, Patch: 0}
|
v1_18_0 = Semver{major: 1, minor: 18, patch: 0}
|
||||||
v1_18_0Pre = Semver{Major: 1, Minor: 18, Patch: 0, Prerelease: "pre"}
|
v1_18_0Pre = Semver{major: 1, minor: 18, patch: 0, prerelease: "pre"}
|
||||||
v1_18_0PreExtra = Semver{Major: 1, Minor: 18, Patch: 0, Prerelease: "pre.1"}
|
v1_18_0PreExtra = Semver{major: 1, minor: 18, patch: 0, prerelease: "pre.1"}
|
||||||
v1_19_0 = Semver{Major: 1, Minor: 19, Patch: 0}
|
v1_19_0 = Semver{major: 1, minor: 19, patch: 0}
|
||||||
v1_18_1 = Semver{Major: 1, Minor: 18, Patch: 1}
|
v1_18_1 = Semver{major: 1, minor: 18, patch: 1}
|
||||||
v1_20_0 = Semver{Major: 1, Minor: 20, Patch: 0}
|
v1_20_0 = Semver{major: 1, minor: 20, patch: 0}
|
||||||
v2_0_0 = Semver{Major: 2, Minor: 0, Patch: 0}
|
v2_0_0 = Semver{major: 2, minor: 0, patch: 0}
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNewVersion(t *testing.T) {
|
func TestNewVersion(t *testing.T) {
|
||||||
@ -32,19 +34,19 @@ func TestNewVersion(t *testing.T) {
|
|||||||
"valid version": {
|
"valid version": {
|
||||||
version: "v1.18.0",
|
version: "v1.18.0",
|
||||||
want: Semver{
|
want: Semver{
|
||||||
Major: 1,
|
major: 1,
|
||||||
Minor: 18,
|
minor: 18,
|
||||||
Patch: 0,
|
patch: 0,
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
"valid version prerelease": {
|
"valid version prerelease": {
|
||||||
version: "v1.18.0-pre+yyyymmddhhmmss-abcdefabcdef",
|
version: "v1.18.0-pre+yyyymmddhhmmss-abcdefabcdef",
|
||||||
want: Semver{
|
want: Semver{
|
||||||
Major: 1,
|
major: 1,
|
||||||
Minor: 18,
|
minor: 18,
|
||||||
Patch: 0,
|
patch: 0,
|
||||||
Prerelease: "pre",
|
prerelease: "pre",
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
@ -53,27 +55,27 @@ func TestNewVersion(t *testing.T) {
|
|||||||
"add prefix": {
|
"add prefix": {
|
||||||
version: "1.18.0",
|
version: "1.18.0",
|
||||||
want: Semver{
|
want: Semver{
|
||||||
Major: 1,
|
major: 1,
|
||||||
Minor: 18,
|
minor: 18,
|
||||||
Patch: 0,
|
patch: 0,
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
"only major.minor": {
|
"only major.minor": {
|
||||||
version: "v1.18",
|
version: "v1.18",
|
||||||
want: Semver{
|
want: Semver{
|
||||||
Major: 1,
|
major: 1,
|
||||||
Minor: 18,
|
minor: 18,
|
||||||
Patch: 0,
|
patch: 0,
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
"only major": {
|
"only major": {
|
||||||
version: "v1",
|
version: "v1",
|
||||||
want: Semver{
|
want: Semver{
|
||||||
Major: 1,
|
major: 1,
|
||||||
Minor: 0,
|
minor: 0,
|
||||||
Patch: 0,
|
patch: 0,
|
||||||
},
|
},
|
||||||
wantErr: false,
|
wantErr: false,
|
||||||
},
|
},
|
||||||
@ -216,60 +218,59 @@ func TestComparison(t *testing.T) {
|
|||||||
|
|
||||||
func TestCanUpgrade(t *testing.T) {
|
func TestCanUpgrade(t *testing.T) {
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
version1 Semver
|
version1 Semver
|
||||||
version2 Semver
|
version2 Semver
|
||||||
want bool
|
wantUpgrade bool
|
||||||
wantErr bool
|
|
||||||
}{
|
}{
|
||||||
"equal": {
|
"equal": {
|
||||||
version1: v1_18_0,
|
version1: v1_18_0,
|
||||||
version2: v1_18_0,
|
version2: v1_18_0,
|
||||||
want: false,
|
wantUpgrade: false,
|
||||||
},
|
},
|
||||||
"patch less than": {
|
"patch less than": {
|
||||||
version1: v1_18_0,
|
version1: v1_18_0,
|
||||||
version2: v1_18_1,
|
version2: v1_18_1,
|
||||||
want: true,
|
wantUpgrade: true,
|
||||||
},
|
},
|
||||||
"minor less then": {
|
"minor less then": {
|
||||||
version1: v1_18_0,
|
version1: v1_18_0,
|
||||||
version2: v1_19_0,
|
version2: v1_19_0,
|
||||||
want: true,
|
wantUpgrade: true,
|
||||||
},
|
},
|
||||||
"minor too big drift": {
|
"minor too big drift": {
|
||||||
version1: v1_18_0,
|
version1: v1_18_0,
|
||||||
version2: v1_20_0,
|
version2: v1_20_0,
|
||||||
want: false,
|
wantUpgrade: false,
|
||||||
},
|
},
|
||||||
"major too big drift": {
|
"major too big drift": {
|
||||||
version1: v1_18_0,
|
version1: v1_18_0,
|
||||||
version2: v2_0_0,
|
version2: v2_0_0,
|
||||||
want: false,
|
wantUpgrade: false,
|
||||||
},
|
},
|
||||||
"greater than": {
|
"greater than": {
|
||||||
version1: v1_18_1,
|
version1: v1_18_1,
|
||||||
version2: v1_18_0,
|
version2: v1_18_0,
|
||||||
want: false,
|
wantUpgrade: false,
|
||||||
},
|
},
|
||||||
"prerelease less than": {
|
"prerelease less than": {
|
||||||
version1: v1_18_0Pre,
|
version1: v1_18_0Pre,
|
||||||
version2: v1_18_0,
|
version2: v1_18_0,
|
||||||
want: true,
|
wantUpgrade: true,
|
||||||
},
|
},
|
||||||
"prerelease greater than": {
|
"prerelease greater than": {
|
||||||
version1: v1_18_0,
|
version1: v1_18_0,
|
||||||
version2: v1_18_0Pre,
|
version2: v1_18_0Pre,
|
||||||
want: false,
|
wantUpgrade: false,
|
||||||
},
|
},
|
||||||
"prerelease equal": {
|
"prerelease equal": {
|
||||||
version1: v1_18_0Pre,
|
version1: v1_18_0Pre,
|
||||||
version2: v1_18_0Pre,
|
version2: v1_18_0Pre,
|
||||||
want: false,
|
wantUpgrade: false,
|
||||||
},
|
},
|
||||||
"prerelease extra": {
|
"prerelease extra": {
|
||||||
version1: v1_18_0Pre,
|
version1: v1_18_0Pre,
|
||||||
version2: v1_18_0PreExtra,
|
version2: v1_18_0PreExtra,
|
||||||
want: true,
|
wantUpgrade: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,7 +278,7 @@ func TestCanUpgrade(t *testing.T) {
|
|||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
assert.Equal(tc.want, tc.version2.IsUpgradeTo(tc.version1))
|
assert.Equal(tc.wantUpgrade, tc.version2.IsUpgradeTo(tc.version1) == nil)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -304,3 +305,89 @@ func TestNextMinor(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVersionMarshalYAML(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
version Semver
|
||||||
|
want string
|
||||||
|
}{
|
||||||
|
"simple": {
|
||||||
|
version: Semver{
|
||||||
|
major: 1,
|
||||||
|
minor: 18,
|
||||||
|
patch: 0,
|
||||||
|
prerelease: "",
|
||||||
|
},
|
||||||
|
want: "v1.18.0\n",
|
||||||
|
},
|
||||||
|
"with prerelease": {
|
||||||
|
version: Semver{
|
||||||
|
major: 1,
|
||||||
|
minor: 18,
|
||||||
|
patch: 0,
|
||||||
|
prerelease: "pre",
|
||||||
|
},
|
||||||
|
want: "v1.18.0-pre\n",
|
||||||
|
},
|
||||||
|
"empty semver": {
|
||||||
|
version: Semver{},
|
||||||
|
want: "v0.0.0\n",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, tc := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
marshalled, err := yaml.Marshal(tc.version)
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tc.want, string(marshalled))
|
||||||
|
|
||||||
|
var unmarshalled Semver
|
||||||
|
err = yaml.Unmarshal(marshalled, &unmarshalled)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tc.version, unmarshalled)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestVersionUnmarshalYAML(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
version []byte
|
||||||
|
want Semver
|
||||||
|
wantError bool
|
||||||
|
}{
|
||||||
|
"empty string": {
|
||||||
|
version: []byte(""),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, tc := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
var actual Semver
|
||||||
|
err := yaml.Unmarshal(tc.version, &actual)
|
||||||
|
if tc.wantError {
|
||||||
|
require.Error(t, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tc.want.Compare(actual), 0, fmt.Sprintf("expected %s, got %s", tc.want, actual))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSort(t *testing.T) {
|
||||||
|
testCases := map[string]struct {
|
||||||
|
input []Semver
|
||||||
|
want []Semver
|
||||||
|
}{
|
||||||
|
"": {
|
||||||
|
input: []Semver{NewFromInt(2, 0, 0, ""), NewFromInt(0, 0, 0, ""), NewFromInt(1, 5, 0, "aa"), NewFromInt(1, 5, 0, "bb"), NewFromInt(1, 0, 0, "")},
|
||||||
|
want: []Semver{NewFromInt(0, 0, 0, ""), NewFromInt(1, 0, 0, ""), NewFromInt(1, 5, 0, "aa"), NewFromInt(1, 5, 0, "bb"), NewFromInt(2, 0, 0, "")},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for name, tc := range testCases {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
Sort(tc.input)
|
||||||
|
require.Equal(t, tc.want, tc.input, fmt.Sprintf("expected %s, got %s", tc.want, tc.input))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -49,7 +49,7 @@ func main() {
|
|||||||
|
|
||||||
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
||||||
log.With(
|
log.With(
|
||||||
zap.String("version", constants.VersionInfo()),
|
zap.String("version", constants.BinaryVersion().String()),
|
||||||
zap.String("cloudProvider", *provider),
|
zap.String("cloudProvider", *provider),
|
||||||
zap.String("attestationVariant", *attestationVariant),
|
zap.String("attestationVariant", *attestationVariant),
|
||||||
).Infof("Constellation Node Join Service")
|
).Infof("Constellation Node Join Service")
|
||||||
|
@ -34,7 +34,7 @@ func main() {
|
|||||||
flag.Parse()
|
flag.Parse()
|
||||||
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
||||||
|
|
||||||
log.With(zap.String("version", constants.VersionInfo())).
|
log.With(zap.String("version", constants.BinaryVersion().String())).
|
||||||
Infof("Constellation Key Management Service")
|
Infof("Constellation Key Management Service")
|
||||||
|
|
||||||
// read master secret and salt
|
// read master secret and salt
|
||||||
|
@ -26,7 +26,7 @@ func main() {
|
|||||||
flag.Parse()
|
flag.Parse()
|
||||||
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
log := logger.New(logger.JSONLog, logger.VerbosityFromInt(*verbosity))
|
||||||
|
|
||||||
log.With(zap.String("version", constants.VersionInfo()), zap.String("attestationVariant", *attestationVariant)).
|
log.With(zap.String("version", constants.BinaryVersion().String()), zap.String("attestationVariant", *attestationVariant)).
|
||||||
Infof("Constellation Verification Service")
|
Infof("Constellation Verification Service")
|
||||||
|
|
||||||
variant, err := variant.FromString(*attestationVariant)
|
variant, err := variant.FromString(*attestationVariant)
|
||||||
|
Loading…
Reference in New Issue
Block a user