From 9ac12cf8980be9a1f5dfd9efbdf20d3afdd20046 Mon Sep 17 00:00:00 2001 From: Harshavardhana Date: Fri, 13 Sep 2019 16:34:34 -0700 Subject: [PATCH] Remove unusued Set/GetConfigKeys API (#8235) --- cmd/admin-handlers.go | 202 ------------------------- cmd/admin-handlers_test.go | 51 ------- cmd/admin-router.go | 5 - pkg/madmin/README.md | 57 ++----- pkg/madmin/config-commands.go | 59 -------- pkg/madmin/examples/get-config-keys.go | 54 ------- pkg/madmin/examples/set-config-keys.go | 53 ------- 7 files changed, 9 insertions(+), 472 deletions(-) delete mode 100644 pkg/madmin/examples/get-config-keys.go delete mode 100644 pkg/madmin/examples/set-config-keys.go diff --git a/cmd/admin-handlers.go b/cmd/admin-handlers.go index 84a20c1c6..97b341ed0 100644 --- a/cmd/admin-handlers.go +++ b/cmd/admin-handlers.go @@ -17,12 +17,9 @@ package cmd import ( - "bytes" "context" "crypto/subtle" - "encoding/base64" "encoding/json" - "errors" "fmt" "io" "io/ioutil" @@ -38,8 +35,6 @@ import ( humanize "github.com/dustin/go-humanize" "github.com/gorilla/mux" - "github.com/tidwall/gjson" - "github.com/tidwall/sjson" "github.com/minio/minio/cmd/crypto" xhttp "github.com/minio/minio/cmd/http" @@ -952,25 +947,6 @@ func (a adminAPIHandlers) GetConfigHandler(w http.ResponseWriter, r *http.Reques writeSuccessResponseJSON(w, econfigData) } -// Disable tidwall json array notation in JSON key path so -// users can set json with a key as a number. -// In tidwall json, notify.webhook.0 = val means { "notify" : { "webhook" : [val] }} -// In MinIO, notify.webhook.0 = val means { "notify" : { "webhook" : {"0" : val}}} -func normalizeJSONKey(input string) (key string) { - subKeys := strings.Split(input, ".") - for i, k := range subKeys { - if i > 0 { - key += "." - } - if _, err := strconv.Atoi(k); err == nil { - key += ":" + k - } else { - key += k - } - } - return -} - func validateAdminReq(ctx context.Context, w http.ResponseWriter, r *http.Request) ObjectLayer { // Get current object layer instance. objectAPI := newObjectLayerFn() @@ -989,60 +965,6 @@ func validateAdminReq(ctx context.Context, w http.ResponseWriter, r *http.Reques return objectAPI } -// GetConfigHandler - GET /minio/admin/v1/config-keys -// Get some keys in config.json of this minio setup. -func (a adminAPIHandlers) GetConfigKeysHandler(w http.ResponseWriter, r *http.Request) { - ctx := newContext(r, w, "GetConfigKeysHandler") - - objectAPI := validateAdminReq(ctx, w, r) - if objectAPI == nil { - return - } - - var keys []string - queries := r.URL.Query() - - for k := range queries { - keys = append(keys, k) - } - - config, err := readServerConfig(ctx, objectAPI) - if err != nil { - writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) - return - } - - configData, err := json.Marshal(config) - if err != nil { - writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) - return - } - - configStr := string(configData) - newConfigStr := `{}` - - for _, key := range keys { - // sjson.Set does not return an error if key is empty - // we should check by ourselves here - if key == "" { - continue - } - val := gjson.Get(configStr, key) - if j, ierr := sjson.Set(newConfigStr, normalizeJSONKey(key), val.Value()); ierr == nil { - newConfigStr = j - } - } - - password := config.GetCredential().SecretKey - econfigData, err := madmin.EncryptData(password, []byte(newConfigStr)) - if err != nil { - writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) - return - } - - writeSuccessResponseJSON(w, []byte(econfigData)) -} - // AdminError - is a generic error for all admin APIs. type AdminError struct { Code string @@ -1624,130 +1546,6 @@ func (a adminAPIHandlers) SetConfigHandler(w http.ResponseWriter, r *http.Reques writeSuccessResponseHeadersOnly(w) } -func convertValueType(elem []byte, jsonType gjson.Type) (interface{}, error) { - str := string(elem) - switch jsonType { - case gjson.False, gjson.True: - return strconv.ParseBool(str) - case gjson.JSON: - if gjson.Valid(str) { - return gjson.Parse(str).Value(), nil - } - return nil, errors.New("invalid json") - case gjson.String: - return str, nil - case gjson.Number: - return strconv.ParseFloat(str, 64) - default: - return nil, nil - } -} - -// SetConfigKeysHandler - PUT /minio/admin/v1/config-keys -func (a adminAPIHandlers) SetConfigKeysHandler(w http.ResponseWriter, r *http.Request) { - ctx := newContext(r, w, "SetConfigKeysHandler") - - objectAPI := validateAdminReq(ctx, w, r) - if objectAPI == nil { - return - } - - // Deny if WORM is enabled - if globalWORMEnabled { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrMethodNotAllowed), r.URL) - return - } - - // Load config - configStruct, err := readServerConfig(ctx, objectAPI) - if err != nil { - writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) - return - } - - // Convert config to json bytes - configBytes, err := json.Marshal(configStruct) - if err != nil { - writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) - return - } - - configStr := string(configBytes) - - queries := r.URL.Query() - password := globalServerConfig.GetCredential().SecretKey - - // Set key values in the JSON config - for k := range queries { - // Decode encrypted data associated to the current key - encryptedElem, dErr := base64.StdEncoding.DecodeString(queries.Get(k)) - if dErr != nil { - reqInfo := (&logger.ReqInfo{}).AppendTags("key", k) - ctx = logger.SetReqInfo(ctx, reqInfo) - logger.LogIf(ctx, dErr) - writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), dErr.Error(), r.URL) - return - } - - elem, dErr := madmin.DecryptData(password, bytes.NewBuffer([]byte(encryptedElem))) - if dErr != nil { - logger.LogIf(ctx, dErr) - writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), dErr.Error(), r.URL) - return - } - - // Calculate the type of the current key from the - // original config json - jsonFieldType := gjson.Get(configStr, k).Type - // Convert passed value to json filed type - val, cErr := convertValueType(elem, jsonFieldType) - if cErr != nil { - writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), cErr.Error(), r.URL) - return - } - // Set the key/value in the new json document - if s, sErr := sjson.Set(configStr, normalizeJSONKey(k), val); sErr == nil { - configStr = s - } - } - - configBytes = []byte(configStr) - - // Validate config - var config serverConfig - if err = json.Unmarshal(configBytes, &config); err != nil { - writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) - return - } - - if err = config.Validate(); err != nil { - writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) - return - } - - if err = config.TestNotificationTargets(); err != nil { - writeCustomErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminConfigBadJSON), err.Error(), r.URL) - return - } - - // If credentials for the server are provided via environment, - // then credentials in the provided configuration must match. - if globalIsEnvCreds { - if !globalServerConfig.GetCredential().Equal(config.Credential) { - writeErrorResponseJSON(ctx, w, errorCodes.ToAPIErr(ErrAdminCredentialsMismatch), r.URL) - return - } - } - - if err = saveServerConfig(ctx, objectAPI, &config); err != nil { - writeErrorResponseJSON(ctx, w, toAdminAPIErr(ctx, err), r.URL) - return - } - - // Send success response - writeSuccessResponseHeadersOnly(w) -} - // Returns true if the trace.Info should be traced, // false if certain conditions are not met. // - input entry is not of the type *trace.Info* diff --git a/cmd/admin-handlers_test.go b/cmd/admin-handlers_test.go index 531d9503a..82eaa9d7f 100644 --- a/cmd/admin-handlers_test.go +++ b/cmd/admin-handlers_test.go @@ -25,7 +25,6 @@ import ( "net/http" "net/http/httptest" "net/url" - "reflect" "strings" "sync" "testing" @@ -34,7 +33,6 @@ import ( "github.com/gorilla/mux" "github.com/minio/minio/pkg/auth" "github.com/minio/minio/pkg/madmin" - "github.com/tidwall/gjson" ) var ( @@ -750,52 +748,3 @@ func TestExtractHealInitParams(t *testing.T) { } } - -func TestNormalizeJSONKey(t *testing.T) { - cases := []struct { - input string - correctResult string - }{ - {"notify.webhook.1", "notify.webhook.:1"}, - {"notify.webhook.ok", "notify.webhook.ok"}, - {"notify.webhook.1.2", "notify.webhook.:1.:2"}, - {"abc", "abc"}, - } - for i, tcase := range cases { - res := normalizeJSONKey(tcase.input) - if res != tcase.correctResult { - t.Errorf("Case %d: failed to match", i) - } - } -} - -func TestConvertValueType(t *testing.T) { - cases := []struct { - elem []byte - jt gjson.Type - correctResult interface{} - isError bool - }{ - {[]byte(""), gjson.Null, nil, false}, - {[]byte("t"), gjson.False, true, false}, - {[]byte("f"), gjson.False, false, false}, - {[]byte(`{"a": 1}`), gjson.JSON, map[string]interface{}{"a": float64(1)}, false}, - {[]byte(`abc`), gjson.String, "abc", false}, - {[]byte(`1`), gjson.Number, float64(1), false}, - {[]byte(`a1`), gjson.Number, nil, true}, - {[]byte(`{"A": `), gjson.JSON, nil, true}, - {[]byte(`2`), gjson.False, nil, true}, - } - for i, tc := range cases { - res, err := convertValueType(tc.elem, tc.jt) - if err != nil { - if !tc.isError { - t.Errorf("Case %d: got an error when none was expected", i) - } - } else if err == nil && tc.isError { - t.Errorf("Case %d: got no error though we expected one", i) - } else if !reflect.DeepEqual(res, tc.correctResult) { - t.Errorf("Case %d: result mismatch - got %#v", i, res) - } - } -} diff --git a/cmd/admin-router.go b/cmd/admin-router.go index 47bdd61a6..59a585e9b 100644 --- a/cmd/admin-router.go +++ b/cmd/admin-router.go @@ -77,11 +77,6 @@ func registerAdminRouter(router *mux.Router, enableConfigOps, enableIAMOps bool) adminV1Router.Methods(http.MethodGet).Path("/config").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigHandler)) // Set config adminV1Router.Methods(http.MethodPut).Path("/config").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigHandler)) - - // Get config keys/values - adminV1Router.Methods(http.MethodGet).Path("/config-keys").HandlerFunc(httpTraceHdrs(adminAPI.GetConfigKeysHandler)) - // Set config keys/values - adminV1Router.Methods(http.MethodPut).Path("/config-keys").HandlerFunc(httpTraceHdrs(adminAPI.SetConfigKeysHandler)) } if enableIAMOps { diff --git a/pkg/madmin/README.md b/pkg/madmin/README.md index d1a38e7c3..57d59b187 100644 --- a/pkg/madmin/README.md +++ b/pkg/madmin/README.md @@ -42,14 +42,14 @@ func main() { } ``` -| Service operations | Info operations | Healing operations | Config operations | Top operations | IAM operations | Misc | KMS | -|:------------------------------------|:------------------------------------------------|:-------------------|:----------------------------------|:------------------------|:--------------------------------------|:--------------------------------------------------|:----------------------------------| -| [`ServiceRestart`](#ServiceRestart) | [`ServerInfo`](#ServerInfo) | [`Heal`](#Heal) | [`GetConfig`](#GetConfig) | [`TopLocks`](#TopLocks) | [`AddUser`](#AddUser) | | [`GetKeyStatus`](#GetKeyStatus) | -| [`ServiceStop`](#ServiceStop) | [`ServerCPULoadInfo`](#ServerCPULoadInfo) | | [`SetConfig`](#SetConfig) | | [`SetUserPolicy`](#SetUserPolicy) | [`StartProfiling`](#StartProfiling) | | -| | [`ServerMemUsageInfo`](#ServerMemUsageInfo) | | [`GetConfigKeys`](#GetConfigKeys) | | [`ListUsers`](#ListUsers) | [`DownloadProfilingData`](#DownloadProfilingData) | | -| [`ServiceTrace`](#ServiceTrace) | [`ServerDrivesPerfInfo`](#ServerDrivesPerfInfo) | | [`SetConfigKeys`](#SetConfigKeys) | | [`AddCannedPolicy`](#AddCannedPolicy) | [`ServerUpdate`](#ServerUpdate) | | -| | [`NetPerfInfo`](#NetPerfInfo) | | | | | | | - +| Service operations | Info operations | Healing operations | Config operations | Top operations | IAM operations | Misc | KMS | +|:------------------------------------|:------------------------------------------------|:-------------------|:--------------------------|:------------------------|:--------------------------------------|:--------------------------------------------------|:--------------------------------| +| [`ServiceRestart`](#ServiceRestart) | [`ServerInfo`](#ServerInfo) | [`Heal`](#Heal) | [`GetConfig`](#GetConfig) | [`TopLocks`](#TopLocks) | [`AddUser`](#AddUser) | | [`GetKeyStatus`](#GetKeyStatus) | +| [`ServiceStop`](#ServiceStop) | [`ServerCPULoadInfo`](#ServerCPULoadInfo) | | [`SetConfig`](#SetConfig) | | [`SetUserPolicy`](#SetUserPolicy) | [`StartProfiling`](#StartProfiling) | | +| | [`ServerMemUsageInfo`](#ServerMemUsageInfo) | | | | [`ListUsers`](#ListUsers) | [`DownloadProfilingData`](#DownloadProfilingData) | | +| [`ServiceTrace`](#ServiceTrace) | [`ServerDrivesPerfInfo`](#ServerDrivesPerfInfo) | | | | [`AddCannedPolicy`](#AddCannedPolicy) | [`ServerUpdate`](#ServerUpdate) | | +| | [`NetPerfInfo`](#NetPerfInfo) | | | | | | | + ## 1. Constructor @@ -390,45 +390,6 @@ __Example__ log.Println("SetConfig was successful") ``` - -### GetConfigKeys(keys []string) ([]byte, error) -Get a json document which contains a set of keys and their values from config.json. - -__Example__ - -``` go - configBytes, err := madmClnt.GetConfigKeys([]string{"version", "notify.amqp.1"}) - if err != nil { - log.Fatalf("failed due to: %v", err) - } - - // Pretty-print config received as json. - var buf bytes.Buffer - err = json.Indent(buf, configBytes, "", "\t") - if err != nil { - log.Fatalf("failed due to: %v", err) - } - - log.Println("config received successfully: ", string(buf.Bytes())) -``` - - - -### SetConfigKeys(params map[string]string) error -Set a set of keys and values for MinIO server or distributed setup and restart the MinIO -server for the new configuration changes to take effect. - -__Example__ - -``` go - err := madmClnt.SetConfigKeys(map[string]string{"notify.webhook.1": "{\"enable\": true, \"endpoint\": \"http://example.com/api\"}"}) - if err != nil { - log.Fatalf("failed due to: %v", err) - } - - log.Println("New configuration successfully set") -``` - ## 7. Top operations @@ -582,7 +543,7 @@ __Example__ ## 11. KMS - + ### GetKeyStatus(keyID string) (*KMSKeyStatus, error) Requests status information about one particular KMS master key from a MinIO server. The keyID is optional and the server will diff --git a/pkg/madmin/config-commands.go b/pkg/madmin/config-commands.go index e06208877..5e75ad51d 100644 --- a/pkg/madmin/config-commands.go +++ b/pkg/madmin/config-commands.go @@ -19,12 +19,10 @@ package madmin import ( "bytes" - "encoding/base64" "encoding/json" "errors" "io" "net/http" - "net/url" "github.com/minio/minio/pkg/quick" ) @@ -47,31 +45,6 @@ func (adm *AdminClient) GetConfig() ([]byte, error) { return DecryptData(adm.secretAccessKey, resp.Body) } -// GetConfigKeys - returns partial json or json value from config.json of a minio setup. -func (adm *AdminClient) GetConfigKeys(keys []string) ([]byte, error) { - queryVals := make(url.Values) - for _, k := range keys { - queryVals.Add(k, "") - } - - // Execute GET on /minio/admin/v1/config-keys to get config of a setup. - resp, err := adm.executeMethod("GET", - requestData{ - relPath: "/v1/config-keys", - queryValues: queryVals, - }) - defer closeResponse(resp) - if err != nil { - return nil, err - } - - if resp.StatusCode != http.StatusOK { - return nil, httpRespToErrorResponse(resp) - } - - return DecryptData(adm.secretAccessKey, resp.Body) -} - // SetConfig - set config supplied as config.json for the setup. func (adm *AdminClient) SetConfig(config io.Reader) (err error) { const maxConfigJSONSize = 256 * 1024 // 256KiB @@ -130,35 +103,3 @@ func (adm *AdminClient) SetConfig(config io.Reader) (err error) { return nil } - -// SetConfigKeys - set config keys supplied as config.json for the setup. -func (adm *AdminClient) SetConfigKeys(params map[string]string) error { - queryVals := make(url.Values) - for k, v := range params { - encryptedVal, err := EncryptData(adm.secretAccessKey, []byte(v)) - if err != nil { - return err - } - encodedVal := base64.StdEncoding.EncodeToString(encryptedVal) - queryVals.Add(k, string(encodedVal)) - } - - reqData := requestData{ - relPath: "/v1/config-keys", - queryValues: queryVals, - } - - // Execute PUT on /minio/admin/v1/config-keys to set config. - resp, err := adm.executeMethod("PUT", reqData) - - defer closeResponse(resp) - if err != nil { - return err - } - - if resp.StatusCode != http.StatusOK { - return httpRespToErrorResponse(resp) - } - - return nil -} diff --git a/pkg/madmin/examples/get-config-keys.go b/pkg/madmin/examples/get-config-keys.go deleted file mode 100644 index 641ba08ad..000000000 --- a/pkg/madmin/examples/get-config-keys.go +++ /dev/null @@ -1,54 +0,0 @@ -// +build ignore - -/* - * MinIO Cloud Storage, (C) 2017 MinIO, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package main - -import ( - "bytes" - "encoding/json" - "log" - - "github.com/minio/minio/pkg/madmin" -) - -func main() { - // Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY are - // dummy values, please replace them with original values. - - // API requests are secure (HTTPS) if secure=true and insecure (HTTP) otherwise. - // New returns an MinIO Admin client object. - madmClnt, err := madmin.New("your-minio.example.com:9000", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY", true) - if err != nil { - log.Fatalln(err) - } - - configBytes, err := madmClnt.GetConfigKeys([]string{"notify.amqp.1", "version"}) - if err != nil { - log.Fatalf("failed due to: %v", err) - } - - // Pretty-print config received as json. - var buf bytes.Buffer - err = json.Indent(&buf, configBytes, "", "\t") - if err != nil { - log.Fatalf("failed due to: %v", err) - } - - log.Println("config received successfully: ", string(buf.Bytes())) -} diff --git a/pkg/madmin/examples/set-config-keys.go b/pkg/madmin/examples/set-config-keys.go deleted file mode 100644 index b0eb94a47..000000000 --- a/pkg/madmin/examples/set-config-keys.go +++ /dev/null @@ -1,53 +0,0 @@ -// +build ignore - -/* - * MinIO Cloud Storage, (C) 2017 MinIO, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package main - -import ( - "fmt" - "log" - - "github.com/minio/minio/pkg/madmin" -) - -func main() { - // Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY are - // dummy values, please replace them with original values. - - // Note: YOUR-ACCESSKEYID, YOUR-SECRETACCESSKEY are - // dummy values, please replace them with original values. - - // API requests are secure (HTTPS) if secure=true and insecure (HTTP) otherwise. - // New returns an MinIO Admin client object. - madmClnt, err := madmin.New("your-minio.example.com:9000", "YOUR-ACCESSKEYID", "YOUR-SECRETACCESSKEY", true) - if err != nil { - log.Fatalln(err) - } - - err = madmClnt.SetConfigKeys(map[string]string{ - "domain": "example.com", - "notify.webhook.1": "{\"enable\": true, \"endpoint\": \"http://example.com/api/object-notifications\"}", - }) - - if err != nil { - log.Fatalln(err) - } - - fmt.Println("Setting new configuration successfully executed.") -}