Correcly handle CRLF in the manifest

kops replace/create/delete now correctly handle crlf in the manifest.

This fixes issue #6532
This commit is contained in:
Gennady Trafimenkov 2019-03-03 14:33:36 +03:00
parent 42a1aa5a23
commit 15bd566746
8 changed files with 126 additions and 10 deletions

View File

@ -31,6 +31,7 @@ import (
"k8s.io/kops/pkg/apis/kops/v1alpha1" "k8s.io/kops/pkg/apis/kops/v1alpha1"
"k8s.io/kops/pkg/kopscodecs" "k8s.io/kops/pkg/kopscodecs"
"k8s.io/kops/upup/pkg/fi/cloudup" "k8s.io/kops/upup/pkg/fi/cloudup"
"k8s.io/kops/util/pkg/text"
"k8s.io/kops/util/pkg/vfs" "k8s.io/kops/util/pkg/vfs"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -136,7 +137,7 @@ func RunCreate(f *util.Factory, out io.Writer, c *CreateOptions) error {
} }
} }
// TODO: this does not support a JSON array // TODO: this does not support a JSON array
sections := bytes.Split(bytes.Replace(contents, []byte("\r\n"), []byte("\n"), -1), []byte("\n---\n")) sections := text.SplitContentToSections(contents)
for _, section := range sections { for _, section := range sections {
defaults := &schema.GroupVersionKind{ defaults := &schema.GroupVersionKind{
Group: v1alpha1.SchemeGroupVersion.Group, Group: v1alpha1.SchemeGroupVersion.Group,

View File

@ -20,8 +20,6 @@ import (
"fmt" "fmt"
"io" "io"
"bytes"
"github.com/golang/glog" "github.com/golang/glog"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
@ -32,6 +30,7 @@ import (
"k8s.io/kops/pkg/apis/kops/v1alpha1" "k8s.io/kops/pkg/apis/kops/v1alpha1"
"k8s.io/kops/pkg/kopscodecs" "k8s.io/kops/pkg/kopscodecs"
"k8s.io/kops/pkg/sshcredentials" "k8s.io/kops/pkg/sshcredentials"
"k8s.io/kops/util/pkg/text"
"k8s.io/kops/util/pkg/vfs" "k8s.io/kops/util/pkg/vfs"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -115,7 +114,7 @@ func RunDelete(factory *util.Factory, out io.Writer, d *DeleteOptions) error {
} }
} }
sections := bytes.Split(contents, []byte("\n---\n")) sections := text.SplitContentToSections(contents)
for _, section := range sections { for _, section := range sections {
defaults := &schema.GroupVersionKind{ defaults := &schema.GroupVersionKind{
Group: v1alpha1.SchemeGroupVersion.Group, Group: v1alpha1.SchemeGroupVersion.Group,

View File

@ -17,7 +17,6 @@ limitations under the License.
package main package main
import ( import (
"bytes"
"fmt" "fmt"
"io" "io"
@ -30,6 +29,7 @@ import (
kopsapi "k8s.io/kops/pkg/apis/kops" kopsapi "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/commands" "k8s.io/kops/pkg/commands"
"k8s.io/kops/pkg/kopscodecs" "k8s.io/kops/pkg/kopscodecs"
"k8s.io/kops/util/pkg/text"
"k8s.io/kops/util/pkg/vfs" "k8s.io/kops/util/pkg/vfs"
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" "k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@ -107,7 +107,7 @@ func RunReplace(f *util.Factory, cmd *cobra.Command, out io.Writer, c *replaceOp
return fmt.Errorf("error reading file %q: %v", f, err) return fmt.Errorf("error reading file %q: %v", f, err)
} }
} }
sections := bytes.Split(contents, []byte("\n---\n")) sections := text.SplitContentToSections(contents)
for _, section := range sections { for _, section := range sections {
o, gvk, err := kopscodecs.Decode(section, nil) o, gvk, err := kopscodecs.Decode(section, nil)

View File

@ -17,11 +17,11 @@ limitations under the License.
package kubemanifest package kubemanifest
import ( import (
"bytes"
"fmt" "fmt"
"github.com/ghodss/yaml" "github.com/ghodss/yaml"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/kops/util/pkg/text"
) )
type Manifest struct { type Manifest struct {
@ -32,7 +32,7 @@ func LoadManifestsFrom(contents []byte) ([]*Manifest, error) {
var manifests []*Manifest var manifests []*Manifest
// TODO: Support more separators? // TODO: Support more separators?
sections := bytes.Split(contents, []byte("\n---\n")) sections := text.SplitContentToSections(contents)
for _, section := range sections { for _, section := range sections {
data := make(map[string]interface{}) data := make(map[string]interface{})

View File

@ -17,7 +17,6 @@ limitations under the License.
package testutils package testutils
import ( import (
"bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os" "os"
@ -32,6 +31,7 @@ import (
"k8s.io/kops/pkg/diff" "k8s.io/kops/pkg/diff"
"k8s.io/kops/pkg/kopscodecs" "k8s.io/kops/pkg/kopscodecs"
"k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/util/pkg/text"
) )
type Model struct { type Model struct {
@ -49,7 +49,7 @@ func LoadModel(basedir string) (*Model, error) {
spec := &Model{} spec := &Model{}
sections := bytes.Split(clusterYaml, []byte("\n---\n")) sections := text.SplitContentToSections(clusterYaml)
for _, section := range sections { for _, section := range sections {
defaults := &schema.GroupVersionKind{ defaults := &schema.GroupVersionKind{
Group: v1alpha2.SchemeGroupVersion.Group, Group: v1alpha2.SchemeGroupVersion.Group,

11
util/pkg/text/BUILD.bazel Normal file
View File

@ -0,0 +1,11 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["format.go"],
importpath = "k8s.io/kops/util/pkg/text",
visibility = ["//visibility:public"],
deps = [
"//util/pkg/reflectutils:go_default_library",
],
)

30
util/pkg/text/text.go Normal file
View File

@ -0,0 +1,30 @@
/*
Copyright 2019 The Kubernetes 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 text
import (
"bytes"
)
// SplitContentToSections splits content of a kops manifest into sections.
func SplitContentToSections(content []byte) [][]byte {
// replace windows line endings with unix ones
normalized := bytes.Replace(content, []byte("\r\n"), []byte("\n"), -1)
return bytes.Split(normalized, []byte("\n---\n"))
}

View File

@ -0,0 +1,75 @@
/*
Copyright 2019 The Kubernetes 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 text
import (
"testing"
)
func TestSplitToSections(t *testing.T) {
tests := []struct {
content []byte
numSections int
}{
{
content: []byte(""),
numSections: 1,
},
{
content: []byte("section 1"),
numSections: 1,
},
{
content: []byte("section 1\n"),
numSections: 1,
},
{
content: []byte("section 1\r\n"),
numSections: 1,
},
{
content: []byte("section 1\nanother line\n"),
numSections: 1,
},
{
content: []byte("section 1\r\nanother line\r\n"),
numSections: 1,
},
{
content: []byte("section 1\n---\nsection 2"),
numSections: 2,
},
{
content: []byte("section 1\r\n---\r\nsection 2"),
numSections: 2,
},
{
content: []byte("section 1\n\n---\n\nsection 2"),
numSections: 2,
},
{
content: []byte("section 1\r\n\r\n---\r\n\r\nsection 2"),
numSections: 2,
},
}
for _, test := range tests {
ns := len(SplitContentToSections(test.content))
if ns != test.numSections {
t.Errorf("Expected %v, got %v sections for content %q", test.numSections, ns, string(test.content))
}
}
}