From cf3809d6209d06d12b2fa2a21db5e4fb2f5072cc Mon Sep 17 00:00:00 2001 From: Andrew Lavery Date: Fri, 17 Jul 2020 18:29:10 -0400 Subject: [PATCH] add a route to only update a redactor's enabled status the existing route requires you to update the description, redactor yaml, etc at the same time --- kotsadm/pkg/apiserver/server.go | 1 + kotsadm/pkg/handlers/redact.go | 60 +++++++++++++++++++ kotsadm/pkg/redact/redact.go | 46 +++++++++++++++ kotsadm/pkg/redact/redact_test.go | 95 +++++++++++++++++++++++++++++++ 4 files changed, 202 insertions(+) diff --git a/kotsadm/pkg/apiserver/server.go b/kotsadm/pkg/apiserver/server.go index e8f5d29537..702d975733 100644 --- a/kotsadm/pkg/apiserver/server.go +++ b/kotsadm/pkg/apiserver/server.go @@ -80,6 +80,7 @@ func Start() { r.Path("/api/v1/redact/spec/{slug}").Methods("OPTIONS", "GET").HandlerFunc(handlers.GetRedactMetadataAndYaml) r.Path("/api/v1/redact/spec/{slug}").Methods("POST").HandlerFunc(handlers.SetRedactMetadataAndYaml) r.Path("/api/v1/redact/spec/{slug}").Methods("DELETE").HandlerFunc(handlers.DeleteRedact) + r.Path("/api/v1/redact/enabled/{slug}").Methods("POST").HandlerFunc(handlers.SetRedactMetadataAndYaml) r.PathPrefix("/api/v1/kots/").Methods("OPTIONS").HandlerFunc(handlers.CORS) r.PathPrefix("/api/v1/kots/").Methods("HEAD", "GET", "POST", "PUT", "DELETE").HandlerFunc(handlers.NodeProxy(upstream)) diff --git a/kotsadm/pkg/handlers/redact.go b/kotsadm/pkg/handlers/redact.go index 001cd785a6..8539a6b9a7 100644 --- a/kotsadm/pkg/handlers/redact.go +++ b/kotsadm/pkg/handlers/redact.go @@ -51,6 +51,10 @@ type PostRedactorMetadata struct { Redactor string `json:"redactor"` } +type PostRedactorEnabledMetadata struct { + Enabled bool `json:"enabled"` +} + func UpdateRedact(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Headers", "content-type, origin, accept, authorization") @@ -353,3 +357,59 @@ func DeleteRedact(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) return } + +func SetRedactEnabled(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Headers", "content-type, origin, accept, authorization") + + metadataResponse := GetRedactorResponse{ + Success: false, + } + + sess, err := session.Parse(r.Header.Get("Authorization")) + if err != nil { + logger.Error(err) + metadataResponse.Error = "failed to parse authorization header" + JSON(w, 401, metadataResponse) + return + } + + // we don't currently have roles, all valid tokens are valid sessions + if sess == nil || sess.ID == "" { + metadataResponse.Error = "no session in auth header" + JSON(w, 401, metadataResponse) + return + } + + redactorSlug := mux.Vars(r)["slug"] + + updateRedactRequest := PostRedactorEnabledMetadata{} + if err := json.NewDecoder(r.Body).Decode(&updateRedactRequest); err != nil { + logger.Error(err) + metadataResponse.Error = "failed to decode request body" + JSON(w, 400, metadataResponse) + return + } + + updatedRedactor, err := redact.SetRedactEnabled(redactorSlug, updateRedactRequest.Enabled) + if err != nil { + logger.Error(err) + metadataResponse.Error = "failed to update redactor status" + JSON(w, 400, metadataResponse) + return + } + + marshalled, err := util.MarshalIndent(2, updatedRedactor.Redact) + if err != nil { + logger.Error(err) + metadataResponse.Error = "failed to marshal redactor" + JSON(w, http.StatusInternalServerError, metadataResponse) + return + } + + metadataResponse.Success = true + metadataResponse.Metadata = updatedRedactor.Metadata + metadataResponse.Redactor = string(marshalled) + JSON(w, http.StatusOK, metadataResponse) + return +} diff --git a/kotsadm/pkg/redact/redact.go b/kotsadm/pkg/redact/redact.go index 3b9b7d62ce..15f5cbf999 100644 --- a/kotsadm/pkg/redact/redact.go +++ b/kotsadm/pkg/redact/redact.go @@ -186,6 +186,52 @@ func SetRedactYaml(slug, description string, enabled, newRedact bool, yamlBytes return redactorEntry, nil } +// sets whether an individual redactor is enabled +func SetRedactEnabled(slug string, enabled bool) (*RedactorMetadata, error) { + configMap, _, err := getConfigmap() + if err != nil { + return nil, err + } + + newData, redactorEntry, err := setRedactEnabled(slug, enabled, time.Now(), configMap.Data) + if err != nil { + return nil, err + } + + configMap.Data = newData + + _, err = writeConfigmap(configMap) + if err != nil { + return nil, errors.Wrapf(err, "write configMap with updated redact") + } + return redactorEntry, nil +} + +func setRedactEnabled(slug string, enabled bool, currentTime time.Time, data map[string]string) (map[string]string, *RedactorMetadata, error) { + redactorEntry := RedactorMetadata{} + redactString, ok := data[slug] + if !ok { + return nil, nil, fmt.Errorf("redactor %s not found", slug) + } + + // unmarshal existing redactor + err := json.Unmarshal([]byte(redactString), &redactorEntry) + if err != nil { + return nil, nil, errors.Wrapf(err, "unable to parse redactor %s", slug) + } + + redactorEntry.Metadata.Enabled = enabled + redactorEntry.Metadata.Updated = currentTime + + jsonBytes, err := json.Marshal(redactorEntry) + if err != nil { + return nil, nil, errors.Wrapf(err, "unable to marshal redactor %s", slug) + } + + data[slug] = string(jsonBytes) + return data, &redactorEntry, nil +} + func setRedactYaml(slug, description string, enabled, newRedact bool, currentTime time.Time, yamlBytes []byte, data map[string]string) (map[string]string, *RedactorMetadata, error) { // parse yaml as redactor newRedactorSpec, err := parseRedact(yamlBytes) diff --git a/kotsadm/pkg/redact/redact_test.go b/kotsadm/pkg/redact/redact_test.go index 53a0380fc0..cdd5dd1842 100644 --- a/kotsadm/pkg/redact/redact_test.go +++ b/kotsadm/pkg/redact/redact_test.go @@ -419,3 +419,98 @@ spec: {}`, }) } } + +func Test_setRedactEnabled(t *testing.T) { + previousTime, err := time.Parse(time.RFC3339, "2010-06-15T14:26:10.721619-04:00") + if err != nil { + panic(err) + } + + testTime, err := time.Parse(time.RFC3339, "2020-06-15T14:26:10.721619-04:00") + if err != nil { + panic(err) + } + + type args struct { + slug string + enabled bool + data map[string]string + } + tests := []struct { + name string + args args + newMap map[string]string + newMetadata *RedactorMetadata + expectedSlug string + }{ + { + name: "update existing redact", + args: args{ + slug: "update-redact", + enabled: false, + data: map[string]string{ + "update-redact": `{"metadata":{"name":"update redact","slug":"update-redact","createdAt":"2010-06-15T14:26:10.721619-04:00","updatedAt":"2010-06-15T14:26:10.721619-04:00","enabled":true,"description":"a description"},"redact":"kind: Redactor\napiVersion: troubleshoot.replicated.com/v1beta1\nmetadata:\n name: update redact"}`, + "leave-untouched": `other keys should not be modified`, + }, + }, + newMap: map[string]string{ + "update-redact": `{"metadata":{"name":"update redact","slug":"update-redact","createdAt":"2010-06-15T14:26:10.721619-04:00","updatedAt":"2020-06-15T14:26:10.721619-04:00","enabled":false,"description":"a description"},"redact":"kind: Redactor\napiVersion: troubleshoot.replicated.com/v1beta1\nmetadata:\n name: update redact"}`, + "leave-untouched": `other keys should not be modified`, + }, + newMetadata: &RedactorMetadata{ + Redact: `kind: Redactor +apiVersion: troubleshoot.replicated.com/v1beta1 +metadata: + name: update redact`, + Metadata: RedactorList{ + Name: "update redact", + Slug: "update-redact", + Enabled: false, + Description: "a description", + Created: previousTime, + Updated: testTime, + }, + }, + }, + { + name: "updated time changes even if enabled does not", + args: args{ + slug: "update-redact", + enabled: true, + data: map[string]string{ + "update-redact": `{"metadata":{"name":"update redact","slug":"update-redact","createdAt":"2010-06-15T14:26:10.721619-04:00","updatedAt":"2010-06-15T14:26:10.721619-04:00","enabled":true,"description":"a description"},"redact":"kind: Redactor\napiVersion: troubleshoot.replicated.com/v1beta1\nmetadata:\n name: update redact"}`, + "leave-untouched": `other keys should not be modified`, + }, + }, + newMap: map[string]string{ + "update-redact": `{"metadata":{"name":"update redact","slug":"update-redact","createdAt":"2010-06-15T14:26:10.721619-04:00","updatedAt":"2020-06-15T14:26:10.721619-04:00","enabled":true,"description":"a description"},"redact":"kind: Redactor\napiVersion: troubleshoot.replicated.com/v1beta1\nmetadata:\n name: update redact"}`, + "leave-untouched": `other keys should not be modified`, + }, + newMetadata: &RedactorMetadata{ + Redact: `kind: Redactor +apiVersion: troubleshoot.replicated.com/v1beta1 +metadata: + name: update redact`, + Metadata: RedactorList{ + Name: "update redact", + Slug: "update-redact", + Enabled: true, + Description: "a description", + Created: previousTime, + Updated: testTime, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + req := require.New(t) + + newMap, newMetadata, err := setRedactEnabled(tt.args.slug, tt.args.enabled, testTime, tt.args.data) + req.NoError(err) + + req.Equal(tt.newMap, newMap) + req.Equal(tt.newMetadata, newMetadata) + }) + } +}