blob: c319d9989f5ceb95a68ee513ec48a24135b713fb [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
sbarbari17d7e222019-11-05 10:02:29 -050017package db
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040018
19import (
20 "errors"
21 "fmt"
Scott Baker807addd2019-10-24 15:16:21 -070022 "github.com/opencord/voltha-lib-go/v2/pkg/db/kvstore"
23 "github.com/opencord/voltha-lib-go/v2/pkg/log"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040024 "strconv"
Stephane Barbariedc5022d2018-11-19 15:21:44 -050025 "sync"
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040026)
27
Stephane Barbariedc5022d2018-11-19 15:21:44 -050028// Backend structure holds details for accessing the kv store
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040029type Backend struct {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050030 sync.RWMutex
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040031 Client kvstore.Client
32 StoreType string
33 Host string
34 Port int
35 Timeout int
36 PathPrefix string
37}
38
Stephane Barbariedc5022d2018-11-19 15:21:44 -050039// NewBackend creates a new instance of a Backend structure
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040040func NewBackend(storeType string, host string, port int, timeout int, pathPrefix string) *Backend {
41 var err error
42
43 b := &Backend{
44 StoreType: storeType,
45 Host: host,
46 Port: port,
47 Timeout: timeout,
48 PathPrefix: pathPrefix,
49 }
50
51 address := host + ":" + strconv.Itoa(port)
52 if b.Client, err = b.newClient(address, timeout); err != nil {
Stephane Barbariee0a4c792019-01-16 11:26:29 -050053 log.Errorw("failed-to-create-kv-client",
54 log.Fields{
55 "type": storeType, "host": host, "port": port,
56 "timeout": timeout, "prefix": pathPrefix,
57 "error": err.Error(),
58 })
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040059 }
60
61 return b
62}
63
64func (b *Backend) newClient(address string, timeout int) (kvstore.Client, error) {
65 switch b.StoreType {
66 case "consul":
67 return kvstore.NewConsulClient(address, timeout)
68 case "etcd":
69 return kvstore.NewEtcdClient(address, timeout)
70 }
Stephane Barbariee0a4c792019-01-16 11:26:29 -050071 return nil, errors.New("unsupported-kv-store")
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040072}
73
74func (b *Backend) makePath(key string) string {
Stephane Barbarieec0919b2018-09-05 14:14:29 -040075 path := fmt.Sprintf("%s/%s", b.PathPrefix, key)
Stephane Barbarieec0919b2018-09-05 14:14:29 -040076 return path
77}
Stephane Barbariedc5022d2018-11-19 15:21:44 -050078
79// List retrieves one or more items that match the specified key
sbarbari17d7e222019-11-05 10:02:29 -050080func (b *Backend) List(key string) (map[string]*kvstore.KVPair, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050081 b.Lock()
82 defer b.Unlock()
83
84 formattedPath := b.makePath(key)
sbarbari17d7e222019-11-05 10:02:29 -050085 log.Debugw("listing-key", log.Fields{"key": key, "path": formattedPath})
Stephane Barbariedc5022d2018-11-19 15:21:44 -050086
sbarbari17d7e222019-11-05 10:02:29 -050087 return b.Client.List(formattedPath, b.Timeout)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040088}
Stephane Barbariedc5022d2018-11-19 15:21:44 -050089
90// Get retrieves an item that matches the specified key
sbarbari17d7e222019-11-05 10:02:29 -050091func (b *Backend) Get(key string) (*kvstore.KVPair, error) {
Stephane Barbariedc5022d2018-11-19 15:21:44 -050092 b.Lock()
93 defer b.Unlock()
94
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -040095 formattedPath := b.makePath(key)
sbarbari17d7e222019-11-05 10:02:29 -050096 log.Debugw("getting-key", log.Fields{"key": key, "path": formattedPath})
Stephane Barbariedc5022d2018-11-19 15:21:44 -050097
sbarbari17d7e222019-11-05 10:02:29 -050098 return b.Client.Get(formattedPath, b.Timeout)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040099}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500100
101// Put stores an item value under the specifed key
sbarbari17d7e222019-11-05 10:02:29 -0500102func (b *Backend) Put(key string, value interface{}) error {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500103 b.Lock()
104 defer b.Unlock()
105
Stephane Barbarie88fbe7f2018-09-25 12:25:23 -0400106 formattedPath := b.makePath(key)
sbarbari17d7e222019-11-05 10:02:29 -0500107 log.Debugw("putting-key", log.Fields{"key": key, "value": string(value.([]byte)), "path": formattedPath})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500108
sbarbari17d7e222019-11-05 10:02:29 -0500109 return b.Client.Put(formattedPath, value, b.Timeout)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400110}
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500111
112// Delete removes an item under the specified key
sbarbari17d7e222019-11-05 10:02:29 -0500113func (b *Backend) Delete(key string) error {
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500114 b.Lock()
115 defer b.Unlock()
116
117 formattedPath := b.makePath(key)
sbarbari17d7e222019-11-05 10:02:29 -0500118 log.Debugw("deleting-key", log.Fields{"key": key, "path": formattedPath})
Stephane Barbariedc5022d2018-11-19 15:21:44 -0500119
sbarbari17d7e222019-11-05 10:02:29 -0500120 return b.Client.Delete(formattedPath, b.Timeout)
Stephane Barbarie4a2564d2018-07-26 11:02:58 -0400121}
Stephane Barbariee0a4c792019-01-16 11:26:29 -0500122
123// CreateWatch starts watching events for the specified key
124func (b *Backend) CreateWatch(key string) chan *kvstore.Event {
125 b.Lock()
126 defer b.Unlock()
127
128 formattedPath := b.makePath(key)
129 log.Debugw("creating-key-watch", log.Fields{"key": key, "path": formattedPath})
130
131 return b.Client.Watch(formattedPath)
132}
133
134// DeleteWatch stops watching events for the specified key
135func (b *Backend) DeleteWatch(key string, ch chan *kvstore.Event) {
136 b.Lock()
137 defer b.Unlock()
138
139 formattedPath := b.makePath(key)
140 log.Debugw("deleting-key-watch", log.Fields{"key": key, "path": formattedPath})
141
142 b.Client.CloseWatch(formattedPath, ch)
143}