Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rpk profile: more #11296

Merged
merged 21 commits into from
Jun 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/go/rpk/pkg/cli/cluster/logdirs.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ where revision is a Redpanda internal concept.
listed, err := adm.ListTopics(context.Background(), topics...)
out.MaybeDie(err, "unable to describe topics: %v", err)
listed.EachError(func(d kadm.TopicDetail) {
fmt.Fprintf(os.Stderr, "unable to discover the partitions on topic %q: %v", d.Topic, d.Err)
fmt.Fprintf(os.Stderr, "unable to discover the partitions on topic %q: %v\n", d.Topic, d.Err)
})
s = listed.TopicsSet()
}
Expand Down
40 changes: 40 additions & 0 deletions src/go/rpk/pkg/cli/profile/clear.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright 2023 Redpanda Data, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.md
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0

package profile

import (
"github.com/redpanda-data/redpanda/src/go/rpk/pkg/config"
"github.com/redpanda-data/redpanda/src/go/rpk/pkg/out"
"github.com/spf13/afero"
"github.com/spf13/cobra"
)

func newClearCommand(fs afero.Fs, p *config.Params) *cobra.Command {
return &cobra.Command{
Use: "clear",
Short: "Clear the current profile",
Long: `Clear the current profile

This small command clears the current profile, which can be useful to unset an
prod cluster profile.
`,
Args: cobra.ExactArgs(0),
Run: func(_ *cobra.Command, args []string) {
cfg, err := p.Load(fs)
out.MaybeDie(err, "unable to load config: %v", err)
y, ok := cfg.ActualRpkYaml()
if !ok {
return
}
y.CurrentProfile = ""
y.Write(fs)
},
}
}
69 changes: 52 additions & 17 deletions src/go/rpk/pkg/cli/profile/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ package profile

