docker/swarmkit

View on GitHub
swarmd/cmd/swarmctl/service/inspect.go

Summary

Maintainability
D
1 day
Test Coverage
package service

import (
    "errors"
    "fmt"
    "io"
    "os"
    "sort"
    "strings"
    "text/tabwriter"

    "github.com/dustin/go-humanize"
    gogotypes "github.com/gogo/protobuf/types"
    "github.com/moby/swarmkit/swarmd/cmd/swarmctl/common"
    "github.com/moby/swarmkit/swarmd/cmd/swarmctl/task"
    "github.com/moby/swarmkit/v2/api"
    "github.com/moby/swarmkit/v2/api/genericresource"
    "github.com/spf13/cobra"
)

func printServiceSummary(service *api.Service, running int) {
    w := tabwriter.NewWriter(os.Stdout, 8, 8, 8, ' ', 0)
    defer w.Flush()

    task := service.Spec.Task
    common.FprintfIfNotEmpty(w, "ID\t: %s\n", service.ID)
    common.FprintfIfNotEmpty(w, "Name\t: %s\n", service.Spec.Annotations.Name)
    if len(service.Spec.Annotations.Labels) > 0 {
        fmt.Fprintln(w, "Labels\t")
        for k, v := range service.Spec.Annotations.Labels {
            fmt.Fprintf(w, "  %s\t: %s\n", k, v)
        }
    }
    common.FprintfIfNotEmpty(w, "Replicas\t: %s\n", getServiceReplicasTxt(service, running))

    if service.UpdateStatus != nil {
        fmt.Fprintln(w, "Update Status\t")
        fmt.Fprintln(w, " State\t:", service.UpdateStatus.State)
        started, err := gogotypes.TimestampFromProto(service.UpdateStatus.StartedAt)
        if err == nil {
            fmt.Fprintln(w, " Started\t:", humanize.Time(started))
        }
        if service.UpdateStatus.State == api.UpdateStatus_COMPLETED {
            completed, err := gogotypes.TimestampFromProto(service.UpdateStatus.CompletedAt)
            if err == nil {
                fmt.Fprintln(w, " Completed\t:", humanize.Time(completed))
            }
        }
        fmt.Fprintln(w, " Message\t:", service.UpdateStatus.Message)
    }

    fmt.Fprintln(w, "Template\t")
    fmt.Fprintln(w, " Container\t")
    ctr := service.Spec.Task.GetContainer()
    common.FprintfIfNotEmpty(w, "  Image\t: %s\n", ctr.Image)
    common.FprintfIfNotEmpty(w, "  Command\t: %q\n", strings.Join(ctr.Command, " "))
    common.FprintfIfNotEmpty(w, "  Args\t: [%s]\n", strings.Join(ctr.Args, ", "))
    common.FprintfIfNotEmpty(w, "  Env\t: [%s]\n", strings.Join(ctr.Env, ", "))
    if task.Placement != nil {
        common.FprintfIfNotEmpty(w, "  Constraints\t: %s\n", strings.Join(task.Placement.Constraints, ", "))
    }

    if task.Resources != nil {
        res := task.Resources
        fmt.Fprintln(w, "  Resources\t")
        printResources := func(w io.Writer, r *api.Resources) {
            if r.NanoCPUs != 0 {
                fmt.Fprintf(w, "      CPU\t: %g\n", float64(r.NanoCPUs)/1e9)
            }
            if r.MemoryBytes != 0 {
                fmt.Fprintf(w, "      Memory\t: %s\n", humanize.IBytes(uint64(r.MemoryBytes)))
            }
            if len(r.Generic) != 0 {
                fmt.Fprintln(w, "      Generic Resources\t")
            }

            for _, r := range r.Generic {
                k := genericresource.Kind(r)
                v := genericresource.Value(r)
                fmt.Fprintf(w, "        %s\t: %s\n", k, v)
            }

        }
        if res.Reservations != nil {
            fmt.Fprintln(w, "    Reservations:\t")
            printResources(w, res.Reservations)
        }
        if res.Limits != nil {
            fmt.Fprintln(w, "    Limits:\t")
            printResources(w, res.Limits)
        }
    }
    if len(service.Spec.Task.Networks) > 0 {
        fmt.Fprint(w, "  Networks:")
        for _, n := range service.Spec.Task.Networks {
            fmt.Fprintf(w, " %s", n.Target)
        }
    }

    if service.Endpoint != nil && len(service.Endpoint.Ports) > 0 {
        fmt.Fprintln(w, "\nPorts:")
        for _, port := range service.Endpoint.Ports {
            fmt.Fprintf(w, "    - Name\t= %s\n", port.Name)
            fmt.Fprintf(w, "      Protocol\t= %s\n", port.Protocol)
            fmt.Fprintf(w, "      Port\t= %d\n", port.TargetPort)
            fmt.Fprintf(w, "      SwarmPort\t= %d\n", port.PublishedPort)
        }
    }

    if len(ctr.Mounts) > 0 {
        fmt.Fprintln(w, "  Mounts:")
        for _, v := range ctr.Mounts {
            fmt.Fprintf(w, "    - target = %s\n", v.Target)
            fmt.Fprintf(w, "      source = %s\n", v.Source)
            fmt.Fprintf(w, "      readonly = %v\n", v.ReadOnly)
            fmt.Fprintf(w, "      type = %v\n", strings.ToLower(v.Type.String()))
        }
    }

    if len(ctr.Secrets) > 0 {
        fmt.Fprintln(w, "  Secrets:")
        for _, sr := range ctr.Secrets {
            var targetName, mode string
            if sr.GetFile() != nil {
                targetName = sr.GetFile().Name
                mode = "FILE"
            }
            fmt.Fprintf(w, "    [%s] %s@%s:%s\n", mode, sr.SecretName, sr.SecretID, targetName)
        }
    }

    if len(ctr.Configs) > 0 {
        fmt.Fprintln(w, "  Configs:")
        for _, cr := range ctr.Configs {
            var targetName, mode string
            if cr.GetFile() != nil {
                targetName = cr.GetFile().Name
                mode = "FILE"
            }
            fmt.Fprintf(w, "    [%s] %s@%s:%s\n", mode, cr.ConfigName, cr.ConfigID, targetName)
        }
    }

    if task.LogDriver != nil {
        fmt.Fprintf(w, "  LogDriver\t: %s\n", task.LogDriver.Name)
        var keys []string

        if task.LogDriver.Options != nil {
            for k := range task.LogDriver.Options {
                keys = append(keys, k)
            }
            sort.Strings(keys)

            for _, k := range keys {
                v := task.LogDriver.Options[k]
                if v != "" {
                    fmt.Fprintf(w, "    %s\t: %s\n", k, v)
                } else {
                    fmt.Fprintf(w, "    %s\t\n", k)

                }
            }
        }
    }
}

