github.com/oam-dev/kubevela@v1.9.11/references/cli/traits.go (about)

     1  /*
     2  Copyright 2021 The KubeVela 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 cli
    18  
    19  import (
    20  	"context"
    21  	"encoding/json"
    22  	"strings"
    23  
    24  	"github.com/pkg/errors"
    25  	"github.com/spf13/cobra"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
    28  	"sigs.k8s.io/controller-runtime/pkg/client"
    29  	"sigs.k8s.io/controller-runtime/pkg/client/config"
    30  
    31  	core "github.com/oam-dev/kubevela/apis/core.oam.dev"
    32  	"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
    33  	"github.com/oam-dev/kubevela/apis/types"
    34  	common2 "github.com/oam-dev/kubevela/pkg/utils/common"
    35  	cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
    36  	"github.com/oam-dev/kubevela/references/common"
    37  )
    38  
    39  var (
    40  	regName string
    41  	regURL  string
    42  	token   string
    43  	label   string
    44  	filter  filterFunc
    45  )
    46  
    47  // NewTraitCommand creates `traits` command
    48  func NewTraitCommand(c common2.Args, order string, ioStreams cmdutil.IOStreams) *cobra.Command {
    49  	var isDiscover bool
    50  	cmd := &cobra.Command{
    51  		Use:     "trait",
    52  		Aliases: []string{"traits"},
    53  		Short:   "List/get traits.",
    54  		Long:    "List trait types installed and discover more in registry.",
    55  		Example: `vela trait`,
    56  		RunE: func(cmd *cobra.Command, args []string) error {
    57  			// parse label filter
    58  			if label != "" {
    59  				words := strings.Split(label, "=")
    60  				if len(words) < 2 {
    61  					return errors.New("label is invalid")
    62  				}
    63  				filter = createLabelFilter(words[0], words[1])
    64  			}
    65  
    66  			var registry Registry
    67  			var err error
    68  			if isDiscover {
    69  				if regURL != "" {
    70  					ioStreams.Infof("Showing trait definition from url: %s\n", regURL)
    71  					registry, err = NewRegistry(context.Background(), token, "temporary-registry", regURL)
    72  					if err != nil {
    73  						return errors.Wrap(err, "creating registry err, please check registry url")
    74  					}
    75  				} else {
    76  					ioStreams.Infof("Showing trait definition from registry: %s\n", regName)
    77  					registry, err = GetRegistry(regName)
    78  					if err != nil {
    79  						return errors.Wrap(err, "get registry err")
    80  					}
    81  				}
    82  				return PrintTraitListFromRegistry(registry, ioStreams, filter)
    83  
    84  			}
    85  			return PrintInstalledTraitDef(c, ioStreams, filter)
    86  		},
    87  		Annotations: map[string]string{
    88  			types.TagCommandType:  types.TypeExtension,
    89  			types.TagCommandOrder: order,
    90  		},
    91  	}
    92  	cmd.SetOut(ioStreams.Out)
    93  	cmd.AddCommand(
    94  		NewTraitGetCommand(c, ioStreams),
    95  	)
    96  	cmd.Flags().BoolVar(&isDiscover, "discover", false, "discover traits in registries")
    97  	cmd.PersistentFlags().StringVar(&regURL, "url", "", "specify the registry URL")
    98  	cmd.PersistentFlags().StringVar(&token, "token", "", "specify token when using --url to specify registry url")
    99  	cmd.PersistentFlags().StringVar(&regName, "registry", DefaultRegistry, "specify the registry name")
   100  	cmd.Flags().StringVar(&label, types.LabelArg, "", "a label to filter components, the format is `--label type=terraform`")
   101  	cmd.SetOut(ioStreams.Out)
   102  	return cmd
   103  }
   104  
   105  // NewTraitGetCommand creates `trait get` command
   106  func NewTraitGetCommand(c common2.Args, ioStreams cmdutil.IOStreams) *cobra.Command {
   107  	cmd := &cobra.Command{
   108  		Use:     "get <trait>",
   109  		Short:   "get trait from registry",
   110  		Long:    "get trait from registry",
   111  		Example: "vela trait get <trait>",
   112  		RunE: func(cmd *cobra.Command, args []string) error {
   113  			if len(args) < 1 {
   114  				ioStreams.Error("you must specify the trait name")
   115  				return nil
   116  			}
   117  			name := args[0]
   118  			var registry Registry
   119  			var err error
   120  
   121  			if regURL != "" {
   122  				ioStreams.Infof("Getting trait definition from url: %s\n", regURL)
   123  				registry, err = NewRegistry(context.Background(), token, "temporary-registry", regURL)
   124  				if err != nil {
   125  					return errors.Wrap(err, "creating registry err, please check registry url")
   126  				}
   127  			} else {
   128  				ioStreams.Infof("Getting trait definition from registry: %s\n", regName)
   129  				registry, err = GetRegistry(regName)
   130  				if err != nil {
   131  					return errors.Wrap(err, "get registry err")
   132  				}
   133  			}
   134  			return errors.Wrap(InstallTraitByNameFromRegistry(c, ioStreams, name, registry), "install trait definition err")
   135  		},
   136  	}
   137  	return cmd
   138  }
   139  
   140  // PrintTraitListFromRegistry print a table which shows all traits from registry
   141  func PrintTraitListFromRegistry(registry Registry, ioStreams cmdutil.IOStreams, filter filterFunc) error {
   142  	var scheme = runtime.NewScheme()
   143  	err := core.AddToScheme(scheme)
   144  	if err != nil {
   145  		return err
   146  	}
   147  	err = clientgoscheme.AddToScheme(scheme)
   148  	if err != nil {
   149  		return err
   150  	}
   151  	k8sClient, err := client.New(config.GetConfigOrDie(), client.Options{Scheme: scheme})
   152  	if err != nil {
   153  		return err
   154  	}
   155  
   156  	caps, err := registry.ListCaps()
   157  	if err != nil {
   158  		return err
   159  	}
   160  
   161  	table := newUITable()
   162  
   163  	var installedList v1beta1.TraitDefinitionList
   164  	err = k8sClient.List(context.Background(), &installedList, client.InNamespace(types.DefaultKubeVelaNS))
   165  	if err != nil {
   166  		return err
   167  	}
   168  
   169  	table.AddRow("NAME", "REGISTRY", "DEFINITION", "APPLIES-TO", "STATUS")
   170  	for _, c := range caps {
   171  		if filter != nil && !filter(c) {
   172  			continue
   173  		}
   174  		if c.Type != types.TypeTrait {
   175  			continue
   176  		}
   177  		c.Status = uninstalled
   178  		for _, ins := range installedList.Items {
   179  			if ins.Name == c.Name {
   180  				c.Status = installed
   181  			}
   182  		}
   183  		table.AddRow(c.Name, "default", c.CrdName, c.AppliesTo, c.Status)
   184  	}
   185  	ioStreams.Info(table.String())
   186  
   187  	return nil
   188  }
   189  
   190  // InstallTraitByNameFromRegistry will install given traitName trait to cluster
   191  func InstallTraitByNameFromRegistry(args common2.Args, ioStream cmdutil.IOStreams, traitName string, registry Registry) error {
   192  	_, data, err := registry.GetCap(traitName)
   193  	if err != nil {
   194  		return err
   195  	}
   196  
   197  	k8sClient, err := args.GetClient()
   198  	if err != nil {
   199  		return err
   200  	}
   201  
   202  	err = common.InstallTraitDefinition(k8sClient, data, ioStream)
   203  	if err != nil {
   204  		return err
   205  	}
   206  	ioStream.Info("Successfully install trait:", traitName)
   207  	return nil
   208  }
   209  
   210  // PrintInstalledTraitDef will print all TraitDefinition in cluster
   211  func PrintInstalledTraitDef(c common2.Args, io cmdutil.IOStreams, filter filterFunc) error {
   212  	var list v1beta1.TraitDefinitionList
   213  	clt, err := c.GetClient()
   214  	if err != nil {
   215  		return err
   216  	}
   217  	err = clt.List(context.Background(), &list)
   218  	if err != nil {
   219  		return errors.Wrap(err, "get trait definition list error")
   220  	}
   221  
   222  	table := newUITable()
   223  	table.AddRow("NAME", "APPLIES-TO")
   224  	table.AddRow("NAME", "APPLIES-TO", "DESCRIPTION")
   225  
   226  	for _, td := range list.Items {
   227  		data, err := json.Marshal(td)
   228  		if err != nil {
   229  			io.Infof("error encoding definition: %s\n", td.Name)
   230  			continue
   231  		}
   232  		capa, err := ParseCapability(clt.RESTMapper(), data)
   233  		if err != nil {
   234  			io.Errorf("error parsing capability: %s (message: %s)\n", td.Name, err.Error())
   235  			continue
   236  		}
   237  		if filter != nil && !filter(capa) {
   238  			continue
   239  		}
   240  		table.AddRow(capa.Name, capa.AppliesTo, capa.Description)
   241  	}
   242  	io.Info(table.String())
   243  	return nil
   244  }
   245  
   246  const installed = "installed"
   247  const uninstalled = "uninstalled"