cli: add --workspace flag to set base directory for Constellation workspace (#2148)

* Remove `--config` and `--master-secret` falgs

* Add `--workspace` flag

* In CLI, only work on files with paths created from `cli/internal/cmd`

* Properly print values for GCP on IAM create when not directly updating the config

---------

Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
Daniel Weiße 2023-08-04 13:53:51 +02:00 committed by GitHub
parent ec33530c38
commit d1ace13713
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
57 changed files with 966 additions and 1145 deletions

View file

@ -162,8 +162,8 @@ func TestInitialize(t *testing.T) {
cmd.SetErr(&errOut)
// Flags
cmd.Flags().String("config", constants.ConfigFilename, "") // register persistent flag manually
cmd.Flags().Bool("force", true, "") // register persistent flag manually
cmd.Flags().String("workspace", "", "") // register persistent flag manually
cmd.Flags().Bool("force", true, "") // register persistent flag manually
// File system preparation
fs := afero.NewMemMapFs()
@ -175,7 +175,7 @@ func TestInitialize(t *testing.T) {
require.NoError(fileHandler.WriteYAML(constants.ConfigFilename, config, file.OptNone))
if tc.idFile != nil {
tc.idFile.CloudProvider = tc.provider
require.NoError(fileHandler.WriteJSON(constants.ClusterIDsFileName, tc.idFile, file.OptNone))
require.NoError(fileHandler.WriteJSON(constants.ClusterIDsFilename, tc.idFile, file.OptNone))
}
if tc.serviceAccKey != nil {
require.NoError(fileHandler.WriteJSON(serviceAccPath, tc.serviceAccKey, file.OptNone))
@ -301,9 +301,8 @@ func TestWriteOutput(t *testing.T) {
UID: "test-uid",
IP: "cluster-ip",
}
i := newInitCmd(nil, nil, fileHandler, nil, &stubMerger{}, logger.NewTest(t))
err := i.writeOutput(idFile, resp.GetInitSuccess(), false, &out)
err := i.writeOutput(idFile, resp.GetInitSuccess(), false, &out, "")
require.NoError(err)
// assert.Contains(out.String(), ownerID)
assert.Contains(out.String(), clusterID)
@ -314,29 +313,39 @@ func TestWriteOutput(t *testing.T) {
assert.NoError(err)
assert.Equal(string(resp.GetInitSuccess().GetKubeconfig()), string(adminConf))
idsFile, err := afs.ReadFile(constants.ClusterIDsFileName)
idsFile, err := afs.ReadFile(constants.ClusterIDsFilename)
assert.NoError(err)
var testIDFile clusterid.File
err = json.Unmarshal(idsFile, &testIDFile)
assert.NoError(err)
assert.Equal(expectedIDFile, testIDFile)
// test config merging
out.Reset()
require.NoError(afs.Remove(constants.AdminConfFilename))
err = i.writeOutput(idFile, resp.GetInitSuccess(), true, &out)
// test custom workspace
err = i.writeOutput(idFile, resp.GetInitSuccess(), true, &out, "some/path")
require.NoError(err)
// assert.Contains(out.String(), ownerID)
assert.Contains(out.String(), clusterID)
assert.Contains(out.String(), adminConfPath("some/path"))
out.Reset()
// File is written to current working dir, we simply pass the workspace for generating readable user output
require.NoError(afs.Remove(constants.AdminConfFilename))
// test config merging
err = i.writeOutput(idFile, resp.GetInitSuccess(), true, &out, "")
require.NoError(err)
// assert.Contains(out.String(), ownerID)
assert.Contains(out.String(), clusterID)
assert.Contains(out.String(), constants.AdminConfFilename)
assert.Contains(out.String(), "Constellation kubeconfig merged with default config")
assert.Contains(out.String(), "You can now connect to your cluster")
out.Reset()
require.NoError(afs.Remove(constants.AdminConfFilename))
// test config merging with env vars set
i.merger = &stubMerger{envVar: "/some/path/to/kubeconfig"}
out.Reset()
require.NoError(afs.Remove(constants.AdminConfFilename))
err = i.writeOutput(idFile, resp.GetInitSuccess(), true, &out)
err = i.writeOutput(idFile, resp.GetInitSuccess(), true, &out, "")
require.NoError(err)
// assert.Contains(out.String(), ownerID)
assert.Contains(out.String(), clusterID)
@ -345,79 +354,29 @@ func TestWriteOutput(t *testing.T) {
assert.Contains(out.String(), "Warning: KUBECONFIG environment variable is set")
}
func TestReadOrGenerateMasterSecret(t *testing.T) {
func TestGenerateMasterSecret(t *testing.T) {
testCases := map[string]struct {
filename string
createFileFunc func(handler file.Handler) error
fs func() afero.Fs
wantErr bool
}{
"file with secret exists": {
filename: "someSecret",
fs: afero.NewMemMapFs,
"file already exists": {
fs: afero.NewMemMapFs,
createFileFunc: func(handler file.Handler) error {
return handler.WriteJSON(
"someSecret",
constants.MasterSecretFilename,
uri.MasterSecret{Key: []byte("constellation-master-secret"), Salt: []byte("constellation-32Byte-length-salt")},
file.OptNone,
)
},
wantErr: false,
wantErr: true,
},
"no file given": {
filename: "",
"file does not exist": {
createFileFunc: func(handler file.Handler) error { return nil },
fs: afero.NewMemMapFs,
wantErr: false,
},
"file does not exist": {
filename: "nonExistingSecret",
createFileFunc: func(handler file.Handler) error { return nil },
fs: afero.NewMemMapFs,
wantErr: true,
},
"file is empty": {
filename: "emptySecret",
createFileFunc: func(handler file.Handler) error {
return handler.Write("emptySecret", []byte{}, file.OptNone)
},
fs: afero.NewMemMapFs,
wantErr: true,
},
"salt too short": {
filename: "shortSecret",
createFileFunc: func(handler file.Handler) error {
return handler.WriteJSON(
"shortSecret",
uri.MasterSecret{Key: []byte("constellation-master-secret"), Salt: []byte("short")},
file.OptNone,
)
},
fs: afero.NewMemMapFs,
wantErr: true,
},
"key too short": {
filename: "shortSecret",
createFileFunc: func(handler file.Handler) error {
return handler.WriteJSON(
"shortSecret",
uri.MasterSecret{Key: []byte("short"), Salt: []byte("constellation-32Byte-length-salt")},
file.OptNone,
)
},
fs: afero.NewMemMapFs,
wantErr: true,
},
"invalid file content": {
filename: "unencodedSecret",
createFileFunc: func(handler file.Handler) error {
return handler.Write("unencodedSecret", []byte("invalid-constellation-master-secret"), file.OptNone)
},
fs: afero.NewMemMapFs,
wantErr: true,
},
"file not writeable": {
filename: "",
createFileFunc: func(handler file.Handler) error { return nil },
fs: func() afero.Fs { return afero.NewReadOnlyFs(afero.NewMemMapFs()) },
wantErr: true,
@ -434,21 +393,17 @@ func TestReadOrGenerateMasterSecret(t *testing.T) {
var out bytes.Buffer
i := newInitCmd(nil, nil, fileHandler, nil, nil, logger.NewTest(t))
secret, err := i.readOrGenerateMasterSecret(&out, tc.filename)
secret, err := i.generateMasterSecret(&out, "")
if tc.wantErr {
assert.Error(err)
} else {
assert.NoError(err)
if tc.filename == "" {
require.Contains(out.String(), constants.MasterSecretFilename)
filename := strings.Split(out.String(), "./")
tc.filename = strings.Trim(filename[1], "\n")
}
require.Contains(out.String(), constants.MasterSecretFilename)
var masterSecret uri.MasterSecret
require.NoError(fileHandler.ReadJSON(tc.filename, &masterSecret))
require.NoError(fileHandler.ReadJSON(constants.MasterSecretFilename, &masterSecret))
assert.Equal(masterSecret.Key, secret.Key)
assert.Equal(masterSecret.Salt, secret.Salt)
}
@ -491,8 +446,8 @@ func TestAttestation(t *testing.T) {
defer initServer.GracefulStop()
cmd := NewInitCmd()
cmd.Flags().String("config", constants.ConfigFilename, "") // register persistent flag manually
cmd.Flags().Bool("force", true, "") // register persistent flag manually
cmd.Flags().String("workspace", "", "") // register persistent flag manually
cmd.Flags().Bool("force", true, "") // register persistent flag manually
var out bytes.Buffer
cmd.SetOut(&out)
var errOut bytes.Buffer
@ -500,7 +455,7 @@ func TestAttestation(t *testing.T) {
fs := afero.NewMemMapFs()
fileHandler := file.NewHandler(fs)
require.NoError(fileHandler.WriteJSON(constants.ClusterIDsFileName, existingIDFile, file.OptNone))
require.NoError(fileHandler.WriteJSON(constants.ClusterIDsFilename, existingIDFile, file.OptNone))
cfg := config.Default()
cfg.Image = "v0.0.0" // is the default version of the the CLI (before build injects the real version)