|  | /* | 
|  | * Licensed to the Apache Software Foundation (ASF) under one | 
|  | * or more contributor license agreements.  See the NOTICE file | 
|  | * distributed with this work for additional information | 
|  | * regarding copyright ownership.  The ASF licenses this file | 
|  | * to you 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 executor | 
|  |  | 
|  | import ( | 
|  | "encoding/json" | 
|  | "fmt" | 
|  | "sort" | 
|  | "strings" | 
|  |  | 
|  | "github.com/apache/incubator-pegasus/admin-cli/util" | 
|  | "github.com/apache/incubator-pegasus/go-client/session" | 
|  | ) | 
|  |  | 
|  | // map[*util.PegasusNode]*util.Result is not sorted, pass nodes is for print sorted result | 
|  | type printResponse func(nodeType session.NodeType, sortedNodeList []string, resp map[string]*util.Result) | 
|  |  | 
|  | type action struct { | 
|  | request util.HTTPRequestFunc | 
|  | print   printResponse | 
|  | } | 
|  |  | 
|  | var actionsMap = map[string]action{ | 
|  | "list": {listConfig, printConfigList}, | 
|  | "get":  {getConfig, printConfigValue}, | 
|  | "set":  {updateConfig, printConfigUpdate}, | 
|  | } | 
|  |  | 
|  | var sectionsMap = map[session.NodeType]string{ | 
|  | session.NodeTypeMeta:    "meta_server,security", | 
|  | session.NodeTypeReplica: "pegasus.server,security,replication,block_service,nfs,task", | 
|  | // TODO(jiashuo1) support collector | 
|  | } | 
|  |  | 
|  | type response struct { | 
|  | Name    string | 
|  | Section string | 
|  | Tags    string | 
|  | Value   string | 
|  | } | 
|  |  | 
|  | // TODO(jiashuo1) not support update collector config | 
|  | func ConfigCommand(client *Client, nodeType session.NodeType, nodeAddr string, name string, actionType string, value string) error { | 
|  | var nodes []*util.PegasusNode | 
|  | if len(nodeAddr) == 0 { | 
|  | // send http-commands to all nodeType nodes | 
|  | nodes = client.Nodes.GetAllNodes(nodeType) | 
|  | } else { | 
|  | n, err := client.Nodes.GetNode(nodeAddr, nodeType) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | nodes = append(nodes, n) | 
|  | } | 
|  |  | 
|  | if ac, ok := actionsMap[actionType]; ok { | 
|  | cmd := util.Arguments{ | 
|  | Name:  name, | 
|  | Value: value, | 
|  | } | 
|  | results := util.BatchCallHTTP(nodes, ac.request, cmd) | 
|  |  | 
|  | var sortedNodeList []string | 
|  | for _, n := range nodes { | 
|  | sortedNodeList = append(sortedNodeList, n.CombinedAddr()) | 
|  | } | 
|  | sort.Strings(sortedNodeList) | 
|  | ac.print(nodeType, sortedNodeList, results) | 
|  | } else { | 
|  | return fmt.Errorf("invalid request type: %s", actionType) | 
|  | } | 
|  |  | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func listConfig(addr string, cmd util.Arguments) (string, error) { | 
|  | url := fmt.Sprintf("http://%s/configs", addr) | 
|  | return util.CallHTTPGet(url) | 
|  | } | 
|  |  | 
|  | func printConfigList(nodeType session.NodeType, sortedNodeList []string, results map[string]*util.Result) { | 
|  | fmt.Printf("CMD: list \n") | 
|  | for _, node := range sortedNodeList { | 
|  | cmdRes := results[node] | 
|  | if cmdRes.Err != nil { | 
|  | fmt.Printf("[%s] %s\n", node, cmdRes.Err) | 
|  | continue | 
|  | } | 
|  |  | 
|  | var respMap map[string]response | 
|  | err := json.Unmarshal([]byte(cmdRes.Resp), &respMap) | 
|  | if err != nil { | 
|  | fmt.Printf("[%s] %s\n", node, err) | 
|  | continue | 
|  | } | 
|  |  | 
|  | fmt.Printf("[%s]\n", node) | 
|  | var resultSorted []string | 
|  | for _, value := range respMap { | 
|  | if value.Tags == "flag_tag::FT_MUTABLE" && strings.Contains(sectionsMap[nodeType], value.Section) { | 
|  | resultSorted = append(resultSorted, fmt.Sprintf("\t[%s] %s=%s\n", value.Section, value.Name, value.Value)) | 
|  | } | 
|  | } | 
|  | sort.Strings(resultSorted) | 
|  | resStr := fmt.Sprintf("%s", resultSorted) | 
|  | // resStr is like [...], print need delete the `[` and `]` character | 
|  | fmt.Print(resStr[1 : len(resStr)-1]) | 
|  | } | 
|  | } | 
|  |  | 
|  | func getConfig(addr string, cmd util.Arguments) (string, error) { | 
|  | url := fmt.Sprintf("http://%s/config?name=%s", addr, cmd.Name) | 
|  | return util.CallHTTPGet(url) | 
|  | } | 
|  |  | 
|  | func printConfigValue(nodeType session.NodeType, sortedNodeList []string, results map[string]*util.Result) { | 
|  | fmt.Printf("CMD: get \n") | 
|  | for _, node := range sortedNodeList { | 
|  | cmdRes := results[node] | 
|  | if cmdRes.Err != nil { | 
|  | fmt.Printf("[%s] %s\n", node, cmdRes.Err) | 
|  | continue | 
|  | } | 
|  |  | 
|  | var resp response | 
|  | err := json.Unmarshal([]byte(cmdRes.Resp), &resp) | 
|  | if err != nil { | 
|  | fmt.Printf("[%s] %s\n", node, cmdRes.Resp) | 
|  | continue | 
|  | } | 
|  |  | 
|  | if !strings.Contains(sectionsMap[nodeType], resp.Section) { | 
|  | fmt.Printf("[%s] %s is not config on %s\n", node, resp.Name, nodeType) | 
|  | continue | 
|  | } | 
|  |  | 
|  | fmt.Printf("[%s] %s=%s\n", node, resp.Name, resp.Value) | 
|  | } | 
|  | } | 
|  |  | 
|  | func updateConfig(addr string, cmd util.Arguments) (string, error) { | 
|  | url := fmt.Sprintf("http://%s/updateConfig?%s=%s", addr, cmd.Name, cmd.Value) | 
|  | return util.CallHTTPGet(url) | 
|  | } | 
|  |  | 
|  | func printConfigUpdate(nodeType session.NodeType, sortedNodeList []string, results map[string]*util.Result) { | 
|  | fmt.Printf("CMD: set \n") | 
|  | for _, node := range sortedNodeList { | 
|  | cmdRes := results[node] | 
|  | if cmdRes.Err != nil { | 
|  | fmt.Printf("[%s] %s\n", node, cmdRes.Err) | 
|  | continue | 
|  | } | 
|  |  | 
|  | var resMap map[string]string | 
|  | err := json.Unmarshal([]byte(cmdRes.Resp), &resMap) | 
|  | if err != nil { | 
|  | fmt.Printf("[%s] %s\n", node, err) | 
|  | continue | 
|  | } | 
|  |  | 
|  | fmt.Printf("[%s] %s\n", node, resMap["update_status"]) | 
|  | } | 
|  | } |