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  }