-
Notifications
You must be signed in to change notification settings - Fork 214
/
Copy pathstrategy.go
152 lines (130 loc) · 3.56 KB
/
strategy.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package secrets
import (
"encoding/json"
"errors"
"fmt"
"gopkg.in/yaml.v3"
)
// Set is an actual set of resolved values.
// This is the output of resolving a parameter or credential set file.
type Set map[string]string
// Merge merges a second Set into the base.
//
// Duplicate names are not allow and will result in an
// error, this is the case even if the values are identical.
func (s Set) Merge(s2 Set) error {
for k, v := range s2 {
if _, ok := s[k]; ok {
return fmt.Errorf("ambiguous value resolution: %q is already present in base sets, cannot merge", k)
}
s[k] = v
}
return nil
}
// SourceMap maps from a parameter or credential name to a source strategy for resolving its value.
type SourceMap struct {
// Name is the name of the parameter or credential.
Name string `json:"name" yaml:"name"`
// Source defines a strategy for resolving a value from the specified source.
Source Source `json:"source,omitempty" yaml:"source,omitempty"`
// ResolvedValue holds the resolved parameter or credential value.
// When a parameter or credential is resolved, it is loaded into this field. In all
// other cases, it is empty. This field is omitted during serialization.
ResolvedValue string `json:"-" yaml:"-"`
}
// Source specifies how to resolve a parameter or credential from an external
// source.
type Source struct {
// Strategy to resolve the source value, e.g. "secret" or "env".
Strategy string
// Hint to the strategy handler on how to resolve the value.
// For example the name of the secret in a secret store or name of an environment variable.
Hint string
}
func (s Source) MarshalRaw() interface{} {
if s.Strategy == "" {
return nil
}
return map[string]interface{}{s.Strategy: s.Hint}
}
func (s *Source) UnmarshalRaw(raw map[string]interface{}) error {
switch len(raw) {
case 0:
s.Strategy = ""
s.Hint = ""
return nil
case 1:
for k, v := range raw {
s.Strategy = k
if value, ok := v.(string); ok {
s.Hint = value
} else if s.Strategy == "value" {
value, err := unmarshalRawValue(v)
if err != nil {
return err
}
s.Hint = value
} else {
s.Hint = fmt.Sprintf("%v", s.Hint)
}
}
return nil
default:
return errors.New("multiple key/value pairs specified for source but only one may be defined")
}
}
func unmarshalRawValue(rawValue interface{}) (string, error) {
switch value := rawValue.(type) {
case []interface{}, map[string]interface{}:
encodedValue, err := json.Marshal(value)
if err != nil {
return "", fmt.Errorf("unable to convert %T into a string: %w", value, err)
}
return string(encodedValue), nil
case nil:
return "", nil
default:
return fmt.Sprintf("%v", value), nil
}
}
var (
_ json.Marshaler = Source{}
_ json.Unmarshaler = &Source{}
_ yaml.Marshaler = Source{}
_ yaml.Unmarshaler = &Source{}
)
func (s Source) MarshalJSON() ([]byte, error) {
raw := s.MarshalRaw()
return json.Marshal(raw)
}
func (s *Source) UnmarshalJSON(data []byte) error {
var raw map[string]interface{}
err := json.Unmarshal(data, &raw)
if err != nil {
return err
}
return s.UnmarshalRaw(raw)
}
func (s *Source) UnmarshalYAML(value *yaml.Node) error {
var raw map[string]interface{}
err := value.Decode(&raw)
if err != nil {
return err
}
return s.UnmarshalRaw(raw)
}
func (s Source) MarshalYAML() (interface{}, error) {
return s.MarshalRaw(), nil
}
type StrategyList []SourceMap
func (l StrategyList) Less(i, j int) bool {
return l[i].Name < l[j].Name
}
func (l StrategyList) Swap(i, j int) {
tmp := l[i]
l[i] = l[j]
l[j] = tmp
}
func (l StrategyList) Len() int {
return len(l)
}