forked from jontours/vars-to-credhub
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtransformer.go
132 lines (117 loc) · 3.69 KB
/
transformer.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
121
122
123
124
125
126
127
128
129
130
131
132
package main
import (
"fmt"
"io"
"strings"
"gopkg.in/yaml.v2"
)
// Importable represents a credential to be loaded into Credhub via `bulk-import`
type Importable struct {
Name string `yaml:"name"`
Type string `yaml:"type"`
Value interface{} `yaml:"value,omitempty"`
}
// BulkImport represents what will be actually sent to Credhub
type BulkImport struct {
Credentials []Importable `yaml:"credentials"`
}
// Utility to test if something is a map
func isMap(x interface{}) bool {
t := fmt.Sprintf("%T", x)
return strings.HasPrefix(t, "map[")
}
// Utility to test if something is a an array
func isArray(x interface{}) bool {
t := fmt.Sprintf("%T", x)
return strings.HasPrefix(t, "[]inter")
}
func handleMapSlice(mapVal yaml.MapSlice, prefix string, parentKey string) Importable {
idxToDelete := -1
for idx, item := range mapVal {
if item.Value == "public_key_fingerprint" {
idxToDelete = idx
break
}
}
value := mapVal
if idxToDelete >= 0 {
value = append(mapVal[:idxToDelete], mapVal[idxToDelete+1:]...)
}
return Importable{
Name: fmt.Sprintf("%s/%s", prefix, parentKey),
Type: getType(parentKey, fmt.Sprint(mapVal)),
Value: value,
}
}
func handleMap(mapVal map[interface{}]interface{}, prefix string, parentKey string) Importable {
//RSA key types if output from bosh will have a fingerprint that credhub
//can't deal with, so we'll just remove it. Delete is harmless if the
//key DNE - so just do it on every map.
delete(mapVal, "public_key_fingerprint")
return Importable{
Name: fmt.Sprintf("%s/%s", prefix, parentKey),
Type: getType(parentKey, fmt.Sprint(mapVal)),
Value: mapVal,
}
}
func handleArray(arrayVal []interface{}, prefix string, key string) Importable {
return Importable{
Name: fmt.Sprintf("%s/%s", prefix, key),
Type: "json",
Value: arrayVal,
}
}
func getType(key string, valStr string) string {
//attempt to guess the type for the item, default to "value"
if strings.Contains(key, "password") || strings.Contains(key, "secret") {
return "password"
//the cert check should be above rsa since a cert may also contain a pk
} else if strings.Contains(valStr, "CERTIFICATE---") {
return "certificate"
} else if strings.Contains(valStr, "KEY---") {
return "rsa"
}
return "value"
}
func makeImportable(prefix string, key string, valStr string) Importable {
return Importable{
Name: fmt.Sprintf("%s/%s", prefix, key),
Type: getType(key, valStr),
Value: valStr,
}
}
// Transform performs the translation from vars file to import file
func Transform(prefix string, input io.Reader) (BulkImport, error) {
decoder := yaml.NewDecoder(input)
var pipelineVars yaml.MapSlice
err := decoder.Decode(&pipelineVars)
if err != nil {
return BulkImport{
Credentials: nil,
}, err
}
vals := make([]Importable, 0, len(pipelineVars))
for _, mapItem := range pipelineVars {
key := mapItem.Key
val := mapItem.Value
// Let's require, for now, simple types & maps in the var field
switch valType := val.(type) {
case yaml.MapSlice:
vals = append(vals, handleMapSlice(val.(yaml.MapSlice), prefix, key.(string)))
default:
if isMap(val) {
vals = append(vals, handleMap(val.(map[interface{}]interface{}), prefix, key.(string)))
} else if isArray(val) {
vals = append(vals, handleArray(val.([]interface{}), prefix, key.(string)))
} else {
return BulkImport{}, fmt.Errorf("Invalid value type in vars file %T. Currently only primitive values & maps are supported", valType)
}
case bool, float32, float64, int, int16, int32, int64, string, uint, uint16, uint32, uint64, nil:
valStr := fmt.Sprint(val)
vals = append(vals, makeImportable(prefix, key.(string), valStr))
}
}
return BulkImport{
Credentials: vals,
}, nil
}