util.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright 2015 The etcd Authors
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package command
  15. import (
  16. "context"
  17. "encoding/hex"
  18. "fmt"
  19. "io/ioutil"
  20. "net/http"
  21. "regexp"
  22. "strconv"
  23. "strings"
  24. "time"
  25. v3 "go.etcd.io/etcd/clientv3"
  26. pb "go.etcd.io/etcd/mvcc/mvccpb"
  27. "github.com/spf13/cobra"
  28. )
  29. func printKV(isHex bool, valueOnly bool, kv *pb.KeyValue) {
  30. k, v := string(kv.Key), string(kv.Value)
  31. if isHex {
  32. k = addHexPrefix(hex.EncodeToString(kv.Key))
  33. v = addHexPrefix(hex.EncodeToString(kv.Value))
  34. }
  35. if !valueOnly {
  36. fmt.Println(k)
  37. }
  38. fmt.Println(v)
  39. }
  40. func addHexPrefix(s string) string {
  41. ns := make([]byte, len(s)*2)
  42. for i := 0; i < len(s); i += 2 {
  43. ns[i*2] = '\\'
  44. ns[i*2+1] = 'x'
  45. ns[i*2+2] = s[i]
  46. ns[i*2+3] = s[i+1]
  47. }
  48. return string(ns)
  49. }
  50. func argify(s string) []string {
  51. r := regexp.MustCompile(`"(?:[^"\\]|\\.)*"|'[^']*'|[^'"\s]\S*[^'"\s]?`)
  52. args := r.FindAllString(s, -1)
  53. for i := range args {
  54. if len(args[i]) == 0 {
  55. continue
  56. }
  57. if args[i][0] == '\'' {
  58. // 'single-quoted string'
  59. args[i] = args[i][1 : len(args)-1]
  60. } else if args[i][0] == '"' {
  61. // "double quoted string"
  62. if _, err := fmt.Sscanf(args[i], "%q", &args[i]); err != nil {
  63. ExitWithError(ExitInvalidInput, err)
  64. }
  65. }
  66. }
  67. return args
  68. }
  69. func commandCtx(cmd *cobra.Command) (context.Context, context.CancelFunc) {
  70. timeOut, err := cmd.Flags().GetDuration("command-timeout")
  71. if err != nil {
  72. ExitWithError(ExitError, err)
  73. }
  74. return context.WithTimeout(context.Background(), timeOut)
  75. }
  76. func isCommandTimeoutFlagSet(cmd *cobra.Command) bool {
  77. commandTimeoutFlag := cmd.Flags().Lookup("command-timeout")
  78. if commandTimeoutFlag == nil {
  79. panic("expect command-timeout flag to exist")
  80. }
  81. return commandTimeoutFlag.Changed
  82. }
  83. // get the process_resident_memory_bytes from <server:2379>/metrics
  84. func endpointMemoryMetrics(host string) float64 {
  85. residentMemoryKey := "process_resident_memory_bytes"
  86. var residentMemoryValue string
  87. if !strings.HasPrefix(host, `http://`) {
  88. host = "http://" + host
  89. }
  90. url := host + "/metrics"
  91. resp, err := http.Get(url)
  92. if err != nil {
  93. fmt.Println(fmt.Sprintf("fetch error: %v", err))
  94. return 0.0
  95. }
  96. byts, readerr := ioutil.ReadAll(resp.Body)
  97. resp.Body.Close()
  98. if readerr != nil {
  99. fmt.Println(fmt.Sprintf("fetch error: reading %s: %v", url, readerr))
  100. return 0.0
  101. }
  102. for _, line := range strings.Split(string(byts), "\n") {
  103. if strings.HasPrefix(line, residentMemoryKey) {
  104. residentMemoryValue = strings.TrimSpace(strings.TrimPrefix(line, residentMemoryKey))
  105. break
  106. }
  107. }
  108. if residentMemoryValue == "" {
  109. fmt.Println(fmt.Sprintf("could not find: %v", residentMemoryKey))
  110. return 0.0
  111. }
  112. residentMemoryBytes, parseErr := strconv.ParseFloat(residentMemoryValue, 64)
  113. if parseErr != nil {
  114. fmt.Println(fmt.Sprintf("parse error: %v", parseErr))
  115. return 0.0
  116. }
  117. return residentMemoryBytes
  118. }
  119. // compact keyspace history to a provided revision
  120. func compact(c *v3.Client, rev int64) {
  121. fmt.Printf("Compacting with revision %d\n", rev)
  122. ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  123. _, err := c.Compact(ctx, rev, v3.WithCompactPhysical())
  124. cancel()
  125. if err != nil {
  126. ExitWithError(ExitError, err)
  127. }
  128. fmt.Printf("Compacted with revision %d\n", rev)
  129. }
  130. // defrag a given endpoint
  131. func defrag(c *v3.Client, ep string) {
  132. fmt.Printf("Defragmenting %q\n", ep)
  133. ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  134. _, err := c.Defragment(ctx, ep)
  135. cancel()
  136. if err != nil {
  137. ExitWithError(ExitError, err)
  138. }
  139. fmt.Printf("Defragmented %q\n", ep)
  140. }