diff --git a/pkg/ccl/cliccl/BUILD.bazel b/pkg/ccl/cliccl/BUILD.bazel index c4458bd4c2d2..ad638e24ad57 100644 --- a/pkg/ccl/cliccl/BUILD.bazel +++ b/pkg/ccl/cliccl/BUILD.bazel @@ -43,7 +43,6 @@ go_library( "//pkg/util/timeutil", "@com_github_cockroachdb_errors//:errors", "@com_github_cockroachdb_errors//oserror", - "@com_github_cockroachdb_pebble//vfs", "@com_github_cockroachdb_redact//:redact", "@com_github_lestrrat_go_jwx//jwk", "@com_github_olekukonko_tablewriter//:tablewriter", diff --git a/pkg/ccl/cliccl/ear.go b/pkg/ccl/cliccl/ear.go index 1eaa965b813f..8d0a1cab56d0 100644 --- a/pkg/ccl/cliccl/ear.go +++ b/pkg/ccl/cliccl/ear.go @@ -10,59 +10,53 @@ package cliccl import ( "bytes" - "context" + "cmp" "fmt" "io" - "os" - "sort" + "slices" "github.com/cockroachdb/cockroach/pkg/ccl/storageccl/engineccl/enginepbccl" "github.com/cockroachdb/cockroach/pkg/cli" - "github.com/cockroachdb/cockroach/pkg/storage" "github.com/cockroachdb/cockroach/pkg/storage/enginepb" "github.com/cockroachdb/cockroach/pkg/storage/fs" "github.com/cockroachdb/cockroach/pkg/util/protoutil" - "github.com/cockroachdb/cockroach/pkg/util/stop" "github.com/cockroachdb/errors" - "github.com/cockroachdb/pebble/vfs" "github.com/spf13/cobra" ) -func runDecrypt(_ *cobra.Command, args []string) (returnErr error) { +func runDecrypt(cmd *cobra.Command, args []string) (returnErr error) { dir, inPath := args[0], args[1] var outPath string if len(args) > 2 { outPath = args[2] } - stopper := stop.NewStopper() - defer stopper.Stop(context.Background()) - - db, err := cli.OpenEngine(dir, stopper, fs.ReadOnly, storage.MustExist) + env, err := cli.OpenFilesystemEnv(dir, fs.ReadOnly) if err != nil { return errors.Wrap(err, "could not open store") } + defer func() { returnErr = errors.CombineErrors(returnErr, env.Close()) }() // Open the specified file through the FS, decrypting it. - f, err := db.Open(inPath) + f, err := env.DefaultFS.Open(inPath) if err != nil { return errors.Wrapf(err, "could not open input file %s", inPath) } defer f.Close() // Copy the raw bytes into the destination file. - outFile := os.Stdout + out := cmd.OutOrStdout() if outPath != "" { - outFile, err = os.OpenFile(outPath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600) + outFile, err := env.UnencryptedFS.Create(outPath) if err != nil { return errors.Wrapf(err, "could not open output file %s", outPath) } defer outFile.Close() + out = outFile } - if _, err = io.Copy(outFile, f); err != nil { + if _, err = io.Copy(out, f); err != nil { return errors.Wrapf(err, "could not write to output file") } - return nil } @@ -87,23 +81,22 @@ func (f fileEntry) String() string { return b.String() } -func runList(cmd *cobra.Command, args []string) error { +func runList(cmd *cobra.Command, args []string) (returnErr error) { dir := args[0] - fr := &fs.FileRegistry{ - FS: vfs.Default, - DBDir: dir, - ReadOnly: true, - NumOldRegistryFiles: fs.DefaultNumOldFileRegistryFiles, + env, err := cli.OpenFilesystemEnv(dir, fs.ReadOnly) + if err != nil { + return errors.Wrap(err, "could not open store") } - if err := fr.Load(cmd.Context()); err != nil { - return errors.Wrapf(err, "could not load file registry") + defer func() { returnErr = errors.CombineErrors(returnErr, env.Close()) }() + + if env.Registry == nil { + return errors.Newf("encryption-at-rest not enabled") } - defer func() { _ = fr.Close() }() // List files and print to stdout. var entries []fileEntry - for name, entry := range fr.List() { + for name, entry := range env.Registry.List() { var encSettings enginepbccl.EncryptionSettings settings := entry.EncryptionSettings if err := protoutil.Unmarshal(settings, &encSettings); err != nil { @@ -115,12 +108,9 @@ func runList(cmd *cobra.Command, args []string) error { settings: encSettings, }) } - sort.Slice(entries, func(i, j int) bool { - return entries[i].name < entries[j].name - }) + slices.SortFunc(entries, func(a, b fileEntry) int { return cmp.Compare(a.name, b.name) }) for _, e := range entries { _, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s\n", e) } - return nil } diff --git a/pkg/ccl/cliccl/ear_test.go b/pkg/ccl/cliccl/ear_test.go index 002bfa42b703..7f97fc4eac81 100644 --- a/pkg/ccl/cliccl/ear_test.go +++ b/pkg/ccl/cliccl/ear_test.go @@ -160,8 +160,8 @@ func TestList(t *testing.T) { var b bytes.Buffer cmd.SetOut(&b) cmd.SetErr(&b) - err = runList(cmd, []string{dir}) - require.NoError(t, err) + require.NoError(t, cmd.Flags().Set("enterprise-encryption", encSpecStr)) + require.NoError(t, runList(cmd, []string{dir})) return b.String() }) } diff --git a/pkg/cli/debug.go b/pkg/cli/debug.go index ad596c09ca44..e8e85f80bef1 100644 --- a/pkg/cli/debug.go +++ b/pkg/cli/debug.go @@ -172,26 +172,34 @@ func (f *keyFormat) Type() string { return "hex|base64" } +// OpenFilesystemEnv opens the filesystem environment at 'dir'. Note that +// opening the fs.Env will acquire the directory lock and prevent opening of the +// engine through [OpenEngine]. If the caller wishes to then open the storage +// engine, they should manually open it using storage.Open. The returned Env has +// 1 reference and the caller must ensure it's closed. +func OpenFilesystemEnv(dir string, rw fs.RWMode) (*fs.Env, error) { + envConfig := fs.EnvConfig{RW: rw} + if PopulateEnvConfigHook != nil { + if err := PopulateEnvConfigHook(dir, &envConfig); err != nil { + return nil, err + } + } + return fs.InitEnv(context.Background(), vfs.Default, dir, envConfig) +} + // OpenEngine opens the engine at 'dir'. Depending on the supplied options, // an empty engine might be initialized. func OpenEngine( dir string, stopper *stop.Stopper, rw fs.RWMode, opts ...storage.ConfigOption, ) (storage.Engine, error) { - maxOpenFiles, err := server.SetOpenFileLimitForOneStore() + env, err := OpenFilesystemEnv(dir, rw) if err != nil { return nil, err } - envConfig := fs.EnvConfig{RW: rw} - if PopulateEnvConfigHook != nil { - if err := PopulateEnvConfigHook(dir, &envConfig); err != nil { - return nil, err - } - } - env, err := fs.InitEnv(context.Background(), vfs.Default, dir, envConfig) + maxOpenFiles, err := server.SetOpenFileLimitForOneStore() if err != nil { return nil, err } - db, err := storage.Open( context.Background(), env,