package app import ( "errors" "fmt" "coopcloud.tech/abra/cli/internal" "coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/config" containerPkg "coopcloud.tech/abra/pkg/container" "coopcloud.tech/abra/pkg/upstream/container" "github.com/docker/cli/cli/command" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/sirupsen/logrus" "github.com/urfave/cli/v2" ) var user string var userFlag = &cli.StringFlag{ Name: "user", Value: "", Destination: &user, } var noTTY bool var noTTYFlag = &cli.BoolFlag{ Name: "no-tty", Value: false, Destination: &noTTY, } var appRunCommand = &cli.Command{ Name: "run", Flags: []cli.Flag{ noTTYFlag, userFlag, }, Aliases: []string{"r"}, ArgsUsage: " ...", Usage: "Run a command in a service container", Action: func(c *cli.Context) error { app := internal.ValidateApp(c) if c.Args().Len() < 2 { internal.ShowSubcommandHelpAndError(c, errors.New("no provided?")) } if c.Args().Len() < 3 { internal.ShowSubcommandHelpAndError(c, errors.New("no provided?")) } cl, err := client.New(app.Server) if err != nil { logrus.Fatal(err) } serviceName := c.Args().Get(1) stackAndServiceName := fmt.Sprintf("%s_%s", app.StackName(), serviceName) filters := filters.NewArgs() filters.Add("name", stackAndServiceName) targetContainer, err := containerPkg.GetContainer(c.Context, cl, filters, true) if err != nil { logrus.Fatal(err) } cmd := c.Args().Slice()[2:] execCreateOpts := types.ExecConfig{ AttachStderr: true, AttachStdin: true, AttachStdout: true, Cmd: cmd, Detach: false, Tty: true, } if user != "" { execCreateOpts.User = user } if noTTY { execCreateOpts.Tty = false } // FIXME: an absolutely monumental hack to instantiate another command-line // client withing our command-line client so that we pass something down // the tubes that satisfies the necessary interface requirements. We should // refactor our vendored container code to not require all this cruft. For // now, It Works. dcli, err := command.NewDockerCli() if err != nil { logrus.Fatal(err) } if err := container.RunExec(dcli, cl, targetContainer.ID, &execCreateOpts); err != nil { logrus.Fatal(err) } return nil }, BashComplete: func(c *cli.Context) { switch c.NArg() { case 0: appNames, err := config.GetAppNames() if err != nil { logrus.Warn(err) } for _, a := range appNames { fmt.Println(a) } case 1: appName := c.Args().First() serviceNames, err := config.GetAppServiceNames(appName) if err != nil { logrus.Warn(err) } for _, s := range serviceNames { fmt.Println(s) } } }, }