package app import ( "context" "encoding/json" "fmt" "time" "coopcloud.tech/abra/cli/internal" appPkg "coopcloud.tech/abra/pkg/app" "coopcloud.tech/abra/pkg/autocomplete" "coopcloud.tech/abra/pkg/client" "coopcloud.tech/abra/pkg/formatter" "coopcloud.tech/abra/pkg/log" "coopcloud.tech/abra/pkg/recipe" abraService "coopcloud.tech/abra/pkg/service" stack "coopcloud.tech/abra/pkg/upstream/stack" "github.com/buger/goterm" dockerFormatter "github.com/docker/cli/cli/command/formatter" containerTypes "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/filters" dockerClient "github.com/docker/docker/client" "github.com/urfave/cli" ) var appPsCommand = cli.Command{ Name: "ps", Aliases: []string{"p"}, Usage: "Check app status", ArgsUsage: "", Description: "Show status of a deployed app.", Flags: []cli.Flag{ internal.MachineReadableFlag, internal.WatchFlag, internal.DebugFlag, }, Before: internal.SubCommandBefore, BashComplete: autocomplete.AppNameComplete, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) cl, err := client.New(app.Server) if err != nil { log.Fatal(err) } isDeployed, deployedVersion, err := stack.IsDeployed(context.Background(), cl, app.StackName()) if err != nil { log.Fatal(err) } if !isDeployed { log.Fatalf("%s is not deployed?", app.Name) } statuses, err := appPkg.GetAppStatuses([]appPkg.App{app}, true) if statusMeta, ok := statuses[app.StackName()]; ok { if _, exists := statusMeta["chaos"]; !exists { if err := recipe.EnsureVersion(app.Recipe, deployedVersion); err != nil { log.Fatal(err) } } } if !internal.Watch { showPSOutput(app, cl) return nil } goterm.Clear() for { goterm.MoveCursor(1, 1) showPSOutput(app, cl) goterm.Flush() time.Sleep(2 * time.Second) } }, } // showPSOutput renders ps output. func showPSOutput(app appPkg.App, cl *dockerClient.Client) { composeFiles, err := recipe.GetComposeFiles(app.Recipe, app.Env) if err != nil { log.Fatal(err) return } deployOpts := stack.Deploy{ Composefiles: composeFiles, Namespace: app.StackName(), Prune: false, ResolveImage: stack.ResolveImageAlways, } compose, err := appPkg.GetAppComposeConfig(app.Name, deployOpts, app.Env) if err != nil { log.Fatal(err) return } var tablerows [][]string allContainerStats := make(map[string]map[string]string) for _, service := range compose.Services { filters := filters.NewArgs() filters.Add("name", fmt.Sprintf("^%s_%s", app.StackName(), service.Name)) containers, err := cl.ContainerList(context.Background(), containerTypes.ListOptions{Filters: filters}) if err != nil { log.Fatal(err) return } var containerStats map[string]string if len(containers) == 0 { containerStats = map[string]string{ "service": service.Name, "image": "unknown", "created": "unknown", "status": "unknown", "state": "unknown", "ports": "unknown", } } else { container := containers[0] containerStats = map[string]string{ "service": abraService.ContainerToServiceName(container.Names, app.StackName()), "image": formatter.RemoveSha(container.Image), "created": formatter.HumanDuration(container.Created), "status": container.Status, "state": container.State, "ports": dockerFormatter.DisplayablePorts(container.Ports), } } allContainerStats[containerStats["service"]] = containerStats tablerow := []string{ containerStats["service"], containerStats["image"], containerStats["created"], containerStats["status"], containerStats["state"], containerStats["ports"], } tablerows = append(tablerows, tablerow) } if internal.MachineReadable { jsonstring, err := json.Marshal(allContainerStats) if err != nil { log.Fatal(err) } fmt.Println(string(jsonstring)) return } tableCol := []string{"service", "image", "created", "status", "state", "ports"} table := formatter.CreateTable(tableCol) for _, row := range tablerows { table.Append(row) } table.Render() }