mirror of https://github.com/helm/helm
Signed-off-by: Matt Butcher <matt.butcher@microsoft.com>pull/8573/head
parent
0498f0e5a2
commit
c6d9765529
@ -1,3 +1,3 @@
|
||||
apiVersion: v1
|
||||
entries: {}
|
||||
generated: "2020-06-23T10:01:59.2530763-07:00"
|
||||
generated: "2020-09-01T10:53:17.923514-06:00"
|
||||
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package postrender
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
// Reparse attempts to split a YAML stream as returned by a post-rendered back into a map of files
|
||||
//
|
||||
// Elsewhere in Helm, it treats individual YAMLs as filename/content pairs. The post-render
|
||||
// is inserted into the middle of that context. Thus, when a post-render returns, we need
|
||||
// a way to convert it back into a map[string]string. There are no assumptions about
|
||||
// what the filename looks like when it comes back from the postrenderer, so we can take
|
||||
// some liberties with naming here that we cannot take in other contexts.
|
||||
//
|
||||
// Note that the YAML specification is very clear that the string '\n---\n' is a document
|
||||
// split sequence. So we can cheaply process using that method. Also we rely on the
|
||||
// Kubernetes requirement that metadata.name is a required field for all valid Kubernetes
|
||||
// resource instances, as are apiVersion and kind.
|
||||
func Reparse(manifest []byte) (map[string]string, error) {
|
||||
sep := []byte("\n---\n")
|
||||
manifests := bytes.Split(manifest, sep)
|
||||
files := map[string]string{}
|
||||
|
||||
for _, resource := range manifests {
|
||||
if s := strings.TrimSpace(string(resource)); s == "" {
|
||||
continue
|
||||
}
|
||||
h := &header{}
|
||||
if err := yaml.Unmarshal(resource, h); err != nil {
|
||||
return files, errors.Wrap(err, "manifest returned from post render is not well-formed")
|
||||
}
|
||||
|
||||
// Name and Kind are required on every manifest
|
||||
if h.Kind == "" {
|
||||
return files, fmt.Errorf("manifest returned by post-render has no kind:\n%s", resource)
|
||||
}
|
||||
if h.Metadata.Name == "" {
|
||||
return files, fmt.Errorf("manifest returned by post-render has no name:\n%s", resource)
|
||||
}
|
||||
name := h.filename()
|
||||
if _, ok := files[name]; ok {
|
||||
return files, fmt.Errorf("two or more post-rendered objects have the name %q", name)
|
||||
}
|
||||
files[name] = string(resource)
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
type header struct {
|
||||
APIVersion string `json:"apiVersion"`
|
||||
Kind string
|
||||
Metadata struct {
|
||||
Name string
|
||||
}
|
||||
}
|
||||
|
||||
func (h *header) filename() string {
|
||||
name := ""
|
||||
if h.APIVersion != "" {
|
||||
name = h.APIVersion + "."
|
||||
}
|
||||
return fmt.Sprintf("%s%s.%s.yaml", name, h.Kind, h.Metadata.Name)
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright The Helm Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package postrender
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var goodYaml = `
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: hollow-men
|
||||
data: |-
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
Not with a bang but a whimper.
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: waste-land
|
||||
data: |-
|
||||
To Carthage then I came
|
||||
Burning burning burning burning
|
||||
`
|
||||
|
||||
var duplicateYaml = `
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: hollow-men
|
||||
data: |-
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
Not with a bang but a whimper.
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: hollow-men
|
||||
data: |-
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
Not with a bang but a whimper.
|
||||
`
|
||||
|
||||
var nonameYaml = `
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
data: |-
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
Not with a bang but a whimper.
|
||||
`
|
||||
var unkindYaml = `
|
||||
---
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: hollow-men
|
||||
data: |-
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
Not with a bang but a whimper.
|
||||
`
|
||||
|
||||
var hollowMen = `apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: hollow-men
|
||||
data: |-
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
This is the way the world ends
|
||||
Not with a bang but a whimper.`
|
||||
|
||||
func TestReparse(t *testing.T) {
|
||||
is := assert.New(t)
|
||||
res, err := Reparse([]byte(goodYaml))
|
||||
is.NoError(err, goodYaml)
|
||||
|
||||
is.Len(res, 2, "two map entries")
|
||||
names := []string{"v1.ConfigMap.hollow-men.yaml", "v1.ConfigMap.waste-land.yaml"}
|
||||
for _, name := range names {
|
||||
content, ok := res[name]
|
||||
is.True(ok, "entry for %s exists", name)
|
||||
is.NotEmpty(content)
|
||||
}
|
||||
is.Equal(hollowMen, res[names[0]], "content matches")
|
||||
|
||||
// duplicate failure
|
||||
_, err = Reparse([]byte(duplicateYaml))
|
||||
is.Error(err, "duplicate YAML fails to parse")
|
||||
|
||||
// name is missing
|
||||
_, err = Reparse([]byte(nonameYaml))
|
||||
is.Error(err, "unnamed object fails to parse")
|
||||
|
||||
// kind is missing
|
||||
_, err = Reparse([]byte(unkindYaml))
|
||||
is.Error(err, "kindless object fails to parse")
|
||||
}
|
Loading…
Reference in new issue