abra/cli/app/ps.go

155 lines
3.9 KiB
Go

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"
"coopcloud.tech/abra/pkg/recipe"
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: "<domain>",
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)
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 := app.Recipe.EnsureVersion(deployedVersion); err != nil {
log.Fatal(err)
}
}
}
showPSOutput(app, cl)
return nil
},
}
// showPSOutput renders ps output.
func showPSOutput(app appPkg.App, cl *dockerClient.Client) {
r := recipe.Get(app.Name)
composeFiles, err := r.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 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()
}