diff --git a/go/action_kit_commons/diskfill/diskfill_process.go b/go/action_kit_commons/diskfill/diskfill_process.go index 41a3101..fd2c87c 100644 --- a/go/action_kit_commons/diskfill/diskfill_process.go +++ b/go/action_kit_commons/diskfill/diskfill_process.go @@ -7,13 +7,14 @@ package diskfill import ( "context" "fmt" - "github.com/rs/zerolog/log" - "github.com/steadybit/action-kit/go/action_kit_commons/utils" "os/exec" "path/filepath" "strconv" "strings" "time" + + "github.com/rs/zerolog/log" + "github.com/steadybit/action-kit/go/action_kit_commons/utils" ) type diskfillProcess struct { @@ -92,3 +93,17 @@ func (df *diskfillProcess) Args() []string { func (df *diskfillProcess) Noop() bool { return df.cmd.Args[0] == "echo" && df.cmd.Args[1] == "noop" } + +func CheckPathWritableProcess(ctx context.Context, targetPath string) error { + if out, err := utils.RootCommandContext(ctx, "test", "-d", targetPath).CombinedOutput(); err != nil { + return fmt.Errorf("target path %q does not exist: %w: %s", targetPath, err, string(out)) + } + + checkFile := filepath.Join(targetPath, ".steadybit-diskfill-check") + if out, err := utils.RootCommandContext(ctx, "touch", checkFile).CombinedOutput(); err != nil { + return fmt.Errorf("target path %q is not writable: %w: %s", targetPath, err, string(out)) + } + + _ = utils.RootCommandContext(ctx, "rm", "-f", checkFile).Run() + return nil +} diff --git a/go/action_kit_commons/diskfill/diskfill_runc.go b/go/action_kit_commons/diskfill/diskfill_runc.go index 87ad31a..ec8a23a 100644 --- a/go/action_kit_commons/diskfill/diskfill_runc.go +++ b/go/action_kit_commons/diskfill/diskfill_runc.go @@ -5,6 +5,7 @@ package diskfill import ( + "bytes" "context" "fmt" "path/filepath" @@ -142,7 +143,7 @@ func createBundle(ctx context.Context, r ociruntime.OciRuntime, sidecar SidecarO if targetPath != "" { if err := bundle.MountFromProcess(ctx, sidecar.TargetProcess.Pid, targetPath, mountpointInContainer); err != nil { - log.Warn().Err(err).Msgf("failed to mount %s", targetPath) + return nil, fmt.Errorf("failed to mount %s: %w", targetPath, err) } } @@ -183,6 +184,31 @@ func createBundle(ctx context.Context, r ociruntime.OciRuntime, sidecar SidecarO return bundle, nil } +func CheckPathWritableRunc(ctx context.Context, r ociruntime.OciRuntime, sidecar SidecarOpts, targetPath string) error { + bundle, err := createBundle(ctx, r, sidecar, targetPath, + "sh", "-c", "test -d "+mountpointInContainer+" && touch "+mountpointInContainer+"/.steadybit-diskfill-check && rm -f "+mountpointInContainer+"/.steadybit-diskfill-check") + if err != nil { + return fmt.Errorf("target path %q is not accessible: %w", targetPath, err) + } + defer func() { + if err := bundle.Remove(); err != nil { + log.Warn().Str("id", bundle.ContainerId()).Err(err).Msg("failed to remove bundle") + } + }() + + var errb bytes.Buffer + err = r.Run(ctx, bundle, ociruntime.IoOpts{Stderr: &errb}) + defer func() { + if err := r.Delete(context.Background(), bundle.ContainerId(), true); err != nil { + log.Debug().Str("id", bundle.ContainerId()).Err(err).Msg("failed to delete check container") + } + }() + if err != nil { + return fmt.Errorf("target path %q does not exist or is not writable: %w: %s", targetPath, err, errb.String()) + } + return nil +} + func getNextContainerId(executionId uuid.UUID, suffix string) string { return fmt.Sprintf("sb-diskfill-%d-%s-%s", time.Now().UnixMilli(), utils.ShortenUUID(executionId), suffix) }