blob: dc0e6bd8812f78617edcb2690c7313123f87f3c9 [file] [log] [blame]
khenaidoobf6e7bb2018-08-14 22:27:29 -04001/*
2 * Copyright 2018-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 */
Stephane Barbariedc5022d2018-11-19 15:21:44 -050016
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040017package model
18
19import (
20 "errors"
21 "fmt"
khenaidoob9203542018-09-17 22:56:37 -040022 "github.com/opencord/voltha-go/common/log"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040023 "github.com/opencord/voltha-go/db/kvstore"
24 "strconv"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050025 "sync"
Stephane Barbarieec0919b2018-09-05 14:14:29 -040026 "time"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040027)
28
29//TODO: missing cache stuff
30//TODO: missing retry stuff
31//TODO: missing proper logging
32
Stephane Barbariedc5022d2018-11-19 15:21:44 -050033// Backend structure holds details for accessing the kv store
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040034type Backend struct {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050035 sync.RWMutex
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040036 Client kvstore.Client
37 StoreType string
38 Host string
39 Port int
40 Timeout int
41 PathPrefix string
42}
43
Stephane Barbariedc5022d2018-11-19 15:21:44 -050044// NewBackend creates a new instance of a Backend structure
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040045func NewBackend(storeType string, host string, port int, timeout int, pathPrefix string) *Backend {
46 var err error
47
48 b := &Backend{
49 StoreType: storeType,
50 Host: host,
51 Port: port,
52 Timeout: timeout,
53 PathPrefix: pathPrefix,
54 }
55
56 address := host + ":" + strconv.Itoa(port)
57 if b.Client, err = b.newClient(address, timeout); err != nil {
Stephane Barbariee0a4c792019-01-16 11:26:29 -050058 log.Errorw("failed-to-create-kv-client",
59 log.Fields{
60 "type": storeType, "host": host, "port": port,
61 "timeout": timeout, "prefix": pathPrefix,
62 "error": err.Error(),
63 })
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040064 }
65
66 return b
67}
68
69func (b *Backend) newClient(address string, timeout int) (kvstore.Client, error) {
70 switch b.StoreType {
71 case "consul":
72 return kvstore.NewConsulClient(address, timeout)
73 case "etcd":
74 return kvstore.NewEtcdClient(address, timeout)
75 }
Stephane Barbariee0a4c792019-01-16 11:26:29 -050076 return nil, errors.New("unsupported-kv-store")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040077}
78
79func (b *Backend) makePath(key string) string {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040080 path := fmt.Sprintf("%s/%s", b.PathPrefix, key)
Stephane Barbarieec0919b2018-09-05 14:14:29 -040081 return path
82}
Stephane Barbariedc5022d2018-11-19 15:21:44 -050083
84// List retrieves one or more items that match the specified key
Stephane Barbarieec0919b2018-09-05 14:14:29 -040085func (b *Backend) List(key string) (map[string]*kvstore.KVPair, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050086 b.Lock()
87 defer b.Unlock()
88
89 formattedPath := b.makePath(key)
Stephane Barbariee0a4c792019-01-16 11:26:29 -050090 log.Debugw("listing-key", log.Fields{"key": key, "path": formattedPath})
Stephane Barbariedc5022d2018-11-19 15:21:44 -050091
92 return b.Client.List(formattedPath, b.Timeout)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040093}
Stephane Barbariedc5022d2018-11-19 15:21:44 -050094
95// Get retrieves an item that matches the specified key
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040096func (b *Backend) Get(key string) (*kvstore.KVPair, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050097 b.Lock()
98 defer b.Unlock()
99
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400100 formattedPath := b.makePath(key)
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500101 log.Debugw("getting-key", log.Fields{"key": key, "path": formattedPath})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500102
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400103 start := time.Now()
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400104 err, pair := b.Client.Get(formattedPath, b.Timeout)
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400105 stop := time.Now()
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500106
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400107 GetProfiling().AddToDatabaseRetrieveTime(stop.Sub(start).Seconds())
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500108
Stephane Barbarieec0919b2018-09-05 14:14:29 -0400109 return err, pair
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400110}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500111
112// Put stores an item value under the specifed key
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400113func (b *Backend) Put(key string, value interface{}) error {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500114 b.Lock()
115 defer b.Unlock()
116
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400117 formattedPath := b.makePath(key)
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500118 log.Debugw("putting-key", log.Fields{"key": key, "value": string(value.([]byte)), "path": formattedPath})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500119
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400120 return b.Client.Put(formattedPath, value, b.Timeout)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400121}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500122
123// Delete removes an item under the specified key
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400124func (b *Backend) Delete(key string) error {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500125 b.Lock()
126 defer b.Unlock()
127
128 formattedPath := b.makePath(key)
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500129 log.Debugw("deleting-key", log.Fields{"key": key, "path": formattedPath})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500130
131 return b.Client.Delete(formattedPath, b.Timeout)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400132}
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500133
134// CreateWatch starts watching events for the specified key
135func (b *Backend) CreateWatch(key string) chan *kvstore.Event {
136 b.Lock()
137 defer b.Unlock()
138
139 formattedPath := b.makePath(key)
140 log.Debugw("creating-key-watch", log.Fields{"key": key, "path": formattedPath})
141
142 return b.Client.Watch(formattedPath)
143}
144
145// DeleteWatch stops watching events for the specified key
146func (b *Backend) DeleteWatch(key string, ch chan *kvstore.Event) {
147 b.Lock()
148 defer b.Unlock()
149
150 formattedPath := b.makePath(key)
151 log.Debugw("deleting-key-watch", log.Fields{"key": key, "path": formattedPath})
152
153 b.Client.CloseWatch(formattedPath, ch)
154}