blob: 6113b3ac3533e4e8db5485fe60233203048f07e1 [file] [log] [blame]
khenaidoo59ce9dd2019-11-11 13:05:32 -05001/*
2 * Copyright 2019-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
khenaidoob6238b32020-04-07 12:07:36 -040016package etcd
khenaidoo59ce9dd2019-11-11 13:05:32 -050017
18import (
Neha Sharma94f16a92020-06-26 04:17:55 +000019 "context"
khenaidooc7005fc2019-11-18 19:23:57 -050020 "fmt"
khenaidoo59ce9dd2019-11-11 13:05:32 -050021 "go.etcd.io/etcd/embed"
khenaidooc7005fc2019-11-18 19:23:57 -050022 "net/url"
khenaidoo59ce9dd2019-11-11 13:05:32 -050023 "os"
24 "time"
25)
26
27const (
khenaidooc7005fc2019-11-18 19:23:57 -050028 serverStartUpTimeout = 10 * time.Second // Maximum time allowed to wait for the Etcd server to be ready
29 defaultLocalPersistentStorage = "voltha.test.embed.etcd"
khenaidoo59ce9dd2019-11-11 13:05:32 -050030)
31
32//EtcdServer represents an embedded Etcd server. It is used for testing only.
33type EtcdServer struct {
34 server *embed.Etcd
35}
36
khenaidooc7005fc2019-11-18 19:23:57 -050037func islogLevelValid(logLevel string) bool {
38 valid := []string{"debug", "info", "warn", "error", "panic", "fatal"}
39 for _, l := range valid {
40 if l == logLevel {
41 return true
42 }
43 }
44 return false
45}
46
47/*
48* MKConfig creates an embedded Etcd config
49* :param configName: A name for this config
50* :param clientPort: The port the etcd client will connect to (do not use 2379 for unit test)
51* :param peerPort: The port the etcd server will listen for its peers (do not use 2380 for unit test)
52* :param localPersistentStorageDir: The name of a local directory which will hold the Etcd server data
53* :param logLevel: One of debug, info, warn, error, panic, or fatal. Default 'info'.
54 */
Neha Sharma94f16a92020-06-26 04:17:55 +000055func MKConfig(ctx context.Context, configName string, clientPort, peerPort int, localPersistentStorageDir string, logLevel string) *embed.Config {
khenaidooc7005fc2019-11-18 19:23:57 -050056 cfg := embed.NewConfig()
57 cfg.Name = configName
58 cfg.Dir = localPersistentStorageDir
59 cfg.Logger = "zap"
60 if !islogLevelValid(logLevel) {
Neha Sharma94f16a92020-06-26 04:17:55 +000061 logger.Fatalf(ctx, "Invalid log level -%s", logLevel)
khenaidooc7005fc2019-11-18 19:23:57 -050062 }
63 cfg.LogLevel = logLevel
64 acurl, err := url.Parse(fmt.Sprintf("http://localhost:%d", clientPort))
65 if err != nil {
Neha Sharma94f16a92020-06-26 04:17:55 +000066 logger.Fatalf(ctx, "Invalid client port -%d", clientPort)
khenaidooc7005fc2019-11-18 19:23:57 -050067 }
68 cfg.ACUrls = []url.URL{*acurl}
69 cfg.LCUrls = []url.URL{*acurl}
70
71 apurl, err := url.Parse(fmt.Sprintf("http://localhost:%d", peerPort))
72 if err != nil {
Neha Sharma94f16a92020-06-26 04:17:55 +000073 logger.Fatalf(ctx, "Invalid peer port -%d", peerPort)
khenaidooc7005fc2019-11-18 19:23:57 -050074 }
75 cfg.LPUrls = []url.URL{*apurl}
76 cfg.APUrls = []url.URL{*apurl}
77
78 cfg.ClusterState = embed.ClusterStateFlagNew
79 cfg.InitialCluster = cfg.Name + "=" + apurl.String()
80
81 return cfg
82}
83
khenaidoo59ce9dd2019-11-11 13:05:32 -050084//getDefaultCfg specifies the default config
85func getDefaultCfg() *embed.Config {
86 cfg := embed.NewConfig()
khenaidooc7005fc2019-11-18 19:23:57 -050087 cfg.Dir = defaultLocalPersistentStorage
khenaidoo59ce9dd2019-11-11 13:05:32 -050088 cfg.Logger = "zap"
89 cfg.LogLevel = "error"
90 return cfg
91}
92
93//StartEtcdServer creates and starts an embedded Etcd server. A local directory to store data is created for the
94//embedded server lifetime (for the duration of a unit test. The server runs at localhost:2379.
Neha Sharma94f16a92020-06-26 04:17:55 +000095func StartEtcdServer(ctx context.Context, cfg *embed.Config) *EtcdServer {
khenaidoo59ce9dd2019-11-11 13:05:32 -050096 // If the server is already running, just return
97 if cfg == nil {
98 cfg = getDefaultCfg()
99 }
100 // Remove the local directory as
101 // a safeguard for the case where a prior test failed
khenaidooc7005fc2019-11-18 19:23:57 -0500102 if err := os.RemoveAll(cfg.Dir); err != nil {
Neha Sharma94f16a92020-06-26 04:17:55 +0000103 logger.Fatalf(ctx, "Failure removing local directory %s", cfg.Dir)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500104 }
105 e, err := embed.StartEtcd(cfg)
106 if err != nil {
Neha Sharma94f16a92020-06-26 04:17:55 +0000107 logger.Fatal(ctx, err)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500108 }
109 select {
110 case <-e.Server.ReadyNotify():
Neha Sharma94f16a92020-06-26 04:17:55 +0000111 logger.Debug(ctx, "Embedded Etcd server is ready!")
khenaidoo59ce9dd2019-11-11 13:05:32 -0500112 case <-time.After(serverStartUpTimeout):
113 e.Server.HardStop() // trigger a shutdown
114 e.Close()
Neha Sharma94f16a92020-06-26 04:17:55 +0000115 logger.Fatal(ctx, "Embedded Etcd server took too long to start!")
khenaidoo59ce9dd2019-11-11 13:05:32 -0500116 case err := <-e.Err():
117 e.Server.HardStop() // trigger a shutdown
118 e.Close()
Neha Sharma94f16a92020-06-26 04:17:55 +0000119 logger.Fatalf(ctx, "Embedded Etcd server errored out - %s", err)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500120 }
121 return &EtcdServer{server: e}
122}
123
124//Stop closes the embedded Etcd server and removes the local data directory as well
Neha Sharma94f16a92020-06-26 04:17:55 +0000125func (es *EtcdServer) Stop(ctx context.Context) {
khenaidoo59ce9dd2019-11-11 13:05:32 -0500126 if es != nil {
khenaidooc7005fc2019-11-18 19:23:57 -0500127 storage := es.server.Config().Dir
khenaidoo59ce9dd2019-11-11 13:05:32 -0500128 es.server.Server.HardStop()
129 es.server.Close()
khenaidooc7005fc2019-11-18 19:23:57 -0500130 if err := os.RemoveAll(storage); err != nil {
Neha Sharma94f16a92020-06-26 04:17:55 +0000131 logger.Fatalf(ctx, "Failure removing local directory %s", es.server.Config().Dir)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500132 }
133 }
134}