github.com/containerd/Containerd@v1.4.13/cmd/ctr/commands/plugins/plugins.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package plugins 18 19 import ( 20 "fmt" 21 "os" 22 "sort" 23 "strings" 24 "text/tabwriter" 25 26 "github.com/containerd/containerd/api/types" 27 "github.com/containerd/containerd/cmd/ctr/commands" 28 "github.com/containerd/containerd/platforms" 29 v1 "github.com/opencontainers/image-spec/specs-go/v1" 30 "github.com/urfave/cli" 31 "google.golang.org/grpc/codes" 32 ) 33 34 // Command is a cli command that outputs plugin information 35 var Command = cli.Command{ 36 Name: "plugins", 37 Aliases: []string{"plugin"}, 38 Usage: "provides information about containerd plugins", 39 Subcommands: []cli.Command{ 40 listCommand, 41 }, 42 } 43 44 var listCommand = cli.Command{ 45 Name: "list", 46 Aliases: []string{"ls"}, 47 Usage: "lists containerd plugins", 48 Flags: []cli.Flag{ 49 cli.BoolFlag{ 50 Name: "quiet,q", 51 Usage: "print only the plugin ids", 52 }, 53 cli.BoolFlag{ 54 Name: "detailed,d", 55 Usage: "print detailed information about each plugin", 56 }, 57 }, 58 Action: func(context *cli.Context) error { 59 var ( 60 quiet = context.Bool("quiet") 61 detailed = context.Bool("detailed") 62 ) 63 client, ctx, cancel, err := commands.NewClient(context) 64 if err != nil { 65 return err 66 } 67 defer cancel() 68 ps := client.IntrospectionService() 69 response, err := ps.Plugins(ctx, context.Args()) 70 if err != nil { 71 return err 72 } 73 if quiet { 74 for _, plugin := range response.Plugins { 75 fmt.Println(plugin.ID) 76 } 77 return nil 78 } 79 w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0) 80 if detailed { 81 first := true 82 for _, plugin := range response.Plugins { 83 if !first { 84 fmt.Fprintln(w, "\t\t\t") 85 } 86 first = false 87 fmt.Fprintln(w, "Type:\t", plugin.Type) 88 fmt.Fprintln(w, "ID:\t", plugin.ID) 89 if len(plugin.Requires) > 0 { 90 fmt.Fprintln(w, "Requires:\t") 91 for _, r := range plugin.Requires { 92 fmt.Fprintln(w, "\t", r) 93 } 94 } 95 if len(plugin.Platforms) > 0 { 96 fmt.Fprintln(w, "Platforms:\t", prettyPlatforms(plugin.Platforms)) 97 } 98 99 if len(plugin.Exports) > 0 { 100 fmt.Fprintln(w, "Exports:\t") 101 for k, v := range plugin.Exports { 102 fmt.Fprintln(w, "\t", k, "\t", v) 103 } 104 } 105 106 if len(plugin.Capabilities) > 0 { 107 fmt.Fprintln(w, "Capabilities:\t", strings.Join(plugin.Capabilities, ",")) 108 } 109 110 if plugin.InitErr != nil { 111 fmt.Fprintln(w, "Error:\t") 112 fmt.Fprintln(w, "\t Code:\t", codes.Code(plugin.InitErr.Code)) 113 fmt.Fprintln(w, "\t Message:\t", plugin.InitErr.Message) 114 } 115 } 116 return w.Flush() 117 } 118 119 fmt.Fprintln(w, "TYPE\tID\tPLATFORMS\tSTATUS\t") 120 for _, plugin := range response.Plugins { 121 status := "ok" 122 123 if plugin.InitErr != nil { 124 status = "error" 125 } 126 127 var platformColumn = "-" 128 if len(plugin.Platforms) > 0 { 129 platformColumn = prettyPlatforms(plugin.Platforms) 130 } 131 if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t\n", 132 plugin.Type, 133 plugin.ID, 134 platformColumn, 135 status, 136 ); err != nil { 137 return err 138 } 139 } 140 return w.Flush() 141 }, 142 } 143 144 func prettyPlatforms(pspb []types.Platform) string { 145 psm := map[string]struct{}{} 146 for _, p := range pspb { 147 psm[platforms.Format(v1.Platform{ 148 OS: p.OS, 149 Architecture: p.Architecture, 150 Variant: p.Variant, 151 })] = struct{}{} 152 } 153 var ps []string 154 for p := range psm { 155 ps = append(ps, p) 156 } 157 sort.Stable(sort.StringSlice(ps)) 158 return strings.Join(ps, ",") 159 }