cli: support StackIT provider on config generate (#1803)

* support stackit provider on config generate

* update cli reference

* default config values

* deploy csi driver

Co-authored-by: Moritz Eckert <m1gh7ym0@gmail.com>

---------

Co-authored-by: Moritz Eckert <m1gh7ym0@gmail.com>
This commit is contained in:
Moritz Sanft 2023-05-30 09:02:50 +02:00 committed by GitHub
parent a0dea7e69b
commit 6d5e7e1f7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 108 additions and 32 deletions

View File

@ -25,7 +25,7 @@ import (
func newConfigGenerateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "generate {aws|azure|gcp|openstack|qemu}",
Use: "generate {aws|azure|gcp|openstack|qemu|stackit}",
Short: "Generate a default configuration file",
Long: "Generate a default configuration file for your selected cloud provider.",
Args: cobra.MatchAll(
@ -61,10 +61,10 @@ func runConfigGenerate(cmd *cobra.Command, args []string) error {
fileHandler := file.NewHandler(afero.NewOsFs())
provider := cloudprovider.FromString(args[0])
cg := &configGenerateCmd{log: log}
return cg.configGenerate(cmd, fileHandler, provider)
return cg.configGenerate(cmd, fileHandler, provider, args[0])
}
func (cg *configGenerateCmd) configGenerate(cmd *cobra.Command, fileHandler file.Handler, provider cloudprovider.Provider) error {
func (cg *configGenerateCmd) configGenerate(cmd *cobra.Command, fileHandler file.Handler, provider cloudprovider.Provider, rawProvider string) error {
flags, err := parseGenerateFlags(cmd)
if err != nil {
return err
@ -72,7 +72,7 @@ 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, err := createConfigWithAttestationType(provider, flags.attestationVariant)
conf, err := createConfigWithAttestationType(provider, rawProvider, flags.attestationVariant)
if err != nil {
return fmt.Errorf("creating config: %w", err)
}
@ -102,8 +102,8 @@ func (cg *configGenerateCmd) configGenerate(cmd *cobra.Command, fileHandler file
}
// createConfig creates a config file for the given provider.
func createConfigWithAttestationType(provider cloudprovider.Provider, attestationVariant variant.Variant) (*config.Config, error) {
conf := config.Default()
func createConfigWithAttestationType(provider cloudprovider.Provider, rawProvider string, attestationVariant variant.Variant) (*config.Config, error) {
conf := config.Default().WithOpenStackProviderDefaults(rawProvider)
conf.RemoveProviderExcept(provider)
// set a lower default for QEMU's state disk
@ -128,7 +128,8 @@ func createConfigWithAttestationType(provider cloudprovider.Provider, attestatio
// createConfig creates a config file for the given provider.
func createConfig(provider cloudprovider.Provider) *config.Config {
res, _ := createConfigWithAttestationType(provider, variant.Dummy{})
// rawProvider can be hardcoded as it only matters for OpenStack
res, _ := createConfigWithAttestationType(provider, "", variant.Dummy{})
return res
}
@ -186,7 +187,7 @@ func parseGenerateFlags(cmd *cobra.Command) (generateFlags, error) {
func generateCompletion(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) {
switch len(args) {
case 0:
return []string{"aws", "gcp", "azure", "qemu"}, cobra.ShellCompDirectiveNoFileComp
return []string{"aws", "gcp", "azure", "qemu", "stackit"}, cobra.ShellCompDirectiveNoFileComp
default:
return []string{}, cobra.ShellCompDirectiveError
}

View File

@ -55,7 +55,7 @@ func TestConfigGenerateKubernetesVersion(t *testing.T) {
require.NoError(err)
cg := &configGenerateCmd{log: logger.NewTest(t)}
err = cg.configGenerate(cmd, fileHandler, cloudprovider.Unknown)
err = cg.configGenerate(cmd, fileHandler, cloudprovider.Unknown, "")
if tc.wantErr {
assert.Error(err)
@ -74,7 +74,7 @@ func TestConfigGenerateDefault(t *testing.T) {
cmd := newConfigGenerateCmd()
cg := &configGenerateCmd{log: logger.NewTest(t)}
require.NoError(cg.configGenerate(cmd, fileHandler, cloudprovider.Unknown))
require.NoError(cg.configGenerate(cmd, fileHandler, cloudprovider.Unknown, ""))
var readConfig config.Config
err := fileHandler.ReadYAML(constants.ConfigFilename, &readConfig)
@ -82,23 +82,59 @@ func TestConfigGenerateDefault(t *testing.T) {
assert.Equal(*config.Default(), readConfig)
}
func TestConfigGenerateDefaultGCPSpecific(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
func TestConfigGenerateDefaultProviderSpecific(t *testing.T) {
providers := []cloudprovider.Provider{
cloudprovider.AWS,
cloudprovider.Azure,
cloudprovider.GCP,
cloudprovider.OpenStack,
}
fileHandler := file.NewHandler(afero.NewMemMapFs())
cmd := newConfigGenerateCmd()
for _, provider := range providers {
t.Run(provider.String(), func(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
wantConf := config.Default()
wantConf.RemoveProviderAndAttestationExcept(cloudprovider.GCP)
fileHandler := file.NewHandler(afero.NewMemMapFs())
cmd := newConfigGenerateCmd()
cg := &configGenerateCmd{log: logger.NewTest(t)}
require.NoError(cg.configGenerate(cmd, fileHandler, cloudprovider.GCP))
wantConf := config.Default()
wantConf.RemoveProviderAndAttestationExcept(provider)
var readConfig config.Config
err := fileHandler.ReadYAML(constants.ConfigFilename, &readConfig)
assert.NoError(err)
assert.Equal(*wantConf, readConfig)
cg := &configGenerateCmd{log: logger.NewTest(t)}
require.NoError(cg.configGenerate(cmd, fileHandler, provider, ""))
var readConfig config.Config
err := fileHandler.ReadYAML(constants.ConfigFilename, &readConfig)
assert.NoError(err)
assert.Equal(*wantConf, readConfig)
})
}
}
func TestConfigGenerateWithStackIt(t *testing.T) {
openStackProviders := []string{"stackit"}
for _, openStackProvider := range openStackProviders {
t.Run(openStackProvider, func(t *testing.T) {
assert := assert.New(t)
require := require.New(t)
fileHandler := file.NewHandler(afero.NewMemMapFs())
cmd := newConfigGenerateCmd()
wantConf := config.Default().WithOpenStackProviderDefaults(openStackProvider)
wantConf.RemoveProviderAndAttestationExcept(cloudprovider.OpenStack)
cg := &configGenerateCmd{log: logger.NewTest(t)}
require.NoError(cg.configGenerate(cmd, fileHandler, cloudprovider.OpenStack, openStackProvider))
var readConfig config.Config
err := fileHandler.ReadYAML(constants.ConfigFilename, &readConfig)
assert.NoError(err)
assert.Equal(*wantConf, readConfig)
})
}
}
func TestConfigGenerateDefaultExists(t *testing.T) {
@ -109,7 +145,7 @@ func TestConfigGenerateDefaultExists(t *testing.T) {
cmd := newConfigGenerateCmd()
cg := &configGenerateCmd{log: logger.NewTest(t)}
require.Error(cg.configGenerate(cmd, fileHandler, cloudprovider.Unknown))
require.Error(cg.configGenerate(cmd, fileHandler, cloudprovider.Unknown, ""))
}
func TestConfigGenerateFileFlagRemoved(t *testing.T) {
@ -120,7 +156,7 @@ func TestConfigGenerateFileFlagRemoved(t *testing.T) {
cmd.ResetFlags()
cg := &configGenerateCmd{log: logger.NewTest(t)}
require.Error(cg.configGenerate(cmd, fileHandler, cloudprovider.Unknown))
require.Error(cg.configGenerate(cmd, fileHandler, cloudprovider.Unknown, ""))
}
func TestConfigGenerateStdOut(t *testing.T) {
@ -135,7 +171,7 @@ func TestConfigGenerateStdOut(t *testing.T) {
require.NoError(cmd.Flags().Set("file", "-"))
cg := &configGenerateCmd{log: logger.NewTest(t)}
require.NoError(cg.configGenerate(cmd, fileHandler, cloudprovider.Unknown))
require.NoError(cg.configGenerate(cmd, fileHandler, cloudprovider.Unknown, ""))
var readConfig config.Config
require.NoError(yaml.NewDecoder(&outBuffer).Decode(&readConfig))
@ -153,10 +189,11 @@ func TestNoValidProviderAttestationCombination(t *testing.T) {
{cloudprovider.AWS, variant.AzureTrustedLaunch{}},
{cloudprovider.GCP, variant.AWSNitroTPM{}},
{cloudprovider.QEMU, variant.GCPSEVES{}},
{cloudprovider.OpenStack, variant.AWSNitroTPM{}},
}
for _, test := range tests {
t.Run("", func(t *testing.T) {
_, err := createConfigWithAttestationType(test.provider, test.attestation)
_, err := createConfigWithAttestationType(test.provider, "", test.attestation)
assert.Error(err)
})
}
@ -204,7 +241,7 @@ func TestValidProviderAttestationCombination(t *testing.T) {
}
for _, test := range tests {
t.Run(fmt.Sprintf("Provider:%s,Attestation:%s", test.provider, test.attestation), func(t *testing.T) {
sut, err := createConfigWithAttestationType(test.provider, test.attestation)
sut, err := createConfigWithAttestationType(test.provider, "", test.attestation)
assert := assert.New(t)
assert.NoError(err)
assert.Equal(test.expected, sut.Attestation)
@ -259,7 +296,7 @@ func TestAttestationArgument(t *testing.T) {
fileHandler := file.NewHandler(afero.NewMemMapFs())
cg := &configGenerateCmd{log: logger.NewTest(t)}
err := cg.configGenerate(cmd, fileHandler, test.provider)
err := cg.configGenerate(cmd, fileHandler, test.provider, "")
if test.expectErr {
assert.Error(err)
} else {

View File

@ -69,7 +69,7 @@ Generate a default configuration file
Generate a default configuration file for your selected cloud provider.
```
constellation config generate {aws|azure|gcp|openstack|qemu} [flags]
constellation config generate {aws|azure|gcp|openstack|qemu|stackit} [flags]
```
### Options

View File

@ -64,6 +64,10 @@ func (p *Provider) UnmarshalYAML(unmarshal func(any) error) error {
// FromString returns cloud provider from string.
func FromString(s string) Provider {
s = strings.ToLower(s)
if isOpenStackProvider(s) {
return OpenStack
}
switch s {
case "aws":
return AWS
@ -71,11 +75,18 @@ func FromString(s string) Provider {
return Azure
case "gcp":
return GCP
case "openstack":
return OpenStack
case "qemu":
return QEMU
default:
return Unknown
}
}
// IsOpenStackProvider returns true if the provider is based on OpenStack.
func isOpenStackProvider(s string) bool {
switch strings.ToLower(s) {
case "openstack", "stackit":
return true
}
return false
}

View File

@ -235,6 +235,10 @@ func TestFromString(t *testing.T) {
input: "openstack",
want: OpenStack,
},
"stackit": {
input: "stackit",
want: OpenStack,
},
"qemu": {
input: "qemu",
want: QEMU,

View File

@ -730,6 +730,29 @@ func (c *Config) Validate(force bool) error {
return &ValidationError{validationErrMsgs: validationErrMsgs}
}
// WithOpenStackProviderDefaults fills the default values for the specific OpenStack provider.
// If the provider is not supported or not an OpenStack provider, the config is returned unchanged.
func (c *Config) WithOpenStackProviderDefaults(openStackProvider string) *Config {
switch openStackProvider {
case "stackit":
c.Provider.OpenStack.Cloud = "stackit"
c.Provider.OpenStack.FlavorID = "2715eabe-3ffc-4c36-b02a-efa8c141a96a"
c.Provider.OpenStack.FloatingIPPoolID = "970ace5c-458f-484a-a660-0903bcfd91ad"
c.Provider.OpenStack.StateDiskType = "storage_premium_perf6"
c.Provider.OpenStack.AuthURL = "https://keystone.api.iaas.eu01.stackit.cloud/v3"
c.Provider.OpenStack.UserDomainName = "portal_mvp"
c.Provider.OpenStack.ProjectDomainName = "portal_mvp"
c.Provider.OpenStack.RegionName = "RegionOne"
c.Provider.OpenStack.DeployYawolLoadBalancer = toPtr(true)
c.Provider.OpenStack.YawolImageID = "43d9bede-1e7a-4ca7-82c5-0a5c72388619"
c.Provider.OpenStack.YawolFlavorID = "3b11b27e-6c73-470d-b595-1d85b95a8cdf"
c.Provider.OpenStack.DeployCSIDriver = toPtr(true)
c.Provider.OpenStack.DirectDownload = toPtr(true)
return c
}
return c
}
// AWSNitroTPM is the configuration for AWS Nitro TPM attestation.
type AWSNitroTPM struct {
// description: |