Skip to content

Commit 68d5064

Browse files
authored
Fix Found duplicate key "resource, , List (v1)" errors (#232)
Fixes #201
1 parent fde6d08 commit 68d5064

File tree

3 files changed

+133
-22
lines changed

3 files changed

+133
-22
lines changed

manifest/parse.go

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -99,31 +99,19 @@ func Parse(manifest string, defaultNamespace string, excludedHooks ...string) ma
9999
if content == "" {
100100
continue
101101
}
102-
var parsedMetadata metadata
103-
if err := yaml.Unmarshal([]byte(content), &parsedMetadata); err != nil {
104-
log.Fatalf("YAML unmarshal error: %s\nCan't unmarshal %s", err, content)
105-
}
106102

107-
// Skip content without any metadata. It is probably a template that
108-
// only contains comments in the current state.
109-
if parsedMetadata.APIVersion == "" && parsedMetadata.Kind == "" {
110-
continue
111-
}
112-
if isHook(parsedMetadata, excludedHooks...) {
113-
continue
103+
parsed, err := parseContent(content, defaultNamespace, excludedHooks...)
104+
if err != nil {
105+
log.Fatalf("%v", err)
114106
}
115107

116-
if parsedMetadata.Metadata.Namespace == "" {
117-
parsedMetadata.Metadata.Namespace = defaultNamespace
118-
}
119-
name := parsedMetadata.String()
120-
if _, ok := result[name]; ok {
121-
log.Printf("Error: Found duplicate key %#v in manifest", name)
122-
} else {
123-
result[name] = &MappingResult{
124-
Name: name,
125-
Kind: parsedMetadata.Kind,
126-
Content: content,
108+
for _, p := range parsed {
109+
name := p.Name
110+
111+
if _, ok := result[name]; ok {
112+
log.Printf("Error: Found duplicate key %#v in manifest", name)
113+
} else {
114+
result[name] = p
127115
}
128116
}
129117
}
@@ -133,6 +121,66 @@ func Parse(manifest string, defaultNamespace string, excludedHooks ...string) ma
133121
return result
134122
}
135123

124+
func parseContent(content string, defaultNamespace string, excludedHooks ...string) ([]*MappingResult, error) {
125+
var parsedMetadata metadata
126+
if err := yaml.Unmarshal([]byte(content), &parsedMetadata); err != nil {
127+
log.Fatalf("YAML unmarshal error: %s\nCan't unmarshal %s", err, content)
128+
}
129+
130+
// Skip content without any metadata. It is probably a template that
131+
// only contains comments in the current state.
132+
if parsedMetadata.APIVersion == "" && parsedMetadata.Kind == "" {
133+
return nil, nil
134+
}
135+
136+
if parsedMetadata.Kind == "List" {
137+
type ListV1 struct {
138+
Items []yaml.MapSlice `yaml:"items"`
139+
}
140+
141+
var list ListV1
142+
143+
if err := yaml.Unmarshal([]byte(content), &list); err != nil {
144+
log.Fatalf("YAML unmarshal error: %s\nCan't unmarshal %s", err, content)
145+
}
146+
147+
var result []*MappingResult
148+
149+
for _, item := range list.Items {
150+
subcontent, err := yaml.Marshal(item)
151+
if err != nil {
152+
log.Printf("YAML marshal error: %s\nCan't marshal %v", err, item)
153+
}
154+
155+
subs, err := parseContent(string(subcontent), defaultNamespace, excludedHooks...)
156+
if err != nil {
157+
return nil, fmt.Errorf("Parsing YAML list item: %v", err)
158+
}
159+
160+
result = append(result, subs...)
161+
}
162+
163+
return result, nil
164+
}
165+
166+
if isHook(parsedMetadata, excludedHooks...) {
167+
return nil, nil
168+
}
169+
170+
if parsedMetadata.Metadata.Namespace == "" {
171+
parsedMetadata.Metadata.Namespace = defaultNamespace
172+
}
173+
174+
name := parsedMetadata.String()
175+
return []*MappingResult{
176+
{
177+
Name: name,
178+
Kind: parsedMetadata.Kind,
179+
Content: content,
180+
},
181+
}, nil
182+
}
183+
136184
func isHook(metadata metadata, hooks ...string) bool {
137185
for _, hook := range hooks {
138186
if metadata.Metadata.Annotations[hookAnnotation] == hook {

manifest/parse_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,19 @@ func TestDeployV1Beta1(t *testing.T) {
7979
)
8080
}
8181

82+
func TestList(t *testing.T) {
83+
spec, err := ioutil.ReadFile("testdata/list.yaml")
84+
require.NoError(t, err)
85+
86+
require.Equal(t,
87+
[]string{
88+
"default, prometheus-operator-example, PrometheusRule (monitoring.coreos.com)",
89+
"default, prometheus-operator-example2, PrometheusRule (monitoring.coreos.com)",
90+
},
91+
foundObjects(Parse(string(spec), "default")),
92+
)
93+
}
94+
8295
func TestEmpty(t *testing.T) {
8396
spec, err := ioutil.ReadFile("testdata/empty.yaml")
8497
require.NoError(t, err)

manifest/testdata/list.yaml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
---
3+
# Source: prometheus-operator/templates/prometheus/additionalPrometheusRules.yaml
4+
apiVersion: v1
5+
kind: List
6+
items:
7+
- apiVersion: monitoring.coreos.com/v1
8+
kind: PrometheusRule
9+
metadata:
10+
name: prometheus-operator-example
11+
namespace: default
12+
labels:
13+
app: prometheus-operator
14+
chart: prometheus-operator-9.3.0
15+
release: "foo"
16+
heritage: "Helm"
17+
spec:
18+
groups:
19+
- name: mygroup
20+
rules:
21+
- annotations:
22+
summary: Container {{ $labels.container }} in Pod {{$labels.namespace}}/{{$labels.pod}}
23+
restarting
24+
expr: count(sum by (pod)(delta(kube_pod_container_status_restarts_total[15m])
25+
> 0))
26+
labels:
27+
severity: warning
28+
record: ContainerRestarted
29+
- apiVersion: monitoring.coreos.com/v1
30+
kind: PrometheusRule
31+
metadata:
32+
name: prometheus-operator-example2
33+
namespace: default
34+
labels:
35+
app: prometheus-operator
36+
chart: prometheus-operator-9.3.0
37+
release: "foo"
38+
heritage: "Helm"
39+
spec:
40+
groups:
41+
- name: mygroup2
42+
rules:
43+
- annotations:
44+
summary: Container {{ $labels.container }} in Pod {{$labels.namespace}}/{{$labels.pod}}
45+
restarting
46+
expr: count(sum by (pod)(delta(kube_pod_container_status_restarts_total[15m])
47+
> 0))
48+
labels:
49+
severity: warning
50+
record: ContainerRestarted

0 commit comments

Comments
 (0)