From 2bf76c9d25b1558fd068c7af8e7d07f3ba8bead9 Mon Sep 17 00:00:00 2001 From: Benjamin Elder Date: Fri, 18 Oct 2019 17:33:28 -0700 Subject: [PATCH] replace kustomize with custom json-patch routine --- go.mod | 7 +- go.sum | 143 +----------------- .../cluster/create/actions/config/config.go | 4 +- pkg/internal/util/kustomize/kustomize.go | 140 ----------------- pkg/internal/util/patch/json6902patch.go | 53 +++++++ pkg/internal/util/patch/matchinfo.go | 53 +++++++ pkg/internal/util/patch/mergepatch.go | 49 ++++++ pkg/internal/util/patch/patch.go | 78 ++++++++++ .../kutomize_test.go => patch/patch_test.go} | 16 +- pkg/internal/util/patch/resource.go | 118 +++++++++++++++ 10 files changed, 374 insertions(+), 287 deletions(-) delete mode 100644 pkg/internal/util/kustomize/kustomize.go create mode 100644 pkg/internal/util/patch/json6902patch.go create mode 100644 pkg/internal/util/patch/matchinfo.go create mode 100644 pkg/internal/util/patch/mergepatch.go create mode 100644 pkg/internal/util/patch/patch.go rename pkg/internal/util/{kustomize/kutomize_test.go => patch/patch_test.go} (96%) create mode 100644 pkg/internal/util/patch/resource.go diff --git a/go.mod b/go.mod index 6f5eb216..966832c8 100644 --- a/go.mod +++ b/go.mod @@ -4,13 +4,16 @@ go 1.13 require ( github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053 + github.com/evanphx/json-patch v4.5.0+incompatible github.com/google/uuid v1.1.1 + github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/pkg/errors v0.8.1 github.com/spf13/cobra v0.0.3 + github.com/spf13/pflag v1.0.5 // indirect golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 + gopkg.in/yaml.v2 v2.2.4 // indirect gopkg.in/yaml.v3 v3.0.0-20191010095647-fc94e3f71652 - k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b // indirect k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d - sigs.k8s.io/kustomize/v3 v3.2.0 + k8s.io/klog v1.0.0 // indirect sigs.k8s.io/yaml v1.1.0 ) diff --git a/go.sum b/go.sum index 0b555f33..76fc82ec 100644 --- a/go.sum +++ b/go.sum @@ -1,165 +1,38 @@ -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= -github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053 h1:H/GMMKYPkEIC3DF/JWQz8Pdd+Feifov2EIgGfNpeogI= github.com/alessio/shellescape v0.0.0-20190409004728-b115ca0f9053/go.mod h1:xW8sBma2LE3QxFSzCnH9qe6gAE2yO9GvQaWwX89HxbE= -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/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw= -github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful v2.9.6+incompatible h1:tfrHha8zJ01ywiOEC1miGY8st1/igzWB8OmvPgoYX7w= -github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0= -github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= -github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= -github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= -github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc= -github.com/go-openapi/spec v0.19.2 h1:SStNd1jRcYtfKCN7R0laGNs80WYYvn5CbBjM2sOmCrE= -github.com/go-openapi/spec v0.19.2/go.mod h1:sCxk3jxKgioEJikev4fgkNmwS+3kuYdJtcsZsD5zxMY= -github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE= -github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE= -github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7 h1:VoRHccBV7zFWlO/I85D1ke/x5Ak9Y7gKm9gkf7LHNhI= -github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= -github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9 h1:Dk8DO58y0wXeNG49dRqzf4HrZAK9lFfTgS/FNtB6NlM= -github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0= -github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= -github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481 h1:IaSjLMT6WvkoZZjspGxy3rdaTEmWLoRm49WbtVUi9sA= -github.com/mailru/easyjson v0.0.0-20190620125010-da37f6c1e481/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c h1:Hww8mOyEKTeON4bZn7FrlLismspbPc1teNRUVH7wLQ8= -github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= -github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c h1:eSfnfIuwhxZyULg1NNuZycJcYkjYVGYe7FczwQReM6U= -github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= -github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/spf13/cobra v0.0.2/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8 h1:1wopBVtVdWnn03fZelqdXTqk7U7zPQCb+T4rbU9ZEoU= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190621203818-d432491b9138 h1:t8BZD9RDjkm9/h7yYN6kE8oaeov5r9aztkB7zKA5Tkg= -golang.org/x/sys v0.0.0-20190621203818-d432491b9138/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= +gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20191010095647-fc94e3f71652 h1:VKvJ/mQ4BgCjZUDggYFxTe0qv9jPMHsZPD4Xt91Y5H4= gopkg.in/yaml.v3 v3.0.0-20191010095647-fc94e3f71652/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.0.0-20190313235455-40a48860b5ab/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= -k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b h1:aBGgKJUM9Hk/3AE8WaZIApnTxG35kbuQba2w+SXqezo= -k8s.io/api v0.0.0-20190409021203-6e4e0e4f393b/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA= -k8s.io/apimachinery v0.0.0-20190313205120-d7deff9243b1/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d h1:Jmdtdt1ZnoGfWWIIik61Z7nKYgO3J+swQJtPYsP9wHA= k8s.io/apimachinery v0.0.0-20190404173353-6a84e37a896d/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0= -k8s.io/client-go v11.0.0+incompatible h1:LBbX2+lOwY9flffWlJM7f1Ct8V2SRNiMRDFeiwnJo9o= -k8s.io/client-go v11.0.0+incompatible/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s= -k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= -k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/klog v0.3.3 h1:niceAagH1tzskmaie/icWd7ci1wbG7Bf2c6YGcQv+3c= -k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= -k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208 h1:5sW+fEHvlJI3Ngolx30CmubFulwH28DhKjGf70Xmtco= -k8s.io/kube-openapi v0.0.0-20190603182131-db7b694dc208/go.mod h1:nfDlWeOsu3pUf4yWGL+ERqohP4YsZcBJXWMK+gkzOA4= -sigs.k8s.io/kustomize/v3 v3.2.0 h1:EKcEubO29vCbigcMoNynfyZH+ANWkML2UHWibt1Do7o= -sigs.k8s.io/kustomize/v3 v3.2.0/go.mod h1:ztX4zYc/QIww3gSripwF7TBOarBTm5BvyAMem0kCzOE= -sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= +k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= +k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/pkg/internal/cluster/create/actions/config/config.go b/pkg/internal/cluster/create/actions/config/config.go index e2b49092..078990f3 100644 --- a/pkg/internal/cluster/create/actions/config/config.go +++ b/pkg/internal/cluster/create/actions/config/config.go @@ -32,7 +32,7 @@ import ( "sigs.k8s.io/kind/pkg/internal/cluster/create/actions" "sigs.k8s.io/kind/pkg/internal/cluster/kubeadm" "sigs.k8s.io/kind/pkg/internal/cluster/providers/provider/common" - "sigs.k8s.io/kind/pkg/internal/util/kustomize" + "sigs.k8s.io/kind/pkg/internal/util/patch" ) // Action implements action for creating the kubeadm config @@ -137,7 +137,7 @@ func getKubeadmConfig(cfg *config.Cluster, data kubeadm.ConfigData) (path string // apply patches // TODO(bentheelder): this does not respect per node patches at all // either make patches cluster wide, or change this - patched, err := kustomize.Build([]string{config}, patches, jsonPatches) + patched, err := patch.Patch(config, patches, jsonPatches) if err != nil { return "", err } diff --git a/pkg/internal/util/kustomize/kustomize.go b/pkg/internal/util/kustomize/kustomize.go deleted file mode 100644 index 4c217b7a..00000000 --- a/pkg/internal/util/kustomize/kustomize.go +++ /dev/null @@ -1,140 +0,0 @@ -/* -Copyright 2018 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 kustomize contains helpers for working with embedded kustomize commands -package kustomize - -import ( - "fmt" - "path/filepath" - "runtime" - - "sigs.k8s.io/kustomize/v3/k8sdeps/kunstruct" - "sigs.k8s.io/kustomize/v3/k8sdeps/transformer" - "sigs.k8s.io/kustomize/v3/pkg/fs" - "sigs.k8s.io/kustomize/v3/pkg/gvk" - "sigs.k8s.io/kustomize/v3/pkg/loader" - "sigs.k8s.io/kustomize/v3/pkg/plugins" - "sigs.k8s.io/kustomize/v3/pkg/resmap" - "sigs.k8s.io/kustomize/v3/pkg/resource" - "sigs.k8s.io/kustomize/v3/pkg/target" - "sigs.k8s.io/kustomize/v3/pkg/types" - "sigs.k8s.io/kustomize/v3/pkg/validators" - "sigs.k8s.io/kustomize/v3/plugin/builtin" - "sigs.k8s.io/yaml" - - "sigs.k8s.io/kind/pkg/errors" - - "sigs.k8s.io/kind/pkg/internal/apis/config" -) - -// Build takes a set of resource blobs (yaml), patches (strategic merge patch) -// https://github.com/kubernetes/community/blob/master/contributors/devel/strategic-merge-patch.md -// and returns the `kustomize build` result as a yaml blob -// It does this in-memory using the build cobra command -func Build(resources, patches []string, patchesJSON6902 []config.PatchJSON6902) (string, error) { - // write the resources and patches to an in memory fs with a generated - // kustomization.yaml - memFS := fs.MakeFakeFS() // fs.MakeFsInMemory() - fakeDir := "/" - // for Windows we need this to be a drive because kustomize uses filepath.Abs() - // which will add a drive letter if there is none. which drive letter is - // unimportant as the path is on the fake filesystem anyhow - if runtime.GOOS == "windows" { - fakeDir = `C:\` - } - - // NOTE: we always write this header as you cannot build without any resources - kustomization := &types.Kustomization{ - TypeMeta: types.TypeMeta{ - APIVersion: types.KustomizationVersion, - Kind: types.KustomizationKind, - }, - PatchesStrategicMerge: make([]types.PatchStrategicMerge, 0, len(patches)), - PatchesJson6902: make([]types.PatchJson6902, 0, len(patchesJSON6902)), - Resources: make([]string, 0, len(resources)), - } - - for i, resource := range resources { - // this cannot error per docs - name := fmt.Sprintf("resource-%d.yaml", i) - _ = memFS.WriteFile(filepath.Join(fakeDir, name), []byte(resource)) - kustomization.Resources = append(kustomization.Resources, name) - } - - for i, patch := range patches { - // this cannot error per docs - name := fmt.Sprintf("patch-%d.yaml", i) - _ = memFS.WriteFile(filepath.Join(fakeDir, name), []byte(patch)) - kustomization.PatchesStrategicMerge = append(kustomization.PatchesStrategicMerge, types.PatchStrategicMerge(name)) - } - - for i, patch := range patchesJSON6902 { - // this cannot error per docs - name := fmt.Sprintf("patch-json6902-%d.yaml", i) - _ = memFS.WriteFile(filepath.Join(fakeDir, name), []byte(patch.Patch)) - kustomization.PatchesJson6902 = append(kustomization.PatchesJson6902, types.PatchJson6902{ - Path: name, - Target: &types.PatchTarget{ - Gvk: gvk.Gvk{ - Group: patch.Group, - Version: patch.Version, - }, - Name: patch.Name, - Namespace: patch.Namespace, - }, - }) - } - - // Write out kustomization.yaml - buf, err := yaml.Marshal(kustomization) - if err != nil { - return "", errors.Wrap(err, "error marshaling kustomization.yaml") - } - if err := memFS.WriteFile(filepath.Join(fakeDir, "kustomization.yaml"), buf); err != nil { - return "", errors.Wrap(err, "error writing kustomization.yaml to memFS") - } - - // now we can build the kustomization - // Note; kustomize has internalized cmd build kustomize 3.2.0 - lrc := loader.RestrictionRootOnly - ldr, err := loader.NewLoader(lrc, validators.MakeFakeValidator(), fakeDir, memFS) - if err != nil { - return "", errors.Wrap(err, "error executing kustomize build") - } - defer func() { - _ = ldr.Cleanup() - }() - rf := resmap.NewFactory(resource.NewFactory(kunstruct.NewKunstructuredFactoryImpl()), transformer.NewFactoryImpl()) - pc := plugins.DefaultPluginConfig() - kt, err := target.NewKustTarget(ldr, rf, transformer.NewFactoryImpl(), plugins.NewLoader(pc, rf)) - if err != nil { - return "", errors.Wrap(err, "error executing kustomize build") - } - allResources, err := kt.MakeCustomizedResMap() - if err != nil { - return "", errors.Wrap(err, "error executing kustomize build") - } - err = builtin.NewLegacyOrderTransformerPlugin().Transform(allResources) - if err != nil { - return "", errors.Wrap(err, "error executing kustomize build") - } - yamlResources, err := allResources.AsYaml() - if err != nil { - return "", errors.Wrap(err, "error executing kustomize build") - } - return string(yamlResources), nil -} diff --git a/pkg/internal/util/patch/json6902patch.go b/pkg/internal/util/patch/json6902patch.go new file mode 100644 index 00000000..3974992a --- /dev/null +++ b/pkg/internal/util/patch/json6902patch.go @@ -0,0 +1,53 @@ +/* +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 ( + jsonpatch "github.com/evanphx/json-patch" + + "sigs.k8s.io/yaml" + + "sigs.k8s.io/kind/pkg/errors" + + "sigs.k8s.io/kind/pkg/internal/apis/config" +) + +type json6902Patch struct { + raw string // raw original contents + patch jsonpatch.Patch // processed JSON 6902 patch + matchInfo matchInfo // used to match resources +} + +func convertJSON6902Patches(patchesJSON6902 []config.PatchJSON6902) ([]json6902Patch, error) { + patches := []json6902Patch{} + for _, configPatch := range patchesJSON6902 { + patchJSON, err := yaml.YAMLToJSON([]byte(configPatch.Patch)) + if err != nil { + return nil, errors.WithStack(err) + } + patch, err := jsonpatch.DecodePatch(patchJSON) + if err != nil { + return nil, errors.WithStack(err) + } + patches = append(patches, json6902Patch{ + raw: configPatch.Patch, + patch: patch, + matchInfo: matchInfoForConfigJSON6902Patch(configPatch), + }) + } + return patches, nil +} diff --git a/pkg/internal/util/patch/matchinfo.go b/pkg/internal/util/patch/matchinfo.go new file mode 100644 index 00000000..0f87d5f7 --- /dev/null +++ b/pkg/internal/util/patch/matchinfo.go @@ -0,0 +1,53 @@ +/* +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 ( + "sigs.k8s.io/yaml" + + "sigs.k8s.io/kind/pkg/errors" + + "sigs.k8s.io/kind/pkg/internal/apis/config" +) + +// we match resources and patches on their v1 TypeMeta +type matchInfo struct { + Kind string `json:"kind,omitempty"` + APIVersion string `json:"apiVersion,omitempty"` +} + +func parseYAMLMatchInfo(raw string) (matchInfo, error) { + m := matchInfo{} + if err := yaml.Unmarshal([]byte(raw), &m); err != nil { + return matchInfo{}, errors.Wrap(err, "failed to parse type meta") + } + return m, nil +} + +func matchInfoForConfigJSON6902Patch(patch config.PatchJSON6902) matchInfo { + return matchInfo{ + Kind: patch.Kind, + APIVersion: groupVersionToAPIVersion(patch.Group, patch.Version), + } +} + +func groupVersionToAPIVersion(group, version string) string { + if group == "" { + return version + } + return group + "/" + version +} diff --git a/pkg/internal/util/patch/mergepatch.go b/pkg/internal/util/patch/mergepatch.go new file mode 100644 index 00000000..7b8679f7 --- /dev/null +++ b/pkg/internal/util/patch/mergepatch.go @@ -0,0 +1,49 @@ +/* +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 ( + "sigs.k8s.io/yaml" + + "sigs.k8s.io/kind/pkg/errors" +) + +type mergePatch struct { + raw string // the original raw data + json []byte // the processed data (in JSON form) + matchInfo matchInfo // for matching resources +} + +func parseMergePatches(rawPatches []string) ([]mergePatch, error) { + patches := []mergePatch{} + for _, raw := range rawPatches { + matchInfo, err := parseYAMLMatchInfo(raw) + if err != nil { + return nil, errors.WithStack(err) + } + json, err := yaml.YAMLToJSON([]byte(raw)) + if err != nil { + return nil, errors.WithStack(err) + } + patches = append(patches, mergePatch{ + raw: raw, + json: json, + matchInfo: matchInfo, + }) + } + return patches, nil +} diff --git a/pkg/internal/util/patch/patch.go b/pkg/internal/util/patch/patch.go new file mode 100644 index 00000000..9f9972b3 --- /dev/null +++ b/pkg/internal/util/patch/patch.go @@ -0,0 +1,78 @@ +/* +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 contains helpers for patching yaml +package patch + +import ( + "strings" + + "sigs.k8s.io/kind/pkg/errors" + + "sigs.k8s.io/kind/pkg/internal/apis/config" +) + +// Patch takes a yaml document stream to patch, merge patches, and JSON 6902 patches +// It returns a patched a yaml document stream. +// +// Matching is performed on Kubernetes style v1 TypeMeta fields (kind and apiVersion), +// between the yaml documents and the patches. +// +// Patches match if their kind and apiVersion match a document, with the exception +// that if the patch does not set apiVersion it will be ignored. +func Patch(toPatch string, patches []string, patches6902 []config.PatchJSON6902) (string, error) { + // pre-process, including splitting up documents etc. + resources, err := parseResources(toPatch) + if err != nil { + return "", errors.Wrap(err, "failed to parse yaml to patch") + } + mergePatches, err := parseMergePatches(patches) + if err != nil { + return "", errors.Wrap(err, "failed to parse patches") + } + json6902patches, err := convertJSON6902Patches(patches6902) + if err != nil { + return "", errors.Wrap(err, "failed to parse JSON 6902 patches") + } + // apply patches and build result + builder := &strings.Builder{} + for i, r := range resources { + // apply merge patches + for _, p := range mergePatches { + if _, err := r.applyMergePatch(p); err != nil { + return "", errors.Wrap(err, "failed to apply patch") + } + } + // apply RFC 6902 JSON patches + for _, p := range json6902patches { + if _, err := r.apply6902Patch(p); err != nil { + return "", errors.Wrap(err, "failed to apply JSON 6902 patch") + } + } + // write out result + if err := r.encodeTo(builder); err != nil { + return "", errors.Wrap(err, "failed to write patched resource") + } + // write document separator + if i+1 < len(resources) { + if _, err := builder.WriteString("---\n"); err != nil { + return "", errors.Wrap(err, "failed to write document separator") + } + } + } + // verify that all patches were used + return builder.String(), nil +} diff --git a/pkg/internal/util/kustomize/kutomize_test.go b/pkg/internal/util/patch/patch_test.go similarity index 96% rename from pkg/internal/util/kustomize/kutomize_test.go rename to pkg/internal/util/patch/patch_test.go index 2952d01c..dfa87e8b 100644 --- a/pkg/internal/util/kustomize/kutomize_test.go +++ b/pkg/internal/util/patch/patch_test.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kustomize +package patch import ( "testing" @@ -23,10 +23,10 @@ import ( "sigs.k8s.io/kind/pkg/internal/util/assert" ) -func TestBuild(t *testing.T) { +func TestPatch(t *testing.T) { type testCase struct { Name string - Resources []string + ToPatch string Patches []string PatchesJSON6902 []config.PatchJSON6902 ExpectError bool @@ -35,26 +35,26 @@ func TestBuild(t *testing.T) { cases := []testCase{ { Name: "kubeadm config no patches", - Resources: []string{normalKubeadmConfig}, + ToPatch: normalKubeadmConfig, ExpectError: false, ExpectOutput: normalKubeadmConfigKustomized, }, { Name: "kubeadm config bogus patches", - Resources: []string{normalKubeadmConfig}, + ToPatch: normalKubeadmConfig, Patches: []string{"b o g u s"}, ExpectError: true, }, { Name: "kubeadm config one merge-patch", - Resources: []string{normalKubeadmConfig}, + ToPatch: normalKubeadmConfig, Patches: []string{trivialPatch}, ExpectError: false, ExpectOutput: normalKubeadmConfigTrivialPatched, }, { Name: "kubeadm config one merg-patch, one 6902 patch", - Resources: []string{normalKubeadmConfig}, + ToPatch: normalKubeadmConfig, Patches: []string{trivialPatch}, PatchesJSON6902: []config.PatchJSON6902{trivialPatch6902}, ExpectError: false, @@ -65,7 +65,7 @@ func TestBuild(t *testing.T) { tc := tc // capture test case t.Run(tc.Name, func(t *testing.T) { t.Parallel() - out, err := Build(tc.Resources, tc.Patches, tc.PatchesJSON6902) + out, err := Patch(tc.ToPatch, tc.Patches, tc.PatchesJSON6902) assert.ExpectError(t, tc.ExpectError, err) if err == nil { assert.StringEqual(t, tc.ExpectOutput, out) diff --git a/pkg/internal/util/patch/resource.go b/pkg/internal/util/patch/resource.go new file mode 100644 index 00000000..02002b33 --- /dev/null +++ b/pkg/internal/util/patch/resource.go @@ -0,0 +1,118 @@ +/* +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 ( + "io" + "io/ioutil" + "strings" + + jsonpatch "github.com/evanphx/json-patch" + + yamlutil "k8s.io/apimachinery/pkg/util/yaml" + "sigs.k8s.io/yaml" + + "sigs.k8s.io/kind/pkg/errors" +) + +type resource struct { + raw string // the original raw data + json []byte // the processed data (in JSON form), may be mutated + matchInfo matchInfo // for matching patches +} + +func (r *resource) apply6902Patch(patch json6902Patch) (matches bool, err error) { + if !r.matches(patch.matchInfo) { + return false, nil + } + patched, err := patch.patch.Apply(r.json) + if err != nil { + return true, errors.WithStack(err) + } + r.json = patched + return true, nil +} + +func (r *resource) applyMergePatch(patch mergePatch) (matches bool, err error) { + if !r.matches(patch.matchInfo) { + return false, nil + } + patched, err := jsonpatch.MergePatch(r.json, patch.json) + if err != nil { + return true, errors.WithStack(err) + } + r.json = patched + return true, nil +} + +func (r resource) matches(o matchInfo) bool { + m := &r.matchInfo + // we require kind to match, but if the patch does not specify + // APIVersion we ignore it (eg to allow trivial patches across kubeadm versions) + return m.Kind == o.Kind && (o.APIVersion == "" || m.APIVersion == o.APIVersion) +} + +func (r *resource) encodeTo(w io.Writer) error { + encoded, err := yaml.JSONToYAML(r.json) + if err != nil { + return errors.WithStack(err) + } + if _, err := w.Write(encoded); err != nil { + return errors.WithStack(err) + } + return nil +} + +func parseResources(yamlDocumentStream string) ([]resource, error) { + resources := []resource{} + documents, err := splitYAMLDocuments(yamlDocumentStream) + if err != nil { + return nil, err + } + for _, raw := range documents { + matchInfo, err := parseYAMLMatchInfo(raw) + if err != nil { + return nil, errors.WithStack(err) + } + json, err := yaml.YAMLToJSON([]byte(raw)) + if err != nil { + return nil, errors.WithStack(err) + } + resources = append(resources, resource{ + raw: raw, + json: json, + matchInfo: matchInfo, + }) + } + return resources, nil +} + +func splitYAMLDocuments(yamlDocumentStream string) ([]string, error) { + documents := []string{} + buff := make([]byte, len(yamlDocumentStream)) + r := yamlutil.NewDocumentDecoder(ioutil.NopCloser(strings.NewReader(yamlDocumentStream))) + for { + n, err := r.Read(buff) + if err == io.EOF { + break + } else if err != nil { + return nil, errors.Wrap(err, "error splitting documents") + } + documents = append(documents, string(buff[:n])) + } + return documents, nil +}