blob: 487b9911c8499c293bc9bf328367dbe21892f1c5 [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 */
16package mocks
17
18import (
khenaidooc7005fc2019-11-18 19:23:57 -050019 "fmt"
khenaidoo59ce9dd2019-11-11 13:05:32 -050020 "go.etcd.io/etcd/embed"
khenaidooc7005fc2019-11-18 19:23:57 -050021 "net/url"
khenaidoo59ce9dd2019-11-11 13:05:32 -050022 "os"
23 "time"
24)
25
26const (
khenaidooc7005fc2019-11-18 19:23:57 -050027 serverStartUpTimeout = 10 * time.Second // Maximum time allowed to wait for the Etcd server to be ready
28 defaultLocalPersistentStorage = "voltha.test.embed.etcd"
khenaidoo59ce9dd2019-11-11 13:05:32 -050029)
30
31//EtcdServer represents an embedded Etcd server. It is used for testing only.
32type EtcdServer struct {
33 server *embed.Etcd
34}
35
khenaidooc7005fc2019-11-18 19:23:57 -050036func islogLevelValid(logLevel string) bool {
37 valid := []string{"debug", "info", "warn", "error", "panic", "fatal"}
38 for _, l := range valid {
39 if l == logLevel {
40 return true
41 }
42 }
43 return false
44}
45
46/*
47* MKConfig creates an embedded Etcd config
48* :param configName: A name for this config
49* :param clientPort: The port the etcd client will connect to (do not use 2379 for unit test)
50* :param peerPort: The port the etcd server will listen for its peers (do not use 2380 for unit test)
51* :param localPersistentStorageDir: The name of a local directory which will hold the Etcd server data
52* :param logLevel: One of debug, info, warn, error, panic, or fatal. Default 'info'.
53 */
54func MKConfig(configName string, clientPort, peerPort int, localPersistentStorageDir string, logLevel string) *embed.Config {
55 cfg := embed.NewConfig()
56 cfg.Name = configName
57 cfg.Dir = localPersistentStorageDir
58 cfg.Logger = "zap"
59 if !islogLevelValid(logLevel) {
khenaidoob332f9b2020-01-16 16:25:26 -050060 logger.Fatalf("Invalid log level -%s", logLevel)
khenaidooc7005fc2019-11-18 19:23:57 -050061 }
62 cfg.LogLevel = logLevel
63 acurl, err := url.Parse(fmt.Sprintf("http://localhost:%d", clientPort))
64 if err != nil {
khenaidoob332f9b2020-01-16 16:25:26 -050065 logger.Fatalf("Invalid client port -%d", clientPort)
khenaidooc7005fc2019-11-18 19:23:57 -050066 }
67 cfg.ACUrls = []url.URL{*acurl}
68 cfg.LCUrls = []url.URL{*acurl}
69
70 apurl, err := url.Parse(fmt.Sprintf("http://localhost:%d", peerPort))
71 if err != nil {
khenaidoob332f9b2020-01-16 16:25:26 -050072 logger.Fatalf("Invalid peer port -%d", peerPort)
khenaidooc7005fc2019-11-18 19:23:57 -050073 }
74 cfg.LPUrls = []url.URL{*apurl}
75 cfg.APUrls = []url.URL{*apurl}
76
77 cfg.ClusterState = embed.ClusterStateFlagNew
78 cfg.InitialCluster = cfg.Name + "=" + apurl.String()
79
80 return cfg
81}
82
khenaidoo59ce9dd2019-11-11 13:05:32 -050083//getDefaultCfg specifies the default config
84func getDefaultCfg() *embed.Config {
85 cfg := embed.NewConfig()
khenaidooc7005fc2019-11-18 19:23:57 -050086 cfg.Dir = defaultLocalPersistentStorage
khenaidoo59ce9dd2019-11-11 13:05:32 -050087 cfg.Logger = "zap"
88 cfg.LogLevel = "error"
89 return cfg
90}
91
92//StartEtcdServer creates and starts an embedded Etcd server. A local directory to store data is created for the
93//embedded server lifetime (for the duration of a unit test. The server runs at localhost:2379.
94func StartEtcdServer(cfg *embed.Config) *EtcdServer {
95 // If the server is already running, just return
96 if cfg == nil {
97 cfg = getDefaultCfg()
98 }
99 // Remove the local directory as
100 // a safeguard for the case where a prior test failed
khenaidooc7005fc2019-11-18 19:23:57 -0500101 if err := os.RemoveAll(cfg.Dir); err != nil {
khenaidoob332f9b2020-01-16 16:25:26 -0500102 logger.Fatalf("Failure removing local directory %s", cfg.Dir)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500103 }
104 e, err := embed.StartEtcd(cfg)
105 if err != nil {
khenaidoob332f9b2020-01-16 16:25:26 -0500106 logger.Fatal(err)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500107 }
108 select {
109 case <-e.Server.ReadyNotify():
khenaidoob332f9b2020-01-16 16:25:26 -0500110 logger.Debug("Embedded Etcd server is ready!")
khenaidoo59ce9dd2019-11-11 13:05:32 -0500111 case <-time.After(serverStartUpTimeout):
112 e.Server.HardStop() // trigger a shutdown
113 e.Close()
khenaidoob332f9b2020-01-16 16:25:26 -0500114 logger.Fatal("Embedded Etcd server took too long to start!")
khenaidoo59ce9dd2019-11-11 13:05:32 -0500115 case err := <-e.Err():
116 e.Server.HardStop() // trigger a shutdown
117 e.Close()
khenaidoob332f9b2020-01-16 16:25:26 -0500118 logger.Fatalf("Embedded Etcd server errored out - %s", err)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500119 }
120 return &EtcdServer{server: e}
121}
122
123//Stop closes the embedded Etcd server and removes the local data directory as well
124func (es *EtcdServer) Stop() {
125 if es != nil {
khenaidooc7005fc2019-11-18 19:23:57 -0500126 storage := es.server.Config().Dir
khenaidoo59ce9dd2019-11-11 13:05:32 -0500127 es.server.Server.HardStop()
128 es.server.Close()
khenaidooc7005fc2019-11-18 19:23:57 -0500129 if err := os.RemoveAll(storage); err != nil {
khenaidoob332f9b2020-01-16 16:25:26 -0500130 logger.Fatalf("Failure removing local directory %s", es.server.Config().Dir)
khenaidoo59ce9dd2019-11-11 13:05:32 -0500131 }
132 }
133}