This repository has been archived by the owner on Dec 7, 2023. It is now read-only.
/
kube_secret.go
120 lines (107 loc) · 3.59 KB
/
kube_secret.go
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
package resource
import (
"context"
"crypto/sha256"
"fmt"
"path/filepath"
"sort"
"strings"
"github.com/weaveworks/cluster-api-provider-existinginfra/pkg/plan"
)
// KubeSecret writes secrets to the filesystem where they can be picked up by daemons
type KubeSecret struct {
Base
// SecretName is the name of the secret to read
SecretName string `structs:"secretName"`
// Checksum contains the sha256 checksum of the secret data
Checksum [sha256.Size]byte `structs:"checksum"`
// DestinationDirectory is the location in which to write stored file data
DestinationDirectory string `structs:"destinationDirectory"`
// SecretData holds the actual secret contents -- not serialized
SecretData SecretData `structs:"-" plan:"hide"`
// FileNameTransform transforms a secret key into the file name for its contents
FileNameTransform func(string) string
}
// SecretData maps names to values as in Kubernetes v1.Secret
type SecretData map[string][]byte
var (
_ plan.Resource = plan.RegisterResource(&KubeSecret{})
)
func flattenMap(m map[string][]byte) []byte {
items := []string{}
for key, val := range m {
items = append(items, fmt.Sprintf("%s:%v", key, val))
}
sort.Strings(items)
return []byte(strings.Join(items, ","))
}
// NewKubeSecretResource creates a new object from secret data
func NewKubeSecretResource(secretName string, secretData SecretData, destinationDirectory string, fileNameTransform func(string) string) (*KubeSecret, error) {
return &KubeSecret{
SecretName: secretName,
Checksum: sha256.Sum256(flattenMap(secretData)),
DestinationDirectory: destinationDirectory,
SecretData: secretData,
FileNameTransform: fileNameTransform,
}, nil
}
// State implements plan.Resource.
func (ks *KubeSecret) State() plan.State {
return plan.State(map[string]interface{}{"checksum": ks.Checksum})
}
func (ks *KubeSecret) QueryState(ctx context.Context, runner plan.Runner) (plan.State, error) {
data := ks.SecretData
for fname := range data {
path := filepath.Join(ks.DestinationDirectory, ks.FileNameTransform(fname))
exists, err := fileExists(ctx, runner, path)
if err != nil {
return nil, err
}
if !exists {
return plan.EmptyState, nil
}
contents, err := runner.RunCommand(ctx, fmt.Sprintf("cat %s", path), nil)
if err != nil {
return nil, err
}
data[fname] = []byte(contents)
}
return plan.State(map[string]interface{}{"checksum": sha256.Sum256(flattenMap(data))}), nil
}
func fileExists(ctx context.Context, runner plan.Runner, path string) (bool, error) {
result, err := runner.RunCommand(ctx, fmt.Sprintf("[ -f %s ] && echo 'yes' || true", path), nil)
if err != nil {
return false, err
}
return result == "yes", nil
}
// Apply implements plan.Resource.
func (ks *KubeSecret) Apply(ctx context.Context, runner plan.Runner, diff plan.Diff) (bool, error) {
for fname, contents := range ks.SecretData {
err := WriteFile(ctx, contents, filepath.Join(ks.DestinationDirectory, ks.FileNameTransform(fname)), 0600, runner)
if err != nil {
return false, err
}
}
return true, nil
}
// Undo implements plan.Resource.
func (ks *KubeSecret) Undo(ctx context.Context, runner plan.Runner, current plan.State) error {
if len(ks.SecretData) == 0 {
return nil
}
var sb strings.Builder
sb.WriteString("{")
shouldWriteComma := false
for filename := range ks.SecretData {
if shouldWriteComma {
sb.WriteString(",")
} else {
shouldWriteComma = true
}
sb.WriteString(ks.FileNameTransform(filename))
}
sb.WriteString("}")
_, err := runner.RunCommand(ctx, fmt.Sprintf("rm -f %s/%s", ks.DestinationDirectory, sb.String()), nil)
return err
}