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(®URL, "url", "", "specify the registry URL") 89 cmd.PersistentFlags().StringVar(®Name, "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 }