github.com/olli-ai/jx/v2@v2.0.400-0.20210921045218-14731b4dd448/pkg/io/config_store.go (about) 1 package io 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 7 "github.com/ghodss/yaml" 8 "github.com/olli-ai/jx/v2/pkg/util" 9 "github.com/olli-ai/jx/v2/pkg/vault" 10 "github.com/pkg/errors" 11 ) 12 13 // ConfigStore provides an interface for storing configs 14 type ConfigStore interface { 15 // Write saves some secret data to the store 16 Write(name string, bytes []byte) error 17 18 // Read reads some secret data from the store 19 Read(name string) ([]byte, error) 20 21 // WriteObject writes a named object to the store 22 WriteObject(name string, object interface{}) error 23 24 // ReadObject reads an object from the store 25 ReadObject(name string, object interface{}) error 26 } 27 28 type fileStore struct { 29 } 30 31 // NewFileStore creates a ConfigStore that stores its data to the filesystem 32 func NewFileStore() ConfigStore { 33 return &fileStore{} 34 } 35 36 // Write writes a secret to the filesystem 37 func (f *fileStore) Write(fileName string, bytes []byte) error { 38 return ioutil.WriteFile(fileName, bytes, util.DefaultWritePermissions) 39 } 40 41 // WriteObject writes a secret to the filesystem in YAML format 42 func (f *fileStore) WriteObject(fileName string, object interface{}) error { 43 y, err := yaml.Marshal(object) 44 if err != nil { 45 return errors.Wrapf(err, "unable to marshal object to yaml: %v", object) 46 } 47 return f.Write(fileName, y) 48 } 49 50 // Read reads a secret form the filesystem 51 func (f *fileStore) Read(fileName string) ([]byte, error) { 52 return ioutil.ReadFile(fileName) 53 } 54 55 // ReadObject reads an object from the filesystem as yaml 56 func (f *fileStore) ReadObject(fileName string, object interface{}) error { 57 data, err := f.Read(fileName) 58 if err != nil { 59 return errors.Wrapf(err, "unable to read %s", fileName) 60 } 61 return yaml.Unmarshal(data, object) 62 } 63 64 type vaultStore struct { 65 client vault.Client 66 path string 67 } 68 69 // NewVaultStore creates a new store which stores its data in Vault 70 func NewVaultStore(client vault.Client, path string) ConfigStore { 71 return &vaultStore{ 72 client: client, 73 path: path, 74 } 75 } 76 77 // Write store a secret in vault as an array of bytes 78 func (v *vaultStore) Write(name string, bytes []byte) error { 79 data := map[string]interface{}{ 80 "data": bytes, 81 } 82 _, err := v.client.Write(v.secretPath(name), data) 83 if err != nil { 84 return errors.Wrapf(err, "unable to write data for secret '%s' to vault", name) 85 } 86 return nil 87 } 88 89 // Read reads a secret from vault which was stored as an array of bytes 90 func (v *vaultStore) Read(name string) ([]byte, error) { 91 secret, err := v.client.Read(v.secretPath(name)) 92 if err != nil { 93 return nil, errors.Wrapf(err, "unable to read '%s' secret from vault", name) 94 } 95 data, ok := secret["data"] 96 if !ok { 97 return nil, fmt.Errorf("data not found for secret '%s'", name) 98 } 99 100 bytes, ok := data.([]byte) 101 if !ok { 102 return nil, fmt.Errorf("unable to convert the secret content '%s' to bytes", name) 103 } 104 105 return bytes, nil 106 } 107 108 // WriteObject writes a generic named object to vault 109 func (v *vaultStore) WriteObject(name string, object interface{}) error { 110 y, err := yaml.Marshal(object) 111 if err != nil { 112 return errors.Wrapf(err, "unable to marshal object to yaml: %v", object) 113 } 114 _, err = v.client.WriteYaml(v.secretPath(name), string(y)) 115 if err != nil { 116 return errors.Wrapf(err, "writing the %q secret in YAMl format to vault", name) 117 } 118 return nil 119 } 120 121 // ReadObject reads a generic named object from vault 122 func (v *vaultStore) ReadObject(name string, object interface{}) error { 123 data, err := v.client.ReadYaml(v.secretPath(name)) 124 if err != nil { 125 return errors.Wrapf(err, "reading the %q secret in YAMl fromat from vault", name) 126 } 127 return yaml.Unmarshal([]byte(data), object) 128 } 129 130 func (v *vaultStore) secretPath(name string) string { 131 return v.path + name 132 }