cli: add --kubernetes flag (#1226)

The flag can be used to specify a Kubernetes version
in format MAJOR.MINOR and let the CLI extend the
value with the patch version.
This commit is contained in:
Otto Bittner 2023-02-21 14:05:41 +01:00 committed by GitHub
parent 477d667360
commit da7a870f54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 105 additions and 13 deletions

View File

@ -8,14 +8,18 @@ package cmd
import (
"fmt"
"strings"
"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/constants"
"github.com/edgelesssys/constellation/v2/internal/file"
"github.com/edgelesssys/constellation/v2/internal/versions"
"github.com/siderolabs/talos/pkg/machinery/config/encoder"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"golang.org/x/mod/semver"
)
func newConfigGenerateCmd() *cobra.Command {
@ -31,12 +35,14 @@ func newConfigGenerateCmd() *cobra.Command {
RunE: runConfigGenerate,
}
cmd.Flags().StringP("file", "f", constants.ConfigFilename, "path to output file, or '-' for stdout")
cmd.Flags().StringP("kubernetes", "k", semver.MajorMinor(config.Default().KubernetesVersion), "Kubernetes version to use in format MAJOR.MINOR")
return cmd
}
type generateFlags struct {
file string
file string
k8sVersion string
}
type configGenerateCmd struct {
@ -64,6 +70,11 @@ func (cg *configGenerateCmd) configGenerate(cmd *cobra.Command, fileHandler file
cg.log.Debugf("Parsed flags as %v", flags)
cg.log.Debugf("Using cloud provider %s", provider.String())
conf := createConfig(provider)
extendedVersion := config.K8sVersionFromMajorMinor(flags.k8sVersion)
if extendedVersion == "" {
return fmt.Errorf("kubernetes (%s) does not specify a valid Kubernetes version. Supported versions: %s", strings.TrimPrefix(flags.k8sVersion, "v"), supportedVersions())
}
conf.KubernetesVersion = extendedVersion
if flags.file == "-" {
content, err := encoder.NewEncoder(conf).Encode()
if err != nil {
@ -101,13 +112,36 @@ func createConfig(provider cloudprovider.Provider) *config.Config {
return conf
}
// supportedVersions prints the supported version without v prefix and without patch version.
// Should only be used when accepting Kubernetes versions from --kubernetes.
func supportedVersions() string {
builder := strings.Builder{}
for i, version := range versions.SupportedK8sVersions() {
if i > 0 {
builder.WriteString(" ")
}
builder.WriteString(strings.TrimPrefix(semver.MajorMinor(version), "v"))
}
return builder.String()
}
func parseGenerateFlags(cmd *cobra.Command) (generateFlags, error) {
file, err := cmd.Flags().GetString("file")
if err != nil {
return generateFlags{}, fmt.Errorf("parsing config generate flags: %w", err)
return generateFlags{}, fmt.Errorf("parsing file flag: %w", err)
}
k8sVersion, err := cmd.Flags().GetString("kubernetes")
if err != nil {
return generateFlags{}, fmt.Errorf("parsing kuberentes flag: %w", err)
}
prefixedVersion := compatibility.EnsurePrefixV(k8sVersion)
if !semver.IsValid(prefixedVersion) {
return generateFlags{}, fmt.Errorf("kubernetes flag does not specify a valid semantic version: %s", k8sVersion)
}
return generateFlags{
file: file,
file: file,
k8sVersion: prefixedVersion,
}, nil
}

View File

@ -15,12 +15,54 @@ import (
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/file"
"github.com/edgelesssys/constellation/v2/internal/logger"
"github.com/edgelesssys/constellation/v2/internal/versions"
"github.com/spf13/afero"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/mod/semver"
"gopkg.in/yaml.v3"
)
func TestConfigGenerateKubernetesVersion(t *testing.T) {
testCases := map[string]struct {
version string
wantErr bool
}{
"success": {
version: semver.MajorMinor(string(versions.Default)),
},
"no semver": {
version: "asdf",
wantErr: true,
},
"not supported": {
version: "1111",
wantErr: true,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
fileHandler := file.NewHandler(afero.NewMemMapFs())
cmd := newConfigGenerateCmd()
err := cmd.Flags().Set("kubernetes", tc.version)
require.NoError(err)
cg := &configGenerateCmd{log: logger.NewTest(t)}
err = cg.configGenerate(cmd, fileHandler, cloudprovider.Unknown)
if tc.wantErr {
assert.Error(err)
return
}
assert.NoError(err)
})
}
}
func TestConfigGenerateDefault(t *testing.T) {
assert := assert.New(t)
require := require.New(t)

View File

@ -327,19 +327,35 @@ func (c *Config) validateK8sVersion(fl validator.FieldLevel) bool {
if !semver.IsValid(configVersion) {
return false
}
var extendedVersion string
switch semver.MajorMinor(configVersion) {
case semver.MajorMinor(string(versions.V1_24)):
extendedVersion = string(versions.V1_24)
case semver.MajorMinor(string(versions.V1_25)):
extendedVersion = string(versions.V1_25)
case semver.MajorMinor(string(versions.V1_26)):
extendedVersion = string(versions.V1_26)
default:
extendedVersion := K8sVersionFromMajorMinor(semver.MajorMinor(configVersion))
if extendedVersion == "" {
return false
}
valid := versions.IsSupportedK8sVersion(extendedVersion)
if !valid {
return false
}
c.KubernetesVersion = extendedVersion
return versions.IsSupportedK8sVersion(extendedVersion)
return true
}
// K8sVersionFromMajorMinor takes a semver in format MAJOR.MINOR
// and returns the version in format MAJOR.MINOR.PATCH with the
// supported patch version as PATCH.
func K8sVersionFromMajorMinor(version string) string {
switch version {
case semver.MajorMinor(string(versions.V1_24)):
return string(versions.V1_24)
case semver.MajorMinor(string(versions.V1_25)):
return string(versions.V1_25)
case semver.MajorMinor(string(versions.V1_26)):
return string(versions.V1_26)
default:
return ""
}
}
func registerVersionCompatibilityError(ut ut.Translator) error {