import (
"context"
"errors"
"fmt"
"os"
"time"

"github.com/redpanda-data/redpanda/src/go/rpk/pkg/cloudapi"
Expand All @@ -26,10 +28,11 @@ import (

func newCreateCommand(fs afero.Fs, p *config.Params) *cobra.Command {
var (
set []string
fromSimple string
fromCloud string
description string
set []string
fromRedpanda string
fromProfile string
fromCloud string
description string
)

cmd := &cobra.Command{
Expand All @@ -40,8 +43,14 @@ func newCreateCommand(fs afero.Fs, p *config.Params) *cobra.Command {
There are multiple ways to create a profile. If no name is provided, the
name "default" is used.

* If you have an older redpanda.yaml, you can use --from-simple to generate
a new profile from the existing redpanda.yaml file.
* You can use --from-redpanda to generate a new profile from an existing
redpanda.yaml file. The special values "current" create a profile from the
current redpanda.yaml as it is loaded within rpk.

* You can use --from-profile to generate a profile from an existing profile or
from from a profile in a yaml file. First, the filename is checked, then an
existing profile name is checked. The special value "current" creates a new
profile from the existing profile.

* You can use --from-cloud to generate a profile from an existing cloud cluster
id. Note that you must be logged in with 'rpk cloud login' first.
Expand All @@ -53,7 +62,7 @@ name "default" is used.
latter corresponds to the path kafka_api.tls.enabled in the profile's YAML.

The --set flag is always applied last and can be used to set additional fields
in tandem with --from-simple or --from-cloud.
in tandem with --from-redpanda or --from-cloud.
twmb marked this conversation as resolved.
Show resolved Hide resolved

The --set flag supports autocompletion, suggesting the -X key format. If you
begin writing a YAML path, the flag will suggest the rest of the path.
Expand Down Expand Up @@ -81,7 +90,7 @@ rpk always switches to the newly created profile.

ctx, cancel := context.WithTimeout(cmd.Context(), 10*time.Second)
defer cancel()
cloudMTLS, cloudSASL, err := createCtx(ctx, fs, y, cfg, fromSimple, fromCloud, set, name, description)
cloudMTLS, cloudSASL, err := createCtx(ctx, fs, y, cfg, fromRedpanda, fromProfile, fromCloud, set, name, description)
out.MaybeDieErr(err)

fmt.Printf("Created and switched to new profile %q.\n", name)
Expand All @@ -96,7 +105,8 @@ rpk always switches to the newly created profile.
}

cmd.Flags().StringSliceVarP(&set, "set", "s", nil, "Create and switch to a new profile, setting profile fields with key=value pairs")
cmd.Flags().StringVar(&fromSimple, "from-simple", "", "Create and switch to a new profile from a (simpler to define) redpanda.yaml file")
cmd.Flags().StringVar(&fromRedpanda, "from-redpanda", "", "Create and switch to a new profile from a redpanda.yaml file")
cmd.Flags().StringVar(&fromProfile, "from-profile", "", "Create and switch to a new profile from an existing profile or from a profile in a yaml file")
cmd.Flags().StringVar(&fromCloud, "from-cloud", "", "Create and switch to a new profile generated from a Redpanda Cloud cluster ID")
cmd.Flags().StringVarP(&description, "description", "d", "", "Optional description of the profile")

Expand All @@ -111,14 +121,15 @@ func createCtx(
fs afero.Fs,
y *config.RpkYaml,
cfg *config.Config,
fromSimple string,
fromRedpanda string,
fromProfile string,
fromCloud string,
set []string,
name string,
description string,
) (cloudMTLS, cloudSASL bool, err error) {
if fromCloud != "" && fromSimple != "" {
return false, false, fmt.Errorf("cannot use --from-cloud and --from-simple together")
if (fromCloud != "" && fromRedpanda != "") || (fromCloud != "" && fromProfile != "") || (fromRedpanda != "" && fromProfile != "") {
return false, false, fmt.Errorf("can only use one of --from-cloud, --from-redpanda, or --from-profile")
}
if p := y.Profile(name); p != nil {
return false, false, fmt.Errorf("profile %q already exists", name)
Expand All @@ -133,19 +144,43 @@ func createCtx(
return false, false, err
}

case fromSimple != "":
case fromProfile != "":
switch {
case fromProfile == "current":
p = *cfg.VirtualProfile()
default:
raw, err := afero.ReadFile(fs, fromProfile)
if err != nil {
if !errors.Is(err, os.ErrNotExist) {
return false, false, fmt.Errorf("unable to read file %q: %v", fromProfile, err)
}
y, err := cfg.ActualRpkYamlOrEmpty()
if err != nil {
return false, false, fmt.Errorf("file %q does not exist, and we cannot read rpk.yaml: %v", fromProfile, err)
}
src := y.Profile(fromProfile)
if src == nil {
return false, false, fmt.Errorf("unable to find profile %q", fromProfile)
}
p = *src
} else if err := yaml.Unmarshal(raw, &p); err != nil {
return false, false, fmt.Errorf("unable to yaml decode file %q: %v", fromProfile, err)
}
}

case fromRedpanda != "":
var nodeCfg config.RpkNodeConfig
switch {
case fromSimple == "loaded" || fromSimple == "current":
case fromRedpanda == "current":
nodeCfg = cfg.VirtualRedpandaYaml().Rpk
default:
raw, err := afero.ReadFile(fs, fromSimple)
raw, err := afero.ReadFile(fs, fromRedpanda)
if err != nil {
return false, false, fmt.Errorf("unable to read file %q: %v", fromSimple, err)
return false, false, fmt.Errorf("unable to read file %q: %v", fromRedpanda, err)
}
var rpyaml config.RedpandaYaml
if err := yaml.Unmarshal(raw, &rpyaml); err != nil {
return false, false, fmt.Errorf("unable to yaml decode file %q: %v", fromSimple, err)
return false, false, fmt.Errorf("unable to yaml decode file %q: %v", fromRedpanda, err)
}
nodeCfg = rpyaml.Rpk
}
Expand Down
48 changes: 48 additions & 0 deletions src/go/rpk/pkg/cli/profile/current.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2023 Redpanda Data, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.md
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0

package profile

import (
"fmt"

"github.com/redpanda-data/redpanda/src/go/rpk/pkg/config"
"github.com/redpanda-data/redpanda/src/go/rpk/pkg/out"
"github.com/spf13/afero"
"github.com/spf13/cobra"
)

func newCurrentCommand(fs afero.Fs, p *config.Params) *cobra.Command {
var noNewline bool
cmd := &cobra.Command{
Use: "current",
Short: "Print the current profile name",
Long: `Print the current profile name.

This is a tiny command that simply prints the current profile name, which may
be useful in scripts, or a PS1, or to confirm what you have selected.
`,
Args: cobra.ExactArgs(0),
Run: func(_ *cobra.Command, args []string) {
cfg, err := p.Load(fs)
out.MaybeDie(err, "unable to load config: %v", err)

if !noNewline {
defer fmt.Println()
}
y, ok := cfg.ActualRpkYaml()
if !ok {
return
}
fmt.Print(y.CurrentProfile)
},
}
cmd.Flags().BoolVarP(&noNewline, "no-newline", "n", false, "Do not print a newline after the profile name")
return cmd
}
2 changes: 1 addition & 1 deletion src/go/rpk/pkg/cli/profile/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ was the selected profile, rpk will use in-memory defaults until a new profile
is selected.
`,
Args: cobra.ExactArgs(1),
ValidArgsFunction: validProfiles(fs, p),
ValidArgsFunction: ValidProfiles(fs, p),
Run: func(_ *cobra.Command, args []string) {
cfg, err := p.Load(fs)
out.MaybeDie(err, "unable to load config: %v", err)
Expand Down
4 changes: 2 additions & 2 deletions src/go/rpk/pkg/cli/profile/edit.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ If you want to edit the current raw profile as it exists in rpk.yaml, you
can use the --raw flag.
`,
Args: cobra.MaximumNArgs(1),
ValidArgsFunction: validProfiles(fs, p),
ValidArgsFunction: ValidProfiles(fs, p),
Run: func(_ *cobra.Command, args []string) {
cfg, err := p.Load(fs)
out.MaybeDie(err, "unable to load config: %v", err)
Expand Down Expand Up @@ -63,7 +63,7 @@ can use the --raw flag.
out.MaybeDieErr(err)

var renamed, updatedCurrent bool
if update.Name != name {
if update.Name != name && update.Name != "" {
renamed = true
if y.CurrentProfile == name {
updatedCurrent = true
Expand Down
47 changes: 47 additions & 0 deletions src/go/rpk/pkg/cli/profile/edit_defaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright 2023 Redpanda Data, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.md
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0

package profile

import (
"fmt"

"github.com/redpanda-data/redpanda/src/go/rpk/pkg/config"
rpkos "github.com/redpanda-data/redpanda/src/go/rpk/pkg/os"
"github.com/redpanda-data/redpanda/src/go/rpk/pkg/out"
"github.com/spf13/afero"
"github.com/spf13/cobra"
)

func newEditDefaultsCommand(fs afero.Fs, p *config.Params) *cobra.Command {
cmd := &cobra.Command{
Use: "edit-defaults",
twmb marked this conversation as resolved.
Show resolved Hide resolved
Short: "Edit rpk defaults",
Long: `Edit rpk defaults.

This command opens your default editor to edit the specified profile, or
the current profile if no profile is specified.
`,
Args: cobra.ExactArgs(0),
Run: func(*cobra.Command, []string) {
cfg, err := p.Load(fs)
out.MaybeDie(err, "unable to load config: %v", err)
y, err := cfg.ActualRpkYamlOrEmpty()
out.MaybeDie(err, "unable to load config: %v", err)

y.Defaults, err = rpkos.EditTmpYAMLFile(fs, y.Defaults)
out.MaybeDieErr(err)

err = y.Write(fs)
out.MaybeDie(err, "unable to write rpk.yaml: %v", err)
fmt.Println("Defaults updated successfully.")
},
}
return cmd
}
2 changes: 1 addition & 1 deletion src/go/rpk/pkg/cli/profile/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ variables applied. If you wish to print the current raw profile as it exists
in rpk.yaml, you can use the --raw flag.
`,
Args: cobra.MaximumNArgs(1),
ValidArgsFunction: validProfiles(fs, p),
ValidArgsFunction: ValidProfiles(fs, p),
Run: func(_ *cobra.Command, args []string) {
cfg, err := p.Load(fs)
out.MaybeDie(err, "unable to load config: %v", err)
Expand Down
38 changes: 38 additions & 0 deletions src/go/rpk/pkg/cli/profile/print_defaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright 2023 Redpanda Data, Inc.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.md
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0

package profile

import (
"fmt"

"github.com/redpanda-data/redpanda/src/go/rpk/pkg/config"
"github.com/redpanda-data/redpanda/src/go/rpk/pkg/out"
"github.com/spf13/afero"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)

func newPrintDefaultsCommand(fs afero.Fs, p *config.Params) *cobra.Command {
return &cobra.Command{
Use: "print-defaults",
Short: "Print rpk default",
Long: `Print rpk defaults.`,
Args: cobra.ExactArgs(0),
Run: func(_ *cobra.Command, args []string) {
cfg, err := p.Load(fs)
out.MaybeDie(err, "unable to load config: %v", err)

y := cfg.VirtualRpkYaml()
m, err := yaml.Marshal(y.Defaults)
out.MaybeDie(err, "unable to encode profile: %v", err)
fmt.Println(string(m))
},
}
}
8 changes: 7 additions & 1 deletion src/go/rpk/pkg/cli/profile/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,25 @@ your configuration in one place.

cmd.AddCommand(
newCreateCommand(fs, p),
newClearCommand(fs, p),
newCurrentCommand(fs, p),
newDeleteCommand(fs, p),
newEditCommand(fs, p),
newEditDefaultsCommand(fs, p),
newListCommand(fs, p),
newPrintCommand(fs, p),
newPrintDefaultsCommand(fs, p),
newPromptCommand(fs, p),
newRenameToCommand(fs, p),
newSetCommand(fs, p),
newSetDefaultsCommand(fs, p),
newUseCommand(fs, p),
)

return cmd
}

func validProfiles(fs afero.Fs, p *config.Params) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
func ValidProfiles(fs afero.Fs, p *config.Params) func(*cobra.Command, []string, string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, _ []string, toComplete string) ([]string, cobra.ShellCompDirective) {
cfg, err := p.Load(fs)
if err != nil {
Expand Down
Loading