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  }