From 80a57ca174bec78de921866f5fdcee61bba26089 Mon Sep 17 00:00:00 2001 From: p4u1 Date: Mon, 18 Aug 2025 17:44:05 +0200 Subject: [PATCH] copy secret without relying on cat being installed in the container --- cli/app/move.go | 119 +++++++++++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/cli/app/move.go b/cli/app/move.go index 5bdf44c0..051116a0 100644 --- a/cli/app/move.go +++ b/cli/app/move.go @@ -13,10 +13,9 @@ import ( "coopcloud.tech/abra/pkg/client" containerPkg "coopcloud.tech/abra/pkg/container" "coopcloud.tech/abra/pkg/log" - "coopcloud.tech/abra/pkg/upstream/container" + "coopcloud.tech/abra/pkg/secret" "coopcloud.tech/abra/pkg/upstream/convert" "coopcloud.tech/abra/pkg/upstream/stack" - "github.com/docker/cli/cli/command" "github.com/docker/docker/api/types" containertypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" @@ -78,15 +77,53 @@ checkout as-is. Recipe commit hashes are also supported as values for return err } - dcli, err := command.NewDockerCli() - if err != nil { - return err - } secretsToStore := map[string]string{} volumes := map[string]containertypes.MountPoint{} + + composeFiles, err := app.Recipe.GetComposeFiles(app.Env) + if err != nil { + log.Fatal(err) + } + + filtersSecret, err := app.Filters(false, false) + if err != nil { + log.Fatal(err) + } + + secretList, err := cl.SecretList(context.Background(), types.SecretListOptions{Filters: filtersSecret}) + if err != nil { + log.Fatal(err) + } + + secretConfigs, err := secret.ReadSecretsConfig(app.Path, composeFiles, app.StackName()) + if err != nil { + log.Fatal(err) + } + + opts := stack.Deploy{Composefiles: composeFiles, Namespace: app.StackName()} + compose, err := appPkg.GetAppComposeConfig(app.Name, opts, app.Env) + if err != nil { + log.Fatal(err) + } for _, s := range services { log.Info("service", s.Spec.Name) - // stackAndServiceName := fmt.Sprintf("^%s_%s", app.StackName(), s.Spec.Name) + + secretNames := map[string]string{} + for _, serviceCompose := range compose.Services { + if app.StackName()+"_"+serviceCompose.Name != s.Spec.Name { + continue + } + + for _, secret := range serviceCompose.Secrets { + for _, s := range secretList { + if s.Spec.Name == app.StackName()+"_"+secret.Source+"_"+secretConfigs[secret.Source].Version { + secretNames[secret.Source] = s.ID + break + } + } + } + } + f := filters.NewArgs() f.Add("name", s.Spec.Name) targetContainer, err := containerPkg.GetContainer(context.Background(), cl, f, true) @@ -100,51 +137,27 @@ checkout as-is. Recipe commit hashes are also supported as values for } } - execCreateOpts := containertypes.ExecOptions{ - AttachStderr: false, - AttachStdin: false, - AttachStdout: true, - Cmd: []string{"ls", "/run/secrets"}, - Detach: false, - Tty: false, - } - out, err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts, false) - if err != nil { - log.Error(out) - continue - } - for _, secret := range strings.Split(strings.TrimSpace(out), "\n") { - if _, ok := secretsToStore[secret]; ok { + for secretName, secretID := range secretNames { + if _, ok := secretsToStore[secretName]; ok { continue } - log.Debugf("extracting secret %s", secret) + log.Debugf("extracting secret %s", secretName) - execCreateOpts := containertypes.ExecOptions{ - AttachStderr: false, - AttachStdin: false, - AttachStdout: true, - Cmd: []string{"cat", fmt.Sprintf("/run/secrets/%s", secret)}, - Detach: false, - Tty: false, - } - out, err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts, false) + out, err := exec.Command("ssh", app.Server, "-tt", fmt.Sprintf("sudo cat /var/lib/docker/containers/%s/mounts/secrets/%s", targetContainer.ID, secretID)).Output() if err != nil { - return err + fmt.Println(string(out)) + fmt.Println(err) + continue } - secretsToStore[secret] = out + secretsToStore[secretName] = string(out) } } - composeFiles, err := app.Recipe.GetComposeFiles(app.Env) - if err != nil { - log.Fatal(err) - } - - opts := stack.Deploy{Composefiles: composeFiles, Namespace: app.StackName()} - compose, err := appPkg.GetAppComposeConfig(app.Name, opts, app.Env) - if err != nil { - log.Fatal(err) + if internal.Dry { + fmt.Println(secretsToStore) + fmt.Println(volumes) + return nil } stack.WaitTimeout, err = appPkg.GetTimeoutFromLabel(compose, app.StackName()) if err != nil { @@ -162,19 +175,10 @@ checkout as-is. Recipe commit hashes are also supported as values for if err != nil { return err } - filters, err := app.Filters(false, false) - if err != nil { - log.Fatal(err) - } - - secretList, err := cl.SecretList(context.Background(), types.SecretListOptions{Filters: filters}) for _, s := range secretList { sname := strings.Split(strings.TrimPrefix(s.Spec.Name, app.StackName()+"_"), "_") secretName := strings.Join(sname[:len(sname)-1], "_") data := secretsToStore[secretName] - fmt.Println(s.Spec.Name) - fmt.Println(secretName) - fmt.Println(data) if err := client.StoreSecret(cl2, s.Spec.Name, data); err != nil { log.Info(err) } @@ -220,7 +224,6 @@ checkout as-is. Recipe commit hashes are also supported as values for } } - fmt.Println(strings.ReplaceAll(app.Path, app.Server, args[1])) if err := copyFile(app.Path, strings.ReplaceAll(app.Path, app.Server, args[1])); err != nil { return err } @@ -290,3 +293,13 @@ func copyFile(src string, dst string) error { } return nil } + +func init() { + AppMoveCommand.Flags().BoolVarP( + &internal.Dry, + "dry-run", + "r", + false, + "report changes that would be made", + ) +}