Skip to content

Commit

Permalink
Merge pull request #96 from local-deploy/DL-T-95
Browse files Browse the repository at this point in the history
add new command "status"
  • Loading branch information
varrcan committed Aug 26, 2023
2 parents cdc2370 + 5384da3 commit db30952
Show file tree
Hide file tree
Showing 14 changed files with 416 additions and 71 deletions.
62 changes: 16 additions & 46 deletions command/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"fmt"
"sort"

"github.com/docker/cli/cli/command/formatter"
"github.com/docker/compose/v2/pkg/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
Expand All @@ -16,25 +15,6 @@ import (
"golang.org/x/sync/errgroup"
)

type containerSummary struct {
ID string
Name string
State string
Health string
IPAddress string
ExitCode int
Publishers portPublishers
}

type portPublishers []portPublisher

type portPublisher struct {
URL string
TargetPort int
PublishedPort int
Protocol string
}

func psCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "ps",
Expand Down Expand Up @@ -64,17 +44,25 @@ func runPs() error {

networkName := project.Env.GetString("NETWORK_NAME")
containers, err := getProjectContainers(ctx, cli, networkName)
if err != nil {
return err
}

var data [][]string
data = append(data, []string{"ID", "Name", "State", "IP", "Ports"})
if len(containers) == 0 {
pterm.FgYellow.Printfln("The project is not running")
return nil
}

data := make([][]string, len(containers)+1)
data[0] = []string{"ID", "Name", "State", "IP", "Ports"}
for _, container := range containers {
status := container.State
if status == "running" && container.Health != "" {
status = fmt.Sprintf("%s (%s)", container.State, container.Health)
} else if status == "exited" || status == "dead" {
status = fmt.Sprintf("%s (%d)", container.State, container.ExitCode)
}
con := []string{container.ID[:12], container.Name, status, container.IPAddress, displayablePorts(container)}
con := []string{container.ID[:12], container.Name, status, container.IPAddress, cli.DisplayablePorts(container)}
data = append(data, con)
}

Expand All @@ -86,24 +74,24 @@ func runPs() error {
return err
}

func getProjectContainers(ctx context.Context, cli *docker.Client, projectName string) ([]containerSummary, error) {
func getProjectContainers(ctx context.Context, cli *docker.Client, projectName string) ([]docker.ContainerSummary, error) {
containerFilter := filters.NewArgs(filters.Arg("label", fmt.Sprintf("%s=%s", api.ProjectLabel, projectName)))
containers, _ := cli.ContainerList(ctx, types.ContainerListOptions{Filters: containerFilter, All: true})

netFilters := filters.NewArgs(filters.Arg("name", projectName+"_default"))
network, _ := cli.NetworkList(ctx, types.NetworkListOptions{Filters: netFilters})

summary := make([]containerSummary, len(containers))
summary := make([]docker.ContainerSummary, len(containers))
eg, ctx := errgroup.WithContext(ctx)
for i, container := range containers {
i, container := i, container
eg.Go(func() error {
var publishers []portPublisher
var publishers []docker.PortPublisher
sort.Slice(container.Ports, func(i, j int) bool {
return container.Ports[i].PrivatePort < container.Ports[j].PrivatePort
})
for _, p := range container.Ports {
publishers = append(publishers, portPublisher{
publishers = append(publishers, docker.PortPublisher{
URL: p.IP,
TargetPort: int(p.PrivatePort),
PublishedPort: int(p.PublicPort),
Expand Down Expand Up @@ -138,7 +126,7 @@ func getProjectContainers(ctx context.Context, cli *docker.Client, projectName s
}
}

summary[i] = containerSummary{
summary[i] = docker.ContainerSummary{
ID: container.ID,
Name: docker.GetCanonicalContainerName(container),
State: container.State,
Expand All @@ -152,21 +140,3 @@ func getProjectContainers(ctx context.Context, cli *docker.Client, projectName s
}
return summary, eg.Wait()
}

func displayablePorts(c containerSummary) string {
if c.Publishers == nil {
return ""
}

ports := make([]types.Port, len(c.Publishers))
for i, pub := range c.Publishers {
ports[i] = types.Port{
IP: pub.URL,
PrivatePort: uint16(pub.TargetPort),
PublicPort: uint16(pub.PublishedPort),
Type: pub.Protocol,
}
}

return formatter.DisplayablePorts(ports)
}
1 change: 1 addition & 0 deletions command/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func Execute() {
recreateCommand(),
serviceCommand(),
selfUpdateCommand(),
statusCommand(),
templateCreateCommand(),
versionCommand(),
)
Expand Down
178 changes: 178 additions & 0 deletions command/status.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
package command

import (
"context"
"fmt"
"sort"

"github.com/docker/compose/v2/pkg/api"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/local-deploy/dl/helper"
"github.com/local-deploy/dl/utils/docker"
"github.com/pterm/pterm"
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"
)

func statusCommand() *cobra.Command {
cmd := &cobra.Command{
Use: "status",
Short: "Show dl status",
Long: `List of containers started by dl.`,
RunE: func(cmd *cobra.Command, args []string) error {
err := runStatus()
if err != nil {
return err
}

return nil
},
}
return cmd
}

func runStatus() error {
ctx := context.Background()

cli, err := docker.NewClient()
if err != nil {
pterm.FgRed.Printfln("Failed to connect to socket")
return err
}

pterm.DefaultBasicText.Print("# ")
if cli.IsServiceRunning(ctx) {
green := pterm.NewStyle(pterm.FgLightGreen, pterm.BgDefault, pterm.Bold)
green.Println("dl is running")
} else {
red := pterm.NewStyle(pterm.FgLightRed, pterm.BgDefault, pterm.Bold)
red.Println("dl is not running")

return nil
}

services, err := getServices(ctx, cli)
if err != nil {
return err
}

projects, err := getProjects(ctx, cli)
if err != nil {
return err
}

err = render(cli, "services", services)
if err != nil {
return err
}

err = render(cli, "projects", projects)
if err != nil {
return err
}

return nil
}

func getServices(ctx context.Context, cli *docker.Client) ([]docker.ContainerSummary, error) {
containerFilter := filters.NewArgs(
filters.Arg("label", fmt.Sprintf("%s=%s", api.ProjectLabel, "dl-services")),
)
containers, _ := cli.ContainerList(ctx, types.ContainerListOptions{Filters: containerFilter, All: true})

return calculate(ctx, cli, containers)
}

func getProjects(ctx context.Context, cli *docker.Client) ([]docker.ContainerSummary, error) {
containerFilter := filters.NewArgs(
filters.Arg("label", fmt.Sprintf("%s=%s", api.WorkingDirLabel, helper.TemplateDir())),
)
containers, _ := cli.ContainerList(ctx, types.ContainerListOptions{Filters: containerFilter, All: true})

return calculate(ctx, cli, containers)
}

func calculate(ctx context.Context, cli *docker.Client, containers []types.Container) ([]docker.ContainerSummary, error) {
summary := make([]docker.ContainerSummary, len(containers))
eg, ctx := errgroup.WithContext(ctx)
for i, container := range containers {
i, container := i, container
eg.Go(func() error {
var publishers []docker.PortPublisher
sort.Slice(container.Ports, func(i, j int) bool {
return container.Ports[i].PrivatePort < container.Ports[j].PrivatePort
})
for _, port := range container.Ports {
publishers = append(publishers, docker.PortPublisher{
URL: port.IP,
TargetPort: int(port.PrivatePort),
PublishedPort: int(port.PublicPort),
Protocol: port.Type,
})
}

inspect, err := cli.ContainerInspect(ctx, container.ID)
if err != nil {
return err
}

var (
health string
exitCode int
)
if inspect.State != nil {
switch inspect.State.Status {
case "running":
if inspect.State.Health != nil {
health = inspect.State.Health.Status
}
case "exited", "dead":
exitCode = inspect.State.ExitCode
}
}

summary[i] = docker.ContainerSummary{
ID: container.ID,
Name: docker.GetCanonicalContainerName(container),
State: container.State,
Health: health,
ExitCode: exitCode,
Publishers: publishers,
}
return nil
})
}
return summary, eg.Wait()
}

func render(cli *docker.Client, title string, containers []docker.ContainerSummary) error {
if len(containers) == 0 {
return nil
}

pterm.Println()
pterm.DefaultBasicText.Print("## ")
green := pterm.NewStyle(pterm.FgLightYellow, pterm.BgDefault, pterm.Bold)
green.Println(title)

data := make([][]string, len(containers)+1)
data[0] = []string{"ID", "Name", "State", "Ports"}
for _, container := range containers {
status := container.State
if status == "running" && container.Health != "" {
status = fmt.Sprintf("%s (%s)", container.State, container.Health)
} else if status == "exited" || status == "dead" {
status = fmt.Sprintf("%s (%d)", container.State, container.ExitCode)
}
con := []string{container.ID[:12], container.Name, status, cli.DisplayablePorts(container)}
data = append(data, con)
}

err := pterm.DefaultTable.WithHasHeader().WithData(data).Render()
if err != nil {
return err
}

return err
}
15 changes: 3 additions & 12 deletions command/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,11 @@ import (
"os/exec"
"strings"

"github.com/docker/compose/v2/pkg/api"
"github.com/docker/compose/v2/pkg/progress"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
"github.com/docker/docker/client"
"github.com/local-deploy/dl/helper"
"github.com/local-deploy/dl/project"
"github.com/local-deploy/dl/utils"
"github.com/local-deploy/dl/utils/docker"
"github.com/pterm/pterm"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -46,19 +43,13 @@ func upRun() {
}

ctx := context.Background()
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
cli, err := docker.NewClient()
if err != nil {
pterm.FgRed.Printfln("Failed to connect to socket")
return
}

containerFilter := filters.NewArgs(
filters.Arg("name", "traefik"),
filters.Arg("label", fmt.Sprintf("%s=%s", api.ProjectLabel, "dl-services")),
)
traefikExists, _ := cli.ContainerList(ctx, types.ContainerListOptions{Filters: containerFilter})

if len(traefikExists) == 0 {
if !cli.IsServiceRunning(ctx) {
err := startLocalServices()
if err != nil {
pterm.FgRed.Println(err)
Expand Down
2 changes: 2 additions & 0 deletions docs/dl.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Complete documentation is available at https://local-deploy.github.io/
### SEE ALSO

* [dl bash](dl_bash.md) - Login to PHP container
* [dl cert](dl_cert.md) - CA certificate management
* [dl completion](dl_completion.md) - Generate completion script
* [dl config](dl_config.md) - Application configuration
* [dl deploy](dl_deploy.md) - Downloading db and files from the production server
Expand All @@ -27,6 +28,7 @@ Complete documentation is available at https://local-deploy.github.io/
* [dl recreate](dl_recreate.md) - Recreate containers
* [dl self-update](dl_self-update.md) - Update dl
* [dl service](dl_service.md) - Local services configuration
* [dl status](dl_status.md) - List containers
* [dl templates](dl_templates.md) - Regenerate docker-compose files
* [dl up](dl_up.md) - Up project
* [dl version](dl_version.md) - Print the version number
Expand Down
26 changes: 26 additions & 0 deletions docs/dl_cert.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## dl cert

CA certificate management

### Synopsis

Generating and (un)installing a root certificate in Firefox and/or Chrome/Chromium browsers.

### Options

```
-h, --help help for cert
```

### Options inherited from parent commands

```
--debug Show more output
```

### SEE ALSO

* [dl](dl.md) - Deploy Local
* [dl cert install](dl_cert_install.md) - Installing CA certificate
* [dl cert uninstall](dl_cert_uninstall.md) - Removing CA certificate

0 comments on commit db30952

Please sign in to comment.