Skip to content

Commit bdb1264

Browse files
authored
Merge pull request #14 from carlpett/support-lists
Add support for lists
2 parents 34ffe3a + 2cd4a7c commit bdb1264

5 files changed

Lines changed: 233 additions & 14 deletions

File tree

sops/data_sops_file.go

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,23 +98,50 @@ func dataSourceFileRead(d *schema.ResourceData, meta interface{}) error {
9898
//
9999
// All keys will be joined by dot
100100
// e.g. {"a": {"b":"c"}} => {"a.b":"c"}
101+
// or {"a": {"b":[1,2]}} => {"a.b.0":1, "a.b.1": 2}
101102
func flatten(data map[string]interface{}) map[string]string {
102-
flattened := map[string]string{}
103-
for key, value := range data {
104-
switch t := value.(type) {
105-
case string, int:
106-
flattened[key] = fmt.Sprint(t)
103+
ret := make(map[string]string)
104+
for k, v := range data {
105+
switch typed := v.(type) {
107106
case map[interface{}]interface{}:
108-
f := flatten(convertMap(t))
109-
for k, v := range f {
110-
// Join all keys with dot
111-
flattened[fmt.Sprintf("%s.%s", key, k)] = v
107+
for fk, fv := range flatten(convertMap(typed)) {
108+
ret[fmt.Sprintf("%s.%s", k, fk)] = fv
109+
}
110+
case map[string]interface{}:
111+
for fk, fv := range flatten(typed) {
112+
ret[fmt.Sprintf("%s.%s", k, fk)] = fv
113+
}
114+
case []interface{}:
115+
for fk, fv := range flattenSlice(typed) {
116+
ret[fmt.Sprintf("%s.%s", k, fk)] = fv
117+
}
118+
default:
119+
ret[k] = fmt.Sprint(typed)
120+
}
121+
}
122+
return ret
123+
}
124+
func flattenSlice(data []interface{}) map[string]string {
125+
ret := make(map[string]string)
126+
for idx, v := range data {
127+
switch typed := v.(type) {
128+
case map[interface{}]interface{}:
129+
for fk, fv := range flatten(convertMap(typed)) {
130+
ret[fmt.Sprintf("%d.%s", idx, fk)] = fv
131+
}
132+
case map[string]interface{}:
133+
for fk, fv := range flatten(typed) {
134+
ret[fmt.Sprintf("%d.%s", idx, fk)] = fv
135+
}
136+
case []interface{}:
137+
for fk, fv := range flattenSlice(typed) {
138+
ret[fmt.Sprintf("%d.%s", idx, fk)] = fv
112139
}
113140
default:
114-
fmt.Printf("unexpected type %T", t)
141+
ret[fmt.Sprint(idx)] = fmt.Sprint(typed)
115142
}
116143
}
117-
return flattened
144+
return ret
118145
}
119146

120147
func convertMap(originalMap map[interface{}]interface{}) map[string]interface{} {

sops/data_sops_file_test.go

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package sops
33
import (
44
"fmt"
55
"os"
6+
"reflect"
67
"testing"
78

89
"github.com/hashicorp/terraform/helper/resource"
@@ -26,6 +27,9 @@ func TestDataSourceSopsFile_basic(t *testing.T) {
2627
Config: config,
2728
Check: resource.ComposeTestCheckFunc(
2829
resource.TestCheckResourceAttr("data.sops_file.test_basic", "data.hello", "world"),
30+
resource.TestCheckResourceAttr("data.sops_file.test_basic", "data.integer", "0"),
31+
resource.TestCheckResourceAttr("data.sops_file.test_basic", "data.float", "0.2"),
32+
resource.TestCheckResourceAttr("data.sops_file.test_basic", "data.bool", "true"),
2933
),
3034
},
3135
},
@@ -81,3 +85,133 @@ func TestDataSourceSopsFile_raw(t *testing.T) {
8185
},
8286
})
8387
}
88+
89+
const configTestDataSourceSopsFile_simplelist = `
90+
data "sops_file" "test_list" {
91+
source_file = "%s/test-fixtures/simple-list.yaml"
92+
}`
93+
94+
func TestDataSourceSopsFile_simplelist(t *testing.T) {
95+
wd, err := os.Getwd()
96+
if err != nil {
97+
t.Fatal(err)
98+
}
99+
config := fmt.Sprintf(configTestDataSourceSopsFile_simplelist, wd)
100+
resource.UnitTest(t, resource.TestCase{
101+
Providers: testAccProviders,
102+
Steps: []resource.TestStep{
103+
{
104+
Config: config,
105+
Check: resource.ComposeTestCheckFunc(
106+
resource.TestCheckResourceAttr("data.sops_file.test_list", "data.a_list.0", "val1"),
107+
resource.TestCheckResourceAttr("data.sops_file.test_list", "data.a_list.1", "val2"),
108+
),
109+
},
110+
},
111+
})
112+
}
113+
114+
const configTestDataSourceSopsFile_complexlist = `
115+
data "sops_file" "test_list" {
116+
source_file = "%s/test-fixtures/complex-list.yaml"
117+
}`
118+
119+
func TestDataSourceSopsFile_complexlist(t *testing.T) {
120+
wd, err := os.Getwd()
121+
if err != nil {
122+
t.Fatal(err)
123+
}
124+
config := fmt.Sprintf(configTestDataSourceSopsFile_complexlist, wd)
125+
resource.UnitTest(t, resource.TestCase{
126+
Providers: testAccProviders,
127+
Steps: []resource.TestStep{
128+
{
129+
Config: config,
130+
Check: resource.ComposeTestCheckFunc(
131+
resource.TestCheckResourceAttr("data.sops_file.test_list", "data.a_list.0.name", "foo"),
132+
resource.TestCheckResourceAttr("data.sops_file.test_list", "data.a_list.0.index", "0"),
133+
resource.TestCheckResourceAttr("data.sops_file.test_list", "data.a_list.1.name", "bar"),
134+
resource.TestCheckResourceAttr("data.sops_file.test_list", "data.a_list.1.index", "1"),
135+
),
136+
},
137+
},
138+
})
139+
}
140+
141+
func TestFlattening(t *testing.T) {
142+
tc := []struct {
143+
name string
144+
input map[string]interface{}
145+
expected map[string]string
146+
}{
147+
{
148+
name: "all data types become strings",
149+
input: map[string]interface{}{
150+
"a_string": "foo",
151+
"an_integer": 12,
152+
"a_bool": true,
153+
"a_float": 1.1,
154+
},
155+
expected: map[string]string{
156+
"a_string": "foo",
157+
"an_integer": "12",
158+
"a_bool": "true",
159+
"a_float": "1.1",
160+
},
161+
},
162+
{
163+
name: "dicts are unnested",
164+
input: map[string]interface{}{
165+
"a_dict": map[string]interface{}{"foo": "bar"},
166+
},
167+
expected: map[string]string{
168+
"a_dict.foo": "bar",
169+
},
170+
},
171+
{
172+
name: "lists are unpacked with index keys",
173+
input: map[string]interface{}{
174+
"a_list": []interface{}{1, 2},
175+
},
176+
expected: map[string]string{
177+
"a_list.0": "1",
178+
"a_list.1": "2",
179+
},
180+
},
181+
{
182+
name: "deep nesting",
183+
/*
184+
This test corresponds to this yaml structure:
185+
foo:
186+
- a: 1
187+
b:
188+
c:
189+
- d: 2
190+
*/
191+
input: map[string]interface{}{
192+
"foo": []interface{}{
193+
map[string]interface{}{
194+
"a": 1,
195+
"b": map[string]interface{}{
196+
"c": []interface{}{
197+
map[string]interface{}{"d": 2},
198+
},
199+
},
200+
},
201+
},
202+
},
203+
expected: map[string]string{
204+
"foo.0.a": "1",
205+
"foo.0.b.c.0.d": "2",
206+
},
207+
},
208+
}
209+
for _, c := range tc {
210+
t.Run(c.name, func(t *testing.T) {
211+
output := flatten(c.input)
212+
if !reflect.DeepEqual(c.expected, output) {
213+
t.Errorf("Unexpected flattening output, expected %v, got %v", c.expected, output)
214+
}
215+
})
216+
}
217+
}

sops/test-fixtures/basic.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
# Content is hello: world
21
hello: ENC[AES256_GCM,data:gzR9Gz4=,iv:cbMZU1nUyo5mFCW+Vel2UYbnbMA/0wKxsQzy/WVAYw8=,tag:tETDJMCJYo+4K4LwsSw4Dw==,type:str]
2+
integer: ENC[AES256_GCM,data:9w==,iv:8gMmdZTOgdGdHlXvipvz4qchxFWMwKg95Zzvh/I84G4=,tag:jxzxI0m7stEK+zr+yc0Wsg==,type:int]
3+
float: ENC[AES256_GCM,data:UtBf,iv:Z7hdgplz8QP9JyC/DX5WWiazdYjBvZTVolvyf9VNvyw=,tag:v8VujtMTcuM4GuZKGreVbA==,type:float]
4+
bool: ENC[AES256_GCM,data:xW/sRw==,iv:0vXeg5/SBUDo8dmHHpDTdxMwpoCdx+ERE7dq4UgqVsc=,tag:RweVRArPBVskGtnPBiQ0Yg==,type:bool]
35
sops:
46
kms: []
57
gcp_kms: []
68
azure_kv: []
7-
lastmodified: '2019-01-23T12:24:04Z'
8-
mac: ENC[AES256_GCM,data:o5djAPas9xAoEK1mrIcnPcY2isYZJDj7k0Hc6VaowFfNUyB7U3uHnHHYWuibhJAoFtr5Cq59oNC/f/O7RvppjrSG6jqxjDQhppqLZbFLi6s10evoGsRvS32OB2AUGG8UwiWf2qbFp1/9ZMtjdh6nVUeKd+pSX6foApPHeexYjfM=,iv:xqGdZzM4Khnz86oGDFAoLrK3axllUcROHaje2LMgIW8=,tag:vNDll77V9QpEZ2T/GvPnQw==,type:str]
9+
lastmodified: '2019-04-26T18:43:59Z'
10+
mac: ENC[AES256_GCM,data:UdHBCIrxfP+FjXwi0++Y1MUdAZ3hAa34OfG/w911zimF2YR+Mqv7PD15Osqa9GotQ5idzJEAzvz6pRVm7J388s0g2E53zBjCfLO/dcrkmVRdjTw2WYM17ewGM61HlNB9EKPe38B/eTH6PP1pTs5vjplEM/3FDblglKw8koUDdp0=,iv:LmRycuJjAoyGaY8qazR6G5CEuyD8JYCe3OO9UTek6kE=,tag:pfpB4HNE1qVmhO1QdZvVkQ==,type:str]
911
pgp:
1012
- created_at: '2019-01-23T10:01:20Z'
1113
enc: |-
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
a_list:
2+
- name: ENC[AES256_GCM,data:nX7D,iv:HdTElsGgx0Z2LcNmUGSbMCTyVhRD0UQMi8ztAEYQqJQ=,tag:D/sIqf+TXpUhyTbugEPpww==,type:str]
3+
index: ENC[AES256_GCM,data:uw==,iv:1Tz2jR86XjGVRKwaY3XO8gAH102xEKDFr/MNQbxO8GU=,tag:avkgp+Q9CraUC+hjuhYyXQ==,type:int]
4+
- name: ENC[AES256_GCM,data:uNO3,iv:y9ip72kPma2nTrJsqCn/+DDKLc6GeOeuEHEO2Tf2h9A=,tag:eTux2TxifhzMtWFYmlMnKA==,type:str]
5+
index: ENC[AES256_GCM,data:fA==,iv:6Vmcm5FRa3vLwtt5P4IjiOtJi76TfKIg+D8Bx10jaTA=,tag:EN7hJoYOXmyEynvCy7GZ6w==,type:int]
6+
sops:
7+
kms: []
8+
gcp_kms: []
9+
azure_kv: []
10+
lastmodified: '2019-04-26T18:39:26Z'
11+
mac: ENC[AES256_GCM,data:Fw/zyoOVaQtGxVSdg2Wz5IHeRSuubjVb4ll8VPd6Prt4382gevlkzuv0TSAj9wAgGSiuXjeGU397kUkmDksdtsMgieh7XQxPuIoBHMaXuyvOtwBWtli8yAIkgU/lRr4Ablp3F8ZycHXPrNEm2oLonJLeSJDQKjJm4NsSP6brBs4=,iv:0JOTx4zHLoLmQFgMnh20RU1Sk0ONGR/gSoVMMHVGvFU=,tag:/BX9c/6HMM+0l38zWEwP4w==,type:str]
12+
pgp:
13+
- created_at: '2019-04-26T18:38:53Z'
14+
enc: |-
15+
-----BEGIN PGP MESSAGE-----
16+
17+
wcBMA/FdPFBXWyBuAQgAhUoPCTPjOpBexkgh5dMr2LTCb4ZsajkTXTa9a/wIJiBn
18+
TT1FRsQE2W+S9Yb/ClCz+ULearuUVYH0pUp7k+MDbpMt/SOMlIEA9JO0H631LqOS
19+
YLssnVOP/dsMH8uyhNCVuyLOHvVB3WMMxED+ic1m8oSbokqtIyCz5hmwR5MChebC
20+
nB42lqM8ZzRDS8DEBCykv78ityQFuLatog787sNxL9ExSeQ9iuLuu84UT4dWI4XF
21+
WUwwzyT3AUMbBkqftkucIi0iut+AORlgzyNAFlxxn4jXU10yl6iZvHj/Y76rJppm
22+
i2C4E15bS8fLrFtX7PsfnMLJOOSS+sulwr4THCFt39LgAeQtfxdz1iufUxQ+ePj4
23+
0w8x4ct/4EvgUuGE0OAD4oFkaCDgy+VbRWJQZn25OFLGUDMF+AUwnLnUu89hd/Ls
24+
ymrlCHWwIODS5M6xr6Rwx4agrWiURZUc95HiCknA7+FI3QA=
25+
=OUk7
26+
-----END PGP MESSAGE-----
27+
fp: 3CE5CC7219D6597CE6488BF1BF36CD3D0749A11A
28+
unencrypted_suffix: _unencrypted
29+
version: 3.2.0
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
a_list:
2+
- ENC[AES256_GCM,data:sxhIdQ==,iv:y2HITUKrZ/JgJT+9+UI5BDj1SMaGO0pTSvjJhsSW6r4=,tag:ZuCjI7N9WKjAshTaPYpspQ==,type:str]
3+
- ENC[AES256_GCM,data:6yi4mg==,iv:KS4tBgQAXDfpPeWD6Ew6w1jolp4L9VY7NswmqVjivPE=,tag:9P8obopM4+BN4F9Jk2vGig==,type:str]
4+
sops:
5+
kms: []
6+
gcp_kms: []
7+
azure_kv: []
8+
lastmodified: '2019-04-26T17:16:27Z'
9+
mac: ENC[AES256_GCM,data:6JzbXJfM7e4xP6qhGCSWQLal9YlXg2LmI9LSoX753Lu0uh6HuG7m02yA06Ls66jnNDzvHnxvCUobeuakuZeUNCp0+omu1pVgbs28Cx9cEya8SVwgrfBW9pQQMC8LEXSvesymDH4d78cWSUZrhLG6glOxTSZjV8Odl2/DSufuR2o=,iv:nh13+n7+ESX0eI0XmPOG9VgE9TZGz5YHjWKsNAdw3DI=,tag:Ucj6NSfEuRJIFGfaxc23Ww==,type:str]
10+
pgp:
11+
- created_at: '2019-04-26T17:16:11Z'
12+
enc: |-
13+
-----BEGIN PGP MESSAGE-----
14+
15+
wcBMA/FdPFBXWyBuAQgAmkN+YgyBOF+823IZdmGecxMWkuIB06wdRr339y1tGehi
16+
h1FxLlrwJU59ITCgjdzBJ0z0UCOqBP5qnwpzINu51LjtLEDMk9UOOmMfJdKLZ+5W
17+
3O2YuTXgKl2MfPqt6Oy17pGZaiSTNyrvI29TkkPyhi3fuTr0stg9LxL4s9qQvWjM
18+
kadq4ww3wwDL7VgxFxUfgF/CJALtRrdAbO3Fa63JXvOpeoa7huU75dnFleGDhFos
19+
WYNY2oK3U9q/wk9XtlTuArotALrveQI+UQgwQG9+19UMTTJyTcc26zXHIS7ROHND
20+
5qws6zlMhzKRXbvrH9CYbp1CSSvgOyG+UY2nphKURdLgAeQBS9lUL7wFklvXmgvB
21+
Dig84cjD4AngTuE7QeAk4h4xTlLgD+WTZFtU4gpa9061GRRGM8FGVw3DaRpXWHy0
22+
SUH3c/XifuCs5MExqB7LXKtX1SP81ynrTcLi0MH1r+Gt3gA=
23+
=O+MY
24+
-----END PGP MESSAGE-----
25+
fp: 3CE5CC7219D6597CE6488BF1BF36CD3D0749A11A
26+
unencrypted_suffix: _unencrypted
27+
version: 3.2.0

0 commit comments

Comments
 (0)