mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
file handler: Add "mkdirAll" flag
Signed-off-by: Malte Poll <mp@edgeless.systems>
This commit is contained in:
parent
49a1a07049
commit
e10a47f255
@ -112,7 +112,7 @@ func createAWS(cmd *cobra.Command, cl ec2client, fileHandler file.Handler, confi
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := fileHandler.WriteJSON(*config.StatePath, stat, false); err != nil {
|
if err := fileHandler.WriteJSON(*config.StatePath, stat, file.OptNone); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ func TestCreateAWS(t *testing.T) {
|
|||||||
fs := afero.NewMemMapFs()
|
fs := afero.NewMemMapFs()
|
||||||
fileHandler := file.NewHandler(fs)
|
fileHandler := file.NewHandler(fs)
|
||||||
if tc.existingState != nil {
|
if tc.existingState != nil {
|
||||||
require.NoError(fileHandler.WriteJSON(*config.StatePath, *tc.existingState, false))
|
require.NoError(fileHandler.WriteJSON(*config.StatePath, *tc.existingState, file.OptNone))
|
||||||
}
|
}
|
||||||
|
|
||||||
err := createAWS(cmd, tc.client, fileHandler, config, "xlarge", "name", 3)
|
err := createAWS(cmd, tc.client, fileHandler, config, "xlarge", "name", 3)
|
||||||
|
@ -120,7 +120,7 @@ func createAzure(cmd *cobra.Command, cl azureclient, fileHandler file.Handler, c
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := fileHandler.WriteJSON(*config.StatePath, stat, false); err != nil {
|
if err := fileHandler.WriteJSON(*config.StatePath, stat, file.OptNone); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ func TestCreateAzure(t *testing.T) {
|
|||||||
fs := afero.NewMemMapFs()
|
fs := afero.NewMemMapFs()
|
||||||
fileHandler := file.NewHandler(fs)
|
fileHandler := file.NewHandler(fs)
|
||||||
if tc.existingState != nil {
|
if tc.existingState != nil {
|
||||||
require.NoError(fileHandler.WriteJSON(*config.StatePath, *tc.existingState, false))
|
require.NoError(fileHandler.WriteJSON(*config.StatePath, *tc.existingState, file.OptNone))
|
||||||
}
|
}
|
||||||
|
|
||||||
err := createAzure(cmd, tc.client, fileHandler, config, "Standard_D2s_v3", 3, 2)
|
err := createAzure(cmd, tc.client, fileHandler, config, "Standard_D2s_v3", 3, 2)
|
||||||
|
@ -114,7 +114,7 @@ func createGCP(cmd *cobra.Command, cl gcpclient, fileHandler file.Handler, confi
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := fileHandler.WriteJSON(*config.StatePath, stat, false); err != nil {
|
if err := fileHandler.WriteJSON(*config.StatePath, stat, file.OptNone); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ func TestCreateGCP(t *testing.T) {
|
|||||||
fs := afero.NewMemMapFs()
|
fs := afero.NewMemMapFs()
|
||||||
fileHandler := file.NewHandler(fs)
|
fileHandler := file.NewHandler(fs)
|
||||||
if tc.existingState != nil {
|
if tc.existingState != nil {
|
||||||
require.NoError(fileHandler.WriteJSON(*config.StatePath, *tc.existingState, false))
|
require.NoError(fileHandler.WriteJSON(*config.StatePath, *tc.existingState, file.OptNone))
|
||||||
}
|
}
|
||||||
|
|
||||||
err := createGCP(cmd, tc.client, fileHandler, config, "n2d-standard-2", 3, 2)
|
err := createGCP(cmd, tc.client, fileHandler, config, "n2d-standard-2", 3, 2)
|
||||||
|
@ -49,7 +49,7 @@ func TestCheckDirClean(t *testing.T) {
|
|||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
for _, f := range tc.existingFiles {
|
for _, f := range tc.existingFiles {
|
||||||
require.NoError(tc.fileHandler.Write(f, []byte{1, 2, 3}, false))
|
require.NoError(tc.fileHandler.Write(f, []byte{1, 2, 3}, file.OptNone))
|
||||||
}
|
}
|
||||||
|
|
||||||
err := checkDirClean(tc.fileHandler, config)
|
err := checkDirClean(tc.fileHandler, config)
|
||||||
|
@ -101,7 +101,7 @@ func initialize(ctx context.Context, cmd *cobra.Command, protCl protoClient, ser
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := fileHandler.WriteJSON(*config.StatePath, stat, true); err != nil {
|
if err := fileHandler.WriteJSON(*config.StatePath, stat, file.OptOverwrite); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ func writeWGQuickFile(fileHandler file.Handler, config *config.Config, vpnHandle
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return fileHandler.Write(*config.WGQuickConfigPath, data, false)
|
return fileHandler.Write(*config.WGQuickConfigPath, data, file.OptNone)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r activationResult) writeOutput(wr io.Writer, fileHandler file.Handler, config *config.Config) error {
|
func (r activationResult) writeOutput(wr io.Writer, fileHandler file.Handler, config *config.Config) error {
|
||||||
@ -245,7 +245,7 @@ func (r activationResult) writeOutput(wr io.Writer, fileHandler file.Handler, co
|
|||||||
tw.Flush()
|
tw.Flush()
|
||||||
fmt.Fprintln(wr)
|
fmt.Fprintln(wr)
|
||||||
|
|
||||||
if err := fileHandler.Write(*config.AdminConfPath, []byte(r.kubeconfig), false); err != nil {
|
if err := fileHandler.Write(*config.AdminConfPath, []byte(r.kubeconfig), file.OptNone); err != nil {
|
||||||
return fmt.Errorf("write kubeconfig: %w", err)
|
return fmt.Errorf("write kubeconfig: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,7 +360,7 @@ func readOrGeneratedMasterSecret(w io.Writer, fileHandler file.Handler, filename
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if err := fileHandler.Write(*config.MasterSecretPath, []byte(base64.StdEncoding.EncodeToString(masterSecret)), false); err != nil {
|
if err := fileHandler.Write(*config.MasterSecretPath, []byte(base64.StdEncoding.EncodeToString(masterSecret)), file.OptNone); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fmt.Fprintf(w, "Your Constellation master secret was successfully written to ./%s\n", *config.MasterSecretPath)
|
fmt.Fprintf(w, "Your Constellation master secret was successfully written to ./%s\n", *config.MasterSecretPath)
|
||||||
|
@ -336,7 +336,7 @@ func TestInitialize(t *testing.T) {
|
|||||||
cmd.SetErr(&errOut)
|
cmd.SetErr(&errOut)
|
||||||
fs := afero.NewMemMapFs()
|
fs := afero.NewMemMapFs()
|
||||||
fileHandler := file.NewHandler(fs)
|
fileHandler := file.NewHandler(fs)
|
||||||
require.NoError(fileHandler.WriteJSON(*config.StatePath, tc.existingState, false))
|
require.NoError(fileHandler.WriteJSON(*config.StatePath, tc.existingState, file.OptNone))
|
||||||
|
|
||||||
// Write key file to filesystem and set path in flag.
|
// Write key file to filesystem and set path in flag.
|
||||||
require.NoError(afero.Afero{Fs: fs}.WriteFile("privK", []byte(tc.privKey), 0o600))
|
require.NoError(afero.Afero{Fs: fs}.WriteFile("privK", []byte(tc.privKey), 0o600))
|
||||||
@ -444,7 +444,7 @@ func TestReadOrGenerateVPNKey(t *testing.T) {
|
|||||||
|
|
||||||
testKey := []byte(base64.StdEncoding.EncodeToString([]byte("32bytesWireGuardKeyForTheTesting")))
|
testKey := []byte(base64.StdEncoding.EncodeToString([]byte("32bytesWireGuardKeyForTheTesting")))
|
||||||
fileHandler := file.NewHandler(afero.NewMemMapFs())
|
fileHandler := file.NewHandler(afero.NewMemMapFs())
|
||||||
require.NoError(fileHandler.Write("testKey", testKey, false))
|
require.NoError(fileHandler.Write("testKey", testKey, file.OptNone))
|
||||||
|
|
||||||
privK, pubK, err := readOrGenerateVPNKey(fileHandler, "testKey")
|
privK, pubK, err := readOrGenerateVPNKey(fileHandler, "testKey")
|
||||||
assert.NoError(err)
|
assert.NoError(err)
|
||||||
@ -525,7 +525,7 @@ func TestReadOrGeneratedMasterSecret(t *testing.T) {
|
|||||||
config := config.Default()
|
config := config.Default()
|
||||||
|
|
||||||
if tc.createFile {
|
if tc.createFile {
|
||||||
require.NoError(fileHandler.Write(tc.filename, []byte(tc.filecontent), false))
|
require.NoError(fileHandler.Write(tc.filename, []byte(tc.filecontent), file.OptNone))
|
||||||
}
|
}
|
||||||
|
|
||||||
var out bytes.Buffer
|
var out bytes.Buffer
|
||||||
@ -697,7 +697,7 @@ func TestAutoscaleFlag(t *testing.T) {
|
|||||||
fs := afero.NewMemMapFs()
|
fs := afero.NewMemMapFs()
|
||||||
fileHandler := file.NewHandler(fs)
|
fileHandler := file.NewHandler(fs)
|
||||||
vpnHandler := stubVPNHandler{}
|
vpnHandler := stubVPNHandler{}
|
||||||
require.NoError(fileHandler.WriteJSON(*config.StatePath, tc.existingState, false))
|
require.NoError(fileHandler.WriteJSON(*config.StatePath, tc.existingState, file.OptNone))
|
||||||
|
|
||||||
// Write key file to filesystem and set path in flag.
|
// Write key file to filesystem and set path in flag.
|
||||||
require.NoError(afero.Afero{Fs: fs}.WriteFile("privK", []byte(tc.privKey), 0o600))
|
require.NoError(afero.Afero{Fs: fs}.WriteFile("privK", []byte(tc.privKey), 0o600))
|
||||||
|
@ -9,10 +9,28 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
"path"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Option is a bitmask of options for file operations.
|
||||||
|
type Option uint
|
||||||
|
|
||||||
|
// Has determines if a set of options contains the given options.
|
||||||
|
func (o Option) Has(op Option) bool {
|
||||||
|
return o&op == op
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// OptNone is a no-op.
|
||||||
|
OptNone Option = 1 << iota / 2
|
||||||
|
// OptOverwrite overwrites an existing file.
|
||||||
|
OptOverwrite
|
||||||
|
// OptMkdirAll creates the path to the file.
|
||||||
|
OptMkdirAll
|
||||||
|
)
|
||||||
|
|
||||||
// Handler handles file interaction.
|
// Handler handles file interaction.
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
fs *afero.Afero
|
fs *afero.Afero
|
||||||
@ -35,11 +53,14 @@ func (h *Handler) Read(name string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write writes the data bytes into the file with the given name.
|
// Write writes the data bytes into the file with the given name.
|
||||||
// If a file already exists at path and overwrite is true, the file will be
|
func (h *Handler) Write(name string, data []byte, options Option) error {
|
||||||
// overwritten. Otherwise, an error is returned.
|
if options.Has(OptMkdirAll) {
|
||||||
func (h *Handler) Write(name string, data []byte, overwrite bool) error {
|
if err := h.fs.MkdirAll(path.Dir(name), os.ModePerm); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
flags := os.O_WRONLY | os.O_CREATE | os.O_EXCL
|
flags := os.O_WRONLY | os.O_CREATE | os.O_EXCL
|
||||||
if overwrite {
|
if options.Has(OptOverwrite) {
|
||||||
flags = os.O_WRONLY | os.O_CREATE | os.O_TRUNC
|
flags = os.O_WRONLY | os.O_CREATE | os.O_TRUNC
|
||||||
}
|
}
|
||||||
file, err := h.fs.OpenFile(name, flags, 0o644)
|
file, err := h.fs.OpenFile(name, flags, 0o644)
|
||||||
@ -64,14 +85,12 @@ func (h *Handler) ReadJSON(name string, content interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteJSON marshals the content interface to JSON and writes it to the path with the given name.
|
// WriteJSON marshals the content interface to JSON and writes it to the path with the given name.
|
||||||
// If a file already exists and overwrite is true, the file will be
|
func (h *Handler) WriteJSON(name string, content interface{}, options Option) error {
|
||||||
// overwritten. Otherwise, an error is returned.
|
|
||||||
func (h *Handler) WriteJSON(name string, content interface{}, overwrite bool) error {
|
|
||||||
jsonData, err := json.MarshalIndent(content, "", "\t")
|
jsonData, err := json.MarshalIndent(content, "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return h.Write(name, jsonData, overwrite)
|
return h.Write(name, jsonData, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove deletes the file with the given name.
|
// Remove deletes the file with the given name.
|
||||||
|
@ -80,12 +80,12 @@ func TestWriteJSON(t *testing.T) {
|
|||||||
notMarshalableContent := struct{ Foo chan int }{Foo: make(chan int)}
|
notMarshalableContent := struct{ Foo chan int }{Foo: make(chan int)}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
fs afero.Fs
|
fs afero.Fs
|
||||||
setupFs func(af afero.Afero) error
|
setupFs func(af afero.Afero) error
|
||||||
name string
|
name string
|
||||||
content interface{}
|
content interface{}
|
||||||
overwrite bool
|
options Option
|
||||||
wantErr bool
|
wantErr bool
|
||||||
}{
|
}{
|
||||||
"successful write": {
|
"successful write": {
|
||||||
fs: afero.NewMemMapFs(),
|
fs: afero.NewMemMapFs(),
|
||||||
@ -93,11 +93,11 @@ func TestWriteJSON(t *testing.T) {
|
|||||||
content: someContent,
|
content: someContent,
|
||||||
},
|
},
|
||||||
"successful overwrite": {
|
"successful overwrite": {
|
||||||
fs: afero.NewMemMapFs(),
|
fs: afero.NewMemMapFs(),
|
||||||
setupFs: func(af afero.Afero) error { return af.WriteFile("test/statefile", []byte{}, 0o644) },
|
setupFs: func(af afero.Afero) error { return af.WriteFile("test/statefile", []byte{}, 0o644) },
|
||||||
name: "test/statefile",
|
name: "test/statefile",
|
||||||
content: someContent,
|
content: someContent,
|
||||||
overwrite: true,
|
options: OptOverwrite,
|
||||||
},
|
},
|
||||||
"read only fs": {
|
"read only fs": {
|
||||||
fs: afero.NewReadOnlyFs(afero.NewMemMapFs()),
|
fs: afero.NewReadOnlyFs(afero.NewMemMapFs()),
|
||||||
@ -118,6 +118,15 @@ func TestWriteJSON(t *testing.T) {
|
|||||||
content: notMarshalableContent,
|
content: notMarshalableContent,
|
||||||
wantErr: true,
|
wantErr: true,
|
||||||
},
|
},
|
||||||
|
"mkdirAll works": {
|
||||||
|
fs: afero.NewMemMapFs(),
|
||||||
|
name: "test/statefile",
|
||||||
|
content: someContent,
|
||||||
|
options: OptMkdirAll,
|
||||||
|
},
|
||||||
|
// TODO: add tests for mkdirAll actually creating the necessary folders when https://github.com/spf13/afero/issues/270 is fixed.
|
||||||
|
// Currently, MemMapFs will create files in nonexistent directories due to a bug in afero,
|
||||||
|
// making it impossible to test the actual behavior of the mkdirAll parameter.
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, tc := range testCases {
|
for name, tc := range testCases {
|
||||||
@ -131,9 +140,9 @@ func TestWriteJSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if tc.wantErr {
|
if tc.wantErr {
|
||||||
assert.Error(handler.WriteJSON(tc.name, tc.content, tc.overwrite))
|
assert.Error(handler.WriteJSON(tc.name, tc.content, tc.options))
|
||||||
} else {
|
} else {
|
||||||
assert.NoError(handler.WriteJSON(tc.name, tc.content, tc.overwrite))
|
assert.NoError(handler.WriteJSON(tc.name, tc.content, tc.options))
|
||||||
resultContent := &testContent{}
|
resultContent := &testContent{}
|
||||||
assert.NoError(handler.ReadJSON(tc.name, resultContent))
|
assert.NoError(handler.ReadJSON(tc.name, resultContent))
|
||||||
assert.Equal(tc.content, *resultContent)
|
assert.Equal(tc.content, *resultContent)
|
||||||
|
@ -27,5 +27,5 @@ func FromFile(fileHandler file.Handler) (*NodeState, error) {
|
|||||||
|
|
||||||
// ToFile writes a NodeState to disk.
|
// ToFile writes a NodeState to disk.
|
||||||
func (nodeState *NodeState) ToFile(fileHandler file.Handler) error {
|
func (nodeState *NodeState) ToFile(fileHandler file.Handler) error {
|
||||||
return fileHandler.WriteJSON(nodeStatePath, nodeState, false)
|
return fileHandler.WriteJSON(nodeStatePath, nodeState, false, true)
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,7 @@ func TestFromFile(t *testing.T) {
|
|||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
fileHandler := file.NewHandler(afero.NewMemMapFs())
|
fileHandler := file.NewHandler(afero.NewMemMapFs())
|
||||||
require.NoError(fileHandler.WriteJSON(configName, tc.from, false))
|
require.NoError(fileHandler.WriteJSON(configName, tc.from, file.OptNone))
|
||||||
|
|
||||||
result, err := FromFile(fileHandler, tc.configName)
|
result, err := FromFile(fileHandler, tc.configName)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user