mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-06-19 19:54:22 -04:00
cli: generate state file during constellation config generate
(#2455)
* create state file during config generate * use written file in `constellation create` * document creation of state file * remove accidentally added test * check error when writing state file
This commit is contained in:
parent
e5513f14e6
commit
25b23689ad
6 changed files with 70 additions and 22 deletions
|
@ -10,6 +10,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/cli/internal/state"
|
||||||
"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/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
|
@ -25,8 +26,8 @@ import (
|
||||||
func newConfigGenerateCmd() *cobra.Command {
|
func newConfigGenerateCmd() *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "generate {aws|azure|gcp|openstack|qemu|stackit}",
|
Use: "generate {aws|azure|gcp|openstack|qemu|stackit}",
|
||||||
Short: "Generate a default configuration file",
|
Short: "Generate a default configuration and state file",
|
||||||
Long: "Generate a default configuration file for your selected cloud provider.",
|
Long: "Generate a default configuration and state file for your selected cloud provider.",
|
||||||
Args: cobra.MatchAll(
|
Args: cobra.MatchAll(
|
||||||
cobra.ExactArgs(1),
|
cobra.ExactArgs(1),
|
||||||
isCloudProvider(0),
|
isCloudProvider(0),
|
||||||
|
@ -92,6 +93,8 @@ func runConfigGenerate(cmd *cobra.Command, args []string) error {
|
||||||
|
|
||||||
func (cg *configGenerateCmd) configGenerate(cmd *cobra.Command, fileHandler file.Handler, provider cloudprovider.Provider, rawProvider string) error {
|
func (cg *configGenerateCmd) configGenerate(cmd *cobra.Command, fileHandler file.Handler, provider cloudprovider.Provider, rawProvider string) error {
|
||||||
cg.log.Debugf("Using cloud provider %s", provider.String())
|
cg.log.Debugf("Using cloud provider %s", provider.String())
|
||||||
|
|
||||||
|
// Config creation
|
||||||
conf, err := createConfigWithAttestationVariant(provider, rawProvider, cg.flags.attestationVariant)
|
conf, err := createConfigWithAttestationVariant(provider, rawProvider, cg.flags.attestationVariant)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("creating config: %w", err)
|
return fmt.Errorf("creating config: %w", err)
|
||||||
|
@ -99,11 +102,25 @@ func (cg *configGenerateCmd) configGenerate(cmd *cobra.Command, fileHandler file
|
||||||
conf.KubernetesVersion = cg.flags.k8sVersion
|
conf.KubernetesVersion = cg.flags.k8sVersion
|
||||||
cg.log.Debugf("Writing YAML data to configuration file")
|
cg.log.Debugf("Writing YAML data to configuration file")
|
||||||
if err := fileHandler.WriteYAML(constants.ConfigFilename, conf, file.OptMkdirAll); err != nil {
|
if err := fileHandler.WriteYAML(constants.ConfigFilename, conf, file.OptMkdirAll); err != nil {
|
||||||
return err
|
return fmt.Errorf("writing config file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.Println("Config file written to", cg.flags.pathPrefixer.PrefixPrintablePath(constants.ConfigFilename))
|
cmd.Println("Config file written to", cg.flags.pathPrefixer.PrefixPrintablePath(constants.ConfigFilename))
|
||||||
cmd.Println("Please fill in your CSP-specific configuration before proceeding.")
|
cmd.Println("Please fill in your CSP-specific configuration before proceeding.")
|
||||||
|
|
||||||
|
// State-file creation
|
||||||
|
stateFile := state.New()
|
||||||
|
switch provider {
|
||||||
|
case cloudprovider.GCP:
|
||||||
|
stateFile.SetInfrastructure(state.Infrastructure{GCP: &state.GCP{}})
|
||||||
|
case cloudprovider.Azure:
|
||||||
|
stateFile.SetInfrastructure(state.Infrastructure{Azure: &state.Azure{}})
|
||||||
|
}
|
||||||
|
if err = stateFile.WriteToFile(fileHandler, constants.StateFilename); err != nil {
|
||||||
|
return fmt.Errorf("writing state file: %w", err)
|
||||||
|
}
|
||||||
|
cmd.Println("State file written to", cg.flags.pathPrefixer.PrefixPrintablePath(constants.StateFilename))
|
||||||
|
|
||||||
cmd.Println("For more information refer to the documentation:")
|
cmd.Println("For more information refer to the documentation:")
|
||||||
cmd.Println("\thttps://docs.edgeless.systems/constellation/getting-started/first-steps")
|
cmd.Println("\thttps://docs.edgeless.systems/constellation/getting-started/first-steps")
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/edgelesssys/constellation/v2/cli/internal/state"
|
||||||
"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/config"
|
"github.com/edgelesssys/constellation/v2/internal/config"
|
||||||
|
@ -103,6 +104,9 @@ func TestConfigGenerateDefault(t *testing.T) {
|
||||||
err := fileHandler.ReadYAML(constants.ConfigFilename, &readConfig)
|
err := fileHandler.ReadYAML(constants.ConfigFilename, &readConfig)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(*config.Default(), readConfig)
|
assert.Equal(*config.Default(), readConfig)
|
||||||
|
|
||||||
|
_, err = state.ReadFromFile(fileHandler, constants.StateFilename)
|
||||||
|
assert.NoError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConfigGenerateDefaultProviderSpecific(t *testing.T) {
|
func TestConfigGenerateDefaultProviderSpecific(t *testing.T) {
|
||||||
|
@ -152,6 +156,15 @@ func TestConfigGenerateDefaultProviderSpecific(t *testing.T) {
|
||||||
err := fileHandler.ReadYAML(constants.ConfigFilename, &readConfig)
|
err := fileHandler.ReadYAML(constants.ConfigFilename, &readConfig)
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
assert.Equal(*wantConf, readConfig)
|
assert.Equal(*wantConf, readConfig)
|
||||||
|
|
||||||
|
stateFile, err := state.ReadFromFile(fileHandler, constants.StateFilename)
|
||||||
|
assert.NoError(err)
|
||||||
|
switch tc.provider {
|
||||||
|
case cloudprovider.GCP:
|
||||||
|
assert.NotNil(stateFile.Infrastructure.GCP)
|
||||||
|
case cloudprovider.Azure:
|
||||||
|
assert.NotNil(stateFile.Infrastructure.Azure)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,8 +191,12 @@ func (c *createCmd) create(cmd *cobra.Command, creator cloudCreator, fileHandler
|
||||||
}
|
}
|
||||||
c.log.Debugf("Successfully created the cloud resources for the cluster")
|
c.log.Debugf("Successfully created the cloud resources for the cluster")
|
||||||
|
|
||||||
state := state.New().SetInfrastructure(infraState)
|
stateFile, err := state.ReadFromFile(fileHandler, constants.StateFilename)
|
||||||
if err := state.WriteToFile(fileHandler, constants.StateFilename); err != nil {
|
if err != nil {
|
||||||
|
return fmt.Errorf("reading state file: %w", err)
|
||||||
|
}
|
||||||
|
stateFile = stateFile.SetInfrastructure(infraState)
|
||||||
|
if err := stateFile.WriteToFile(fileHandler, constants.StateFilename); err != nil {
|
||||||
return fmt.Errorf("writing state file: %w", err)
|
return fmt.Errorf("writing state file: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,13 +220,6 @@ func (c *createCmd) checkDirClean(fileHandler file.Handler) error {
|
||||||
c.flags.pathPrefixer.PrefixPrintablePath(constants.MasterSecretFilename),
|
c.flags.pathPrefixer.PrefixPrintablePath(constants.MasterSecretFilename),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
c.log.Debugf("Checking state file")
|
|
||||||
if _, err := fileHandler.Stat(constants.StateFilename); !errors.Is(err, fs.ErrNotExist) {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"file '%s' already exists in working directory. Constellation won't overwrite previous cluster state. Move it somewhere or delete it before creating a new cluster",
|
|
||||||
c.flags.pathPrefixer.PrefixPrintablePath(constants.StateFilename),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,21 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
fsWithDefaultConfig := func(require *require.Assertions, provider cloudprovider.Provider) afero.Fs {
|
fsWithDefaultConfigAndState := func(require *require.Assertions, provider cloudprovider.Provider) afero.Fs {
|
||||||
|
fs := afero.NewMemMapFs()
|
||||||
|
file := file.NewHandler(fs)
|
||||||
|
require.NoError(file.WriteYAML(constants.ConfigFilename, defaultConfigWithExpectedMeasurements(t, config.Default(), provider)))
|
||||||
|
stateFile := state.New()
|
||||||
|
switch provider {
|
||||||
|
case cloudprovider.GCP:
|
||||||
|
stateFile.SetInfrastructure(state.Infrastructure{GCP: &state.GCP{}})
|
||||||
|
case cloudprovider.Azure:
|
||||||
|
stateFile.SetInfrastructure(state.Infrastructure{Azure: &state.Azure{}})
|
||||||
|
}
|
||||||
|
require.NoError(stateFile.WriteToFile(file, constants.StateFilename))
|
||||||
|
return fs
|
||||||
|
}
|
||||||
|
fsWithoutState := func(require *require.Assertions, provider cloudprovider.Provider) afero.Fs {
|
||||||
fs := afero.NewMemMapFs()
|
fs := afero.NewMemMapFs()
|
||||||
file := file.NewHandler(fs)
|
file := file.NewHandler(fs)
|
||||||
require.NoError(file.WriteYAML(constants.ConfigFilename, defaultConfigWithExpectedMeasurements(t, config.Default(), provider)))
|
require.NoError(file.WriteYAML(constants.ConfigFilename, defaultConfigWithExpectedMeasurements(t, config.Default(), provider)))
|
||||||
|
@ -45,26 +59,26 @@ func TestCreate(t *testing.T) {
|
||||||
wantAbort bool
|
wantAbort bool
|
||||||
}{
|
}{
|
||||||
"create": {
|
"create": {
|
||||||
setupFs: fsWithDefaultConfig,
|
setupFs: fsWithDefaultConfigAndState,
|
||||||
creator: &stubCloudCreator{state: infraState},
|
creator: &stubCloudCreator{state: infraState},
|
||||||
provider: cloudprovider.GCP,
|
provider: cloudprovider.GCP,
|
||||||
yesFlag: true,
|
yesFlag: true,
|
||||||
},
|
},
|
||||||
"interactive": {
|
"interactive": {
|
||||||
setupFs: fsWithDefaultConfig,
|
setupFs: fsWithDefaultConfigAndState,
|
||||||
creator: &stubCloudCreator{state: infraState},
|
creator: &stubCloudCreator{state: infraState},
|
||||||
provider: cloudprovider.Azure,
|
provider: cloudprovider.Azure,
|
||||||
stdin: "yes\n",
|
stdin: "yes\n",
|
||||||
},
|
},
|
||||||
"interactive abort": {
|
"interactive abort": {
|
||||||
setupFs: fsWithDefaultConfig,
|
setupFs: fsWithDefaultConfigAndState,
|
||||||
creator: &stubCloudCreator{},
|
creator: &stubCloudCreator{},
|
||||||
provider: cloudprovider.GCP,
|
provider: cloudprovider.GCP,
|
||||||
stdin: "no\n",
|
stdin: "no\n",
|
||||||
wantAbort: true,
|
wantAbort: true,
|
||||||
},
|
},
|
||||||
"interactive error": {
|
"interactive error": {
|
||||||
setupFs: fsWithDefaultConfig,
|
setupFs: fsWithDefaultConfigAndState,
|
||||||
creator: &stubCloudCreator{},
|
creator: &stubCloudCreator{},
|
||||||
provider: cloudprovider.GCP,
|
provider: cloudprovider.GCP,
|
||||||
stdin: "foo\nfoo\nfoo\n",
|
stdin: "foo\nfoo\nfoo\n",
|
||||||
|
@ -103,8 +117,15 @@ func TestCreate(t *testing.T) {
|
||||||
yesFlag: true,
|
yesFlag: true,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
|
"state file does not exist": {
|
||||||
|
setupFs: fsWithoutState,
|
||||||
|
creator: &stubCloudCreator{},
|
||||||
|
provider: cloudprovider.GCP,
|
||||||
|
yesFlag: true,
|
||||||
|
wantErr: true,
|
||||||
|
},
|
||||||
"create error": {
|
"create error": {
|
||||||
setupFs: fsWithDefaultConfig,
|
setupFs: fsWithDefaultConfigAndState,
|
||||||
creator: &stubCloudCreator{createErr: someErr},
|
creator: &stubCloudCreator{createErr: someErr},
|
||||||
provider: cloudprovider.GCP,
|
provider: cloudprovider.GCP,
|
||||||
yesFlag: true,
|
yesFlag: true,
|
||||||
|
|
|
@ -13,7 +13,7 @@ If you encounter any problem with the following steps, make sure to use the [lat
|
||||||
|
|
||||||
## Create a cluster
|
## Create a cluster
|
||||||
|
|
||||||
1. Create the [configuration file](../workflows/config.md) for your cloud provider.
|
1. Create the [configuration file](../workflows/config.md) and state file for your cloud provider.
|
||||||
|
|
||||||
<tabs groupId="csp">
|
<tabs groupId="csp">
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ constellation [command]
|
||||||
Commands:
|
Commands:
|
||||||
|
|
||||||
* [config](#constellation-config): Work with the Constellation configuration file
|
* [config](#constellation-config): Work with the Constellation configuration file
|
||||||
* [generate](#constellation-config-generate): Generate a default configuration file
|
* [generate](#constellation-config-generate): Generate a default configuration and state file
|
||||||
* [fetch-measurements](#constellation-config-fetch-measurements): Fetch measurements for configured cloud provider and image
|
* [fetch-measurements](#constellation-config-fetch-measurements): Fetch measurements for configured cloud provider and image
|
||||||
* [instance-types](#constellation-config-instance-types): Print the supported instance types for all cloud providers
|
* [instance-types](#constellation-config-instance-types): Print the supported instance types for all cloud providers
|
||||||
* [kubernetes-versions](#constellation-config-kubernetes-versions): Print the Kubernetes versions supported by this CLI
|
* [kubernetes-versions](#constellation-config-kubernetes-versions): Print the Kubernetes versions supported by this CLI
|
||||||
|
@ -64,11 +64,11 @@ Work with the Constellation configuration file.
|
||||||
|
|
||||||
## constellation config generate
|
## constellation config generate
|
||||||
|
|
||||||
Generate a default configuration file
|
Generate a default configuration and state file
|
||||||
|
|
||||||
### Synopsis
|
### Synopsis
|
||||||
|
|
||||||
Generate a default configuration file for your selected cloud provider.
|
Generate a default configuration and state file for your selected cloud provider.
|
||||||
|
|
||||||
```
|
```
|
||||||
constellation config generate {aws|azure|gcp|openstack|qemu|stackit} [flags]
|
constellation config generate {aws|azure|gcp|openstack|qemu|stackit} [flags]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue