1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
package base
import (
"context"
"errors"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/hetznercloud/cli/internal/cmd/cmpl"
"github.com/hetznercloud/cli/internal/cmd/util"
"github.com/hetznercloud/cli/internal/hcapi2"
"github.com/hetznercloud/cli/internal/state"
)
// LabelCmds allows defining commands for adding labels to resources.
type LabelCmds struct {
ResourceNameSingular string
ShortDescriptionAdd string
ShortDescriptionRemove string
NameSuggestions func(client hcapi2.Client) func() []string
LabelKeySuggestions func(client hcapi2.Client) func(idOrName string) []string
FetchLabels func(ctx context.Context, client hcapi2.Client, idOrName string) (map[string]string, int64, error)
SetLabels func(ctx context.Context, client hcapi2.Client, id int64, labels map[string]string) error
}
// AddCobraCommand creates a command that can be registered with cobra.
func (lc *LabelCmds) AddCobraCommand(
ctx context.Context, client hcapi2.Client, tokenEnsurer state.TokenEnsurer,
) *cobra.Command {
cmd := &cobra.Command{
Use: fmt.Sprintf("add-label [FLAGS] %s LABEL", strings.ToUpper(lc.ResourceNameSingular)),
Short: lc.ShortDescriptionAdd,
Args: cobra.ExactArgs(2),
ValidArgsFunction: cmpl.SuggestArgs(cmpl.SuggestCandidatesF(lc.NameSuggestions(client))),
TraverseChildren: true,
DisableFlagsInUseLine: true,
PreRunE: util.ChainRunE(validateAddLabel, tokenEnsurer.EnsureToken),
RunE: func(cmd *cobra.Command, args []string) error {
return lc.RunAdd(ctx, client, cmd, args)
},
}
cmd.Flags().BoolP("overwrite", "o", false, "Overwrite label if it exists already")
return cmd
}
// RunAdd executes an add label command
func (lc *LabelCmds) RunAdd(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, args []string) error {
overwrite, _ := cmd.Flags().GetBool("overwrite")
idOrName := args[0]
labels, id, err := lc.FetchLabels(ctx, client, idOrName)
if err != nil {
return err
}
if labels == nil {
labels = map[string]string{}
}
key, val := util.SplitLabelVars(args[1])
if _, ok := labels[key]; ok && !overwrite {
return fmt.Errorf("label %s on %s %d already exists", key, lc.ResourceNameSingular, id)
}
labels[key] = val
if err := lc.SetLabels(ctx, client, id, labels); err != nil {
return err
}
fmt.Printf("Label %s added to %s %d\n", key, lc.ResourceNameSingular, id)
return nil
}
func validateAddLabel(cmd *cobra.Command, args []string) error {
label := util.SplitLabel(args[1])
if len(label) != 2 {
return fmt.Errorf("invalid label: %s", args[1])
}
return nil
}
// RemoveCobraCommand creates a command that can be registered with cobra.
func (lc *LabelCmds) RemoveCobraCommand(
ctx context.Context, client hcapi2.Client, tokenEnsurer state.TokenEnsurer,
) *cobra.Command {
cmd := &cobra.Command{
Use: fmt.Sprintf("remove-label [FLAGS] %s LABEL", strings.ToUpper(lc.ResourceNameSingular)),
Short: lc.ShortDescriptionRemove,
Args: cobra.RangeArgs(1, 2),
ValidArgsFunction: cmpl.SuggestArgs(
cmpl.SuggestCandidatesF(lc.NameSuggestions(client)),
cmpl.SuggestCandidatesCtx(func(_ *cobra.Command, args []string) []string {
if len(args) != 1 {
return nil
}
return lc.LabelKeySuggestions(client)(args[0])
}),
),
TraverseChildren: true,
DisableFlagsInUseLine: true,
PreRunE: util.ChainRunE(validateRemoveLabel, tokenEnsurer.EnsureToken),
RunE: func(cmd *cobra.Command, args []string) error {
return lc.RunRemove(ctx, client, cmd, args)
},
}
cmd.Flags().BoolP("all", "a", false, "Remove all labels")
return cmd
}
// RunRemove executes a remove label command
func (lc *LabelCmds) RunRemove(ctx context.Context, client hcapi2.Client, cmd *cobra.Command, args []string) error {
all, _ := cmd.Flags().GetBool("all")
idOrName := args[0]
labels, id, err := lc.FetchLabels(ctx, client, idOrName)
if err != nil {
return err
}
if all {
labels = make(map[string]string)
} else {
key := args[1]
if _, ok := labels[key]; !ok {
return fmt.Errorf("label %s on %s %d does not exist", key, lc.ResourceNameSingular, id)
}
delete(labels, key)
}
if err := lc.SetLabels(ctx, client, id, labels); err != nil {
return err
}
if all {
fmt.Printf("All labels removed from %s %d\n", lc.ResourceNameSingular, id)
} else {
fmt.Printf("Label %s removed from %s %d\n", args[1], lc.ResourceNameSingular, id)
}
return nil
}
func validateRemoveLabel(cmd *cobra.Command, args []string) error {
all, _ := cmd.Flags().GetBool("all")
if all && len(args) == 2 {
return errors.New("must not specify a label key when using --all/-a")
}
if !all && len(args) != 2 {
return errors.New("must specify a label key when not using --all/-a")
}
return nil
}
|