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
|
apiVersion: v1
|
||||||
entries: {}
|
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