Purge provider argument from constellation create and verify

This commit is contained in:
Nils Hanke 2022-09-07 15:38:29 +02:00 committed by Nils Hanke
parent 7aded65ea8
commit ce0edc8c80
9 changed files with 31 additions and 233 deletions

View File

@ -23,16 +23,13 @@ import (
// NewCreateCmd returns a new cobra.Command for the create command.
func NewCreateCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create {aws|azure|gcp}",
Use: "create",
Short: "Create instances on a cloud platform for your Constellation cluster",
Long: "Create instances on a cloud platform for your Constellation cluster.",
Args: cobra.MatchAll(
cobra.ExactArgs(1),
isCloudProvider(0),
warnAWS(0),
cobra.ExactArgs(0),
),
ValidArgsFunction: createCompletion,
RunE: runCreate,
RunE: runCreate,
}
cmd.Flags().String("name", "constell", "create the cluster with the specified name")
cmd.Flags().BoolP("yes", "y", false, "create the cluster without further confirmation")
@ -44,15 +41,13 @@ func NewCreateCmd() *cobra.Command {
}
func runCreate(cmd *cobra.Command, args []string) error {
provider := cloudprovider.FromString(args[0])
fileHandler := file.NewHandler(afero.NewOsFs())
creator := cloudcmd.NewCreator(cmd.OutOrStdout())
return create(cmd, creator, fileHandler, provider)
return create(cmd, creator, fileHandler)
}
func create(cmd *cobra.Command, creator cloudCreator, fileHandler file.Handler, provider cloudprovider.Provider,
) (retErr error) {
func create(cmd *cobra.Command, creator cloudCreator, fileHandler file.Handler) (retErr error) {
flags, err := parseCreateFlags(cmd)
if err != nil {
return err
@ -62,7 +57,7 @@ func create(cmd *cobra.Command, creator cloudCreator, fileHandler file.Handler,
return err
}
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath, provider)
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath)
if err != nil {
return fmt.Errorf("reading and validating config: %w", err)
}
@ -92,6 +87,7 @@ func create(cmd *cobra.Command, creator cloudCreator, fileHandler file.Handler,
cmd.Println("")
}
provider := config.GetProvider()
var instanceType string
switch provider {
case cloudprovider.Azure:
@ -216,17 +212,6 @@ func writeIPtoIDFile(fileHandler file.Handler, state state.ConstellationState) e
return fileHandler.WriteJSON(constants.ClusterIDsFileName, idFile, file.OptNone)
}
// createCompletion handles the completion of the create command. It is frequently called
// while the user types arguments of the command to suggest completion.
func createCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
switch len(args) {
case 0:
return []string{"aws", "gcp", "azure"}, cobra.ShellCompDirectiveNoFileComp
default:
return []string{}, cobra.ShellCompDirectiveError
}
}
func must(err error) {
if err != nil {
panic(err)

View File

@ -18,37 +18,10 @@ import (
"github.com/edgelesssys/constellation/internal/file"
"github.com/edgelesssys/constellation/internal/state"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCreateArgumentValidation(t *testing.T) {
testCases := map[string]struct {
args []string
wantErr bool
}{
"gcp": {[]string{"gcp"}, false},
"azure": {[]string{"azure"}, false},
"aws waring": {[]string{"aws"}, true},
"too many args": {[]string{"gcp", "1", "2"}, true},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
err := NewCreateCmd().ValidateArgs(tc.args)
if tc.wantErr {
assert.Error(err)
} else {
assert.NoError(err)
}
})
}
}
func TestCreate(t *testing.T) {
testState := state.ConstellationState{Name: "test", LoadBalancerIP: "192.0.2.1"}
someErr := errors.New("failed")
@ -242,7 +215,7 @@ func TestCreate(t *testing.T) {
fileHandler := file.NewHandler(tc.setupFs(require))
err := create(cmd, tc.creator, fileHandler, tc.provider)
err := create(cmd, tc.creator, fileHandler)
if tc.wantErr {
assert.Error(err)
@ -314,36 +287,6 @@ func TestCheckDirClean(t *testing.T) {
}
}
func TestCreateCompletion(t *testing.T) {
testCases := map[string]struct {
args []string
wantResult []string
wantShellCD cobra.ShellCompDirective
}{
"first arg": {
args: []string{},
wantResult: []string{"aws", "gcp", "azure"},
wantShellCD: cobra.ShellCompDirectiveNoFileComp,
},
"second arg": {
args: []string{"gcp", "foo"},
wantResult: []string{},
wantShellCD: cobra.ShellCompDirectiveError,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
cmd := &cobra.Command{}
result, shellCD := createCompletion(cmd, tc.args, "")
assert.Equal(tc.wantResult, result)
assert.Equal(tc.wantShellCD, shellCD)
})
}
}
func intPtr(i int) *int {
return &i
}

View File

@ -47,12 +47,11 @@ import (
// NewInitCmd returns a new cobra.Command for the init command.
func NewInitCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "init",
Short: "Initialize the Constellation cluster",
Long: "Initialize the Constellation cluster. Start your confidential Kubernetes.",
ValidArgsFunction: initCompletion,
Args: cobra.ExactArgs(0),
RunE: runInitialize,
Use: "init",
Short: "Initialize the Constellation cluster",
Long: "Initialize the Constellation cluster. Start your confidential Kubernetes.",
Args: cobra.ExactArgs(0),
RunE: runInitialize,
}
cmd.Flags().String("master-secret", "", "path to base64-encoded master secret")
cmd.Flags().String("endpoint", "", "endpoint of the bootstrapper, passed as HOST[:PORT]")
@ -92,9 +91,7 @@ func initialize(cmd *cobra.Command, newDialer func(validator *cloudcmd.Validator
return fmt.Errorf("loading Constellation state file: %w", err)
}
provider := cloudprovider.FromString(stat.CloudProvider)
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath, provider)
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath)
if err != nil {
return fmt.Errorf("reading and validating config: %w", err)
}
@ -107,6 +104,7 @@ func initialize(cmd *cobra.Command, newDialer func(validator *cloudcmd.Validator
cmd.Printf("Warning: Constellation with Kubernetes %v is still in preview. Use only for evaluation purposes.\n", k8sVersion)
}
provider := config.GetProvider()
checker := license.NewChecker(quotaChecker, fileHandler)
if err := checker.CheckLicense(cmd.Context(), provider, config.Provider, cmd.Printf); err != nil {
cmd.Printf("License check failed: %v", err)
@ -414,15 +412,6 @@ func getScalingGroupsFromState(stat state.ConstellationState, config *config.Con
}
}
// initCompletion handels the completion of CLI arguments. It is frequently called
// while the user types arguments of the command to suggest completion.
func initCompletion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
if len(args) != 0 {
return []string{}, cobra.ShellCompDirectiveError
}
return []string{}, cobra.ShellCompDirectiveDefault
}
type grpcDialer interface {
Dial(ctx context.Context, target string) (*grpc.ClientConn, error)
}

View File

@ -33,7 +33,6 @@ import (
"github.com/edgelesssys/constellation/internal/oid"
"github.com/edgelesssys/constellation/internal/state"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
@ -273,45 +272,6 @@ func TestWriteOutput(t *testing.T) {
assert.Equal(expectedIDFile, testIDFile)
}
func TestInitCompletion(t *testing.T) {
testCases := map[string]struct {
args []string
toComplete string
wantResult []string
wantShellCD cobra.ShellCompDirective
}{
"first arg": {
args: []string{},
toComplete: "hello",
wantResult: []string{},
wantShellCD: cobra.ShellCompDirectiveDefault,
},
"secnod arg": {
args: []string{"23"},
toComplete: "/test/h",
wantResult: []string{},
wantShellCD: cobra.ShellCompDirectiveError,
},
"third arg": {
args: []string{"./file", "sth"},
toComplete: "./file",
wantResult: []string{},
wantShellCD: cobra.ShellCompDirectiveError,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
cmd := &cobra.Command{}
result, shellCD := initCompletion(cmd, tc.args, tc.toComplete)
assert.Equal(tc.wantResult, result)
assert.Equal(tc.wantShellCD, shellCD)
})
}
}
func TestReadOrGenerateMasterSecret(t *testing.T) {
testCases := map[string]struct {
filename string

View File

@ -11,12 +11,11 @@ import (
"fmt"
"io"
"github.com/edgelesssys/constellation/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/internal/config"
"github.com/edgelesssys/constellation/internal/file"
)
func readConfig(out io.Writer, fileHandler file.Handler, name string, provider cloudprovider.Provider) (*config.Config, error) {
func readConfig(out io.Writer, fileHandler file.Handler, name string) (*config.Config, error) {
if name == "" {
return config.Default(), nil
}
@ -25,13 +24,14 @@ func readConfig(out io.Writer, fileHandler file.Handler, name string, provider c
if err != nil {
return nil, err
}
if err := validateConfig(out, cnf, provider); err != nil {
if err := validateConfig(out, cnf); err != nil {
return nil, err
}
return cnf, nil
}
func validateConfig(out io.Writer, cnf *config.Config, provider cloudprovider.Provider) error {
func validateConfig(out io.Writer, cnf *config.Config) error {
msgs, err := cnf.Validate()
if err != nil {
return fmt.Errorf("performing config validation: %w", err)
@ -46,9 +46,5 @@ func validateConfig(out io.Writer, cnf *config.Config, provider cloudprovider.Pr
return errors.New("invalid configuration")
}
if provider != cloudprovider.Unknown && !cnf.HasProvider(provider) {
return fmt.Errorf("configuration doesn't contain provider: %v", provider)
}
return nil
}

View File

@ -71,13 +71,15 @@ func TestValidateConfig(t *testing.T) {
wantOutput: true,
wantErr: true,
},
"config without provider is ok if no provider required": {
"config without provider is not ok": {
cnf: func() *config.Config {
cnf := config.Default()
cnf.Provider = config.ProviderConfig{}
return cnf
}(),
wantErr: true,
},
"config without required provider": {
cnf: func() *config.Config {
cnf := config.Default()
@ -96,7 +98,7 @@ func TestValidateConfig(t *testing.T) {
out := &bytes.Buffer{}
err := validateConfig(out, tc.cnf, tc.provider)
err := validateConfig(out, tc.cnf)
if tc.wantErr {
assert.Error(err)

View File

@ -68,8 +68,7 @@ func recover(cmd *cobra.Command, fileHandler file.Handler, recoveryClient recove
}
provider := cloudprovider.FromString(stat.CloudProvider)
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath, provider)
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath)
if err != nil {
return fmt.Errorf("reading and validating config: %w", err)
}

View File

@ -17,7 +17,6 @@ import (
"github.com/edgelesssys/constellation/cli/internal/cloudcmd"
"github.com/edgelesssys/constellation/internal/atls"
"github.com/edgelesssys/constellation/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/internal/constants"
"github.com/edgelesssys/constellation/internal/crypto"
"github.com/edgelesssys/constellation/internal/file"
@ -31,15 +30,13 @@ import (
// NewVerifyCmd returns a new cobra.Command for the verify command.
func NewVerifyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "verify {aws|azure|gcp}",
Use: "verify",
Short: "Verify the confidential properties of a Constellation cluster",
Long: `Verify the confidential properties of a Constellation cluster.
If arguments aren't specified, values are read from ` + "`" + constants.ClusterIDsFileName + "`.",
Args: cobra.MatchAll(
cobra.ExactArgs(1),
isCloudProvider(0),
warnAWS(0),
cobra.ExactArgs(0),
),
RunE: runVerify,
}
@ -50,25 +47,23 @@ If arguments aren't specified, values are read from ` + "`" + constants.ClusterI
}
func runVerify(cmd *cobra.Command, args []string) error {
provider := cloudprovider.FromString(args[0])
fileHandler := file.NewHandler(afero.NewOsFs())
verifyClient := &constellationVerifier{dialer: dialer.New(nil, nil, &net.Dialer{})}
return verify(cmd, provider, fileHandler, verifyClient)
return verify(cmd, fileHandler, verifyClient)
}
func verify(
cmd *cobra.Command, provider cloudprovider.Provider, fileHandler file.Handler, verifyClient verifyClient,
) error {
func verify(cmd *cobra.Command, fileHandler file.Handler, verifyClient verifyClient) error {
flags, err := parseVerifyFlags(cmd, fileHandler)
if err != nil {
return err
}
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath, provider)
config, err := readConfig(cmd.OutOrStdout(), fileHandler, flags.configPath)
if err != nil {
return fmt.Errorf("reading and validating config: %w", err)
}
provider := config.GetProvider()
validators, err := cloudcmd.NewValidator(provider, config)
if err != nil {
return err
@ -181,17 +176,6 @@ func addPortIfMissing(endpoint string, defaultPort int) (string, error) {
return "", err
}
// verifyCompletion handles the completion of CLI arguments. It is frequently called
// while the user types arguments of the command to suggest completion.
func verifyCompletion(_ *cobra.Command, args []string, _ string) ([]string, cobra.ShellCompDirective) {
switch len(args) {
case 0:
return []string{"gcp", "azure"}, cobra.ShellCompDirectiveNoFileComp
default:
return []string{}, cobra.ShellCompDirectiveError
}
}
type constellationVerifier struct {
dialer grpcInsecureDialer
}

View File

@ -26,7 +26,6 @@ import (
"github.com/edgelesssys/constellation/internal/oid"
"github.com/edgelesssys/constellation/verify/verifyproto"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc"
@ -34,33 +33,6 @@ import (
rpcStatus "google.golang.org/grpc/status"
)
func TestVerifyCmdArgumentValidation(t *testing.T) {
testCases := map[string]struct {
args []string
wantErr bool
}{
"no args": {[]string{}, true},
"valid azure": {[]string{"azure"}, false},
"valid gcp": {[]string{"gcp"}, false},
"invalid provider": {[]string{"invalid", "192.0.2.1", "1234"}, true},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
cmd := NewVerifyCmd()
err := cmd.ValidateArgs(tc.args)
if tc.wantErr {
assert.Error(err)
} else {
assert.NoError(err)
}
})
}
}
func TestVerify(t *testing.T) {
zeroBase64 := base64.StdEncoding.EncodeToString([]byte("00000000000000000000000000000000"))
someErr := errors.New("failed")
@ -190,7 +162,7 @@ func TestVerify(t *testing.T) {
require.NoError(fileHandler.WriteJSON(constants.ClusterIDsFileName, tc.idFile, file.OptNone))
}
err := verify(cmd, tc.provider, fileHandler, tc.protoClient)
err := verify(cmd, fileHandler, tc.protoClient)
if tc.wantErr {
assert.Error(err)
@ -203,38 +175,6 @@ func TestVerify(t *testing.T) {
}
}
func TestVerifyCompletion(t *testing.T) {
testCases := map[string]struct {
args []string
toComplete string
wantResult []string
wantShellCD cobra.ShellCompDirective
}{
"first arg": {
args: []string{},
toComplete: "az",
wantResult: []string{"gcp", "azure"},
wantShellCD: cobra.ShellCompDirectiveNoFileComp,
},
"additional arg": {
args: []string{"gcp", "foo"},
wantResult: []string{},
wantShellCD: cobra.ShellCompDirectiveError,
},
}
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
assert := assert.New(t)
cmd := &cobra.Command{}
result, shellCD := verifyCompletion(cmd, tc.args, tc.toComplete)
assert.Equal(tc.wantResult, result)
assert.Equal(tc.wantShellCD, shellCD)
})
}
}
func TestVerifyClient(t *testing.T) {
testCases := map[string]struct {
attestationDoc atls.FakeAttestationDoc