138 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package plugins
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"sort"
 | |
| 	"strings"
 | |
| 	"text/tabwriter"
 | |
| 
 | |
| 	introspection "github.com/containerd/containerd/api/services/introspection/v1"
 | |
| 	"github.com/containerd/containerd/api/types"
 | |
| 	"github.com/containerd/containerd/cmd/ctr/commands"
 | |
| 	"github.com/containerd/containerd/platforms"
 | |
| 	"github.com/opencontainers/image-spec/specs-go/v1"
 | |
| 	"github.com/urfave/cli"
 | |
| 	"google.golang.org/grpc/codes"
 | |
| )
 | |
| 
 | |
| // Command is a cli command that outputs plugin information
 | |
| var Command = cli.Command{
 | |
| 	Name:    "plugins",
 | |
| 	Aliases: []string{"plugin"},
 | |
| 	Usage:   "provides information about containerd plugins",
 | |
| 	Flags: []cli.Flag{
 | |
| 		cli.BoolFlag{
 | |
| 			Name:  "quiet,q",
 | |
| 			Usage: "print only the plugin ids",
 | |
| 		},
 | |
| 		cli.BoolFlag{
 | |
| 			Name:  "detailed,d",
 | |
| 			Usage: "print detailed information about each plugin",
 | |
| 		},
 | |
| 	},
 | |
| 	Action: func(context *cli.Context) error {
 | |
| 		var (
 | |
| 			quiet    = context.Bool("quiet")
 | |
| 			detailed = context.Bool("detailed")
 | |
| 		)
 | |
| 		client, ctx, cancel, err := commands.NewClient(context)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		defer cancel()
 | |
| 		ps := client.IntrospectionService()
 | |
| 		response, err := ps.Plugins(ctx, &introspection.PluginsRequest{
 | |
| 			Filters: context.Args(),
 | |
| 		})
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 		if quiet {
 | |
| 			for _, plugin := range response.Plugins {
 | |
| 				fmt.Println(plugin.ID)
 | |
| 			}
 | |
| 			return nil
 | |
| 		}
 | |
| 		w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0)
 | |
| 		if detailed {
 | |
| 			first := true
 | |
| 			for _, plugin := range response.Plugins {
 | |
| 				if !first {
 | |
| 					fmt.Fprintln(w, "\t\t\t")
 | |
| 				}
 | |
| 				first = false
 | |
| 				fmt.Fprintln(w, "Type:\t", plugin.Type)
 | |
| 				fmt.Fprintln(w, "ID:\t", plugin.ID)
 | |
| 				if len(plugin.Requires) > 0 {
 | |
| 					fmt.Fprintln(w, "Requires:\t")
 | |
| 					for _, r := range plugin.Requires {
 | |
| 						fmt.Fprintln(w, "\t", r)
 | |
| 					}
 | |
| 				}
 | |
| 				if len(plugin.Platforms) > 0 {
 | |
| 					fmt.Fprintln(w, "Platforms:\t", prettyPlatforms(plugin.Platforms))
 | |
| 				}
 | |
| 
 | |
| 				if len(plugin.Exports) > 0 {
 | |
| 					fmt.Fprintln(w, "Exports:\t")
 | |
| 					for k, v := range plugin.Exports {
 | |
| 						fmt.Fprintln(w, "\t", k, "\t", v)
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				if len(plugin.Capabilities) > 0 {
 | |
| 					fmt.Fprintln(w, "Capabilities:\t", strings.Join(plugin.Capabilities, ","))
 | |
| 				}
 | |
| 
 | |
| 				if plugin.InitErr != nil {
 | |
| 					fmt.Fprintln(w, "Error:\t")
 | |
| 					fmt.Fprintln(w, "\t Code:\t", codes.Code(plugin.InitErr.Code))
 | |
| 					fmt.Fprintln(w, "\t Message:\t", plugin.InitErr.Message)
 | |
| 				}
 | |
| 			}
 | |
| 			return w.Flush()
 | |
| 		}
 | |
| 
 | |
| 		fmt.Fprintln(w, "TYPE\tID\tPLATFORMS\tSTATUS\t")
 | |
| 		for _, plugin := range response.Plugins {
 | |
| 			status := "ok"
 | |
| 
 | |
| 			if plugin.InitErr != nil {
 | |
| 				status = "error"
 | |
| 			}
 | |
| 
 | |
| 			var platformColumn = "-"
 | |
| 			if len(plugin.Platforms) > 0 {
 | |
| 				platformColumn = prettyPlatforms(plugin.Platforms)
 | |
| 			}
 | |
| 			if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t\n",
 | |
| 				plugin.Type,
 | |
| 				plugin.ID,
 | |
| 				platformColumn,
 | |
| 				status,
 | |
| 			); err != nil {
 | |
| 				return err
 | |
| 			}
 | |
| 		}
 | |
| 		return w.Flush()
 | |
| 	},
 | |
| }
 | |
| 
 | |
| func prettyPlatforms(pspb []types.Platform) string {
 | |
| 	psm := map[string]struct{}{}
 | |
| 	for _, p := range pspb {
 | |
| 		psm[platforms.Format(v1.Platform{
 | |
| 			OS:           p.OS,
 | |
| 			Architecture: p.Architecture,
 | |
| 			Variant:      p.Variant,
 | |
| 		})] = struct{}{}
 | |
| 	}
 | |
| 	var ps []string
 | |
| 	for p := range psm {
 | |
| 		ps = append(ps, p)
 | |
| 	}
 | |
| 	sort.Stable(sort.StringSlice(ps))
 | |
| 	return strings.Join(ps, ",")
 | |
| }
 | 
