github.com/pdmccormick/importable-docker-buildx@v0.0.0-20240426161518-e47091289030/commands/inspect.go (about)

     1  package commands
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"os"
     7  	"sort"
     8  	"strings"
     9  	"text/tabwriter"
    10  	"time"
    11  
    12  	"github.com/docker/buildx/builder"
    13  	"github.com/docker/buildx/driver"
    14  	"github.com/docker/buildx/util/cobrautil/completion"
    15  	"github.com/docker/buildx/util/platformutil"
    16  	"github.com/docker/cli/cli"
    17  	"github.com/docker/cli/cli/command"
    18  	"github.com/docker/cli/cli/debug"
    19  	"github.com/docker/go-units"
    20  	"github.com/spf13/cobra"
    21  )
    22  
    23  type inspectOptions struct {
    24  	bootstrap bool
    25  	builder   string
    26  }
    27  
    28  func runInspect(ctx context.Context, dockerCli command.Cli, in inspectOptions) error {
    29  	b, err := builder.New(dockerCli,
    30  		builder.WithName(in.builder),
    31  		builder.WithSkippedValidation(),
    32  	)
    33  	if err != nil {
    34  		return err
    35  	}
    36  
    37  	timeoutCtx, cancel := context.WithTimeout(ctx, 20*time.Second)
    38  	defer cancel()
    39  
    40  	nodes, err := b.LoadNodes(timeoutCtx, builder.WithData())
    41  	if in.bootstrap {
    42  		var ok bool
    43  		ok, err = b.Boot(ctx)
    44  		if err != nil {
    45  			return err
    46  		}
    47  		if ok {
    48  			nodes, err = b.LoadNodes(timeoutCtx, builder.WithData())
    49  		}
    50  	}
    51  
    52  	w := tabwriter.NewWriter(os.Stdout, 0, 0, 1, ' ', 0)
    53  	fmt.Fprintf(w, "Name:\t%s\n", b.Name)
    54  	fmt.Fprintf(w, "Driver:\t%s\n", b.Driver)
    55  	if !b.NodeGroup.LastActivity.IsZero() {
    56  		fmt.Fprintf(w, "Last Activity:\t%v\n", b.NodeGroup.LastActivity)
    57  	}
    58  
    59  	if err != nil {
    60  		fmt.Fprintf(w, "Error:\t%s\n", err.Error())
    61  	} else if b.Err() != nil {
    62  		fmt.Fprintf(w, "Error:\t%s\n", b.Err().Error())
    63  	}
    64  	if err == nil {
    65  		fmt.Fprintln(w, "")
    66  		fmt.Fprintln(w, "Nodes:")
    67  
    68  		for i, n := range nodes {
    69  			if i != 0 {
    70  				fmt.Fprintln(w, "")
    71  			}
    72  			fmt.Fprintf(w, "Name:\t%s\n", n.Name)
    73  			fmt.Fprintf(w, "Endpoint:\t%s\n", n.Endpoint)
    74  
    75  			var driverOpts []string
    76  			for k, v := range n.DriverOpts {
    77  				driverOpts = append(driverOpts, fmt.Sprintf("%s=%q", k, v))
    78  			}
    79  			if len(driverOpts) > 0 {
    80  				fmt.Fprintf(w, "Driver Options:\t%s\n", strings.Join(driverOpts, " "))
    81  			}
    82  
    83  			if err := n.Err; err != nil {
    84  				fmt.Fprintf(w, "Error:\t%s\n", err.Error())
    85  			} else {
    86  				fmt.Fprintf(w, "Status:\t%s\n", nodes[i].DriverInfo.Status)
    87  				if len(n.BuildkitdFlags) > 0 {
    88  					fmt.Fprintf(w, "BuildKit daemon flags:\t%s\n", strings.Join(n.BuildkitdFlags, " "))
    89  				}
    90  				if nodes[i].Version != "" {
    91  					fmt.Fprintf(w, "BuildKit version:\t%s\n", nodes[i].Version)
    92  				}
    93  				platforms := platformutil.FormatInGroups(n.Node.Platforms, n.Platforms)
    94  				if len(platforms) > 0 {
    95  					fmt.Fprintf(w, "Platforms:\t%s\n", strings.Join(platforms, ", "))
    96  				}
    97  				if debug.IsEnabled() {
    98  					fmt.Fprintf(w, "Features:\n")
    99  					features := nodes[i].Driver.Features(ctx)
   100  					featKeys := make([]string, 0, len(features))
   101  					for k := range features {
   102  						featKeys = append(featKeys, string(k))
   103  					}
   104  					sort.Strings(featKeys)
   105  					for _, k := range featKeys {
   106  						fmt.Fprintf(w, "\t%s:\t%t\n", k, features[driver.Feature(k)])
   107  					}
   108  				}
   109  				if len(nodes[i].Labels) > 0 {
   110  					fmt.Fprintf(w, "Labels:\n")
   111  					for _, k := range sortedKeys(nodes[i].Labels) {
   112  						v := nodes[i].Labels[k]
   113  						fmt.Fprintf(w, "\t%s:\t%s\n", k, v)
   114  					}
   115  				}
   116  				for ri, rule := range nodes[i].GCPolicy {
   117  					fmt.Fprintf(w, "GC Policy rule#%d:\n", ri)
   118  					fmt.Fprintf(w, "\tAll:\t%v\n", rule.All)
   119  					if len(rule.Filter) > 0 {
   120  						fmt.Fprintf(w, "\tFilters:\t%s\n", strings.Join(rule.Filter, " "))
   121  					}
   122  					if rule.KeepDuration > 0 {
   123  						fmt.Fprintf(w, "\tKeep Duration:\t%v\n", rule.KeepDuration.String())
   124  					}
   125  					if rule.KeepBytes > 0 {
   126  						fmt.Fprintf(w, "\tKeep Bytes:\t%s\n", units.BytesSize(float64(rule.KeepBytes)))
   127  					}
   128  				}
   129  			}
   130  		}
   131  	}
   132  
   133  	w.Flush()
   134  
   135  	return nil
   136  }
   137  
   138  func inspectCmd(dockerCli command.Cli, rootOpts *rootOptions) *cobra.Command {
   139  	var options inspectOptions
   140  
   141  	cmd := &cobra.Command{
   142  		Use:   "inspect [NAME]",
   143  		Short: "Inspect current builder instance",
   144  		Args:  cli.RequiresMaxArgs(1),
   145  		RunE: func(cmd *cobra.Command, args []string) error {
   146  			options.builder = rootOpts.builder
   147  			if len(args) > 0 {
   148  				options.builder = args[0]
   149  			}
   150  			return runInspect(cmd.Context(), dockerCli, options)
   151  		},
   152  		ValidArgsFunction: completion.BuilderNames(dockerCli),
   153  	}
   154  
   155  	flags := cmd.Flags()
   156  	flags.BoolVar(&options.bootstrap, "bootstrap", false, "Ensure builder has booted before inspecting")
   157  
   158  	return cmd
   159  }
   160  
   161  func sortedKeys(m map[string]string) []string {
   162  	s := make([]string, len(m))
   163  	i := 0
   164  	for k := range m {
   165  		s[i] = k
   166  		i++
   167  	}
   168  	sort.Strings(s)
   169  	return s
   170  }