github.com/ystia/yorc/v4@v4.3.0/storage/internal/consul/store.go (about) 1 // Copyright 2019 Bull S.A.S. Atos Technologies - Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois, France. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package consul 16 17 import ( 18 "context" 19 "github.com/hashicorp/consul/api" 20 "github.com/pkg/errors" 21 "github.com/ystia/yorc/v4/helper/consulutil" 22 "github.com/ystia/yorc/v4/storage/encoding" 23 "github.com/ystia/yorc/v4/storage/store" 24 "github.com/ystia/yorc/v4/storage/utils" 25 "time" 26 ) 27 28 type consulStore struct { 29 codec encoding.Codec 30 } 31 32 // NewStore returns a new Consul store 33 func NewStore() store.Store { 34 return &consulStore{encoding.JSON} 35 } 36 37 func (c *consulStore) Set(ctx context.Context, k string, v interface{}) error { 38 if err := utils.CheckKeyAndValue(k, v); err != nil { 39 return err 40 } 41 42 data, err := c.codec.Marshal(v) 43 if err != nil { 44 return errors.Wrapf(err, "failed to marshal value %+v due to error:%+v", v, err) 45 } 46 47 return consulutil.StoreConsulKey(k, data) 48 } 49 50 func (c *consulStore) SetCollection(ctx context.Context, keyValues []store.KeyValueIn) error { 51 if keyValues == nil || len(keyValues) == 0 { 52 return nil 53 } 54 ctx, errGroup, consulStore := consulutil.WithContext(ctx) 55 for _, kv := range keyValues { 56 if err := utils.CheckKeyAndValue(kv.Key, kv.Value); err != nil { 57 return err 58 } 59 60 data, err := c.codec.Marshal(kv.Value) 61 if err != nil { 62 return errors.Wrapf(err, "failed to marshal value %+v due to error:%+v", kv.Value, err) 63 } 64 65 consulStore.StoreConsulKey(kv.Key, data) 66 } 67 return errGroup.Wait() 68 } 69 70 func (c *consulStore) Get(k string, v interface{}) (bool, error) { 71 if err := utils.CheckKeyAndValue(k, v); err != nil { 72 return false, err 73 } 74 75 found, value, err := consulutil.GetValue(k) 76 if err != nil || !found { 77 return found, err 78 } 79 80 return true, errors.Wrapf(c.codec.Unmarshal(value, v), "failed to unmarshal data:%q", string(value)) 81 } 82 83 func (c *consulStore) Exist(k string) (bool, error) { 84 if err := utils.CheckKey(k); err != nil { 85 return false, err 86 } 87 88 found, _, err := consulutil.GetValue(k) 89 if err != nil { 90 return false, err 91 } 92 return found, nil 93 } 94 95 func (c *consulStore) Keys(k string) ([]string, error) { 96 return consulutil.GetKeys(k) 97 } 98 99 func (c *consulStore) Delete(ctx context.Context, k string, recursive bool) error { 100 return consulutil.Delete(k, recursive) 101 } 102 103 func (c *consulStore) GetLastModifyIndex(k string) (uint64, error) { 104 _, qm, err := consulutil.GetKV().Get(k, nil) 105 if err != nil || qm == nil { 106 return 0, errors.Errorf("Failed to retrieve last index for key:%q", k) 107 } 108 return qm.LastIndex, nil 109 } 110 111 func (c *consulStore) List(ctx context.Context, k string, waitIndex uint64, timeout time.Duration) ([]store.KeyValueOut, uint64, error) { 112 if err := utils.CheckKey(k); err != nil { 113 return nil, 0, err 114 } 115 116 kvps, qm, err := consulutil.GetKV().List(k, &api.QueryOptions{WaitIndex: waitIndex, WaitTime: timeout}) 117 if err != nil || qm == nil { 118 return nil, 0, err 119 } 120 if kvps == nil { 121 return nil, qm.LastIndex, err 122 } 123 124 values := make([]store.KeyValueOut, 0) 125 for _, kvp := range kvps { 126 var value map[string]interface{} 127 if err := c.codec.Unmarshal(kvp.Value, &value); err != nil { 128 return nil, 0, errors.Wrapf(err, "failed to unmarshal stored value: %q", string(kvp.Value)) 129 } 130 if kvp.ModifyIndex > waitIndex { 131 values = append(values, store.KeyValueOut{ 132 Key: kvp.Key, 133 LastModifyIndex: kvp.ModifyIndex, 134 Value: value, 135 RawValue: kvp.Value, 136 }) 137 } 138 } 139 return values, qm.LastIndex, nil 140 }