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(®URL, "url", "", "specify the registry URL") 98 cmd.PersistentFlags().StringVar(&token, "token", "", "specify token when using --url to specify registry url") 99 cmd.PersistentFlags().StringVar(®Name, "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"