go.ligato.io/vpp-agent/v3@v3.5.0/cmd/agentctl/commands/model.go (about) 1 // Copyright (c) 2019 Cisco and/or its affiliates. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package commands 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "io" 22 "path" 23 "strings" 24 "text/tabwriter" 25 26 "github.com/sirupsen/logrus" 27 "github.com/spf13/cobra" 28 29 "go.ligato.io/vpp-agent/v3/cmd/agentctl/api/types" 30 agentcli "go.ligato.io/vpp-agent/v3/cmd/agentctl/cli" 31 ) 32 33 func NewModelCommand(cli agentcli.Cli) *cobra.Command { 34 cmd := &cobra.Command{ 35 Use: "model", 36 Short: "Manage known models", 37 } 38 cmd.AddCommand( 39 newModelListCommand(cli), 40 newModelInspectCommand(cli), 41 ) 42 return cmd 43 } 44 45 func newModelsCommand(cli agentcli.Cli) *cobra.Command { 46 cmd := newModelListCommand(cli) 47 cmd.Use = "models" 48 cmd.Aliases = nil 49 cmd.Hidden = true 50 return cmd 51 } 52 53 func newModelListCommand(cli agentcli.Cli) *cobra.Command { 54 var opts ModelListOptions 55 cmd := &cobra.Command{ 56 Use: "list PATTERN", 57 Aliases: []string{"ls", "l"}, 58 Short: "List models mathing pattern(s)", 59 Args: cobra.ArbitraryArgs, 60 RunE: func(cmd *cobra.Command, args []string) error { 61 opts.Refs = args 62 if strings.ToLower(opts.Class) == "all" { 63 opts.Class = "" 64 } 65 return runModelList(cli, opts) 66 }, 67 } 68 flags := cmd.Flags() 69 flags.StringVar(&opts.Class, "class", "config", "Filter by model class") 70 flags.StringVarP(&opts.Format, "format", "f", "", "Format output") 71 return cmd 72 } 73 74 type ModelListOptions struct { 75 Class string 76 Refs []string 77 Format string 78 } 79 80 func runModelList(cli agentcli.Cli, opts ModelListOptions) error { 81 ctx, cancel := context.WithCancel(context.Background()) 82 defer cancel() 83 84 allModels, err := cli.Client().ModelList(ctx, types.ModelListOptions{ 85 Class: opts.Class, 86 }) 87 if err != nil { 88 return err 89 } 90 models := filterModelsByRefs(allModels, opts.Refs) 91 92 format := opts.Format 93 if len(format) == 0 { 94 printModelTable(cli.Out(), models) 95 } else { 96 if err := formatAsTemplate(cli.Out(), format, models); err != nil { 97 return err 98 } 99 } 100 101 return nil 102 } 103 104 func printModelTable(out io.Writer, models []types.Model) { 105 var buf bytes.Buffer 106 w := tabwriter.NewWriter(&buf, 0, 0, 2, ' ', 0) 107 fmt.Fprintf(w, "MODEL NAME\tCLASS\tPROTO MESSAGE\tKEY PREFIX\t\n") 108 for _, model := range models { 109 fmt.Fprintf(w, "%s\t%s\t%s\t%s\t\n", 110 model.Name, model.Class, model.ProtoName, model.KeyPrefix) 111 } 112 if err := w.Flush(); err != nil { 113 panic(err) 114 } 115 116 fmt.Fprint(out, buf.String()) 117 } 118 119 func filterModelsByPrefix(models []types.Model, prefixes []string) ([]types.Model, error) { 120 if len(prefixes) == 0 { 121 return models, nil 122 } 123 var filtered []types.Model 124 for _, pref := range prefixes { 125 var model types.Model 126 for _, m := range models { 127 if !strings.HasPrefix(m.Name, pref) { 128 continue 129 } 130 if model.Name != "" { 131 return nil, fmt.Errorf("multiple models found with provided prefix: %s", pref) 132 } 133 model = m 134 } 135 if model.Name == "" { 136 return nil, fmt.Errorf("no model found for provided prefix: %s", pref) 137 } 138 filtered = append(filtered, model) 139 } 140 return filtered, nil 141 } 142 143 func filterModelsByRefs(models []types.Model, refs []string) []types.Model { 144 var filtered []types.Model 145 for _, model := range models { 146 if !matchAnyRef(model, refs) { 147 continue 148 } 149 filtered = append(filtered, model) 150 } 151 return filtered 152 } 153 154 func matchAnyRef(model types.Model, refs []string) bool { 155 if len(refs) == 0 { 156 return true 157 } 158 for _, ref := range refs { 159 if ok, _ := path.Match(ref, model.Name); ok { 160 return true 161 } 162 } 163 return false 164 } 165 166 func newModelInspectCommand(cli agentcli.Cli) *cobra.Command { 167 var ( 168 opts ModelInspectOptions 169 ) 170 cmd := &cobra.Command{ 171 Use: "inspect MODEL [MODEL...]", 172 Aliases: []string{"i"}, 173 Short: "Display detailed information on one or more models", 174 Args: cobra.MinimumNArgs(1), 175 RunE: func(cmd *cobra.Command, args []string) error { 176 opts.Names = args 177 return runModelInspect(cli, opts) 178 }, 179 } 180 cmd.Flags().StringVarP(&opts.Format, "format", "f", "", "Format for the output") 181 return cmd 182 } 183 184 type ModelInspectOptions struct { 185 Names []string 186 Format string 187 } 188 189 func runModelInspect(cli agentcli.Cli, opts ModelInspectOptions) error { 190 ctx, cancel := context.WithCancel(context.Background()) 191 defer cancel() 192 193 allModels, err := cli.Client().ModelList(ctx, types.ModelListOptions{}) 194 if err != nil { 195 return err 196 } 197 models, err := filterModelsByPrefix(allModels, opts.Names) 198 if err != nil { 199 return err 200 } 201 logrus.Debugf("models: %+v", models) 202 203 format := opts.Format 204 if len(format) == 0 { 205 format = "json" 206 } 207 if err := formatAsTemplate(cli.Out(), format, models); err != nil { 208 return err 209 } 210 211 return nil 212 }