1
16
17 package driver
18
19 import (
20 "context"
21 "strconv"
22 "strings"
23 "time"
24
25 "github.com/pkg/errors"
26 v1 "k8s.io/api/core/v1"
27 apierrors "k8s.io/apimachinery/pkg/api/errors"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 kblabels "k8s.io/apimachinery/pkg/labels"
30 "k8s.io/apimachinery/pkg/util/validation"
31 corev1 "k8s.io/client-go/kubernetes/typed/core/v1"
32
33 rspb "helm.sh/helm/v3/pkg/release"
34 )
35
36 var _ Driver = (*Secrets)(nil)
37
38
39 const SecretsDriverName = "Secret"
40
41
42
43 type Secrets struct {
44 impl corev1.SecretInterface
45 Log func(string, ...interface{})
46 }
47
48
49
50 func NewSecrets(impl corev1.SecretInterface) *Secrets {
51 return &Secrets{
52 impl: impl,
53 Log: func(_ string, _ ...interface{}) {},
54 }
55 }
56
57
58 func (secrets *Secrets) Name() string {
59 return SecretsDriverName
60 }
61
62
63
64 func (secrets *Secrets) Get(key string) (*rspb.Release, error) {
65
66 obj, err := secrets.impl.Get(context.Background(), key, metav1.GetOptions{})
67 if err != nil {
68 if apierrors.IsNotFound(err) {
69 return nil, ErrReleaseNotFound
70 }
71 return nil, errors.Wrapf(err, "get: failed to get %q", key)
72 }
73
74 r, err := decodeRelease(string(obj.Data["release"]))
75 r.Labels = filterSystemLabels(obj.ObjectMeta.Labels)
76 return r, errors.Wrapf(err, "get: failed to decode data %q", key)
77 }
78
79
80
81
82 func (secrets *Secrets) List(filter func(*rspb.Release) bool) ([]*rspb.Release, error) {
83 lsel := kblabels.Set{"owner": "helm"}.AsSelector()
84 opts := metav1.ListOptions{LabelSelector: lsel.String()}
85
86 list, err := secrets.impl.List(context.Background(), opts)
87 if err != nil {
88 return nil, errors.Wrap(err, "list: failed to list")
89 }
90
91 var results []*rspb.Release
92
93
94
95 for _, item := range list.Items {
96 rls, err := decodeRelease(string(item.Data["release"]))
97 if err != nil {
98 secrets.Log("list: failed to decode release: %v: %s", item, err)
99 continue
100 }
101
102 rls.Labels = item.ObjectMeta.Labels
103
104 if filter(rls) {
105 results = append(results, rls)
106 }
107 }
108 return results, nil
109 }
110
111
112
113 func (secrets *Secrets) Query(labels map[string]string) ([]*rspb.Release, error) {
114 ls := kblabels.Set{}
115 for k, v := range labels {
116 if errs := validation.IsValidLabelValue(v); len(errs) != 0 {
117 return nil, errors.Errorf("invalid label value: %q: %s", v, strings.Join(errs, "; "))
118 }
119 ls[k] = v
120 }
121
122 opts := metav1.ListOptions{LabelSelector: ls.AsSelector().String()}
123
124 list, err := secrets.impl.List(context.Background(), opts)
125 if err != nil {
126 return nil, errors.Wrap(err, "query: failed to query with labels")
127 }
128
129 if len(list.Items) == 0 {
130 return nil, ErrReleaseNotFound
131 }
132
133 var results []*rspb.Release
134 for _, item := range list.Items {
135 rls, err := decodeRelease(string(item.Data["release"]))
136 if err != nil {
137 secrets.Log("query: failed to decode release: %s", err)
138 continue
139 }
140 rls.Labels = item.ObjectMeta.Labels
141 results = append(results, rls)
142 }
143 return results, nil
144 }
145
146
147
148 func (secrets *Secrets) Create(key string, rls *rspb.Release) error {
149
150 var lbs labels
151
152 lbs.init()
153 lbs.fromMap(rls.Labels)
154 lbs.set("createdAt", strconv.Itoa(int(time.Now().Unix())))
155
156
157 obj, err := newSecretsObject(key, rls, lbs)
158 if err != nil {
159 return errors.Wrapf(err, "create: failed to encode release %q", rls.Name)
160 }
161
162 if _, err := secrets.impl.Create(context.Background(), obj, metav1.CreateOptions{}); err != nil {
163 if apierrors.IsAlreadyExists(err) {
164 return ErrReleaseExists
165 }
166
167 return errors.Wrap(err, "create: failed to create")
168 }
169 return nil
170 }
171
172
173
174 func (secrets *Secrets) Update(key string, rls *rspb.Release) error {
175
176 var lbs labels
177
178 lbs.init()
179 lbs.fromMap(rls.Labels)
180 lbs.set("modifiedAt", strconv.Itoa(int(time.Now().Unix())))
181
182
183 obj, err := newSecretsObject(key, rls, lbs)
184 if err != nil {
185 return errors.Wrapf(err, "update: failed to encode release %q", rls.Name)
186 }
187
188 _, err = secrets.impl.Update(context.Background(), obj, metav1.UpdateOptions{})
189 return errors.Wrap(err, "update: failed to update")
190 }
191
192
193 func (secrets *Secrets) Delete(key string) (rls *rspb.Release, err error) {
194
195 if rls, err = secrets.Get(key); err != nil {
196 return nil, err
197 }
198
199 err = secrets.impl.Delete(context.Background(), key, metav1.DeleteOptions{})
200 return rls, err
201 }
202
203
204
205
206
207
208
209
210
211
212
213
214
215 func newSecretsObject(key string, rls *rspb.Release, lbs labels) (*v1.Secret, error) {
216 const owner = "helm"
217
218
219 s, err := encodeRelease(rls)
220 if err != nil {
221 return nil, err
222 }
223
224 if lbs == nil {
225 lbs.init()
226 }
227
228
229 lbs.fromMap(rls.Labels)
230
231
232 lbs.set("name", rls.Name)
233 lbs.set("owner", owner)
234 lbs.set("status", rls.Info.Status.String())
235 lbs.set("version", strconv.Itoa(rls.Version))
236
237
238
239
240
241
242
243
244
245
246
247
248 return &v1.Secret{
249 ObjectMeta: metav1.ObjectMeta{
250 Name: key,
251 Labels: lbs.toMap(),
252 },
253 Type: "helm.sh/release.v1",
254 Data: map[string][]byte{"release": []byte(s)},
255 }, nil
256 }
257
View as plain text