github.com/pachyderm/pachyderm@v1.13.4/src/server/config/cmds.go (about) 1 package cmds 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "log" 9 "os" 10 "sort" 11 12 "github.com/pachyderm/pachyderm/src/client/pkg/config" 13 "github.com/pachyderm/pachyderm/src/client/pkg/errors" 14 "github.com/pachyderm/pachyderm/src/client/pkg/grpcutil" 15 "github.com/pachyderm/pachyderm/src/server/cmd/pachctl/shell" 16 "github.com/pachyderm/pachyderm/src/server/pkg/cmdutil" 17 18 prompt "github.com/c-bata/go-prompt" 19 "github.com/gogo/protobuf/jsonpb" 20 "github.com/spf13/cobra" 21 ) 22 23 const ( 24 listContextHeader = "ACTIVE\tNAME" 25 ) 26 27 // Cmds returns a slice containing admin commands. 28 func Cmds() []*cobra.Command { 29 marshaller := &jsonpb.Marshaler{ 30 Indent: " ", 31 OrigName: true, 32 } 33 34 var commands []*cobra.Command 35 36 getMetrics := &cobra.Command{ 37 Short: "Gets whether metrics are enabled.", 38 Long: "Gets whether metrics are enabled.", 39 Run: cmdutil.Run(func(args []string) (retErr error) { 40 cfg, err := config.Read(false, false) 41 if err != nil { 42 return err 43 } 44 fmt.Printf("%v\n", cfg.V2.Metrics) 45 return nil 46 }), 47 } 48 commands = append(commands, cmdutil.CreateAlias(getMetrics, "config get metrics")) 49 50 setMetrics := &cobra.Command{ 51 Use: "{{alias}} (true | false)", 52 Short: "Sets whether metrics are enabled.", 53 Long: "Sets whether metrics are enabled.", 54 Run: cmdutil.RunFixedArgs(1, func(args []string) (retErr error) { 55 metrics := true 56 if args[0] == "false" { 57 metrics = false 58 } else if args[0] != "true" { 59 return errors.New("invalid argument; use either `true` or `false`") 60 } 61 62 cfg, err := config.Read(false, false) 63 if err != nil { 64 return err 65 } 66 67 cfg.V2.Metrics = metrics 68 return cfg.Write() 69 }), 70 } 71 commands = append(commands, cmdutil.CreateAlias(setMetrics, "config set metrics")) 72 73 getActiveContext := &cobra.Command{ 74 Short: "Gets the currently active context.", 75 Long: "Gets the currently active context.", 76 Run: cmdutil.Run(func(args []string) (retErr error) { 77 cfg, err := config.Read(false, false) 78 if err != nil { 79 return err 80 } 81 activeContext, _, err := cfg.ActiveContext(false) 82 if err != nil { 83 return err 84 } 85 if activeContext == "" { 86 fmt.Println("NONE") 87 } else { 88 fmt.Printf("%s\n", activeContext) 89 } 90 return nil 91 }), 92 } 93 commands = append(commands, cmdutil.CreateAlias(getActiveContext, "config get active-context")) 94 95 setActiveContext := &cobra.Command{ 96 Use: "{{alias}} <context>", 97 Short: "Sets the currently active context.", 98 Long: "Sets the currently active context.", 99 Run: cmdutil.RunFixedArgs(1, func(args []string) (retErr error) { 100 cfg, err := config.Read(false, false) 101 if err != nil { 102 return err 103 } 104 if _, ok := cfg.V2.Contexts[args[0]]; !ok { 105 return errors.Errorf("context does not exist: %s", args[0]) 106 } 107 cfg.V2.ActiveContext = args[0] 108 return cfg.Write() 109 }), 110 } 111 shell.RegisterCompletionFunc(setActiveContext, contextCompletion) 112 commands = append(commands, cmdutil.CreateAlias(setActiveContext, "config set active-context")) 113 114 getContext := &cobra.Command{ 115 Use: "{{alias}} <context>", 116 Short: "Gets a context.", 117 Long: "Gets the config of a context by its name.", 118 Run: cmdutil.RunFixedArgs(1, func(args []string) (retErr error) { 119 cfg, err := config.Read(false, false) 120 if err != nil { 121 return err 122 } 123 124 context, ok := cfg.V2.Contexts[args[0]] 125 if !ok { 126 return errors.Errorf("context does not exist: %s", args[0]) 127 } 128 129 if err = marshaller.Marshal(os.Stdout, context); err != nil { 130 return err 131 } 132 133 fmt.Println() 134 return nil 135 }), 136 } 137 shell.RegisterCompletionFunc(getContext, contextCompletion) 138 commands = append(commands, cmdutil.CreateAlias(getContext, "config get context")) 139 140 var overwrite bool 141 var kubeContextName string 142 setContext := &cobra.Command{ 143 Use: "{{alias}} <context>", 144 Short: "Set a context.", 145 Long: "Set a context config from a given name and either JSON stdin, or a given kubernetes context.", 146 Run: cmdutil.RunFixedArgs(1, func(args []string) (retErr error) { 147 name := args[0] 148 149 cfg, err := config.Read(false, false) 150 if err != nil { 151 return err 152 } 153 154 if !overwrite { 155 if _, ok := cfg.V2.Contexts[name]; ok { 156 return errors.Errorf("context '%s' already exists, use `--overwrite` if you wish to replace it", args[0]) 157 } 158 } 159 160 var context config.Context 161 if kubeContextName != "" { 162 kubeConfig, err := config.RawKubeConfig() 163 if err != nil { 164 return err 165 } 166 167 kubeContext := kubeConfig.Contexts[kubeContextName] 168 if kubeContext == nil { 169 return errors.Errorf("kubernetes context does not exist: %s", kubeContextName) 170 } 171 172 context = config.Context{ 173 Source: config.ContextSource_IMPORTED, 174 ClusterName: kubeContext.Cluster, 175 AuthInfo: kubeContext.AuthInfo, 176 Namespace: kubeContext.Namespace, 177 } 178 } else { 179 fmt.Println("Reading from stdin.") 180 181 var buf bytes.Buffer 182 var decoder *json.Decoder 183 184 contextReader := io.TeeReader(os.Stdin, &buf) 185 decoder = json.NewDecoder(contextReader) 186 187 if err := jsonpb.UnmarshalNext(decoder, &context); err != nil { 188 if errors.Is(err, io.EOF) { 189 return errors.New("unexpected EOF") 190 } 191 return errors.Wrapf(err, "malformed context") 192 } 193 194 pachdAddress, err := grpcutil.ParsePachdAddress(context.PachdAddress) 195 if err != nil { 196 if !errors.Is(err, grpcutil.ErrNoPachdAddress) { 197 return err 198 } 199 } else { 200 context.PachdAddress = pachdAddress.Qualified() 201 } 202 } 203 204 cfg.V2.Contexts[name] = &context 205 return cfg.Write() 206 }), 207 } 208 setContext.Flags().BoolVar(&overwrite, "overwrite", false, "Overwrite a context if it already exists.") 209 setContext.Flags().StringVarP(&kubeContextName, "kubernetes", "k", "", "Import a given kubernetes context's values into the Pachyderm context.") 210 shell.RegisterCompletionFunc(setContext, contextCompletion) 211 commands = append(commands, cmdutil.CreateAlias(setContext, "config set context")) 212 213 var pachdAddress string 214 var clusterName string 215 var authInfo string 216 var serverCAs string 217 var namespace string 218 var removeClusterDeploymentID bool 219 var updateContext *cobra.Command // standalone declaration so Run() can refer 220 updateContext = &cobra.Command{ 221 Use: "{{alias}} [<context>]", 222 Short: "Updates a context.", 223 Long: "Updates an existing context config from a given name (or the " + 224 "currently-active context, if no name is given).", 225 Run: cmdutil.RunBoundedArgs(0, 1, func(args []string) (retErr error) { 226 cfg, err := config.Read(false, false) 227 if err != nil { 228 return err 229 } 230 231 var context *config.Context 232 if len(args) > 0 { 233 var ok bool 234 context, ok = cfg.V2.Contexts[args[0]] 235 if !ok { 236 return errors.Errorf("context does not exist: %s", args[0]) 237 } 238 } else { 239 var name string 240 var err error 241 name, context, err = cfg.ActiveContext(true) 242 if err != nil { 243 return err 244 } 245 fmt.Printf("editing the currently active context %q\n", name) 246 } 247 248 // Use this method since we want to differentiate between no 249 // flag being set (the value shouldn't be changed) vs the flag 250 // being an empty string (meaning we want to set the value to an 251 // empty string) 252 if updateContext.Flags().Changed("pachd-address") { 253 parsedPachdAddress, err := grpcutil.ParsePachdAddress(pachdAddress) 254 if err != nil { 255 if errors.Is(err, grpcutil.ErrNoPachdAddress) { 256 context.PachdAddress = "" 257 } else { 258 return err 259 } 260 } else { 261 context.PachdAddress = parsedPachdAddress.Qualified() 262 } 263 } 264 if updateContext.Flags().Changed("cluster-name") { 265 context.ClusterName = clusterName 266 } 267 if updateContext.Flags().Changed("auth-info") { 268 context.AuthInfo = authInfo 269 } 270 if updateContext.Flags().Changed("server-cas") { 271 context.ServerCAs = serverCAs 272 } 273 if updateContext.Flags().Changed("namespace") { 274 context.Namespace = namespace 275 } 276 if removeClusterDeploymentID { 277 context.ClusterDeploymentID = "" 278 } 279 280 return cfg.Write() 281 }), 282 } 283 updateContext.Flags().StringVar(&pachdAddress, "pachd-address", "", "Set a new name pachd address.") 284 updateContext.Flags().StringVar(&clusterName, "cluster-name", "", "Set a new cluster name.") 285 updateContext.Flags().StringVar(&authInfo, "auth-info", "", "Set a new k8s auth info.") 286 updateContext.Flags().StringVar(&serverCAs, "server-cas", "", "Set new trusted CA certs.") 287 updateContext.Flags().StringVar(&namespace, "namespace", "", "Set a new namespace.") 288 updateContext.Flags().BoolVar(&removeClusterDeploymentID, "remove-cluster-deployment-id", false, "Remove the cluster deployment ID field, which will be repopulated on the next `pachctl` call using this context.") 289 shell.RegisterCompletionFunc(updateContext, contextCompletion) 290 commands = append(commands, cmdutil.CreateAlias(updateContext, "config update context")) 291 292 deleteContext := &cobra.Command{ 293 Use: "{{alias}} <context>", 294 Short: "Deletes a context.", 295 Long: "Deletes a context.", 296 Run: cmdutil.RunFixedArgs(1, func(args []string) (retErr error) { 297 cfg, err := config.Read(false, false) 298 if err != nil { 299 return err 300 } 301 if _, ok := cfg.V2.Contexts[args[0]]; !ok { 302 return errors.Errorf("context does not exist: %s", args[0]) 303 } 304 if cfg.V2.ActiveContext == args[0] { 305 return errors.New("cannot delete an active context") 306 } 307 delete(cfg.V2.Contexts, args[0]) 308 return cfg.Write() 309 }), 310 } 311 shell.RegisterCompletionFunc(deleteContext, contextCompletion) 312 commands = append(commands, cmdutil.CreateAlias(deleteContext, "config delete context")) 313 314 listContext := &cobra.Command{ 315 Short: "Lists contexts.", 316 Long: "Lists contexts.", 317 Run: cmdutil.Run(func(args []string) (retErr error) { 318 cfg, err := config.Read(false, false) 319 if err != nil { 320 return err 321 } 322 323 keys := make([]string, len(cfg.V2.Contexts)) 324 i := 0 325 for key := range cfg.V2.Contexts { 326 keys[i] = key 327 i++ 328 } 329 sort.Strings(keys) 330 331 activeContext, _, err := cfg.ActiveContext(false) 332 if err != nil { 333 return err 334 } 335 336 fmt.Println(listContextHeader) 337 for _, key := range keys { 338 if key == activeContext { 339 fmt.Printf("*\t%s\n", key) 340 } else { 341 fmt.Printf("\t%s\n", key) 342 } 343 } 344 return nil 345 }), 346 } 347 commands = append(commands, cmdutil.CreateAlias(listContext, "config list context")) 348 349 configDocs := &cobra.Command{ 350 Short: "Manages the pachyderm config.", 351 Long: "Gets/sets pachyderm config values.", 352 } 353 commands = append(commands, cmdutil.CreateDocsAlias(configDocs, "config", " config ")) 354 355 configGetRoot := &cobra.Command{ 356 Short: "Commands for getting pachyderm config values", 357 Long: "Commands for getting pachyderm config values", 358 } 359 commands = append(commands, cmdutil.CreateAlias(configGetRoot, "config get")) 360 361 configSetRoot := &cobra.Command{ 362 Short: "Commands for setting pachyderm config values", 363 Long: "Commands for setting pachyderm config values", 364 } 365 commands = append(commands, cmdutil.CreateAlias(configSetRoot, "config set")) 366 367 configUpdateRoot := &cobra.Command{ 368 Short: "Commands for updating pachyderm config values", 369 Long: "Commands for updating pachyderm config values", 370 } 371 commands = append(commands, cmdutil.CreateAlias(configUpdateRoot, "config update")) 372 373 configDeleteRoot := &cobra.Command{ 374 Short: "Commands for deleting pachyderm config values", 375 Long: "Commands for deleting pachyderm config values", 376 } 377 commands = append(commands, cmdutil.CreateAlias(configDeleteRoot, "config delete")) 378 379 configListRoot := &cobra.Command{ 380 Short: "Commands for listing pachyderm config values", 381 Long: "Commands for listing pachyderm config values", 382 } 383 commands = append(commands, cmdutil.CreateAlias(configListRoot, "config list")) 384 385 return commands 386 } 387 388 func contextCompletion(_, text string, maxCompletions int64) ([]prompt.Suggest, shell.CacheFunc) { 389 cfg, err := config.Read(false, false) 390 if err != nil { 391 log.Fatal(err) 392 } 393 activeContext, _, err := cfg.ActiveContext(false) 394 if err != nil { 395 log.Fatal(err) 396 } 397 var result []prompt.Suggest 398 for name, ctx := range cfg.V2.Contexts { 399 desc := ctx.PachdAddress 400 if name == activeContext { 401 desc += " (active)" 402 } 403 result = append(result, prompt.Suggest{ 404 Text: name, 405 Description: desc, 406 }) 407 } 408 sort.Slice(result, func(i, j int) bool { 409 switch { 410 case result[i].Text == activeContext: 411 return true 412 case result[j].Text == activeContext: 413 return false 414 default: 415 return result[i].Text < result[j].Text 416 } 417 }) 418 return result, shell.CacheAll 419 }