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