mirror of
https://github.com/kubernetes-sigs/kind.git
synced 2025-12-01 07:26:05 +07:00
add patch.TOML
This commit is contained in:
2
go.mod
2
go.mod
@@ -3,9 +3,11 @@ module sigs.k8s.io/kind
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053
|
||||
github.com/evanphx/json-patch v4.5.0+incompatible
|
||||
github.com/mattn/go-isatty v0.0.10
|
||||
github.com/pelletier/go-toml v1.2.0
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/spf13/pflag v1.0.5
|
||||
|
||||
3
go.sum
3
go.sum
@@ -1,3 +1,4 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
@@ -11,6 +12,7 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
|
||||
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
@@ -68,6 +70,7 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
|
||||
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
||||
100
pkg/internal/util/patch/toml.go
Normal file
100
pkg/internal/util/patch/toml.go
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
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 patch
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
|
||||
burntoml "github.com/BurntSushi/toml"
|
||||
jsonpatch "github.com/evanphx/json-patch"
|
||||
toml "github.com/pelletier/go-toml"
|
||||
yaml "gopkg.in/yaml.v3"
|
||||
|
||||
"sigs.k8s.io/kind/pkg/errors"
|
||||
)
|
||||
|
||||
// TOML patches toPatch with the patches (should be TOML merge patches) and patches6902 (should be JSON 6902 patches)
|
||||
func TOML(toPatch string, patches []string, patches6902 []string) (string, error) {
|
||||
// convert to JSON for patching
|
||||
j, err := tomlToJSON([]byte(toPatch))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// apply merge patches
|
||||
for _, patch := range patches {
|
||||
pj, err := tomlToJSON([]byte(patch))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
patched, err := jsonpatch.MergePatch(j, pj)
|
||||
if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
j = patched
|
||||
}
|
||||
// apply JSON 6902 patches
|
||||
for _, patch6902 := range patches6902 {
|
||||
patch, err := jsonpatch.DecodePatch([]byte(patch6902))
|
||||
if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
patched, err := patch.Apply(j)
|
||||
if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
j = patched
|
||||
}
|
||||
// convert result back to TOML
|
||||
return jsonToTOMLString(j)
|
||||
}
|
||||
|
||||
// tomlToJSON converts arbitrary TOML to JSON
|
||||
func tomlToJSON(t []byte) ([]byte, error) {
|
||||
// we use github.com.pelletier/go-toml here to unmarshal arbitrary TOML to JSON
|
||||
tree, err := toml.LoadBytes(t)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
b, err := json.Marshal(tree.ToMap())
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
|
||||
// jsonToTOMLString converts arbitrary JSON to TOML
|
||||
func jsonToTOMLString(j []byte) (string, error) {
|
||||
var unstruct interface{}
|
||||
// We are using yaml.Unmarshal here (instead of json.Unmarshal) because the
|
||||
// Go JSON library doesn't try to pick the right number type (int, float,
|
||||
// etc.) when unmarshalling to interface{}, it just picks float64
|
||||
// universally. go-yaml does go through the effort of picking the right
|
||||
// number type, so we can preserve number type throughout this process.
|
||||
if err := yaml.Unmarshal(j, &unstruct); err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
// we use github.com/BurntSushi/toml here because github.com.pelletier/go-toml
|
||||
// can only marshal structs AND BurntSushi/toml is what contained uses
|
||||
// and has more canonically formatted output (we initially plan to use
|
||||
// this package for patching containerd config)
|
||||
var buff bytes.Buffer
|
||||
if err := burntoml.NewEncoder(&buff).Encode(unstruct); err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
return buff.String(), nil
|
||||
}
|
||||
198
pkg/internal/util/patch/toml_test.go
Normal file
198
pkg/internal/util/patch/toml_test.go
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
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 patch
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sigs.k8s.io/kind/pkg/internal/util/assert"
|
||||
)
|
||||
|
||||
func TestTOML(t *testing.T) {
|
||||
t.Parallel()
|
||||
type testCase struct {
|
||||
Name string
|
||||
ToPatch string
|
||||
Patches []string
|
||||
PatchesJSON6902 []string
|
||||
ExpectError bool
|
||||
ExpectOutput string
|
||||
}
|
||||
cases := []testCase{
|
||||
{
|
||||
Name: "invalid TOML",
|
||||
ToPatch: `🗿`,
|
||||
ExpectError: true,
|
||||
ExpectOutput: "",
|
||||
},
|
||||
{
|
||||
Name: "no patches",
|
||||
ToPatch: `disabled_plugins = ["restart"]
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"`,
|
||||
ExpectError: false,
|
||||
ExpectOutput: `disabled_plugins = ["restart"]
|
||||
|
||||
[plugins]
|
||||
[plugins.cri]
|
||||
[plugins.cri.containerd]
|
||||
[plugins.cri.containerd.runtimes]
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "invalid patch TOML",
|
||||
ToPatch: `disabled_plugins = ["restart"]
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"`,
|
||||
Patches: []string{"🏰"},
|
||||
ExpectError: true,
|
||||
},
|
||||
{
|
||||
Name: "invalid 6902 patch JSON",
|
||||
ToPatch: `disabled_plugins = ["restart"]
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"`,
|
||||
PatchesJSON6902: []string{"🏰"},
|
||||
ExpectError: true,
|
||||
},
|
||||
{
|
||||
Name: "trivial patch",
|
||||
ToPatch: `disabled_plugins = ["restart"]
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"`,
|
||||
Patches: []string{`disabled_plugins=[]`},
|
||||
ExpectError: false,
|
||||
ExpectOutput: `[plugins]
|
||||
[plugins.cri]
|
||||
[plugins.cri.containerd]
|
||||
[plugins.cri.containerd.runtimes]
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "trivial 6902 patch",
|
||||
ToPatch: `disabled_plugins = ["restart"]
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"`,
|
||||
PatchesJSON6902: []string{`[{"op": "remove", "path": "/disabled_plugins"}]`},
|
||||
ExpectError: false,
|
||||
ExpectOutput: `[plugins]
|
||||
[plugins.cri]
|
||||
[plugins.cri.containerd]
|
||||
[plugins.cri.containerd.runtimes]
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "trivial patch and trivial 6902 patch",
|
||||
ToPatch: `disabled_plugins = ["restart"]
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"`,
|
||||
Patches: []string{`disabled_plugins=["foo"]`},
|
||||
PatchesJSON6902: []string{`[{"op": "remove", "path": "/disabled_plugins"}]`},
|
||||
ExpectError: false,
|
||||
ExpectOutput: `[plugins]
|
||||
[plugins.cri]
|
||||
[plugins.cri.containerd]
|
||||
[plugins.cri.containerd.runtimes]
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "invalid path 6902 patch",
|
||||
ToPatch: `disabled_plugins = ["restart"]
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"`,
|
||||
PatchesJSON6902: []string{`[{"op": "remove", "path": "/fooooooo"}]`},
|
||||
ExpectError: true,
|
||||
ExpectOutput: `[plugins]
|
||||
[plugins.cri]
|
||||
[plugins.cri.containerd]
|
||||
[plugins.cri.containerd.runtimes]
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
`,
|
||||
},
|
||||
{
|
||||
Name: "patch registry",
|
||||
ToPatch: `disabled_plugins = ["restart"]
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"`,
|
||||
Patches: []string{`[plugins.cri.registry.mirrors]
|
||||
[plugins.cri.registry.mirrors."registry:5000"]
|
||||
endpoint = ["http://registry:5000"]`},
|
||||
ExpectError: false,
|
||||
ExpectOutput: `disabled_plugins = ["restart"]
|
||||
|
||||
[plugins]
|
||||
[plugins.cri]
|
||||
[plugins.cri.containerd]
|
||||
[plugins.cri.containerd.runtimes]
|
||||
[plugins.cri.containerd.runtimes.runsc]
|
||||
runtime_type = "io.containerd.runsc.v1"
|
||||
[plugins.cri.registry]
|
||||
[plugins.cri.registry.mirrors]
|
||||
[plugins.cri.registry.mirrors."registry:5000"]
|
||||
endpoint = ["http://registry:5000"]
|
||||
[plugins.linux]
|
||||
shim_debug = true
|
||||
`,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
tc := tc // capture test case
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
out, err := TOML(tc.ToPatch, tc.Patches, tc.PatchesJSON6902)
|
||||
assert.ExpectError(t, tc.ExpectError, err)
|
||||
if err == nil {
|
||||
assert.StringEqual(t, tc.ExpectOutput, out)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user