cluster_read_config.go 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. // Copyright 2018 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 tester
  15. import (
  16. "errors"
  17. "fmt"
  18. "io/ioutil"
  19. "net/url"
  20. "path/filepath"
  21. "strings"
  22. "go.etcd.io/etcd/functional/rpcpb"
  23. "go.uber.org/zap"
  24. yaml "gopkg.in/yaml.v2"
  25. )
  26. func read(lg *zap.Logger, fpath string) (*Cluster, error) {
  27. bts, err := ioutil.ReadFile(fpath)
  28. if err != nil {
  29. return nil, err
  30. }
  31. lg.Info("opened configuration file", zap.String("path", fpath))
  32. clus := &Cluster{lg: lg}
  33. if err = yaml.Unmarshal(bts, clus); err != nil {
  34. return nil, err
  35. }
  36. if len(clus.Members) < 3 {
  37. return nil, fmt.Errorf("len(clus.Members) expects at least 3, got %d", len(clus.Members))
  38. }
  39. failpointsEnabled := false
  40. for _, c := range clus.Tester.Cases {
  41. if c == rpcpb.Case_FAILPOINTS.String() {
  42. failpointsEnabled = true
  43. break
  44. }
  45. }
  46. if len(clus.Tester.Cases) == 0 {
  47. return nil, errors.New("cases not found")
  48. }
  49. if clus.Tester.DelayLatencyMs <= clus.Tester.DelayLatencyMsRv*5 {
  50. return nil, fmt.Errorf("delay latency %d ms must be greater than 5x of delay latency random variable %d ms", clus.Tester.DelayLatencyMs, clus.Tester.DelayLatencyMsRv)
  51. }
  52. if clus.Tester.UpdatedDelayLatencyMs == 0 {
  53. clus.Tester.UpdatedDelayLatencyMs = clus.Tester.DelayLatencyMs
  54. }
  55. for _, v := range clus.Tester.Cases {
  56. if _, ok := rpcpb.Case_value[v]; !ok {
  57. return nil, fmt.Errorf("%q is not defined in 'rpcpb.Case_value'", v)
  58. }
  59. }
  60. for _, s := range clus.Tester.Stressers {
  61. if _, ok := rpcpb.StresserType_value[s.Type]; !ok {
  62. return nil, fmt.Errorf("unknown 'StresserType' %+v", s)
  63. }
  64. }
  65. for _, v := range clus.Tester.Checkers {
  66. if _, ok := rpcpb.Checker_value[v]; !ok {
  67. return nil, fmt.Errorf("Checker is unknown; got %q", v)
  68. }
  69. }
  70. if clus.Tester.StressKeySuffixRangeTxn > 100 {
  71. return nil, fmt.Errorf("StressKeySuffixRangeTxn maximum value is 100, got %v", clus.Tester.StressKeySuffixRangeTxn)
  72. }
  73. if clus.Tester.StressKeyTxnOps > 64 {
  74. return nil, fmt.Errorf("StressKeyTxnOps maximum value is 64, got %v", clus.Tester.StressKeyTxnOps)
  75. }
  76. for i, mem := range clus.Members {
  77. if mem.EtcdExec == "embed" && failpointsEnabled {
  78. return nil, errors.New("EtcdExec 'embed' cannot be run with failpoints enabled")
  79. }
  80. if mem.BaseDir == "" {
  81. return nil, fmt.Errorf("BaseDir cannot be empty (got %q)", mem.BaseDir)
  82. }
  83. if mem.Etcd.Name == "" {
  84. return nil, fmt.Errorf("'--name' cannot be empty (got %+v)", mem)
  85. }
  86. if mem.Etcd.DataDir == "" {
  87. return nil, fmt.Errorf("'--data-dir' cannot be empty (got %+v)", mem)
  88. }
  89. if mem.Etcd.SnapshotCount == 0 {
  90. return nil, fmt.Errorf("'--snapshot-count' cannot be 0 (got %+v)", mem.Etcd.SnapshotCount)
  91. }
  92. if mem.Etcd.DataDir == "" {
  93. return nil, fmt.Errorf("'--data-dir' cannot be empty (got %q)", mem.Etcd.DataDir)
  94. }
  95. if mem.Etcd.WALDir == "" {
  96. clus.Members[i].Etcd.WALDir = filepath.Join(mem.Etcd.DataDir, "member", "wal")
  97. }
  98. switch mem.Etcd.InitialClusterState {
  99. case "new":
  100. case "existing":
  101. default:
  102. return nil, fmt.Errorf("'--initial-cluster-state' got %q", mem.Etcd.InitialClusterState)
  103. }
  104. if mem.Etcd.HeartbeatIntervalMs == 0 {
  105. return nil, fmt.Errorf("'--heartbeat-interval' cannot be 0 (got %+v)", mem.Etcd)
  106. }
  107. if mem.Etcd.ElectionTimeoutMs == 0 {
  108. return nil, fmt.Errorf("'--election-timeout' cannot be 0 (got %+v)", mem.Etcd)
  109. }
  110. if int64(clus.Tester.DelayLatencyMs) <= mem.Etcd.ElectionTimeoutMs {
  111. return nil, fmt.Errorf("delay latency %d ms must be greater than election timeout %d ms", clus.Tester.DelayLatencyMs, mem.Etcd.ElectionTimeoutMs)
  112. }
  113. port := ""
  114. listenClientPorts := make([]string, len(clus.Members))
  115. for i, u := range mem.Etcd.ListenClientURLs {
  116. if !isValidURL(u) {
  117. return nil, fmt.Errorf("'--listen-client-urls' has valid URL %q", u)
  118. }
  119. listenClientPorts[i], err = getPort(u)
  120. if err != nil {
  121. return nil, fmt.Errorf("'--listen-client-urls' has no port %q", u)
  122. }
  123. }
  124. for i, u := range mem.Etcd.AdvertiseClientURLs {
  125. if !isValidURL(u) {
  126. return nil, fmt.Errorf("'--advertise-client-urls' has valid URL %q", u)
  127. }
  128. port, err = getPort(u)
  129. if err != nil {
  130. return nil, fmt.Errorf("'--advertise-client-urls' has no port %q", u)
  131. }
  132. if mem.EtcdClientProxy && listenClientPorts[i] == port {
  133. return nil, fmt.Errorf("clus.Members[%d] requires client port proxy, but advertise port %q conflicts with listener port %q", i, port, listenClientPorts[i])
  134. }
  135. }
  136. listenPeerPorts := make([]string, len(clus.Members))
  137. for i, u := range mem.Etcd.ListenPeerURLs {
  138. if !isValidURL(u) {
  139. return nil, fmt.Errorf("'--listen-peer-urls' has valid URL %q", u)
  140. }
  141. listenPeerPorts[i], err = getPort(u)
  142. if err != nil {
  143. return nil, fmt.Errorf("'--listen-peer-urls' has no port %q", u)
  144. }
  145. }
  146. for j, u := range mem.Etcd.AdvertisePeerURLs {
  147. if !isValidURL(u) {
  148. return nil, fmt.Errorf("'--initial-advertise-peer-urls' has valid URL %q", u)
  149. }
  150. port, err = getPort(u)
  151. if err != nil {
  152. return nil, fmt.Errorf("'--initial-advertise-peer-urls' has no port %q", u)
  153. }
  154. if mem.EtcdPeerProxy && listenPeerPorts[j] == port {
  155. return nil, fmt.Errorf("clus.Members[%d] requires peer port proxy, but advertise port %q conflicts with listener port %q", i, port, listenPeerPorts[j])
  156. }
  157. }
  158. if !strings.HasPrefix(mem.Etcd.DataDir, mem.BaseDir) {
  159. return nil, fmt.Errorf("Etcd.DataDir must be prefixed with BaseDir (got %q)", mem.Etcd.DataDir)
  160. }
  161. // TODO: support separate WALDir that can be handled via failure-archive
  162. if !strings.HasPrefix(mem.Etcd.WALDir, mem.BaseDir) {
  163. return nil, fmt.Errorf("Etcd.WALDir must be prefixed with BaseDir (got %q)", mem.Etcd.WALDir)
  164. }
  165. // TODO: only support generated certs with TLS generator
  166. // deprecate auto TLS
  167. if mem.Etcd.PeerAutoTLS && mem.Etcd.PeerCertFile != "" {
  168. return nil, fmt.Errorf("Etcd.PeerAutoTLS 'true', but Etcd.PeerCertFile is %q", mem.Etcd.PeerCertFile)
  169. }
  170. if mem.Etcd.PeerAutoTLS && mem.Etcd.PeerKeyFile != "" {
  171. return nil, fmt.Errorf("Etcd.PeerAutoTLS 'true', but Etcd.PeerKeyFile is %q", mem.Etcd.PeerKeyFile)
  172. }
  173. if mem.Etcd.PeerAutoTLS && mem.Etcd.PeerTrustedCAFile != "" {
  174. return nil, fmt.Errorf("Etcd.PeerAutoTLS 'true', but Etcd.PeerTrustedCAFile is %q", mem.Etcd.PeerTrustedCAFile)
  175. }
  176. if mem.Etcd.ClientAutoTLS && mem.Etcd.ClientCertFile != "" {
  177. return nil, fmt.Errorf("Etcd.ClientAutoTLS 'true', but Etcd.ClientCertFile is %q", mem.Etcd.ClientCertFile)
  178. }
  179. if mem.Etcd.ClientAutoTLS && mem.Etcd.ClientKeyFile != "" {
  180. return nil, fmt.Errorf("Etcd.ClientAutoTLS 'true', but Etcd.ClientKeyFile is %q", mem.Etcd.ClientKeyFile)
  181. }
  182. if mem.Etcd.ClientAutoTLS && mem.Etcd.ClientTrustedCAFile != "" {
  183. return nil, fmt.Errorf("Etcd.ClientAutoTLS 'true', but Etcd.ClientTrustedCAFile is %q", mem.Etcd.ClientTrustedCAFile)
  184. }
  185. if mem.Etcd.PeerClientCertAuth && mem.Etcd.PeerCertFile == "" {
  186. return nil, fmt.Errorf("Etcd.PeerClientCertAuth 'true', but Etcd.PeerCertFile is %q", mem.Etcd.PeerCertFile)
  187. }
  188. if mem.Etcd.PeerClientCertAuth && mem.Etcd.PeerKeyFile == "" {
  189. return nil, fmt.Errorf("Etcd.PeerClientCertAuth 'true', but Etcd.PeerKeyFile is %q", mem.Etcd.PeerCertFile)
  190. }
  191. // only support self-signed certs
  192. if mem.Etcd.PeerClientCertAuth && mem.Etcd.PeerTrustedCAFile == "" {
  193. return nil, fmt.Errorf("Etcd.PeerClientCertAuth 'true', but Etcd.PeerTrustedCAFile is %q", mem.Etcd.PeerCertFile)
  194. }
  195. if !mem.Etcd.PeerClientCertAuth && mem.Etcd.PeerCertFile != "" {
  196. return nil, fmt.Errorf("Etcd.PeerClientCertAuth 'false', but Etcd.PeerCertFile is %q", mem.Etcd.PeerCertFile)
  197. }
  198. if !mem.Etcd.PeerClientCertAuth && mem.Etcd.PeerKeyFile != "" {
  199. return nil, fmt.Errorf("Etcd.PeerClientCertAuth 'false', but Etcd.PeerKeyFile is %q", mem.Etcd.PeerCertFile)
  200. }
  201. if !mem.Etcd.PeerClientCertAuth && mem.Etcd.PeerTrustedCAFile != "" {
  202. return nil, fmt.Errorf("Etcd.PeerClientCertAuth 'false', but Etcd.PeerTrustedCAFile is %q", mem.Etcd.PeerTrustedCAFile)
  203. }
  204. if mem.Etcd.PeerClientCertAuth && mem.Etcd.PeerAutoTLS {
  205. return nil, fmt.Errorf("Etcd.PeerClientCertAuth and Etcd.PeerAutoTLS cannot be both 'true'")
  206. }
  207. if (mem.Etcd.PeerCertFile == "") != (mem.Etcd.PeerKeyFile == "") {
  208. return nil, fmt.Errorf("both Etcd.PeerCertFile %q and Etcd.PeerKeyFile %q must be either empty or non-empty", mem.Etcd.PeerCertFile, mem.Etcd.PeerKeyFile)
  209. }
  210. if mem.Etcd.ClientCertAuth && mem.Etcd.ClientAutoTLS {
  211. return nil, fmt.Errorf("Etcd.ClientCertAuth and Etcd.ClientAutoTLS cannot be both 'true'")
  212. }
  213. if mem.Etcd.ClientCertAuth && mem.Etcd.ClientCertFile == "" {
  214. return nil, fmt.Errorf("Etcd.ClientCertAuth 'true', but Etcd.ClientCertFile is %q", mem.Etcd.PeerCertFile)
  215. }
  216. if mem.Etcd.ClientCertAuth && mem.Etcd.ClientKeyFile == "" {
  217. return nil, fmt.Errorf("Etcd.ClientCertAuth 'true', but Etcd.ClientKeyFile is %q", mem.Etcd.PeerCertFile)
  218. }
  219. if mem.Etcd.ClientCertAuth && mem.Etcd.ClientTrustedCAFile == "" {
  220. return nil, fmt.Errorf("Etcd.ClientCertAuth 'true', but Etcd.ClientTrustedCAFile is %q", mem.Etcd.ClientTrustedCAFile)
  221. }
  222. if !mem.Etcd.ClientCertAuth && mem.Etcd.ClientCertFile != "" {
  223. return nil, fmt.Errorf("Etcd.ClientCertAuth 'false', but Etcd.ClientCertFile is %q", mem.Etcd.PeerCertFile)
  224. }
  225. if !mem.Etcd.ClientCertAuth && mem.Etcd.ClientKeyFile != "" {
  226. return nil, fmt.Errorf("Etcd.ClientCertAuth 'false', but Etcd.ClientKeyFile is %q", mem.Etcd.PeerCertFile)
  227. }
  228. if !mem.Etcd.ClientCertAuth && mem.Etcd.ClientTrustedCAFile != "" {
  229. return nil, fmt.Errorf("Etcd.ClientCertAuth 'false', but Etcd.ClientTrustedCAFile is %q", mem.Etcd.PeerCertFile)
  230. }
  231. if (mem.Etcd.ClientCertFile == "") != (mem.Etcd.ClientKeyFile == "") {
  232. return nil, fmt.Errorf("both Etcd.ClientCertFile %q and Etcd.ClientKeyFile %q must be either empty or non-empty", mem.Etcd.ClientCertFile, mem.Etcd.ClientKeyFile)
  233. }
  234. peerTLS := mem.Etcd.PeerAutoTLS ||
  235. (mem.Etcd.PeerClientCertAuth && mem.Etcd.PeerCertFile != "" && mem.Etcd.PeerKeyFile != "" && mem.Etcd.PeerTrustedCAFile != "")
  236. if peerTLS {
  237. for _, cu := range mem.Etcd.ListenPeerURLs {
  238. var u *url.URL
  239. u, err = url.Parse(cu)
  240. if err != nil {
  241. return nil, err
  242. }
  243. if u.Scheme != "https" { // TODO: support unix
  244. return nil, fmt.Errorf("peer TLS is enabled with wrong scheme %q", cu)
  245. }
  246. }
  247. for _, cu := range mem.Etcd.AdvertisePeerURLs {
  248. var u *url.URL
  249. u, err = url.Parse(cu)
  250. if err != nil {
  251. return nil, err
  252. }
  253. if u.Scheme != "https" { // TODO: support unix
  254. return nil, fmt.Errorf("peer TLS is enabled with wrong scheme %q", cu)
  255. }
  256. }
  257. clus.Members[i].PeerCertPath = mem.Etcd.PeerCertFile
  258. if mem.Etcd.PeerCertFile != "" {
  259. var data []byte
  260. data, err = ioutil.ReadFile(mem.Etcd.PeerCertFile)
  261. if err != nil {
  262. return nil, fmt.Errorf("failed to read %q (%v)", mem.Etcd.PeerCertFile, err)
  263. }
  264. clus.Members[i].PeerCertData = string(data)
  265. }
  266. clus.Members[i].PeerKeyPath = mem.Etcd.PeerKeyFile
  267. if mem.Etcd.PeerKeyFile != "" {
  268. var data []byte
  269. data, err = ioutil.ReadFile(mem.Etcd.PeerKeyFile)
  270. if err != nil {
  271. return nil, fmt.Errorf("failed to read %q (%v)", mem.Etcd.PeerKeyFile, err)
  272. }
  273. clus.Members[i].PeerCertData = string(data)
  274. }
  275. clus.Members[i].PeerTrustedCAPath = mem.Etcd.PeerTrustedCAFile
  276. if mem.Etcd.PeerTrustedCAFile != "" {
  277. var data []byte
  278. data, err = ioutil.ReadFile(mem.Etcd.PeerTrustedCAFile)
  279. if err != nil {
  280. return nil, fmt.Errorf("failed to read %q (%v)", mem.Etcd.PeerTrustedCAFile, err)
  281. }
  282. clus.Members[i].PeerCertData = string(data)
  283. }
  284. }
  285. clientTLS := mem.Etcd.ClientAutoTLS ||
  286. (mem.Etcd.ClientCertAuth && mem.Etcd.ClientCertFile != "" && mem.Etcd.ClientKeyFile != "" && mem.Etcd.ClientTrustedCAFile != "")
  287. if clientTLS {
  288. for _, cu := range mem.Etcd.ListenClientURLs {
  289. var u *url.URL
  290. u, err = url.Parse(cu)
  291. if err != nil {
  292. return nil, err
  293. }
  294. if u.Scheme != "https" { // TODO: support unix
  295. return nil, fmt.Errorf("client TLS is enabled with wrong scheme %q", cu)
  296. }
  297. }
  298. for _, cu := range mem.Etcd.AdvertiseClientURLs {
  299. var u *url.URL
  300. u, err = url.Parse(cu)
  301. if err != nil {
  302. return nil, err
  303. }
  304. if u.Scheme != "https" { // TODO: support unix
  305. return nil, fmt.Errorf("client TLS is enabled with wrong scheme %q", cu)
  306. }
  307. }
  308. clus.Members[i].ClientCertPath = mem.Etcd.ClientCertFile
  309. if mem.Etcd.ClientCertFile != "" {
  310. var data []byte
  311. data, err = ioutil.ReadFile(mem.Etcd.ClientCertFile)
  312. if err != nil {
  313. return nil, fmt.Errorf("failed to read %q (%v)", mem.Etcd.ClientCertFile, err)
  314. }
  315. clus.Members[i].ClientCertData = string(data)
  316. }
  317. clus.Members[i].ClientKeyPath = mem.Etcd.ClientKeyFile
  318. if mem.Etcd.ClientKeyFile != "" {
  319. var data []byte
  320. data, err = ioutil.ReadFile(mem.Etcd.ClientKeyFile)
  321. if err != nil {
  322. return nil, fmt.Errorf("failed to read %q (%v)", mem.Etcd.ClientKeyFile, err)
  323. }
  324. clus.Members[i].ClientCertData = string(data)
  325. }
  326. clus.Members[i].ClientTrustedCAPath = mem.Etcd.ClientTrustedCAFile
  327. if mem.Etcd.ClientTrustedCAFile != "" {
  328. var data []byte
  329. data, err = ioutil.ReadFile(mem.Etcd.ClientTrustedCAFile)
  330. if err != nil {
  331. return nil, fmt.Errorf("failed to read %q (%v)", mem.Etcd.ClientTrustedCAFile, err)
  332. }
  333. clus.Members[i].ClientCertData = string(data)
  334. }
  335. if len(mem.Etcd.LogOutputs) == 0 {
  336. return nil, fmt.Errorf("mem.Etcd.LogOutputs cannot be empty")
  337. }
  338. for _, v := range mem.Etcd.LogOutputs {
  339. switch v {
  340. case "stderr", "stdout", "/dev/null", "default":
  341. default:
  342. if !strings.HasPrefix(v, mem.BaseDir) {
  343. return nil, fmt.Errorf("LogOutput %q must be prefixed with BaseDir %q", v, mem.BaseDir)
  344. }
  345. }
  346. }
  347. }
  348. }
  349. return clus, err
  350. }