From b7e15f3113a09a685a5ed3ef5e1d1d126c7f48dc Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Mon, 15 Apr 2019 10:21:09 -0700 Subject: [PATCH] commands: implementation for inspect Signed-off-by: Tonis Tiigi --- commands/create.go | 6 +- commands/inspect.go | 124 +++++++++++++++++++++++++++--- commands/util.go | 58 ++++++++++++-- driver/docker-container/driver.go | 4 +- driver/driver.go | 20 ++++- 5 files changed, 189 insertions(+), 23 deletions(-) diff --git a/commands/create.go b/commands/create.go index e751908c..63ae4de0 100644 --- a/commands/create.go +++ b/commands/create.go @@ -128,7 +128,11 @@ func runCreate(dockerCli command.Cli, in createOptions, args []string) error { } if in.use && ep != "" { - if err := txn.SetCurrent(ep, ng.Name, false, false); err != nil { + current, err := getCurrentEndpoint(dockerCli) + if err != nil { + return err + } + if err := txn.SetCurrent(current, ng.Name, false, false); err != nil { return err } } diff --git a/commands/inspect.go b/commands/inspect.go index e1981905..3707b943 100644 --- a/commands/inspect.go +++ b/commands/inspect.go @@ -1,17 +1,44 @@ package commands import ( + "context" + "fmt" + "os" + "strings" + "text/tabwriter" + "time" + "github.com/docker/cli/cli" "github.com/docker/cli/cli/command" + "github.com/moby/buildkit/util/appcontext" "github.com/spf13/cobra" + "github.com/tonistiigi/buildx/build" + "github.com/tonistiigi/buildx/driver" "github.com/tonistiigi/buildx/store" + "github.com/tonistiigi/buildx/util/progress" + "golang.org/x/sync/errgroup" ) type inspectOptions struct { bootstrap bool } +type dinfo struct { + di *build.DriverInfo + info *driver.Info + platforms []string + err error +} + +type nginfo struct { + ng *store.NodeGroup + drivers []dinfo + err error +} + func runInspect(dockerCli command.Cli, in inspectOptions, args []string) error { + ctx := appcontext.Context() + txn, release, err := getStore(dockerCli) if err != nil { return err @@ -21,7 +48,7 @@ func runInspect(dockerCli command.Cli, in inspectOptions, args []string) error { var ng *store.NodeGroup if len(args) > 0 { - ng, err = txn.NodeGroupByName(args[0]) + ng, err = getNodeGroup(txn, dockerCli, args[0]) if err != nil { return err } @@ -33,21 +60,59 @@ func runInspect(dockerCli command.Cli, in inspectOptions, args []string) error { } if ng == nil { - ep, err := getCurrentEndpoint(dockerCli) - if err != nil { - return err - } ng = &store.NodeGroup{ Name: "default", - Nodes: []store.Node{ - { - Name: "default", - Endpoint: ep, - }, - }, + Nodes: []store.Node{{ + Name: "default", + Endpoint: "default", + }}, } } + ngi := &nginfo{ng: ng} + + timeoutCtx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + err = loadNodeGroupData(timeoutCtx, dockerCli, ngi) + + if in.bootstrap { + if err := boot(ctx, ngi); err != nil { + return err + } + ngi = &nginfo{ng: ng} + err = loadNodeGroupData(ctx, dockerCli, ngi) + } + + w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0) + fmt.Fprintf(w, "Name:\t%s\n", ngi.ng.Name) + fmt.Fprintf(w, "Driver:\t%s\n", ngi.ng.Driver) + if err != nil { + fmt.Fprintf(w, "Error:\t%s\n", err.Error()) + } else if ngi.err != nil { + fmt.Fprintf(w, "Error:\t%s\n", ngi.err.Error()) + } + fmt.Fprintln(w, "") + fmt.Fprintln(w, "Nodes:") + + for i, n := range ngi.ng.Nodes { + if i != 0 { + fmt.Fprintln(w, "") + } + fmt.Fprintf(w, "Name:\t%s\n", n.Name) + fmt.Fprintf(w, "Endpoint:\t%s\n", n.Endpoint) + if err := ngi.drivers[i].di.Err; err != nil { + fmt.Fprintf(w, "Error:\t%s\n", err.Error()) + } else if err := ngi.drivers[i].err; err != nil { + fmt.Fprintf(w, "Error:\t%s\n", err.Error()) + } else { + fmt.Fprintf(w, "Status:\t%s\n", ngi.drivers[i].info.Status) + fmt.Fprintf(w, "Platforms:\t%s\n", strings.Join(append(n.Platforms, ngi.drivers[i].platforms...), ", ")) + } + } + + w.Flush() + return nil } @@ -71,3 +136,40 @@ func inspectCmd(dockerCli command.Cli) *cobra.Command { return cmd } + +func boot(ctx context.Context, ngi *nginfo) error { + toBoot := make([]int, 0, len(ngi.drivers)) + for i, d := range ngi.drivers { + if d.err != nil || d.di.Err != nil || d.di.Driver == nil || d.info == nil { + continue + } + if d.info.Status != driver.Running { + toBoot = append(toBoot, i) + } + } + if len(toBoot) == 0 { + return nil + } + + pw := progress.NewPrinter(context.TODO(), os.Stderr, "auto") + + mw := progress.NewMultiWriter(pw) + + eg, _ := errgroup.WithContext(ctx) + for _, idx := range toBoot { + func(idx int) { + eg.Go(func() error { + pw := mw.WithPrefix(ngi.ng.Nodes[idx].Name, len(toBoot) > 1) + _, _, err := driver.Boot(ctx, ngi.drivers[idx].di.Driver, pw) + if err != nil { + ngi.drivers[idx].err = err + } + close(pw.Status()) + <-pw.Done() + return nil + }) + }(idx) + } + + return eg.Wait() +} diff --git a/commands/util.go b/commands/util.go index 2f3143e9..324407cb 100644 --- a/commands/util.go +++ b/commands/util.go @@ -5,6 +5,7 @@ import ( "os" "path/filepath" + "github.com/containerd/containerd/platforms" "github.com/docker/cli/cli/command" "github.com/docker/cli/cli/context/docker" dopts "github.com/docker/cli/opts" @@ -148,6 +149,7 @@ func driversForNodeGroup(ctx context.Context, dockerCli command.Cli, ng *store.N if err != nil { return nil, err } + ng.Driver = f.Name() } for i, n := range ng.Nodes { @@ -243,10 +245,52 @@ func getDefaultDrivers(ctx context.Context, dockerCli command.Cli) ([]build.Driv }, nil } -// type ngInfo struct { -// ng *store.NodeGroup -// } -// -// func (i *ngInfo) init(ctx context.Context, boot bool) { -// -// } +func loadInfoData(ctx context.Context, d *dinfo) error { + if d.di.Driver == nil { + return nil + } + info, err := d.di.Driver.Info(ctx) + if err != nil { + return err + } + d.info = info + if info.Status == driver.Running { + c, err := d.di.Driver.Client(ctx) + if err != nil { + return err + } + workers, err := c.ListWorkers(ctx) + if err != nil { + return errors.Wrap(err, "listing workers") + } + for _, w := range workers { + for _, p := range w.Platforms { + d.platforms = append(d.platforms, platforms.Format(p)) + } + } + } + return nil +} + +func loadNodeGroupData(ctx context.Context, dockerCli command.Cli, ngi *nginfo) error { + eg, _ := errgroup.WithContext(ctx) + + dis, err := driversForNodeGroup(ctx, dockerCli, ngi.ng) + if err != nil { + return err + } + ngi.drivers = make([]dinfo, len(dis)) + for i, di := range dis { + ngi.drivers[i].di = &di + func(d *dinfo) { + eg.Go(func() error { + if err := loadInfoData(ctx, d); err != nil { + d.err = err + } + return nil + }) + }(&ngi.drivers[i]) + } + + return eg.Wait() +} diff --git a/driver/docker-container/driver.go b/driver/docker-container/driver.go index 850af59b..389d56a2 100644 --- a/driver/docker-container/driver.go +++ b/driver/docker-container/driver.go @@ -153,7 +153,7 @@ func (d *Driver) Info(ctx context.Context) (*driver.Info, error) { if err != nil { if dockerclient.IsErrNotFound(err) { return &driver.Info{ - Status: driver.Terminated, + Status: driver.Inactive, }, nil } return nil, err @@ -186,7 +186,7 @@ func (d *Driver) Rm(ctx context.Context, force bool) error { if err != nil { return err } - if info.Status != driver.Terminated { + if info.Status != driver.Inactive { return d.DockerAPI.ContainerRemove(ctx, d.Name, dockertypes.ContainerRemoveOptions{ RemoveVolumes: true, Force: true, diff --git a/driver/driver.go b/driver/driver.go index 559c14ff..aaec253c 100644 --- a/driver/driver.go +++ b/driver/driver.go @@ -10,18 +10,34 @@ import ( ) var ErrNotRunning = errors.Errorf("driver not running") -var ErrNotConnecting = errors.Errorf("driver not connection") +var ErrNotConnecting = errors.Errorf("driver not connecting") type Status int const ( - Terminated Status = iota + Inactive Status = iota Starting Running Stopping Stopped ) +func (s Status) String() string { + switch s { + case Inactive: + return "inactive" + case Starting: + return "starting" + case Running: + return "running" + case Stopping: + return "stopping" + case Stopped: + return "stopped" + } + return "unknown" +} + type Info struct { Status Status }