config.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /*
  2. Copyright 2014 CoreOS, Inc.
  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. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package etcdmain
  14. import (
  15. "errors"
  16. "flag"
  17. "fmt"
  18. "log"
  19. "net/url"
  20. "os"
  21. "strings"
  22. "github.com/coreos/etcd/etcdserver"
  23. "github.com/coreos/etcd/pkg/cors"
  24. "github.com/coreos/etcd/pkg/flags"
  25. "github.com/coreos/etcd/pkg/netutil"
  26. "github.com/coreos/etcd/pkg/transport"
  27. "github.com/coreos/etcd/version"
  28. )
  29. const (
  30. proxyFlagOff = "off"
  31. proxyFlagReadonly = "readonly"
  32. proxyFlagOn = "on"
  33. fallbackFlagExit = "exit"
  34. fallbackFlagProxy = "proxy"
  35. clusterStateFlagNew = "new"
  36. clusterStateFlagExisting = "existing"
  37. )
  38. var (
  39. ignored = []string{
  40. "cluster-active-size",
  41. "cluster-remove-delay",
  42. "cluster-sync-interval",
  43. "config",
  44. "force",
  45. "max-result-buffer",
  46. "max-retry-attempts",
  47. "peer-heartbeat-interval",
  48. "peer-election-timeout",
  49. "retry-interval",
  50. "snapshot",
  51. "v",
  52. "vv",
  53. }
  54. ErrConflictBootstrapFlags = fmt.Errorf("multiple discovery or bootstrap flags are set" +
  55. "Choose one of \"initial-cluster\", \"discovery\" or \"discovery-srv\"")
  56. )
  57. type config struct {
  58. *flag.FlagSet
  59. // member
  60. corsInfo *cors.CORSInfo
  61. dir string
  62. lpurls, lcurls []url.URL
  63. maxSnapFiles uint
  64. maxWalFiles uint
  65. name string
  66. snapCount uint64
  67. // TODO: decouple tickMs and heartbeat tick (current heartbeat tick = 1).
  68. // make ticks a cluster wide configuration.
  69. TickMs uint
  70. ElectionMs uint
  71. // clustering
  72. apurls, acurls []url.URL
  73. clusterState *flags.StringsFlag
  74. dnsCluster string
  75. dproxy string
  76. durl string
  77. fallback *flags.StringsFlag
  78. initialCluster string
  79. initialClusterToken string
  80. // proxy
  81. proxy *flags.StringsFlag
  82. // security
  83. clientTLSInfo, peerTLSInfo transport.TLSInfo
  84. // unsafe
  85. forceNewCluster bool
  86. printVersion bool
  87. ignored []string
  88. }
  89. func NewConfig() *config {
  90. cfg := &config{
  91. corsInfo: &cors.CORSInfo{},
  92. clusterState: flags.NewStringsFlag(
  93. clusterStateFlagNew,
  94. clusterStateFlagExisting,
  95. ),
  96. fallback: flags.NewStringsFlag(
  97. fallbackFlagExit,
  98. fallbackFlagProxy,
  99. ),
  100. ignored: ignored,
  101. proxy: flags.NewStringsFlag(
  102. proxyFlagOff,
  103. proxyFlagReadonly,
  104. proxyFlagOn,
  105. ),
  106. }
  107. cfg.FlagSet = flag.NewFlagSet("etcd", flag.ContinueOnError)
  108. fs := cfg.FlagSet
  109. fs.Usage = func() {
  110. fmt.Println(usageline)
  111. fmt.Println(flagsline)
  112. }
  113. // member
  114. fs.Var(cfg.corsInfo, "cors", "Comma-separated white list of origins for CORS (cross-origin resource sharing).")
  115. fs.StringVar(&cfg.dir, "data-dir", "", "Path to the data directory")
  116. fs.Var(flags.NewURLsValue("http://localhost:2380,http://localhost:7001"), "listen-peer-urls", "List of URLs to listen on for peer traffic")
  117. fs.Var(flags.NewURLsValue("http://localhost:2379,http://localhost:4001"), "listen-client-urls", "List of URLs to listen on for client traffic")
  118. fs.UintVar(&cfg.maxSnapFiles, "max-snapshots", defaultMaxSnapshots, "Maximum number of snapshot files to retain (0 is unlimited)")
  119. fs.UintVar(&cfg.maxWalFiles, "max-wals", defaultMaxWALs, "Maximum number of wal files to retain (0 is unlimited)")
  120. fs.StringVar(&cfg.name, "name", "default", "Unique human-readable name for this node")
  121. fs.Uint64Var(&cfg.snapCount, "snapshot-count", etcdserver.DefaultSnapCount, "Number of committed transactions to trigger a snapshot")
  122. fs.UintVar(&cfg.TickMs, "heartbeat-interval", 100, "Time (in milliseconds) of a heartbeat interval.")
  123. fs.UintVar(&cfg.ElectionMs, "election-timeout", 1000, "Time (in milliseconds) for an election to timeout.")
  124. // clustering
  125. fs.Var(flags.NewURLsValue("http://localhost:2380,http://localhost:7001"), "initial-advertise-peer-urls", "List of this member's peer URLs to advertise to the rest of the cluster")
  126. fs.Var(flags.NewURLsValue("http://localhost:2379,http://localhost:4001"), "advertise-client-urls", "List of this member's client URLs to advertise to the rest of the cluster")
  127. fs.StringVar(&cfg.durl, "discovery", "", "Discovery service used to bootstrap the initial cluster")
  128. fs.Var(cfg.fallback, "discovery-fallback", fmt.Sprintf("Valid values include %s", strings.Join(cfg.fallback.Values, ", ")))
  129. if err := cfg.fallback.Set(fallbackFlagProxy); err != nil {
  130. // Should never happen.
  131. log.Panicf("unexpected error setting up discovery-fallback flag: %v", err)
  132. }
  133. fs.StringVar(&cfg.dproxy, "discovery-proxy", "", "HTTP proxy to use for traffic to discovery service")
  134. fs.StringVar(&cfg.dnsCluster, "discovery-srv", "", "DNS domain used to bootstrap initial cluster")
  135. fs.StringVar(&cfg.initialCluster, "initial-cluster", "default=http://localhost:2380,default=http://localhost:7001", "Initial cluster configuration for bootstrapping")
  136. fs.StringVar(&cfg.initialClusterToken, "initial-cluster-token", "etcd-cluster", "Initial cluster token for the etcd cluster during bootstrap")
  137. fs.Var(cfg.clusterState, "initial-cluster-state", "Initial cluster configuration for bootstrapping")
  138. if err := cfg.clusterState.Set(clusterStateFlagNew); err != nil {
  139. // Should never happen.
  140. log.Panicf("unexpected error setting up clusterStateFlag: %v", err)
  141. }
  142. // proxy
  143. fs.Var(cfg.proxy, "proxy", fmt.Sprintf("Valid values include %s", strings.Join(cfg.proxy.Values, ", ")))
  144. if err := cfg.proxy.Set(proxyFlagOff); err != nil {
  145. // Should never happen.
  146. log.Panicf("unexpected error setting up proxyFlag: %v", err)
  147. }
  148. // security
  149. fs.StringVar(&cfg.clientTLSInfo.CAFile, "ca-file", "", "Path to the client server TLS CA file.")
  150. fs.StringVar(&cfg.clientTLSInfo.CertFile, "cert-file", "", "Path to the client server TLS cert file.")
  151. fs.StringVar(&cfg.clientTLSInfo.KeyFile, "key-file", "", "Path to the client server TLS key file.")
  152. fs.StringVar(&cfg.peerTLSInfo.CAFile, "peer-ca-file", "", "Path to the peer server TLS CA file.")
  153. fs.StringVar(&cfg.peerTLSInfo.CertFile, "peer-cert-file", "", "Path to the peer server TLS cert file.")
  154. fs.StringVar(&cfg.peerTLSInfo.KeyFile, "peer-key-file", "", "Path to the peer server TLS key file.")
  155. // unsafe
  156. fs.BoolVar(&cfg.forceNewCluster, "force-new-cluster", false, "Force to create a new one member cluster")
  157. // version
  158. fs.BoolVar(&cfg.printVersion, "version", false, "Print the version and exit")
  159. // backwards-compatibility with v0.4.6
  160. fs.Var(&flags.IPAddressPort{}, "addr", "DEPRECATED: Use -advertise-client-urls instead.")
  161. fs.Var(&flags.IPAddressPort{}, "bind-addr", "DEPRECATED: Use -listen-client-urls instead.")
  162. fs.Var(&flags.IPAddressPort{}, "peer-addr", "DEPRECATED: Use -initial-advertise-peer-urls instead.")
  163. fs.Var(&flags.IPAddressPort{}, "peer-bind-addr", "DEPRECATED: Use -listen-peer-urls instead.")
  164. fs.Var(&flags.DeprecatedFlag{Name: "peers"}, "peers", "DEPRECATED: Use -initial-cluster instead")
  165. fs.Var(&flags.DeprecatedFlag{Name: "peers-file"}, "peers-file", "DEPRECATED: Use -initial-cluster instead")
  166. // ignored
  167. for _, f := range cfg.ignored {
  168. fs.Var(&flags.IgnoredFlag{Name: f}, f, "")
  169. }
  170. return cfg
  171. }
  172. func (cfg *config) Parse(arguments []string) error {
  173. perr := cfg.FlagSet.Parse(arguments)
  174. switch perr {
  175. case nil:
  176. case flag.ErrHelp:
  177. os.Exit(0)
  178. default:
  179. os.Exit(2)
  180. }
  181. if cfg.printVersion {
  182. fmt.Println("etcd version", version.Version)
  183. os.Exit(0)
  184. }
  185. err := flags.SetFlagsFromEnv(cfg.FlagSet)
  186. if err != nil {
  187. log.Fatalf("etcd: %v", err)
  188. }
  189. set := make(map[string]bool)
  190. cfg.FlagSet.Visit(func(f *flag.Flag) {
  191. set[f.Name] = true
  192. })
  193. nSet := 0
  194. for _, v := range []bool{set["discovery"], set["initial-cluster"], set["discovery-srv"]} {
  195. if v {
  196. nSet += 1
  197. }
  198. }
  199. if nSet > 1 {
  200. return ErrConflictBootstrapFlags
  201. }
  202. cfg.lpurls, err = flags.URLsFromFlags(cfg.FlagSet, "listen-peer-urls", "peer-bind-addr", cfg.peerTLSInfo)
  203. if err != nil {
  204. return err
  205. }
  206. cfg.apurls, err = flags.URLsFromFlags(cfg.FlagSet, "initial-advertise-peer-urls", "peer-addr", cfg.peerTLSInfo)
  207. if err != nil {
  208. return err
  209. }
  210. cfg.lcurls, err = flags.URLsFromFlags(cfg.FlagSet, "listen-client-urls", "bind-addr", cfg.clientTLSInfo)
  211. if err != nil {
  212. return err
  213. }
  214. cfg.acurls, err = flags.URLsFromFlags(cfg.FlagSet, "advertise-client-urls", "addr", cfg.clientTLSInfo)
  215. if err != nil {
  216. return err
  217. }
  218. if err := cfg.resolveUrls(); err != nil {
  219. return errors.New("cannot resolve DNS hostnames.")
  220. }
  221. return nil
  222. }
  223. func (cfg *config) resolveUrls() error {
  224. return netutil.ResolveTCPAddrs(cfg.lpurls, cfg.apurls, cfg.lcurls, cfg.acurls)
  225. }
  226. func (cfg config) isNewCluster() bool { return cfg.clusterState.String() == clusterStateFlagNew }
  227. func (cfg config) isProxy() bool { return cfg.proxy.String() != proxyFlagOff }
  228. func (cfg config) isReadonlyProxy() bool { return cfg.proxy.String() == proxyFlagReadonly }
  229. func (cfg config) shouldFallbackToProxy() bool { return cfg.fallback.String() == fallbackFlagProxy }
  230. func (cfg config) electionTicks() int { return int(cfg.ElectionMs / cfg.TickMs) }