Skip to content

Commit 630cec5

Browse files
Jonathan S. Katzjkatz
authored andcommitted
Update labeling interface to be consistent with others
This moves the labeling interface to match that of similar ones, e.g. "annotations." - `pgo create cluster`, `pgo label`, and `pgo delete label` all now have a single `--label` flag. `--label` can be specified multiple times. - The API call itself takes a mapping of key/value pairs. - The API endpoint parameter for `pgo label` and `pgo delete label` is now called `Labels` Issue: [ch10202]
1 parent c3a21f8 commit 630cec5

File tree

17 files changed

+166
-209
lines changed

17 files changed

+166
-209
lines changed

cmd/pgo/cmd/cluster.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ func createCluster(args []string, ns string, createClusterCmd *cobra.Command) {
267267
r.PasswordReplication = PasswordReplication
268268
r.Password = Password
269269
r.SecretFrom = SecretFrom
270-
r.UserLabels = UserLabels
270+
r.UserLabels = getLabels(UserLabels)
271271
r.Policies = PoliciesFlag
272272
r.CCPImageTag = CCPImageTag
273273
r.CCPImage = CCPImage

cmd/pgo/cmd/common.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import (
2020
"fmt"
2121
"os"
2222
"reflect"
23+
"strings"
2324

25+
operatorutil "github.com/crunchydata/postgres-operator/internal/util"
2426
crv1 "github.com/crunchydata/postgres-operator/pkg/apis/crunchydata.com/v1"
2527
)
2628

@@ -85,6 +87,33 @@ func getHeaderLength(value interface{}, fieldName string) int {
8587
return len(field.String())
8688
}
8789

90+
// getLabels determines if the provided labels are in the correct format,
91+
// and if so, will return them in the appropriate map.
92+
//
93+
// If not, we will abort.
94+
func getLabels(labels []string) map[string]string {
95+
clusterLabels := map[string]string{}
96+
97+
for _, label := range labels {
98+
parts := strings.Split(label, "=")
99+
100+
if len(parts) != 2 {
101+
fmt.Printf("invalid label: found %q, should be \"key=value\"\n", label)
102+
os.Exit(1)
103+
}
104+
105+
clusterLabels[parts[0]] = parts[1]
106+
}
107+
108+
// perform a validation that can save us a round trip to the server
109+
if err := operatorutil.ValidateLabels(clusterLabels); err != nil {
110+
fmt.Println(err.Error())
111+
os.Exit(1)
112+
}
113+
114+
return clusterLabels
115+
}
116+
88117
// getMaxLength returns the maxLength of the strings of a particular value in
89118
// the struct. Increases the max length by 1 to include a buffer
90119
func getMaxLength(results []interface{}, title, fieldName string) int {

cmd/pgo/cmd/create.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ var (
3939
Password string
4040
SecretFrom string
4141
PoliciesFlag, PolicyFile string
42-
UserLabels string
42+
UserLabels []string
4343
Tablespaces []string
4444
ServiceType string
4545
ServiceTypePgBouncer string
@@ -392,7 +392,8 @@ func init() {
392392
createClusterCmd.Flags().StringVarP(&CustomConfig, "custom-config", "", "", "The name of a configMap that holds custom PostgreSQL configuration files used to override defaults.")
393393
createClusterCmd.Flags().StringVarP(&Database, "database", "d", "", "If specified, sets the name of the initial database that is created for the user. Defaults to the value set in the PostgreSQL Operator configuration, or if that is not present, the name of the cluster")
394394
createClusterCmd.Flags().BoolVarP(&DisableAutofailFlag, "disable-autofail", "", false, "Disables autofail capabitilies in the cluster following cluster initialization.")
395-
createClusterCmd.Flags().StringVarP(&UserLabels, "labels", "l", "", "The labels to apply to this cluster.")
395+
createClusterCmd.Flags().StringSliceVar(&UserLabels, "label", []string{}, "Add labels to apply to the PostgreSQL cluster, "+
396+
"e.g. \"key=value\", \"prefix/key=value\". Can specify flag multiple times.")
396397
createClusterCmd.Flags().StringVar(&MemoryRequest, "memory", "", "Set the amount of RAM to request, e.g. "+
397398
"1GiB. Overrides the default server value.")
398399
createClusterCmd.Flags().StringVar(&MemoryLimit, "memory-limit", "", "Set the amount of RAM to limit, e.g. "+

cmd/pgo/cmd/delete.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,9 @@ func init() {
170170
deleteCmd.AddCommand(deleteLabelCmd)
171171
// pgo delete label --label
172172
// the label to be deleted
173-
deleteLabelCmd.Flags().StringVar(&LabelCmdLabel, "label", "",
174-
"The label to delete for any selected or specified clusters.")
173+
deleteLabelCmd.Flags().StringSliceVar(&UserLabels, "label", []string{}, "Delete "+
174+
"labels to apply to the PostgreSQL cluster, "+"e.g. \"key=value\", \"prefix/key=value\". "+
175+
"Can specify flag multiple times.")
175176
// "pgo delete label --selector"
176177
// "pgo delete label -s"
177178
// the selector flag that filters which clusters to delete the cluster

cmd/pgo/cmd/label.go

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@ import (
2626
)
2727

2828
var (
29-
LabelCmdLabel string
30-
LabelMap map[string]string
31-
DeleteLabel bool
29+
DeleteLabel bool
3230
)
3331

3432
var labelCmd = &cobra.Command{
@@ -47,22 +45,25 @@ var labelCmd = &cobra.Command{
4745
log.Debug("label called")
4846
if len(args) == 0 && Selector == "" {
4947
fmt.Println("Error: A selector or list of clusters is required to label a policy.")
50-
return
48+
os.Exit(1)
5149
}
52-
if LabelCmdLabel == "" {
50+
51+
if len(UserLabels) == 0 {
5352
fmt.Println("Error: You must specify the label to apply.")
54-
} else {
55-
labelClusters(args, Namespace)
53+
os.Exit(1)
5654
}
55+
56+
labelClusters(args, Namespace)
5757
},
5858
}
5959

6060
func init() {
6161
RootCmd.AddCommand(labelCmd)
6262

63+
labelCmd.Flags().BoolVar(&DryRun, "dry-run", false, "Shows the clusters that the label would be applied to, without labelling them.")
64+
labelCmd.Flags().StringSliceVar(&UserLabels, "label", []string{}, "Add labels to apply to the PostgreSQL cluster, "+
65+
"e.g. \"key=value\", \"prefix/key=value\". Can specify flag multiple times.")
6366
labelCmd.Flags().StringVarP(&Selector, "selector", "s", "", "The selector to use for cluster filtering.")
64-
labelCmd.Flags().StringVarP(&LabelCmdLabel, "label", "", "", "The new label to apply for any selected or specified clusters.")
65-
labelCmd.Flags().BoolVarP(&DryRun, "dry-run", "", false, "Shows the clusters that the label would be applied to, without labelling them.")
6667
}
6768

6869
func labelClusters(clusters []string, ns string) {
@@ -78,7 +79,7 @@ func labelClusters(clusters []string, ns string) {
7879
r.Namespace = ns
7980
r.Selector = Selector
8081
r.DryRun = DryRun
81-
r.LabelCmdLabel = LabelCmdLabel
82+
r.Labels = getLabels(UserLabels)
8283
r.DeleteLabel = DeleteLabel
8384
r.ClientVersion = msgs.PGO_VERSION
8485

@@ -111,7 +112,7 @@ func deleteLabel(args []string, ns string) {
111112
req.Selector = Selector
112113
req.Namespace = ns
113114
req.Args = args
114-
req.LabelCmdLabel = LabelCmdLabel
115+
req.Labels = getLabels(UserLabels)
115116
req.ClientVersion = msgs.PGO_VERSION
116117

117118
response, err := api.DeleteLabel(httpclient, &SessionCredentials, &req)

docs/content/pgo-client/reference/pgo_create_cluster.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ pgo create cluster [flags]
4545
--exporter-memory string Set the amount of memory to request for the Crunchy Postgres Exporter sidecar container. Defaults to server value (24Mi).
4646
--exporter-memory-limit string Set the amount of memory to limit for the Crunchy Postgres Exporter sidecar container.
4747
-h, --help help for cluster
48-
-l, --labels string The labels to apply to this cluster.
48+
--label strings Add labels to apply to the PostgreSQL cluster, e.g. "key=value", "prefix/key=value". Can specify flag multiple times.
4949
--memory string Set the amount of RAM to request, e.g. 1GiB. Overrides the default server value.
5050
--memory-limit string Set the amount of RAM to limit, e.g. 1GiB.
5151
--metrics Adds the crunchy-postgres-exporter container to the database pod.
@@ -136,4 +136,4 @@ pgo create cluster [flags]
136136

137137
* [pgo create](/pgo-client/reference/pgo_create/) - Create a Postgres Operator resource
138138

139-
###### Auto generated by spf13/cobra on 14-Jan-2021
139+
###### Auto generated by spf13/cobra on 18-Jan-2021

docs/content/pgo-client/reference/pgo_delete_label.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pgo delete label [flags]
2121

2222
```
2323
-h, --help help for label
24-
--label string The label to delete for any selected or specified clusters.
24+
--label strings Delete labels to apply to the PostgreSQL cluster, e.g. "key=value", "prefix/key=value". Can specify flag multiple times.
2525
-s, --selector string The selector to use for cluster filtering.
2626
```
2727

@@ -42,4 +42,4 @@ pgo delete label [flags]
4242

4343
* [pgo delete](/pgo-client/reference/pgo_delete/) - Delete an Operator resource
4444

45-
###### Auto generated by spf13/cobra on 14-Jan-2021
45+
###### Auto generated by spf13/cobra on 18-Jan-2021

docs/content/pgo-client/reference/pgo_label.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ pgo label [flags]
2323
```
2424
--dry-run Shows the clusters that the label would be applied to, without labelling them.
2525
-h, --help help for label
26-
--label string The new label to apply for any selected or specified clusters.
26+
--label strings Add labels to apply to the PostgreSQL cluster, e.g. "key=value", "prefix/key=value". Can specify flag multiple times.
2727
-s, --selector string The selector to use for cluster filtering.
2828
```
2929

@@ -44,4 +44,4 @@ pgo label [flags]
4444

4545
* [pgo](/pgo-client/reference/pgo/) - The pgo command line interface.
4646

47-
###### Auto generated by spf13/cobra on 14-Jan-2021
47+
###### Auto generated by spf13/cobra on 18-Jan-2021

internal/apiserver/clusterservice/clusterimpl.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -576,9 +576,7 @@ func CreateCluster(request *msgs.CreateClusterRequest, ns, pgouser string) msgs.
576576
return resp
577577
}
578578

579-
userLabelsMap, err := apiserver.ValidateLabel(request.UserLabels)
580-
581-
if err != nil {
579+
if err := util.ValidateLabels(request.UserLabels); err != nil {
582580
resp.Status.Code = msgs.Error
583581
resp.Status.Msg = err.Error()
584582
return resp
@@ -753,9 +751,6 @@ func CreateCluster(request *msgs.CreateClusterRequest, ns, pgouser string) msgs.
753751
return resp
754752
}
755753

756-
log.Debug("userLabelsMap")
757-
log.Debugf("%v", userLabelsMap)
758-
759754
if request.StorageConfig != "" && !apiserver.IsValidStorageName(request.StorageConfig) {
760755
resp.Status.Code = msgs.Error
761756
resp.Status.Msg = fmt.Sprintf("%q storage config was not found", request.StorageConfig)
@@ -857,7 +852,7 @@ func CreateCluster(request *msgs.CreateClusterRequest, ns, pgouser string) msgs.
857852
}
858853

859854
// Create an instance of our CRD
860-
newInstance := getClusterParams(request, clusterName, userLabelsMap, ns)
855+
newInstance := getClusterParams(request, clusterName, ns)
861856
newInstance.ObjectMeta.Labels[config.LABEL_PGOUSER] = pgouser
862857
newInstance.Spec.BackrestStorageTypes = backrestStorageTypes
863858

@@ -1066,7 +1061,7 @@ func validateConfigPolicies(clusterName, PoliciesFlag, ns string) error {
10661061
return err
10671062
}
10681063

1069-
func getClusterParams(request *msgs.CreateClusterRequest, name string, userLabelsMap map[string]string, ns string) *crv1.Pgcluster {
1064+
func getClusterParams(request *msgs.CreateClusterRequest, name string, ns string) *crv1.Pgcluster {
10701065
spec := crv1.PgclusterSpec{
10711066
Annotations: crv1.ClusterAnnotations{
10721067
Backrest: map[string]string{},
@@ -1363,7 +1358,7 @@ func getClusterParams(request *msgs.CreateClusterRequest, name string, userLabel
13631358

13641359
spec.ServiceType = request.ServiceType
13651360

1366-
spec.UserLabels = userLabelsMap
1361+
spec.UserLabels = request.UserLabels
13671362
spec.UserLabels[config.LABEL_PGO_VERSION] = msgs.PGO_VERSION
13681363

13691364
// override any values from config file

internal/apiserver/common.go

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import (
2727
kerrors "k8s.io/apimachinery/pkg/api/errors"
2828
"k8s.io/apimachinery/pkg/api/resource"
2929
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30-
"k8s.io/apimachinery/pkg/util/validation"
3130
)
3231

3332
const (
@@ -45,8 +44,6 @@ var (
4544
// ErrDBContainerNotFound is an error that indicates that a "database" container
4645
// could not be found in a specific pod
4746
ErrDBContainerNotFound = errors.New("\"database\" container not found in pod")
48-
// ErrLabelInvalid indicates that a label is invalid
49-
ErrLabelInvalid = errors.New("invalid label")
5047
// ErrStandbyNotAllowed contains the error message returned when an API call is not
5148
// permitted because it involves a cluster that is in standby mode
5249
ErrStandbyNotAllowed = errors.New("Action not permitted because standby mode is enabled")
@@ -130,60 +127,6 @@ func ValidateBackrestStorageTypeForCommand(cluster *crv1.Pgcluster, storageTypeS
130127
return nil
131128
}
132129

133-
// ValidateLabel is derived from a legacy method and validates if the input is a
134-
// valid Kubernetes label.
135-
//
136-
// A label is composed of a key and value.
137-
//
138-
// The key can either be a name or have an optional prefix that i
139-
// terminated by a "/", e.g. "prefix/name"
140-
//
141-
// The name must be a valid DNS 1123 value
142-
// THe prefix must be a valid DNS 1123 subdomain
143-
//
144-
// The value can be validated by machinery provided by Kubenretes
145-
//
146-
// Ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
147-
func ValidateLabel(labelStr string) (map[string]string, error) {
148-
labelMap := map[string]string{}
149-
150-
for _, v := range strings.Split(labelStr, ",") {
151-
pair := strings.Split(v, "=")
152-
if len(pair) != 2 {
153-
return labelMap, fmt.Errorf("%w: label format incorrect, requires key=value", ErrLabelInvalid)
154-
}
155-
156-
// first handle the key
157-
keyParts := strings.Split(pair[0], "/")
158-
159-
switch len(keyParts) {
160-
default:
161-
return labelMap, fmt.Errorf("%w: invalid key for "+v, ErrLabelInvalid)
162-
case 2:
163-
if errs := validation.IsDNS1123Subdomain(keyParts[0]); len(errs) > 0 {
164-
return labelMap, fmt.Errorf("%w: invalid key for %s: %s", ErrLabelInvalid, v, strings.Join(errs, ","))
165-
}
166-
167-
if errs := validation.IsDNS1123Label(keyParts[1]); len(errs) > 0 {
168-
return labelMap, fmt.Errorf("%w: invalid key for %s: %s", ErrLabelInvalid, v, strings.Join(errs, ","))
169-
}
170-
case 1:
171-
if errs := validation.IsDNS1123Label(keyParts[0]); len(errs) > 0 {
172-
return labelMap, fmt.Errorf("%w: invalid key for %s: %s", ErrLabelInvalid, v, strings.Join(errs, ","))
173-
}
174-
}
175-
176-
// handle the value
177-
if errs := validation.IsValidLabelValue(pair[1]); len(errs) > 0 {
178-
return labelMap, fmt.Errorf("%w: invalid value for %s: %s", ErrLabelInvalid, v, strings.Join(errs, ","))
179-
}
180-
181-
labelMap[pair[0]] = pair[1]
182-
}
183-
184-
return labelMap, nil
185-
}
186-
187130
// ValidateResourceRequestLimit validates that a Kubernetes Requests/Limit pair
188131
// is valid, both by validating the values are valid quantity values, and then
189132
// by checking that the limit >= request. This also needs to check against the

0 commit comments

Comments
 (0)