github.com/demonoid81/containerd@v1.3.4/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 introspection "github.com/containerd/containerd/api/services/introspection/v1" 27 "github.com/containerd/containerd/api/types" 28 "github.com/containerd/containerd/cmd/ctr/commands" 29 "github.com/containerd/containerd/platforms" 30 v1 "github.com/opencontainers/image-spec/specs-go/v1" 31 "github.com/urfave/cli" 32 "google.golang.org/grpc/codes" 33 ) 34 35 // Command is a cli command that outputs plugin information 36 var Command = cli.Command{ 37 Name: "plugins", 38 Aliases: []string{"plugin"}, 39 Usage: "provides information about containerd plugins", 40 Subcommands: []cli.Command{ 41 listCommand, 42 }, 43 } 44 45 var listCommand = cli.Command{ 46 Name: "list", 47 Aliases: []string{"ls"}, 48 Usage: "lists containerd plugins", 49 Flags: []cli.Flag{ 50 cli.BoolFlag{ 51 Name: "quiet,q", 52 Usage: "print only the plugin ids", 53 }, 54 cli.BoolFlag{ 55 Name: "detailed,d", 56 Usage: "print detailed information about each plugin", 57 }, 58 }, 59 Action: func(context *cli.Context) error { 60 var ( 61 quiet = context.Bool("quiet") 62 detailed = context.Bool("detailed") 63 ) 64 client, ctx, cancel, err := commands.NewClient(context) 65 if err != nil { 66 return err 67 } 68 defer cancel() 69 ps := client.IntrospectionService() 70 response, err := ps.Plugins(ctx, &introspection.PluginsRequest{ 71 Filters: context.Args(), 72 }) 73 if err != nil { 74 return err 75 } 76 if quiet { 77 for _, plugin := range response.Plugins { 78 fmt.Println(plugin.ID) 79 } 80 return nil 81 } 82 w := tabwriter.NewWriter(os.Stdout, 4, 8, 4, ' ', 0) 83 if detailed { 84 first := true 85 for _, plugin := range response.Plugins { 86 if !first { 87 fmt.Fprintln(w, "\t\t\t") 88 } 89 first = false 90 fmt.Fprintln(w, "Type:\t", plugin.Type) 91 fmt.Fprintln(w, "ID:\t", plugin.ID) 92 if len(plugin.Requires) > 0 { 93 fmt.Fprintln(w, "Requires:\t") 94 for _, r := range plugin.Requires { 95 fmt.Fprintln(w, "\t", r) 96 } 97 } 98 if len(plugin.Platforms) > 0 { 99 fmt.Fprintln(w, "Platforms:\t", prettyPlatforms(plugin.Platforms)) 100 } 101 102 if len(plugin.Exports) > 0 { 103 fmt.Fprintln(w, "Exports:\t") 104 for k, v := range plugin.Exports { 105 fmt.Fprintln(w, "\t", k, "\t", v) 106 } 107 } 108 109 if len(plugin.Capabilities) > 0 { 110 fmt.Fprintln(w, "Capabilities:\t", strings.Join(plugin.Capabilities, ",")) 111 } 112 113 if plugin.InitErr != nil { 114 fmt.Fprintln(w, "Error:\t") 115 fmt.Fprintln(w, "\t Code:\t", codes.Code(plugin.InitErr.Code)) 116 fmt.Fprintln(w, "\t Message:\t", plugin.InitErr.Message) 117 } 118 } 119 return w.Flush() 120 } 121 122 fmt.Fprintln(w, "TYPE\tID\tPLATFORMS\tSTATUS\t") 123 for _, plugin := range response.Plugins { 124 status := "ok" 125 126 if plugin.InitErr != nil { 127 status = "error" 128 } 129 130 var platformColumn = "-" 131 if len(plugin.Platforms) > 0 { 132 platformColumn = prettyPlatforms(plugin.Platforms) 133 } 134 if _, err := fmt.Fprintf(w, "%s\t%s\t%s\t%s\t\n", 135 plugin.Type, 136 plugin.ID, 137 platformColumn, 138 status, 139 ); err != nil { 140 return err 141 } 142 } 143 return w.Flush() 144 }, 145 } 146 147 func prettyPlatforms(pspb []types.Platform) string { 148 psm := map[string]struct{}{} 149 for _, p := range pspb { 150 psm[platforms.Format(v1.Platform{ 151 OS: p.OS, 152 Architecture: p.Architecture, 153 Variant: p.Variant, 154 })] = struct{}{} 155 } 156 var ps []string 157 for p := range psm { 158 ps = append(ps, p) 159 } 160 sort.Stable(sort.StringSlice(ps)) 161 return strings.Join(ps, ",") 162 }