var (
    inspectCmd = &cobra.Command{
        Use:   "inspect <service ID>",
        Short: "Inspect a service",
        RunE: func(cmd *cobra.Command, args []string) error {
            if len(args) == 0 {
                return errors.New("service ID missing")
            }

            if len(args) > 1 {
                return errors.New("inspect command takes exactly 1 argument")
            }

            flags := cmd.Flags()

            all, err := flags.GetBool("all")
            if err != nil {
                return err
            }

            c, err := common.Dial(cmd)
            if err != nil {
                return err
            }

            res := common.NewResolver(cmd, c)

            service, err := getService(common.Context(cmd), c, args[0])
            if err != nil {
                return err
            }

            r, err := c.ListTasks(common.Context(cmd),
                &api.ListTasksRequest{
                    Filters: &api.ListTasksRequest_Filters{
                        ServiceIDs: []string{service.ID},
                    },
                })
            if err != nil {
                return err
            }
            var running int
            for _, t := range r.Tasks {
                if t.Status.State == api.TaskStateRunning {
                    running++
                }
            }

            printServiceSummary(service, running)
            if len(r.Tasks) > 0 {
                fmt.Println()
                task.Print(r.Tasks, all, res)
            }

            return nil
        },
    }
)

func init() {
    inspectCmd.Flags().BoolP("all", "a", false, "Show all tasks (default shows just running)")
}