package app import ( "context" "encoding/json" "fmt" "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" abraService "coopcloud.tech/abra/pkg/service" stack "coopcloud.tech/abra/pkg/upstream/stack" 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.DebugFlag, }, Before: internal.SubCommandBefore, BashComplete: autocomplete.AppNameComplete, Action: func(c *cli.Context) error { app := internal.ValidateApp(c) if err := app.Recipe.Ensure(false, false); err != nil { log.Fatal(err) } cl, err := client.New(app.Server) if err != nil { log.Fatal(err) } deployMeta, err := stack.IsDeployed(context.Background(), cl, app.StackName()) if err != nil { log.Fatal(err) } if !deployMeta.IsDeployed { log.Fatalf("%s is not deployed?", app.Name) } chaosVersion := "false" statuses, err := appPkg.GetAppStatuses([]appPkg.App{app}, true) if statusMeta, ok := statuses[app.StackName()]; ok { isChaos, exists := statusMeta["chaos"] if exists && isChaos == "false" { if _, err := app.Recipe.EnsureVersion(deployMeta.Version); err != nil { log.Fatal(err) } } else { chaosVersion, err = app.Recipe.ChaosVersion() if err != nil { log.Fatal(err) } } } showPSOutput(app, cl, deployMeta.Version, chaosVersion) return nil }, } // showPSOutput renders ps output. func showPSOutput(app appPkg.App, cl *dockerClient.Client, deployedVersion, chaosVersion string) { composeFiles, err := app.Recipe.GetComposeFiles(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 rows [][]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 row := []string{ containerStats["service"], containerStats["image"], containerStats["created"], containerStats["status"], containerStats["state"], containerStats["ports"], } rows = append(rows, row) } if internal.MachineReadable { jsonstring, err := json.Marshal(allContainerStats) if err != nil { log.Fatal("unable to convert to JSON: %s", err) } fmt.Println(string(jsonstring)) return } table, err := formatter.CreateTable() if err != nil { log.Fatal(err) } headers := []string{ "SERVICE", "IMAGE", "CREATED", "STATUS", "STATE", "PORTS", } table. Headers(headers...). Rows(rows...) fmt.Println(table) log.Infof("VERSION: %s CHAOS: %s", deployedVersion, chaosVersion) }