524b01aa62e1bddf3fd3fc6fa2a69c29ff6e2a9e
[icn/sdwan.git] /
1 // SPDX-License-Identifier: Apache-2.0
2 // Copyright (c) 2020 Intel Corporation
3
4 package contextdb
5
6 import (
7         "context"
8         "encoding/json"
9         "os"
10         "time"
11
12         pkgerrors "github.com/pkg/errors"
13         "go.etcd.io/etcd/clientv3"
14 )
15
16 // EtcdConfig Configuration values needed for Etcd Client
17 type EtcdConfig struct {
18         Endpoint string
19         CertFile string
20         KeyFile  string
21         CAFile   string
22 }
23
24 // EtcdClient for Etcd
25 type EtcdClient struct {
26         cli      *clientv3.Client
27         endpoint string
28 }
29
30 // Etcd For Mocking purposes
31 type Etcd interface {
32         Put(ctx context.Context, key, val string, opts ...clientv3.OpOption) (*clientv3.PutResponse, error)
33         Get(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error)
34         Delete(ctx context.Context, key string, opts ...clientv3.OpOption) (*clientv3.DeleteResponse, error)
35 }
36
37 var getEtcd = func(e *EtcdClient) Etcd {
38         return e.cli
39 }
40
41 // NewEtcdClient function initializes Etcd client
42 func NewEtcdClient(store *clientv3.Client, c EtcdConfig) (ContextDb, error) {
43         var endpoint string
44         if store == nil {
45                 endpoint = "http://" + c.Endpoint + ":2379"
46
47                 etcdClient := clientv3.Config{
48                         Endpoints:   []string{endpoint},
49                         DialTimeout: 5 * time.Second,
50                 }
51                 if len(os.Getenv("CONTEXTDB_EMCO_USERNAME")) > 0 && len(os.Getenv("CONTEXTDB_EMCO_PASSWORD")) > 0 {
52                         etcdClient.Username = os.Getenv("CONTEXTDB_EMCO_USERNAME")
53                         etcdClient.Password = os.Getenv("CONTEXTDB_EMCO_PASSWORD")
54                 }
55                 var err error
56                 store, err = clientv3.New(etcdClient)
57                 if err != nil {
58                         return nil, pkgerrors.Errorf("Error creating etcd client: %s", err.Error())
59                 }
60         }
61
62         return &EtcdClient{
63                 cli:      store,
64                 endpoint: endpoint,
65         }, nil
66 }
67
68 // Put values in Etcd DB
69 func (e *EtcdClient) Put(key string, value interface{}) error {
70         cli := getEtcd(e)
71         if cli == nil {
72                 return pkgerrors.Errorf("Etcd Client not initialized")
73         }
74         if key == "" {
75                 return pkgerrors.Errorf("Key is null")
76         }
77         if value == nil {
78                 return pkgerrors.Errorf("Value is nil")
79         }
80         v, err := json.Marshal(value)
81         if err != nil {
82                 return pkgerrors.Errorf("Json Marshal error: %s", err.Error())
83         }
84         _, err = cli.Put(context.Background(), key, string(v))
85         if err != nil {
86                 return pkgerrors.Errorf("Error creating etcd entry: %s", err.Error())
87         }
88         return nil
89 }
90
91 // Get values from Etcd DB and decodes from json
92 func (e *EtcdClient) Get(key string, value interface{}) error {
93         cli := getEtcd(e)
94         if cli == nil {
95                 return pkgerrors.Errorf("Etcd Client not initialized")
96         }
97         if key == "" {
98                 return pkgerrors.Errorf("Key is null")
99         }
100         if value == nil {
101                 return pkgerrors.Errorf("Value is nil")
102         }
103         getResp, err := cli.Get(context.Background(), key)
104         if err != nil {
105                 return pkgerrors.Errorf("Error getting etcd entry: %s", err.Error())
106         }
107         if getResp.Count == 0 {
108                 return pkgerrors.Errorf("Key doesn't exist")
109         }
110         return json.Unmarshal(getResp.Kvs[0].Value, value)
111 }
112
113 // GetAllKeys values from Etcd DB
114 func (e *EtcdClient) GetAllKeys(key string) ([]string, error) {
115         cli := getEtcd(e)
116         if cli == nil {
117                 return nil, pkgerrors.Errorf("Etcd Client not initialized")
118         }
119         getResp, err := cli.Get(context.Background(), key, clientv3.WithPrefix())
120         if err != nil {
121                 return nil, pkgerrors.Errorf("Error getting etcd entry: %s", err.Error())
122         }
123         if getResp.Count == 0 {
124                 return nil, pkgerrors.Errorf("Key doesn't exist")
125         }
126         var keys []string
127         for _, ev := range getResp.Kvs {
128                 keys = append(keys, string(ev.Key))
129         }
130         return keys, nil
131 }
132
133 // DeleteAll keys from Etcd DB
134 func (e *EtcdClient) DeleteAll(key string) error {
135         cli := getEtcd(e)
136         if cli == nil {
137                 return pkgerrors.Errorf("Etcd Client not initialized")
138         }
139         _, err := cli.Delete(context.Background(), key, clientv3.WithPrefix())
140         if err != nil {
141                 return pkgerrors.Errorf("Delete failed etcd entry: %s", err.Error())
142         }
143         return nil
144 }
145
146 // Delete values from Etcd DB
147 func (e *EtcdClient) Delete(key string) error {
148         cli := getEtcd(e)
149         if cli == nil {
150                 return pkgerrors.Errorf("Etcd Client not initialized")
151         }
152         _, err := cli.Delete(context.Background(), key)
153         if err != nil {
154                 return pkgerrors.Errorf("Delete failed etcd entry: %s", err.Error())
155         }
156         return nil
157 }
158
159 // HealthCheck for checking health of the etcd cluster
160 func (e *EtcdClient) HealthCheck() error {
161         return nil
162 }