-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathtransformer.go
91 lines (78 loc) · 2.7 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
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 string `yaml:"value,omitempty"`
SubMap map[interface{}]interface{} `yaml:"subMapValue,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[")
}
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)),
SubMap: mapVal,
}
}
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 map[interface{}]interface{}
decoder.Decode(&pipelineVars)
vals := make([]Importable, 0, len(pipelineVars))
for key, val := range pipelineVars {
// Let's require, for now, simple types & maps in the var field
var valStr string
switch v := val.(type) {
default:
if isMap(val) {
vals = append(vals, handleMap(val.(map[interface{}]interface{}), prefix, key.(string)))
} else {
return BulkImport{}, fmt.Errorf("Invalid value type in vars file %T. Currently only primitive values & maps are supported", v)
}
case bool, float32, float64, int, int16, int32, int64, string, uint, uint16, uint32, uint64:
valStr = fmt.Sprint(val)
vals = append(vals, makeImportable(prefix, key.(string), valStr))
}
}
return BulkImport{
Credentials: vals,
}, nil
}