1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
|
package config
import (
"bytes"
"io"
"io/ioutil"
"github.com/xordataexchange/crypt/backend"
"github.com/xordataexchange/crypt/backend/consul"
"github.com/xordataexchange/crypt/backend/etcd"
"github.com/xordataexchange/crypt/encoding/secconf"
)
type KVPair struct {
backend.KVPair
}
type KVPairs []*KVPair
type configManager struct {
keystore []byte
store backend.Store
}
// A ConfigManager retrieves and decrypts configuration from a key/value store.
type ConfigManager interface {
Get(key string) ([]byte, error)
List(key string) (KVPairs, error)
Set(key string, value []byte) error
Watch(key string, stop chan bool) <-chan *Response
}
type standardConfigManager struct {
store backend.Store
}
func NewStandardConfigManager(client backend.Store) (ConfigManager, error) {
return standardConfigManager{client}, nil
}
func NewConfigManager(client backend.Store, keystore io.Reader) (ConfigManager, error) {
bytes, err := ioutil.ReadAll(keystore)
if err != nil {
return nil, err
}
return configManager{bytes, client}, nil
}
// NewStandardEtcdConfigManager returns a new ConfigManager backed by etcd.
func NewStandardEtcdConfigManager(machines []string) (ConfigManager, error) {
store, err := etcd.New(machines)
if err != nil {
return nil, err
}
return NewStandardConfigManager(store)
}
// NewStandardConsulConfigManager returns a new ConfigManager backed by consul.
func NewStandardConsulConfigManager(machines []string) (ConfigManager, error) {
store, err := consul.New(machines)
if err != nil {
return nil, err
}
return NewStandardConfigManager(store)
}
// NewEtcdConfigManager returns a new ConfigManager backed by etcd.
// Data will be encrypted.
func NewEtcdConfigManager(machines []string, keystore io.Reader) (ConfigManager, error) {
store, err := etcd.New(machines)
if err != nil {
return nil, err
}
return NewConfigManager(store, keystore)
}
// NewConsulConfigManager returns a new ConfigManager backed by consul.
// Data will be encrypted.
func NewConsulConfigManager(machines []string, keystore io.Reader) (ConfigManager, error) {
store, err := consul.New(machines)
if err != nil {
return nil, err
}
return NewConfigManager(store, keystore)
}
// Get retrieves and decodes a secconf value stored at key.
func (c configManager) Get(key string) ([]byte, error) {
value, err := c.store.Get(key)
if err != nil {
return nil, err
}
return secconf.Decode(value, bytes.NewBuffer(c.keystore))
}
// Get retrieves a value stored at key.
// convenience function, no additional value provided over
// `etcdctl`
func (c standardConfigManager) Get(key string) ([]byte, error) {
value, err := c.store.Get(key)
if err != nil {
return nil, err
}
return value, err
}
// List retrieves and decodes all secconf value stored under key.
func (c configManager) List(key string) (KVPairs, error) {
list, err := c.store.List(key)
retList := make(KVPairs, len(list))
if err != nil {
return nil, err
}
for i, kv := range list {
retList[i].Key = kv.Key
retList[i].Value, err = secconf.Decode(kv.Value, bytes.NewBuffer(c.keystore))
if err != nil {
return nil, err
}
}
return retList, nil
}
// List retrieves all values under key.
// convenience function, no additional value provided over
// `etcdctl`
func (c standardConfigManager) List(key string) (KVPairs, error) {
list, err := c.store.List(key)
retList := make(KVPairs, len(list))
if err != nil {
return nil, err
}
for i, kv := range list {
retList[i].Key = kv.Key
retList[i].Value = kv.Value
}
return retList, err
}
// Set will put a key/value into the data store
// and encode it with secconf
func (c configManager) Set(key string, value []byte) error {
encodedValue, err := secconf.Encode(value, bytes.NewBuffer(c.keystore))
if err == nil {
err = c.store.Set(key, encodedValue)
}
return err
}
// Set will put a key/value into the data store
func (c standardConfigManager) Set(key string, value []byte) error {
err := c.store.Set(key, value)
return err
}
type Response struct {
Value []byte
Error error
}
func (c configManager) Watch(key string, stop chan bool) <-chan *Response {
resp := make(chan *Response, 0)
backendResp := c.store.Watch(key, stop)
go func() {
for {
select {
case <-stop:
return
case r := <-backendResp:
if r.Error != nil {
resp <- &Response{nil, r.Error}
continue
}
value, err := secconf.Decode(r.Value, bytes.NewBuffer(c.keystore))
resp <- &Response{value, err}
}
}
}()
return resp
}
func (c standardConfigManager) Watch(key string, stop chan bool) <-chan *Response {
resp := make(chan *Response, 0)
backendResp := c.store.Watch(key, stop)
go func() {
for {
select {
case <-stop:
return
case r := <-backendResp:
if r.Error != nil {
resp <- &Response{nil, r.Error}
continue
}
resp <- &Response{r.Value, nil}
}
}
}()
return resp
}
|