From f3457a59565e8da4db3052ff9a69bbddf5c53fb3 Mon Sep 17 00:00:00 2001 From: Yuwen Ma Date: Tue, 29 Mar 2022 00:02:25 -0700 Subject: [PATCH 1/7] update set-namespace logic to support 3 UpdateMode --- functions/go/set-namespace/go.mod | 23 +- functions/go/set-namespace/go.sum | 36 +-- .../go/set-namespace/transformer/consts.go | 50 +++++ .../go/set-namespace/transformer/namespace.go | 210 +++++++++++++----- 4 files changed, 227 insertions(+), 92 deletions(-) create mode 100644 functions/go/set-namespace/transformer/consts.go diff --git a/functions/go/set-namespace/go.mod b/functions/go/set-namespace/go.mod index 63baef15e..72d6085c3 100644 --- a/functions/go/set-namespace/go.mod +++ b/functions/go/set-namespace/go.mod @@ -2,28 +2,31 @@ module github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-na go 1.17 -require github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220316202203-f9115a993ebd +require github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220326221816-442298f7a17c require ( github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-errors/errors v1.4.2 // indirect + github.com/go-errors/errors v1.0.1 // indirect + github.com/go-logr/logr v1.2.0 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.6 // indirect - github.com/go-openapi/swag v0.21.1 // indirect - github.com/google/go-cmp v0.5.6 // indirect - github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/go-openapi/jsonreference v0.19.3 // indirect + github.com/go-openapi/swag v0.19.5 // indirect + github.com/kr/text v0.2.0 // indirect + github.com/mailru/easyjson v0.7.0 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.7.1 // indirect - github.com/xlab/treeprint v1.1.0 // indirect - golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect + github.com/stretchr/testify v1.7.0 // indirect + github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect + golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect golang.org/x/text v0.3.7 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + k8s.io/klog/v2 v2.30.0 // indirect k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect sigs.k8s.io/kustomize/kyaml v0.13.3 // indirect ) diff --git a/functions/go/set-namespace/go.sum b/functions/go/set-namespace/go.sum index c1072cdd7..140effe13 100644 --- a/functions/go/set-namespace/go.sum +++ b/functions/go/set-namespace/go.sum @@ -39,8 +39,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220316202203-f9115a993ebd h1:PzlNXoJTvlzct3n2hw3gmM6C9S/W4wmeaA3qqkM4TTQ= -github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220316202203-f9115a993ebd/go.mod h1:hENpuHQH/bIfHUCuG4hvzb5i4doJ1KTId5EdWBg6AvU= +github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220326221816-442298f7a17c h1:VzQxoP6YklE09HLRhdaKUEtwPwzML0rAho13QqN5W1M= +github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220326221816-442298f7a17c/go.mod h1:hENpuHQH/bIfHUCuG4hvzb5i4doJ1KTId5EdWBg6AvU= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI= github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= @@ -84,9 +84,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= -github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -97,12 +96,10 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= +github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= -github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -147,9 +144,8 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -202,8 +198,6 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= -github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -223,10 +217,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -296,13 +288,11 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= +github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= -github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= -github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -403,10 +393,8 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -475,14 +463,10 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/functions/go/set-namespace/transformer/consts.go b/functions/go/set-namespace/transformer/consts.go new file mode 100644 index 000000000..1ca70a342 --- /dev/null +++ b/functions/go/set-namespace/transformer/consts.go @@ -0,0 +1,50 @@ +// Copyright 2022 Google LLC +// +// 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 transformer + +import ( + "fmt" + "regexp" +) + +const ( + fnConfigAPIVersion = "fn.kpt.dev/v1alpha1" + fnConfigKind = "SetNamespace" + dependsOnAnnotation = "config.kubernetes.io/depends-on" + groupIdx = 0 + namespaceIdx = 2 + kindIdx = 3 + nameIdx = 4 +) + +type UpdateMode int + +var ( + // Users provide the `namespaceSelector`, only update the namespace field matching the`namespaceSelector`. + CustomSelector UpdateMode = 1 + + // The `namespaceSelector` is not given but the input resource contains one and only one namespace object, + // only update the namespace field matching the namespace `metadata.name`. + NsObjectSelector UpdateMode = 2 + + // Neither `namespaceSelector` or namespace objects are given, require all namespace-scoped resources have unique + // namespace value and update this namespace to the new value. + Restrict UpdateMode = 3 + + // /namespaces/// + namespacedResourcePattern = regexp.MustCompile(`\A([-.\w]*)/namespaces/([-.\w]*)/([-.\w]*)/([-.\w]*)\z`) + dependsOnKeyPattern = func(group, kind, name string) string { + return fmt.Sprintf("%s/%s/%s", group, kind, name) + } +) diff --git a/functions/go/set-namespace/transformer/namespace.go b/functions/go/set-namespace/transformer/namespace.go index 25e90b325..48f0c495e 100644 --- a/functions/go/set-namespace/transformer/namespace.go +++ b/functions/go/set-namespace/transformer/namespace.go @@ -15,38 +15,12 @@ package transformer import ( "fmt" - "regexp" + "reflect" "strings" "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" ) -const ( - fnConfigAPIVersion = "fn.kpt.dev/v1alpha1" - fnConfigKind = "SetNamespace" - dependsOnAnnotation = "config.kubernetes.io/depends-on" - groupIdx = 0 - namespaceIdx = 2 - kindIdx = 3 - nameIdx = 4 -) - -var ( - // /namespaces/// - namespacedResourcePattern = regexp.MustCompile(`\A([-.\w]*)/namespaces/([-.\w]*)/([-.\w]*)/([-.\w]*)\z`) - dependsOnKeyPattern = func(group, kind, name string) string { - return fmt.Sprintf("%s/%s/%s", group, kind, name) - } -) - -type Subject struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - ApiGroup string `json:"apiGroup,omitempty" yaml:"apiGroup,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` -} - - func SetNamespace(rl *fn.ResourceList) error { tc := NamespaceTransformer{} // Get "namespace" arguments from FunctionConfig @@ -55,8 +29,10 @@ func SetNamespace(rl *fn.ResourceList) error { rl.Results = append(rl.Results, fn.ErrorConfigObjectResult(err, rl.FunctionConfig)) return nil } - // Update "namespace" to the proper resources. - tc.Transform(rl.Items) + if tc.validate(rl.Items) { + // Update "namespace" to the proper resources. + tc.Transform(rl.Items) + } var result *fn.Result if len(tc.Errors) != 0 { errMsg := strings.Join(tc.Errors, "\n") @@ -68,27 +44,24 @@ func SetNamespace(rl *fn.ResourceList) error { return nil } -type NamespaceTransformer struct { - Namespace string - DependsOnMap map[string]bool - Errors []string -} - +// Config gets the attributes from different FunctionConfig formats. func (p *NamespaceTransformer) Config(o *fn.KubeObject) error { switch { case o.IsGVK("v1", "ConfigMap"): - p.Namespace = o.GetStringOrDie("data", "namespace") - if p.Namespace == "" { + p.NewNamespace = o.GetStringOrDie("data", "namespace") + if p.NewNamespace == "" { return fmt.Errorf("`data.namespace` should not be empty") } + p.MatchingNamespace = o.GetStringOrDie("data", "namespaceSelector") case o.IsGVK(fnConfigAPIVersion, fnConfigKind): - p.Namespace = o.GetStringOrDie("namespace") - if p.Namespace == "" { + p.NewNamespace = o.GetStringOrDie("namespace") + if p.NewNamespace == "" { return fmt.Errorf("`namespace` should not be empty") } + p.MatchingNamespace = o.GetStringOrDie("data", "namespaceSelector") case o.IsGVK("v1", "ConfigMap") && o.GetName() == "kptfile.kpt.dev": - p.Namespace = o.GetStringOrDie("data", "name") - if p.Namespace == "" { + p.NewNamespace = o.GetStringOrDie("data", "name") + if p.NewNamespace == "" { return fmt.Errorf("`data.name` should not be empty") } default: @@ -98,45 +71,152 @@ func (p *NamespaceTransformer) Config(o *fn.KubeObject) error { return nil } +// Transform replace the existing Namespace object, namespace-scoped resources' `metadata.name` and +// other namespace reference fields to the new value. func (p *NamespaceTransformer) Transform(objects []*fn.KubeObject) { p.SetDependsOnMap(objects) for _, o := range objects { switch { + // Skip local resource which `kpt live apply` skips. + case o.IsLocalConfig(): + continue case o.IsGVK("v1", "Namespace"): - o.SetName(p.Namespace) + o.SetName(p.NewNamespace) case o.IsGVK("apiextensions.k8s.io/v1", "CustomResourceDefinition"): - err := o.Set(p.Namespace, "spec", "conversion", "webhook", "clientConfig", "service", "namespace") - if err != nil { - p.Errors = append(p.Errors, err.Error()) - } + p.updateNamespace(o, "spec", "conversion", "webhook", "clientConfig", "service", "namespace") case o.IsGVK("apiregistration.k8s.io/v1", "APIService"): - err := o.Set(p.Namespace, "spec", "service", "namespace") - if err != nil { - p.Errors = append(p.Errors, err.Error()) - } + p.updateNamespace(o, "spec", "service", "namespace") case o.GetKind() == "ClusterRoleBinding" || o.GetKind() == "RoleBinding": var subjects []*Subject o.GetOrDie(&subjects, "subjects") for _, s := range subjects { - if s.Name == "default" { - s.Namespace = p.Namespace + if s.Kind == "ServiceAccount" { + if p.isSelectorMode() && s.Namespace != p.MatchingNamespace { + continue + } + s.Namespace = p.NewNamespace } } o.SetOrDie(&subjects, "subjects") case o.HasNamespace(): // Only update the namespace scoped resource. To determine if a resource is namespace scoped, // we assume its namespace should have been set. - o.SetNamespace(p.Namespace) + p.updateNamespace(o, "metadata", "namespace") default: // skip the cluster scoped resource. We determine if a resource is cluster scoped by // checking if the metadata.namespace is configured. } - // Shall we accept custom fieldspec? - // p.SetCustomFieldSpec(o) p.UpdateAnnotation(o) } } +// updateNamespace updates the namespace in three modes: +// - Restrict mode: always update namespace from the given `fieldpaths` +// - NsObjectSelector mode: update the namespace which matches the Namespace object found in resourceList.items. +// - CustomSelector mode: update the namespace which matches the `namespaceSelector` in resourceList.functionConfig. +func (p *NamespaceTransformer) updateNamespace(o *fn.KubeObject, fieldPaths ...string) { + if p.isSelectorMode() { + ns := o.GetStringOrDie(fieldPaths...) + if ns != p.MatchingNamespace { + return + } + } + if err := o.Set(p.NewNamespace, fieldPaths...); err != nil { + p.Errors = append(p.Errors, err.Error()) + } +} + +// isSelectorMode decides whether the namespace fields should match the given namespace +// before updating. +func (p *NamespaceTransformer) isSelectorMode() bool { + switch p.Mode { + case CustomSelector: + return true + case NsObjectSelector: + return true + default: // Restrict Mode + return false + } +} + +// validate guarantees the input resourceList.items satisfy the UpdateMode requirements. +func (p *NamespaceTransformer) validate(objects []*fn.KubeObject) bool { + nsCount, fromResources := p.listCurrentNamespaces(objects) + // Check "CustomSelector" Mode + if p.MatchingNamespace != "" { + p.Mode = CustomSelector + if len(nsCount) == 0 { + return true + } + p.Errors = append(p.Errors, + "found Namespace objects from the input resources, "+ + "you cannot use `namespaceSelector` in FunctionConfig together with Namespace objects") + return false + } + // Check "NsObjectSelector" Mode + if len(nsCount) > 1 { + msg := fmt.Sprintf("cannot accept more than one Namespace objects from the input resources, found %v", + nsCount) + p.Errors = append(p.Errors, msg) + return false + } + if len(nsCount) == 1 { + matchingNs := reflect.ValueOf(nsCount).MapKeys()[0].String() + if nsCount[matchingNs] > 1 { + msg := fmt.Sprintf("found more than one Namespace objects of the same name %v", matchingNs) + p.Errors = append(p.Errors, msg) + return false + } + p.Mode = NsObjectSelector + p.MatchingNamespace = matchingNs + return true + } + // Check "Restrict" Mode + if len(fromResources) > 1 { + msg := fmt.Sprintf("all input namespace-scoped resources should be under the same namespace "+ + "but found different namespaces: %v ", reflect.ValueOf(fromResources).MapKeys()) + p.Errors = append(p.Errors, msg) + return false + } + p.Mode = Restrict + p.MatchingNamespace = reflect.ValueOf(fromResources).MapKeys()[0].String() + return true +} + +// listCurrentNamespaces iterates the input resourcelist.items and list all namespaces found. +func (p *NamespaceTransformer) listCurrentNamespaces(objects []*fn.KubeObject) (map[string]int, map[string]bool) { + nsCount := map[string]int{} + fromResources := map[string]bool{} + for _, o := range objects { + // Skip local resource which `kpt live apply` skips. + if o.IsLocalConfig() { + continue + } + switch { + case o.IsGVK("v1", "Namespace"): + nsCount[o.GetName()] += 1 + fromResources[o.GetName()] = true + case o.IsGVK("apiextensions.k8s.io/v1", "CustomResourceDefinition"): + ns := o.GetStringOrDie("spec", "conversion", "webhook", "clientConfig", "service", "namespace") + fromResources[ns] = true + case o.IsGVK("apiregistration.k8s.io/v1", "APIService"): + ns := o.GetStringOrDie("spec", "service", "namespace") + fromResources[ns] = true + case o.GetKind() == "ClusterRoleBinding" || o.GetKind() == "RoleBinding": + var subjects []*Subject + o.GetOrDie(&subjects, "subjects") + for _, s := range subjects { + if s.Kind == "ServiceAccount" { + fromResources[s.Namespace] = true + } + } + case o.HasNamespace(): + fromResources[o.GetNamespace()] = true + } + } + return nsCount, fromResources +} + func (p *NamespaceTransformer) SetDependsOnMap(objects []*fn.KubeObject) { p.DependsOnMap = map[string]bool{} for _, o := range objects { @@ -160,8 +240,26 @@ func (p *NamespaceTransformer) UpdateAnnotation(o *fn.KubeObject) { segments := strings.Split(anno, "/") dependsOnkey := dependsOnKeyPattern(segments[groupIdx], segments[kindIdx], segments[nameIdx]) if ok := p.DependsOnMap[dependsOnkey]; ok { - segments[namespaceIdx] = p.Namespace + if p.isSelectorMode() && segments[namespaceIdx] != p.MatchingNamespace { + return + } + segments[namespaceIdx] = p.NewNamespace newAnno := strings.Join(segments, "/") o.SetAnnotation(dependsOnAnnotation, newAnno) } } + +type Subject struct { + Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + ApiGroup string `json:"apiGroup,omitempty" yaml:"apiGroup,omitempty"` + Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` +} + +type NamespaceTransformer struct { + NewNamespace string + MatchingNamespace string + Mode UpdateMode + DependsOnMap map[string]bool + Errors []string +} From 451c1353cdc5e87dbc97ea67c3fbc283df216f71 Mon Sep 17 00:00:00 2001 From: Yuwen Ma Date: Tue, 29 Mar 2022 00:03:13 -0700 Subject: [PATCH 2/7] Modify the set-namespace: - Define visitNamespace with callback function as params to replace multiple individual object iterations. - Define Namespace struct to provide callback functions for different iterations --- functions/go/set-namespace/go.mod | 8 +- functions/go/set-namespace/go.sum | 3 +- .../go/set-namespace/transformer/consts.go | 13 - .../go/set-namespace/transformer/namespace.go | 282 +++++++++--------- 4 files changed, 153 insertions(+), 153 deletions(-) diff --git a/functions/go/set-namespace/go.mod b/functions/go/set-namespace/go.mod index 72d6085c3..89a1ee2ac 100644 --- a/functions/go/set-namespace/go.mod +++ b/functions/go/set-namespace/go.mod @@ -2,7 +2,10 @@ module github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-na go 1.17 -require github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220326221816-442298f7a17c +require ( + github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220326221816-442298f7a17c + k8s.io/apimachinery v0.23.5 +) require ( github.com/PuerkitoBio/purell v1.1.1 // indirect @@ -13,17 +16,14 @@ require ( github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.19.3 // indirect github.com/go-openapi/swag v0.19.5 // indirect - github.com/kr/text v0.2.0 // indirect github.com/mailru/easyjson v0.7.0 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/stretchr/testify v1.7.0 // indirect github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect golang.org/x/text v0.3.7 // indirect - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect k8s.io/klog/v2 v2.30.0 // indirect diff --git a/functions/go/set-namespace/go.sum b/functions/go/set-namespace/go.sum index 140effe13..c22c42ed4 100644 --- a/functions/go/set-namespace/go.sum +++ b/functions/go/set-namespace/go.sum @@ -673,8 +673,9 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.23.4 h1:85gnfXQOWbJa1SiWGpE9EEtHs0UVvDyIsSMpEtl2D4E= k8s.io/api v0.23.4/go.mod h1:i77F4JfyNNrhOjZF7OwwNJS5Y1S9dpwvb9iYRYRczfI= -k8s.io/apimachinery v0.23.4 h1:fhnuMd/xUL3Cjfl64j5ULKZ1/J9n8NuQEgNL+WXWfdM= k8s.io/apimachinery v0.23.4/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= +k8s.io/apimachinery v0.23.5 h1:Va7dwhp8wgkUPWsEXk6XglXWU4IKYLKNlv8VkX7SDM0= +k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM= k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= diff --git a/functions/go/set-namespace/transformer/consts.go b/functions/go/set-namespace/transformer/consts.go index 1ca70a342..55404a542 100644 --- a/functions/go/set-namespace/transformer/consts.go +++ b/functions/go/set-namespace/transformer/consts.go @@ -28,20 +28,7 @@ const ( nameIdx = 4 ) -type UpdateMode int - var ( - // Users provide the `namespaceSelector`, only update the namespace field matching the`namespaceSelector`. - CustomSelector UpdateMode = 1 - - // The `namespaceSelector` is not given but the input resource contains one and only one namespace object, - // only update the namespace field matching the namespace `metadata.name`. - NsObjectSelector UpdateMode = 2 - - // Neither `namespaceSelector` or namespace objects are given, require all namespace-scoped resources have unique - // namespace value and update this namespace to the new value. - Restrict UpdateMode = 3 - // /namespaces/// namespacedResourcePattern = regexp.MustCompile(`\A([-.\w]*)/namespaces/([-.\w]*)/([-.\w]*)/([-.\w]*)\z`) dependsOnKeyPattern = func(group, kind, name string) string { diff --git a/functions/go/set-namespace/transformer/namespace.go b/functions/go/set-namespace/transformer/namespace.go index 48f0c495e..696e18f32 100644 --- a/functions/go/set-namespace/transformer/namespace.go +++ b/functions/go/set-namespace/transformer/namespace.go @@ -19,6 +19,7 @@ import ( "strings" "github.com/GoogleContainerTools/kpt-functions-sdk/go/fn" + "k8s.io/apimachinery/pkg/util/sets" ) func SetNamespace(rl *fn.ResourceList) error { @@ -29,10 +30,8 @@ func SetNamespace(rl *fn.ResourceList) error { rl.Results = append(rl.Results, fn.ErrorConfigObjectResult(err, rl.FunctionConfig)) return nil } - if tc.validate(rl.Items) { - // Update "namespace" to the proper resources. - tc.Transform(rl.Items) - } + // Update "namespace" to the proper resources. + tc.Transform(rl.Items) var result *fn.Result if len(tc.Errors) != 0 { errMsg := strings.Join(tc.Errors, "\n") @@ -52,13 +51,13 @@ func (p *NamespaceTransformer) Config(o *fn.KubeObject) error { if p.NewNamespace == "" { return fmt.Errorf("`data.namespace` should not be empty") } - p.MatchingNamespace = o.GetStringOrDie("data", "namespaceSelector") + p.namespaceSelector = o.GetStringOrDie("data", "namespaceSelector") case o.IsGVK(fnConfigAPIVersion, fnConfigKind): p.NewNamespace = o.GetStringOrDie("namespace") if p.NewNamespace == "" { return fmt.Errorf("`namespace` should not be empty") } - p.MatchingNamespace = o.GetStringOrDie("data", "namespaceSelector") + p.namespaceSelector = o.GetStringOrDie("data", "namespaceSelector") case o.IsGVK("v1", "ConfigMap") && o.GetName() == "kptfile.kpt.dev": p.NewNamespace = o.GetStringOrDie("data", "name") if p.NewNamespace == "" { @@ -74,192 +73,205 @@ func (p *NamespaceTransformer) Config(o *fn.KubeObject) error { // Transform replace the existing Namespace object, namespace-scoped resources' `metadata.name` and // other namespace reference fields to the new value. func (p *NamespaceTransformer) Transform(objects []*fn.KubeObject) { - p.SetDependsOnMap(objects) + namespaces, nsObjCounter := FindAllNamespaces(objects) + if oldNs, ok := p.GetOldNamespace(namespaces, nsObjCounter); ok { + ReplaceNamespace(objects, oldNs, p.NewNamespace) + // Update the resources annotation "config.kubernetes.io/depends-on" which may contain old namespace value. + dependsOnMap := GetDependsOnMap(objects) + UpdateAnnotation(objects, oldNs, p.NewNamespace, dependsOnMap) + } +} + +// VisitNamespaces iterates the `objects` to execute the `callback` function on each corresponding namespace field. +func VisitNamespaces(objects []*fn.KubeObject, callback func(ns *Namespace)) { for _, o := range objects { switch { // Skip local resource which `kpt live apply` skips. case o.IsLocalConfig(): continue case o.IsGVK("v1", "Namespace"): - o.SetName(p.NewNamespace) + ns := NewNamespace(o, []string{"metadata", "name"}) + callback(ns) case o.IsGVK("apiextensions.k8s.io/v1", "CustomResourceDefinition"): - p.updateNamespace(o, "spec", "conversion", "webhook", "clientConfig", "service", "namespace") + fields := []string{"spec", "conversion", "webhook", "clientConfig", "service", "namespace"} + callback(NewNamespace(o, fields)) case o.IsGVK("apiregistration.k8s.io/v1", "APIService"): - p.updateNamespace(o, "spec", "service", "namespace") + fields := []string{"spec", "service", "namespace"} + callback(NewNamespace(o, fields)) + /* TODO(yuwenma): waiting for the new features in kpt-functions-sdk to merge in. case o.GetKind() == "ClusterRoleBinding" || o.GetKind() == "RoleBinding": - var subjects []*Subject - o.GetOrDie(&subjects, "subjects") - for _, s := range subjects { - if s.Kind == "ServiceAccount" { - if p.isSelectorMode() && s.Namespace != p.MatchingNamespace { - continue - } - s.Namespace = p.NewNamespace + subjects := o.GetSliceOrDie("subjects") + for _, s := range subjects { + if s.GetKind() == "ServiceAccount" { + ns := s.GetNamespace() + visitor(ns, false) + nsCollector <- func() { + nsPtr := &ns + p.updateNamespace(nsPtr) + s.SetNamespace(*nsPtr) + o.SetOrDie(&subjects, "subjects") } } - o.SetOrDie(&subjects, "subjects") + } + */ case o.HasNamespace(): // Only update the namespace scoped resource. To determine if a resource is namespace scoped, // we assume its namespace should have been set. - p.updateNamespace(o, "metadata", "namespace") + fields := []string{"metadata", "namespace"} + callback(NewNamespace(o, fields)) default: // skip the cluster scoped resource. We determine if a resource is cluster scoped by // checking if the metadata.namespace is configured. } - p.UpdateAnnotation(o) } } -// updateNamespace updates the namespace in three modes: -// - Restrict mode: always update namespace from the given `fieldpaths` -// - NsObjectSelector mode: update the namespace which matches the Namespace object found in resourceList.items. -// - CustomSelector mode: update the namespace which matches the `namespaceSelector` in resourceList.functionConfig. -func (p *NamespaceTransformer) updateNamespace(o *fn.KubeObject, fieldPaths ...string) { - if p.isSelectorMode() { - ns := o.GetStringOrDie(fieldPaths...) - if ns != p.MatchingNamespace { +// FindAllNamespaces iterates the `objects` to list all namespaces and count the number of Namespace objects. +func FindAllNamespaces(objects []*fn.KubeObject) ([]string, map[string]int) { + nsObjCounter := map[string]int{} + namespaces := sets.NewString() + VisitNamespaces(objects, func(ns *Namespace) { + if ns.Name == "" { return } - } - if err := o.Set(p.NewNamespace, fieldPaths...); err != nil { - p.Errors = append(p.Errors, err.Error()) - } + if ns.IsNamespace { + nsObjCounter[ns.Name] += 1 + } + namespaces.Insert(ns.Name) + }) + return namespaces.List(), nsObjCounter } -// isSelectorMode decides whether the namespace fields should match the given namespace -// before updating. -func (p *NamespaceTransformer) isSelectorMode() bool { - switch p.Mode { - case CustomSelector: - return true - case NsObjectSelector: - return true - default: // Restrict Mode - return false - } +// ReplaceNamespace iterates the `objects` to replace the `OldNs` with `newNs` on namespace field. +func ReplaceNamespace(objects []*fn.KubeObject, oldNs, newNs string) { + VisitNamespaces(objects, func(ns *Namespace) { + if ns.Name == "" { + return + } + if ns.Name == oldNs { + ns.Set(newNs) + } + }) +} + +// GetDependsOnMap iterates `objects` to get the annotation which contains namespace value. +func GetDependsOnMap(objects []*fn.KubeObject) map[string]bool { + dependsOnMap := map[string]bool{} + VisitNamespaces(objects, func(ns *Namespace) { + key := ns.GetDependsOnAnno() + dependsOnMap[key] = true + }) + return dependsOnMap } -// validate guarantees the input resourceList.items satisfy the UpdateMode requirements. -func (p *NamespaceTransformer) validate(objects []*fn.KubeObject) bool { - nsCount, fromResources := p.listCurrentNamespaces(objects) - // Check "CustomSelector" Mode - if p.MatchingNamespace != "" { - p.Mode = CustomSelector +// UpdateAnnotation updates the `objects`'s "config.kubernetes.io/depends-on" annotation which contains namespace value. +func UpdateAnnotation(objects []*fn.KubeObject, oldNs, newNs string, dependsOnMap map[string]bool) { + VisitNamespaces(objects, func(ns *Namespace) { + if ns.DependsOnAnno == "" || !namespacedResourcePattern.MatchString(ns.DependsOnAnno) { + return + } + segments := strings.Split(ns.DependsOnAnno, "/") + dependsOnkey := dependsOnKeyPattern(segments[groupIdx], segments[kindIdx], segments[nameIdx]) + if ok := dependsOnMap[dependsOnkey]; ok { + if segments[namespaceIdx] == oldNs { + segments[namespaceIdx] = newNs + newAnno := strings.Join(segments, "/") + ns.SetDependsOnAnno(newAnno) + } + } + }) +} + +// GetOldNamespace finds the existing namespace and make sure the input resourceList.items satisfy the requirements. +// - no more than one Namespace Object can exist in the input resource.items +// - If Namespace object exists, its name is the `oldNs` +// - If `namespaceSelector` is given, its value is the `oldNs` +// - If neither Namespace object nor `namespaceSelector` found, all resources should have the same namespace value and +// this value is teh `oldNs` +func (p *NamespaceTransformer) GetOldNamespace(fromResources []string, nsCount map[string]int) (string, bool) { + if p.namespaceSelector != "" { if len(nsCount) == 0 { - return true + return p.namespaceSelector, true } p.Errors = append(p.Errors, "found Namespace objects from the input resources, "+ "you cannot use `namespaceSelector` in FunctionConfig together with Namespace objects") - return false + return "", false } - // Check "NsObjectSelector" Mode if len(nsCount) > 1 { msg := fmt.Sprintf("cannot accept more than one Namespace objects from the input resources, found %v", nsCount) p.Errors = append(p.Errors, msg) - return false + return "", false } if len(nsCount) == 1 { - matchingNs := reflect.ValueOf(nsCount).MapKeys()[0].String() - if nsCount[matchingNs] > 1 { - msg := fmt.Sprintf("found more than one Namespace objects of the same name %v", matchingNs) + // Use the namespace object as the matching namespace if `namespaceSelector` is not given. + oldNs := reflect.ValueOf(nsCount).MapKeys()[0].String() + if nsCount[oldNs] > 1 { + msg := fmt.Sprintf("found more than one Namespace objects of the same name %v", oldNs) p.Errors = append(p.Errors, msg) - return false + return "", false } - p.Mode = NsObjectSelector - p.MatchingNamespace = matchingNs - return true + return oldNs, true } - // Check "Restrict" Mode if len(fromResources) > 1 { msg := fmt.Sprintf("all input namespace-scoped resources should be under the same namespace "+ - "but found different namespaces: %v ", reflect.ValueOf(fromResources).MapKeys()) + "but found different namespaces: %v ", strings.Join(fromResources, ",")) p.Errors = append(p.Errors, msg) - return false + return "", false } - p.Mode = Restrict - p.MatchingNamespace = reflect.ValueOf(fromResources).MapKeys()[0].String() - return true + return fromResources[0], true } -// listCurrentNamespaces iterates the input resourcelist.items and list all namespaces found. -func (p *NamespaceTransformer) listCurrentNamespaces(objects []*fn.KubeObject) (map[string]int, map[string]bool) { - nsCount := map[string]int{} - fromResources := map[string]bool{} - for _, o := range objects { - // Skip local resource which `kpt live apply` skips. - if o.IsLocalConfig() { - continue - } - switch { - case o.IsGVK("v1", "Namespace"): - nsCount[o.GetName()] += 1 - fromResources[o.GetName()] = true - case o.IsGVK("apiextensions.k8s.io/v1", "CustomResourceDefinition"): - ns := o.GetStringOrDie("spec", "conversion", "webhook", "clientConfig", "service", "namespace") - fromResources[ns] = true - case o.IsGVK("apiregistration.k8s.io/v1", "APIService"): - ns := o.GetStringOrDie("spec", "service", "namespace") - fromResources[ns] = true - case o.GetKind() == "ClusterRoleBinding" || o.GetKind() == "RoleBinding": - var subjects []*Subject - o.GetOrDie(&subjects, "subjects") - for _, s := range subjects { - if s.Kind == "ServiceAccount" { - fromResources[s.Namespace] = true - } - } - case o.HasNamespace(): - fromResources[o.GetNamespace()] = true - } - } - return nsCount, fromResources +type NamespaceTransformer struct { + NewNamespace string + namespaceSelector string + DependsOnMap map[string]bool + Errors []string } -func (p *NamespaceTransformer) SetDependsOnMap(objects []*fn.KubeObject) { - p.DependsOnMap = map[string]bool{} - for _, o := range objects { - group := o.GetAPIVersion() - if i := strings.Index(o.GetAPIVersion(), "/"); i > -1 { +func NewNamespace(obj *fn.KubeObject, path []string) *Namespace { + setter := func(newNs string) { + obj.Set(newNs, path...) + } + annoSetter := func(newAnno string) { + obj.SetAnnotation(dependsOnAnnotation, newAnno) + } + annoGetter := func() string { + group := obj.GetAPIVersion() + if i := strings.Index(obj.GetAPIVersion(), "/"); i > -1 { group = group[:i] } - key := dependsOnKeyPattern(group, o.GetKind(), o.GetName()) - p.DependsOnMap[key] = true + return dependsOnKeyPattern(group, obj.GetKind(), obj.GetName()) + } + return &Namespace{ + Name: obj.GetStringOrDie(path...), + IsNamespace: obj.IsGVK("v1", "Namespace"), + DependsOnAnno: obj.GetAnnotations()[dependsOnAnnotation], + setter: setter, + annoGetter: annoGetter, + annoSetter: annoSetter, } } -func (p *NamespaceTransformer) UpdateAnnotation(o *fn.KubeObject) { - anno, ok := o.GetAnnotations()[dependsOnAnnotation] - if !ok { - return - } - if !namespacedResourcePattern.MatchString(anno) { - return - } - segments := strings.Split(anno, "/") - dependsOnkey := dependsOnKeyPattern(segments[groupIdx], segments[kindIdx], segments[nameIdx]) - if ok := p.DependsOnMap[dependsOnkey]; ok { - if p.isSelectorMode() && segments[namespaceIdx] != p.MatchingNamespace { - return - } - segments[namespaceIdx] = p.NewNamespace - newAnno := strings.Join(segments, "/") - o.SetAnnotation(dependsOnAnnotation, newAnno) - } +type Namespace struct { + Name string + IsNamespace bool + DependsOnAnno string + obj *fn.KubeObject + setter func(newNs string) + annoGetter func() string + annoSetter func(newDependsOnAnno string) } -type Subject struct { - Kind string `json:"kind,omitempty" yaml:"kind,omitempty"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - ApiGroup string `json:"apiGroup,omitempty" yaml:"apiGroup,omitempty"` - Namespace string `json:"namespace,omitempty" yaml:"namespace,omitempty"` +func (n *Namespace) Set(newNs string) { + n.setter(newNs) } -type NamespaceTransformer struct { - NewNamespace string - MatchingNamespace string - Mode UpdateMode - DependsOnMap map[string]bool - Errors []string +func (n *Namespace) SetDependsOnAnno(newDependsOnAnno string) { + n.annoSetter(newDependsOnAnno) +} + +func (n *Namespace) GetDependsOnAnno() string { + return n.annoGetter() } From b9aec2affd4cd698206654a9577a9694fb449dd3 Mon Sep 17 00:00:00 2001 From: Yuwen Ma Date: Tue, 29 Mar 2022 17:02:53 -0700 Subject: [PATCH 3/7] update README --- functions/go/set-namespace/Dockerfile | 17 +++ functions/go/set-namespace/README.md | 136 ++++++++++++------ functions/go/set-namespace/generated/docs.go | 130 +++++++++++------ .../go/set-namespace/transformer/namespace.go | 65 ++++----- 4 files changed, 225 insertions(+), 123 deletions(-) create mode 100644 functions/go/set-namespace/Dockerfile diff --git a/functions/go/set-namespace/Dockerfile b/functions/go/set-namespace/Dockerfile new file mode 100644 index 000000000..8581e3956 --- /dev/null +++ b/functions/go/set-namespace/Dockerfile @@ -0,0 +1,17 @@ +FROM golang:1.17-alpine3.13 +ENV CGO_ENABLED=0 +WORKDIR /go/src/ + +COPY go.mod go.sum ./ +RUN go mod download + +COPY . . +RUN go build -o /usr/local/bin/function ./ +LABEL type=mutator + +############################################# + +FROM alpine:3.13 +COPY --from=0 /usr/local/bin/function /usr/local/bin/function +ENTRYPOINT ["function"] + diff --git a/functions/go/set-namespace/README.md b/functions/go/set-namespace/README.md index 762475272..bae3a734c 100644 --- a/functions/go/set-namespace/README.md +++ b/functions/go/set-namespace/README.md @@ -17,68 +17,114 @@ Namespaces are often used in the following scenarios: ## Usage -This function can be used with any KRM function orchestrators (e.g. kpt). - -- If the resource is `Namespace`, `set-namespace` updates the `metadata.name` field. -- If the resource is `RoleBinding` or `ClusterRoleBinding` resource, the function updates - the namespace field in the `subjects` element whose name is `default`. -- If the resource is `CustomResourceDefinition` (CRD), `set-namespace` updates the - `spec/conversion/webhook/clientConfig/service/namespace` field. -- If the resource is `APIService`, `set-namespace` updates the - `spec/service/namespace` field. -- If there is a [`depends-on`] annotation for a namespaced resource, the namespace - section of the annotation will be updated if the referenced resource is also - declared in the package. +This function replaces the KRM resources existing namespace to a new value. +### Target KRM resources + +- This function updates all namespace-scoped KRM resources `metadata.namespace` fields. + We determine whether a KRM resource is namespace scoped by checking if it has `metadata.namespace` set and matches the "oldNamespace" + If not, this function won't add new namespace. +- This function updates `RoleBinding` and `ClusterRoleBinding` resources `subjects` element whose kind is `ServiceAccount` + and the subject's `namespace` is set and matches the "oldNamespace". +- This function updates `CustomResourceDefinition` (CRD) `spec/conversion/webhook/clientConfig/service/namespace` field + if the field is set and matches the "oldNamespace" +- This function updates `APIService` `spec/service/namespace` field if the field is set and matches the "oldNamespace" +- This function updates the KRM resources annotation `config.kubernetes.io/depends-on` if this annotation contains the + matching namespace. + +### FunctionConfig + +This function supports the default `ConfigMap` as function config and a custom `SetNamespace`. See below examples + +ConfigMap as functionConfig ```yaml apiVersion: v1 -kind: ServiceAccount -metadata: - name: sa - namespace: example - annotations: - config.kubernetes.io/depends-on: /namespaces/example/ServiceAccount/foo # <= this will NOT be updated (resource not declared) ---- -kind: RoleBinding -apiVersion: rbac.authorization.k8s.io/v1 -metadata: - ... - annotations: - config.kubernetes.io/depends-on: /namespaces/example/ServiceAccount/sa # <== this will be updated (resource declared) -subjects: - - kind: ServiceAccount - name: default # <================== name default is used - namespace: example # <================== this will be updated -roleRef: - kind: Role - name: confluent-operator - apiGroup: rbac.authorization.k8s.io +kind: ConfigMap +data: + namespace: newNamespace # required + namespaceSelector: example # update namespace whose value is "example" to "newNamespace" ``` -This function can be used both declaratively and imperatively. +SetNamespace as functionConfig +```yaml +apiVersion: fn.kpt.dev/v1alpha1 +kind: SetNamespace +namespace: newNamespace # required +namespaceSelector: example # update namespace whose value is "example" to "newNamespace" +``` -### FunctionConfig -There are 2 kinds of `functionConfig` supported by this function: +### Three updating modes -- `ConfigMap` -- A custom resource of kind `SetNamespace` +This function supports three modes to flexibly choose and update the target namespaces. -To use a `ConfigMap` as the `functionConfig`, the desired namespace must be -specified in the `data.namespace` field. +##### Restrict Mode +All target KRM resources namespace has to have the same value. All namespace will be updated to the new value. -To add a namespace `staging` to all resources, we use the -following `functionConfig`: +ConfigMap as functionConfig +```yaml +apiVersion: v1 +kind: ConfigMap +data: + namespace: newNamespace # update all namespace fields to "newNamespace" +``` + +##### DefaultNamespace Mode + +The input `resourcelist.items` contains one and only one namespace object. The function matches the namespace `metadata.name` +with all other KRM resources, and only update the namespace if it matches the namespace object. +If more than one namespace objects are found, raise errors; +```yaml +kind: ResourceList +functionConfig: + apiVersion: v1 + kind: ConfigMap + data: + namespace: newNs +items: +- apiVersion: v1 + kind: Namespace + metadata: + name: example # updated to "newNs" +- apiVersion: v1 + kind: Service + metadata: + name: the-service1 + namespace: example # updated to "newNs" +- apiVersion: v1 + kind: Service + metadata: + name: the-service2 + namespace: irrelevant # skip since namespace does not match "example". +``` + +##### Selector Mode + +Only updates the namespace which matches a given value. The "oldNamespace" refers to the argument in FunctionConfig + +ConfigMap as functionConfig ```yaml apiVersion: v1 kind: ConfigMap -metadata: - name: my-config data: - namespace: staging + namespace: newNamespace + namespaceSelector: example # update namespace whose value is "example" to "newNamespace" +``` + +SetNamespace as functionConfig +```yaml +apiVersion: fn.kpt.dev/v1alpha1 +kind: SetNamespace +namespace: newNamespace +namespaceSelector: example # update namespace whose value is "example" to "newNamespace" ``` +### DependsOn annotation + +DependsOn annotation is a [kpt feature](https://kpt.dev/reference/annotations/depends-on/). This function updates the +namespace segment in a depends-on annotation if matches oldNs + [namespace]: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ diff --git a/functions/go/set-namespace/generated/docs.go b/functions/go/set-namespace/generated/docs.go index 489ae77e0..6f20c8f0a 100644 --- a/functions/go/set-namespace/generated/docs.go +++ b/functions/go/set-namespace/generated/docs.go @@ -8,61 +8,99 @@ of KRM resources.` var SetNamespaceLong = ` ## Usage -This function can be used with any KRM function orchestrators (e.g. kpt). - -- If the resource is ` + "`" + `Namespace` + "`" + `, ` + "`" + `set-namespace` + "`" + ` updates the ` + "`" + `metadata.name` + "`" + ` field. -- If the resource is ` + "`" + `RoleBinding` + "`" + ` or ` + "`" + `ClusterRoleBinding` + "`" + ` resource, the function updates - the namespace field in the ` + "`" + `subjects` + "`" + ` element whose name is ` + "`" + `default` + "`" + `. -- If the resource is ` + "`" + `CustomResourceDefinition` + "`" + ` (CRD), ` + "`" + `set-namespace` + "`" + ` updates the - ` + "`" + `spec/conversion/webhook/clientConfig/service/namespace` + "`" + ` field. -- If the resource is ` + "`" + `APIService` + "`" + `, ` + "`" + `set-namespace` + "`" + ` updates the - ` + "`" + `spec/service/namespace` + "`" + ` field. -- If there is a [` + "`" + `depends-on` + "`" + `] annotation for a namespaced resource, the namespace - section of the annotation will be updated if the referenced resource is also - declared in the package. +This function replaces the KRM resources existing namespace to a new value. - apiVersion: v1 - kind: ServiceAccount - metadata: - name: sa - namespace: example - annotations: - config.kubernetes.io/depends-on: /namespaces/example/ServiceAccount/foo # <= this will NOT be updated (resource not declared) - --- - kind: RoleBinding - apiVersion: rbac.authorization.k8s.io/v1 - metadata: - ... - annotations: - config.kubernetes.io/depends-on: /namespaces/example/ServiceAccount/sa # <== this will be updated (resource declared) - subjects: - - kind: ServiceAccount - name: default # <================== name default is used - namespace: example # <================== this will be updated - roleRef: - kind: Role - name: confluent-operator - apiGroup: rbac.authorization.k8s.io - -This function can be used both declaratively and imperatively. +### Target KRM resources + +- This function updates all namespace-scoped KRM resources ` + "`" + `metadata.namespace` + "`" + ` fields. + We determine whether a KRM resource is namespace scoped by checking if it has ` + "`" + `metadata.namespace` + "`" + ` set and matches the "oldNamespace" + If not, this function won't add new namespace. +- This function updates ` + "`" + `RoleBinding` + "`" + ` and ` + "`" + `ClusterRoleBinding` + "`" + ` resources ` + "`" + `subjects` + "`" + ` element whose kind is ` + "`" + `ServiceAccount` + "`" + ` + and the subject's ` + "`" + `namespace` + "`" + ` is set and matches the "oldNamespace". +- This function updates ` + "`" + `CustomResourceDefinition` + "`" + ` (CRD) ` + "`" + `spec/conversion/webhook/clientConfig/service/namespace` + "`" + ` field + if the field is set and matches the "oldNamespace" +- This function updates ` + "`" + `APIService` + "`" + ` ` + "`" + `spec/service/namespace` + "`" + ` field if the field is set and matches the "oldNamespace" +- This function updates the KRM resources annotation ` + "`" + `config.kubernetes.io/depends-on` + "`" + ` if this annotation contains the + matching namespace. ### FunctionConfig -There are 2 kinds of ` + "`" + `functionConfig` + "`" + ` supported by this function: +This function supports the default ` + "`" + `ConfigMap` + "`" + ` as function config and a custom ` + "`" + `SetNamespace` + "`" + `. See below examples + +ConfigMap as functionConfig + apiVersion: v1 + kind: ConfigMap + data: + namespace: newNamespace # required + namespaceSelector: example # update namespace whose value is "example" to "newNamespace" + +SetNamespace as functionConfig + apiVersion: fn.kpt.dev/v1alpha1 + kind: SetNamespace + namespace: newNamespace # required + namespaceSelector: example # update namespace whose value is "example" to "newNamespace" + + +### Three updating modes + +This function supports three modes to flexibly choose and update the target namespaces. -- ` + "`" + `ConfigMap` + "`" + ` -- A custom resource of kind ` + "`" + `SetNamespace` + "`" + ` +# Restrict Mode: +All target KRM resources namespace has to have the same value. All namespace will be updated to the new value. -To use a ` + "`" + `ConfigMap` + "`" + ` as the ` + "`" + `functionConfig` + "`" + `, the desired namespace must be -specified in the ` + "`" + `data.namespace` + "`" + ` field. +ConfigMap as functionConfig + apiVersion: v1 + kind: ConfigMap + data: + namespace: newNamespace # update all namespace fields to "newNamespace" + +# DefaultNamespace Mode: + +The input ` + "`" + `resourcelist.items` + "`" + ` contains one and only one namespace object. The function matches the namespace ` + "`" + `metadata.name` + "`" + ` +with all other KRM resources, and only update the namespace if it matches the namespace object. +If more than one namespace objects are found, raise errors; -To add a namespace ` + "`" + `staging` + "`" + ` to all resources, we use the -following ` + "`" + `functionConfig` + "`" + `: + kind: ResourceList + functionConfig: + apiVersion: v1 + kind: ConfigMap + data: + namespace: newNs + items: + - apiVersion: v1 + kind: Namespace + metadata: + name: example # updated to "newNs" + - apiVersion: v1 + kind: Service + metadata: + name: the-service1 + namespace: example # updated to "newNs" + - apiVersion: v1 + kind: Service + metadata: + name: the-service2 + namespace: irrelevant # skip since namespace does not match "example". +# Selector Mode: + +Only updates the namespace which matches a given value. The "oldNamespace" refers to the argument in FunctionConfig + +ConfigMap as functionConfig apiVersion: v1 kind: ConfigMap - metadata: - name: my-config data: - namespace: staging + namespace: newNamespace + namespaceSelector: example # update namespace whose value is "example" to "newNamespace" + +SetNamespace as functionConfig + apiVersion: fn.kpt.dev/v1alpha1 + kind: SetNamespace + namespace: newNamespace + namespaceSelector: example # update namespace whose value is "example" to "newNamespace" + +### DependsOn annotation + +DependsOn annotation is a [kpt feature](https://kpt.dev/reference/annotations/depends-on/). This function updates the +namespace segment in a depends-on annotation if matches oldNs ` diff --git a/functions/go/set-namespace/transformer/namespace.go b/functions/go/set-namespace/transformer/namespace.go index 696e18f32..0f91a70dd 100644 --- a/functions/go/set-namespace/transformer/namespace.go +++ b/functions/go/set-namespace/transformer/namespace.go @@ -49,7 +49,14 @@ func (p *NamespaceTransformer) Config(o *fn.KubeObject) error { case o.IsGVK("v1", "ConfigMap"): p.NewNamespace = o.GetStringOrDie("data", "namespace") if p.NewNamespace == "" { - return fmt.Errorf("`data.namespace` should not be empty") + if o.GetName() == "kptfile.kpt.dev" { + p.NewNamespace = o.GetStringOrDie("data", "name") + if p.NewNamespace == "" { + return fmt.Errorf("`data.name` should not be empty") + } + } else { + return fmt.Errorf("`data.namespace` should not be empty") + } } p.namespaceSelector = o.GetStringOrDie("data", "namespaceSelector") case o.IsGVK(fnConfigAPIVersion, fnConfigKind): @@ -58,11 +65,6 @@ func (p *NamespaceTransformer) Config(o *fn.KubeObject) error { return fmt.Errorf("`namespace` should not be empty") } p.namespaceSelector = o.GetStringOrDie("data", "namespaceSelector") - case o.IsGVK("v1", "ConfigMap") && o.GetName() == "kptfile.kpt.dev": - p.NewNamespace = o.GetStringOrDie("data", "name") - if p.NewNamespace == "" { - return fmt.Errorf("`data.name` should not be empty") - } default: return fmt.Errorf("unknown functionConfig Kind=%v ApiVersion=%v, expect `%v` or `ConfigMap`", o.GetKind(), o.GetAPIVersion(), fnConfigKind) @@ -158,7 +160,7 @@ func ReplaceNamespace(objects []*fn.KubeObject, oldNs, newNs string) { func GetDependsOnMap(objects []*fn.KubeObject) map[string]bool { dependsOnMap := map[string]bool{} VisitNamespaces(objects, func(ns *Namespace) { - key := ns.GetDependsOnAnno() + key := ns.GetDependsOnAnnotation() dependsOnMap[key] = true }) return dependsOnMap @@ -167,16 +169,16 @@ func GetDependsOnMap(objects []*fn.KubeObject) map[string]bool { // UpdateAnnotation updates the `objects`'s "config.kubernetes.io/depends-on" annotation which contains namespace value. func UpdateAnnotation(objects []*fn.KubeObject, oldNs, newNs string, dependsOnMap map[string]bool) { VisitNamespaces(objects, func(ns *Namespace) { - if ns.DependsOnAnno == "" || !namespacedResourcePattern.MatchString(ns.DependsOnAnno) { + if ns.DependsOnAnnotation == "" || !namespacedResourcePattern.MatchString(ns.DependsOnAnnotation) { return } - segments := strings.Split(ns.DependsOnAnno, "/") + segments := strings.Split(ns.DependsOnAnnotation, "/") dependsOnkey := dependsOnKeyPattern(segments[groupIdx], segments[kindIdx], segments[nameIdx]) if ok := dependsOnMap[dependsOnkey]; ok { if segments[namespaceIdx] == oldNs { segments[namespaceIdx] = newNs - newAnno := strings.Join(segments, "/") - ns.SetDependsOnAnno(newAnno) + newAnnotation := strings.Join(segments, "/") + ns.SetDependsOnAnnotation(newAnnotation) } } }) @@ -232,12 +234,12 @@ type NamespaceTransformer struct { func NewNamespace(obj *fn.KubeObject, path []string) *Namespace { setter := func(newNs string) { - obj.Set(newNs, path...) + _ = obj.Set(newNs, path...) } - annoSetter := func(newAnno string) { - obj.SetAnnotation(dependsOnAnnotation, newAnno) + annotationSetter := func(newAnnotation string) { + obj.SetAnnotation(dependsOnAnnotation, newAnnotation) } - annoGetter := func() string { + annotationGetter := func() string { group := obj.GetAPIVersion() if i := strings.Index(obj.GetAPIVersion(), "/"); i > -1 { group = group[:i] @@ -245,33 +247,32 @@ func NewNamespace(obj *fn.KubeObject, path []string) *Namespace { return dependsOnKeyPattern(group, obj.GetKind(), obj.GetName()) } return &Namespace{ - Name: obj.GetStringOrDie(path...), - IsNamespace: obj.IsGVK("v1", "Namespace"), - DependsOnAnno: obj.GetAnnotations()[dependsOnAnnotation], - setter: setter, - annoGetter: annoGetter, - annoSetter: annoSetter, + Name: obj.GetStringOrDie(path...), + IsNamespace: obj.IsGVK("v1", "Namespace"), + DependsOnAnnotation: obj.GetAnnotations()[dependsOnAnnotation], + setter: setter, + annotationGetter: annotationGetter, + annotationSetter: annotationSetter, } } type Namespace struct { - Name string - IsNamespace bool - DependsOnAnno string - obj *fn.KubeObject - setter func(newNs string) - annoGetter func() string - annoSetter func(newDependsOnAnno string) + Name string + IsNamespace bool + DependsOnAnnotation string + setter func(newNs string) + annotationGetter func() string + annotationSetter func(newDependsOnAnnotation string) } func (n *Namespace) Set(newNs string) { n.setter(newNs) } -func (n *Namespace) SetDependsOnAnno(newDependsOnAnno string) { - n.annoSetter(newDependsOnAnno) +func (n *Namespace) SetDependsOnAnnotation(newDependsOn string) { + n.annotationSetter(newDependsOn) } -func (n *Namespace) GetDependsOnAnno() string { - return n.annoGetter() +func (n *Namespace) GetDependsOnAnnotation() string { + return n.annotationGetter() } From d9db9664b69952624a753256c9db65e6fa1b25ce Mon Sep 17 00:00:00 2001 From: Yuwen Ma Date: Sun, 3 Apr 2022 18:01:50 -0700 Subject: [PATCH 4/7] Use GetSlice and get/set by string pointer. merge after --- .../.expected/diff.patch | 31 ++++---- .../.expected/config.yaml | 2 +- .../.expected/diff.patch | 10 +-- examples/set-namespace-imperative/README.md | 9 ++- examples/set-namespace-imperative/app.yaml | 15 +++- functions/go/set-namespace/Dockerfile | 17 ---- functions/go/set-namespace/go.mod | 28 ++++--- functions/go/set-namespace/go.sum | 66 ++++++++++++---- .../go/set-namespace/transformer/namespace.go | 78 ++++++++----------- 9 files changed, 141 insertions(+), 115 deletions(-) delete mode 100644 functions/go/set-namespace/Dockerfile diff --git a/examples/set-labels-imperative/.expected/diff.patch b/examples/set-labels-imperative/.expected/diff.patch index a2c2b88dc..8fe95f062 100644 --- a/examples/set-labels-imperative/.expected/diff.patch +++ b/examples/set-labels-imperative/.expected/diff.patch @@ -1,24 +1,19 @@ diff --git a/app.yaml b/app.yaml -index 1e641f7..bb4be90 100644 +index d67a0d2..bf55161 100644 --- a/app.yaml +++ b/app.yaml -@@ -2,6 +2,9 @@ apiVersion: v1 - kind: ConfigMap - metadata: - name: the-map -+ labels: -+ color: orange -+ fruit: apple - data: - some-key: some-value - --- -@@ -10,6 +13,9 @@ kind: MyResource +@@ -9,7 +9,7 @@ apiVersion: v1 + kind: Service metadata: name: the-service - namespace: the-namespace -+ labels: -+ color: orange -+ fruit: apple +- namespace: example ++ namespace: new-ns spec: - selector: - labels: + ports: + - name: etcd-server-ssl +@@ -34,4 +34,4 @@ spec: + apiVersion: v1 + kind: Namespace + metadata: +- name: example ++ name: new-ns \ No newline at end of file diff --git a/examples/set-namespace-imperative/.expected/config.yaml b/examples/set-namespace-imperative/.expected/config.yaml index 55abb6c2e..ba791dff5 100644 --- a/examples/set-namespace-imperative/.expected/config.yaml +++ b/examples/set-namespace-imperative/.expected/config.yaml @@ -1,4 +1,4 @@ testType: eval image: gcr.io/kpt-fn/set-namespace:unstable args: - namespace: example-ns + namespace: new-ns diff --git a/examples/set-namespace-imperative/.expected/diff.patch b/examples/set-namespace-imperative/.expected/diff.patch index 6f0e0d736..8fe95f062 100644 --- a/examples/set-namespace-imperative/.expected/diff.patch +++ b/examples/set-namespace-imperative/.expected/diff.patch @@ -1,19 +1,19 @@ diff --git a/app.yaml b/app.yaml -index 1f8aeee..33e42da 100644 +index d67a0d2..bf55161 100644 --- a/app.yaml +++ b/app.yaml @@ -9,7 +9,7 @@ apiVersion: v1 kind: Service metadata: name: the-service -- namespace: the-namespace -+ namespace: example-ns +- namespace: example ++ namespace: new-ns spec: ports: - name: etcd-server-ssl -@@ -21,4 +21,4 @@ spec: +@@ -34,4 +34,4 @@ spec: apiVersion: v1 kind: Namespace metadata: - name: example -+ name: example-ns ++ name: new-ns \ No newline at end of file diff --git a/examples/set-namespace-imperative/README.md b/examples/set-namespace-imperative/README.md index 93925024d..1bd5637bc 100644 --- a/examples/set-namespace-imperative/README.md +++ b/examples/set-namespace-imperative/README.md @@ -2,9 +2,9 @@ ### Overview -This examples shows how to set namespace in the `.metadata.namespace` field on -all resources by running [`set-namespace`] function imperatively. Resources that -are known to be cluster-scoped will be skipped. +This examples shows how to replace KRM resources' namespace fields by matching +the namespace with the namespace object's `metadata.name`. +The example uses `kpt fn eval` to run the function imperatively. ### Fetch the example package @@ -27,6 +27,7 @@ The desired namespace is provided after `--` and it will be converted to ### Expected result -Check all resources have `metadata.namespace` set to `example-ns`: +Only the namespace fields which match the `namespace` "example" object has the value updated to +`new-ns`: [`set-namespace`]: https://catalog.kpt.dev/set-namespace/v0.1/ diff --git a/examples/set-namespace-imperative/app.yaml b/examples/set-namespace-imperative/app.yaml index 1f8aeeead..d67a0d24a 100644 --- a/examples/set-namespace-imperative/app.yaml +++ b/examples/set-namespace-imperative/app.yaml @@ -9,7 +9,20 @@ apiVersion: v1 kind: Service metadata: name: the-service - namespace: the-namespace + namespace: example +spec: + ports: + - name: etcd-server-ssl + port: 2380 + - name: etcd-client-ssl + port: 2379 + publishNotReadyAddresses: true +--- +apiVersion: v1 +kind: Service +metadata: + name: the-service + namespace: not-match-example spec: ports: - name: etcd-server-ssl diff --git a/functions/go/set-namespace/Dockerfile b/functions/go/set-namespace/Dockerfile deleted file mode 100644 index 8581e3956..000000000 --- a/functions/go/set-namespace/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM golang:1.17-alpine3.13 -ENV CGO_ENABLED=0 -WORKDIR /go/src/ - -COPY go.mod go.sum ./ -RUN go mod download - -COPY . . -RUN go build -o /usr/local/bin/function ./ -LABEL type=mutator - -############################################# - -FROM alpine:3.13 -COPY --from=0 /usr/local/bin/function /usr/local/bin/function -ENTRYPOINT ["function"] - diff --git a/functions/go/set-namespace/go.mod b/functions/go/set-namespace/go.mod index 89a1ee2ac..9c21e60a8 100644 --- a/functions/go/set-namespace/go.mod +++ b/functions/go/set-namespace/go.mod @@ -3,7 +3,7 @@ module github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-na go 1.17 require ( - github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220326221816-442298f7a17c + github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220405020624-e5817d5d2014 k8s.io/apimachinery v0.23.5 ) @@ -11,22 +11,26 @@ require ( github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/go-errors/errors v1.0.1 // indirect - github.com/go-logr/logr v1.2.0 // indirect + github.com/go-errors/errors v1.4.2 // indirect + github.com/go-logr/logr v1.2.3 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.19.3 // indirect - github.com/go-openapi/swag v0.19.5 // indirect - github.com/mailru/easyjson v0.7.0 // indirect + github.com/go-openapi/jsonreference v0.19.6 // indirect + github.com/go-openapi/swag v0.21.1 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/gnostic v0.6.7 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.7.7 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/stretchr/testify v1.7.0 // indirect - github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect - golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect + github.com/stretchr/testify v1.7.1 // indirect + github.com/xlab/treeprint v1.1.0 // indirect + golang.org/x/net v0.0.0-20220403103023-749bd193bc2b // indirect golang.org/x/text v0.3.7 // indirect + google.golang.org/protobuf v1.28.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect - k8s.io/klog/v2 v2.30.0 // indirect - k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 // indirect - sigs.k8s.io/kustomize/kyaml v0.13.3 // indirect + k8s.io/klog/v2 v2.60.1 // indirect + k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661 // indirect + sigs.k8s.io/kustomize/kyaml v0.13.6 // indirect ) diff --git a/functions/go/set-namespace/go.sum b/functions/go/set-namespace/go.sum index c22c42ed4..3ec64c97f 100644 --- a/functions/go/set-namespace/go.sum +++ b/functions/go/set-namespace/go.sum @@ -39,9 +39,10 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220326221816-442298f7a17c h1:VzQxoP6YklE09HLRhdaKUEtwPwzML0rAho13QqN5W1M= -github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220326221816-442298f7a17c/go.mod h1:hENpuHQH/bIfHUCuG4hvzb5i4doJ1KTId5EdWBg6AvU= +github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220405020624-e5817d5d2014 h1:NAhq6yh7qg7FE6ijZH3yTXDPHwyvg/5n7gg19w9fhFo= +github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220405020624-e5817d5d2014/go.mod h1:hENpuHQH/bIfHUCuG4hvzb5i4doJ1KTId5EdWBg6AvU= github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= 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-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M= @@ -53,7 +54,9 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM= +github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -61,6 +64,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= @@ -77,29 +81,35 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU= -github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE= github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= -github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= +github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs= +github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= +github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU= +github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -131,9 +141,13 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/gnostic v0.5.7-v3refs/go.mod h1:73MKFl6jIHelAJNaBGFzt3SPtZULs9dYrGFt8OiIsHQ= +github.com/google/gnostic v0.6.7 h1:+Y1YRZcjCfWkTYgH4Xq2+SL4DmkE2s84REwd3O2gnlU= +github.com/google/gnostic v0.6.7/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= @@ -198,6 +212,8 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -217,8 +233,10 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= @@ -271,6 +289,7 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -288,11 +307,16 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca h1:1CFlNzQhALwjS9mBAUkycX616GzgsuYUOCHA5+HSlXI= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= +github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -308,6 +332,7 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= @@ -393,8 +418,11 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY= +golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= +golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -463,10 +491,14 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -536,6 +568,7 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= @@ -608,6 +641,7 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -628,6 +662,7 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -641,6 +676,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -680,11 +717,13 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8 k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E= k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE= k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y= -k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw= k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= +k8s.io/klog/v2 v2.60.1 h1:VW25q3bZx9uE3vvdL6M8ezOX79vA2Aq1nEWLqNQclHc= +k8s.io/klog/v2 v2.60.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= -k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4= k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk= +k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661 h1:nqYOUleKLC/0P1zbU29F5q6aoezM6MOAVz+iyfQbZ5M= +k8s.io/kube-openapi v0.0.0-20220401212409-b28bf2818661/go.mod h1:daOouuuwd9JXpv1L7Y34iV3yf6nxzipkKMWWlqlvK9M= k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= k8s.io/utils v0.0.0-20211116205334-6203023598ed h1:ck1fRPWPJWsMd8ZRFsWc6mh/zHp5fZ/shhbrgPUxDAE= k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= @@ -693,8 +732,9 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 h1:fD1pz4yfdADVNfFmcP2aBEtudwUQ1AlLnRBALr33v3s= sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNzagwnNoseA6OxSUutVw05NhYDRs= -sigs.k8s.io/kustomize/kyaml v0.13.3 h1:tNNQIC+8cc+aXFTVg+RtQAOsjwUdYBZRAgYOVI3RBc4= sigs.k8s.io/kustomize/kyaml v0.13.3/go.mod h1:/ya3Gk4diiQzlE4mBh7wykyLRFZNvqlbh+JnwQ9Vhrc= +sigs.k8s.io/kustomize/kyaml v0.13.6 h1:eF+wsn4J7GOAXlvajv6OknSunxpcOBQQqsnPxObtkGs= +sigs.k8s.io/kustomize/kyaml v0.13.6/go.mod h1:yHP031rn1QX1lr/Xd934Ri/xdVNG8BE2ECa78Ht/kEg= sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw= sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y= sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4= diff --git a/functions/go/set-namespace/transformer/namespace.go b/functions/go/set-namespace/transformer/namespace.go index 0f91a70dd..e27b60428 100644 --- a/functions/go/set-namespace/transformer/namespace.go +++ b/functions/go/set-namespace/transformer/namespace.go @@ -22,13 +22,13 @@ import ( "k8s.io/apimachinery/pkg/util/sets" ) -func SetNamespace(rl *fn.ResourceList) error { +func SetNamespace(rl *fn.ResourceList) (bool, error) { tc := NamespaceTransformer{} // Get "namespace" arguments from FunctionConfig err := tc.Config(rl.FunctionConfig) if err != nil { rl.Results = append(rl.Results, fn.ErrorConfigObjectResult(err, rl.FunctionConfig)) - return nil + return true, nil } // Update "namespace" to the proper resources. tc.Transform(rl.Items) @@ -40,7 +40,7 @@ func SetNamespace(rl *fn.ResourceList) error { result = fn.GeneralResult("namespace updated", fn.Info) } rl.Results = append(rl.Results, result) - return nil + return true, nil } // Config gets the attributes from different FunctionConfig formats. @@ -84,43 +84,42 @@ func (p *NamespaceTransformer) Transform(objects []*fn.KubeObject) { } } -// VisitNamespaces iterates the `objects` to execute the `callback` function on each corresponding namespace field. -func VisitNamespaces(objects []*fn.KubeObject, callback func(ns *Namespace)) { +// VisitNamespaces iterates the `objects` to execute the `visitor` function on each corresponding namespace field. +func VisitNamespaces(objects []*fn.KubeObject, visitor func(namespace *Namespace)) { for _, o := range objects { switch { // Skip local resource which `kpt live apply` skips. case o.IsLocalConfig(): continue case o.IsGVK("v1", "Namespace"): - ns := NewNamespace(o, []string{"metadata", "name"}) - callback(ns) + namespace := o.GetStringOrDie("metadata", "name") + visitor(NewNamespace(o, &namespace)) + o.SetOrDie(&namespace, "metadata", "name") case o.IsGVK("apiextensions.k8s.io/v1", "CustomResourceDefinition"): - fields := []string{"spec", "conversion", "webhook", "clientConfig", "service", "namespace"} - callback(NewNamespace(o, fields)) + namespace := o.GetStringOrDie("spec", "conversion", "webhook", "clientConfig", "service", "namespace") + visitor(NewNamespace(o, &namespace)) + o.SetOrDie(&namespace, "spec", "conversion", "webhook", "clientConfig", "service", "namespace") case o.IsGVK("apiregistration.k8s.io/v1", "APIService"): - fields := []string{"spec", "service", "namespace"} - callback(NewNamespace(o, fields)) - /* TODO(yuwenma): waiting for the new features in kpt-functions-sdk to merge in. + namespace := o.GetStringOrDie("spec", "service", "namespace") + visitor(NewNamespace(o, &namespace)) + o.SetOrDie(&namespace, "spec", "service", "namespace") case o.GetKind() == "ClusterRoleBinding" || o.GetKind() == "RoleBinding": - subjects := o.GetSliceOrDie("subjects") - for _, s := range subjects { - if s.GetKind() == "ServiceAccount" { - ns := s.GetNamespace() - visitor(ns, false) - nsCollector <- func() { - nsPtr := &ns - p.updateNamespace(nsPtr) - s.SetNamespace(*nsPtr) - o.SetOrDie(&subjects, "subjects") + subjects := o.GetSlice("subjects") + for _, s := range subjects { + var ns string + found, _ := s.Get(&ns, "namespace") + if found { + visitor(NewNamespace(o, &ns)) + _ = s.Set(&ns, "namespace") } } - } - */ + o.SetOrDie(&subjects, "subjects") case o.HasNamespace(): // Only update the namespace scoped resource. To determine if a resource is namespace scoped, // we assume its namespace should have been set. - fields := []string{"metadata", "namespace"} - callback(NewNamespace(o, fields)) + namespace := o.GetStringOrDie("metadata", "namespace") + visitor(NewNamespace(o, &namespace)) + o.SetOrDie(&namespace, "metadata", "namespace") default: // skip the cluster scoped resource. We determine if a resource is cluster scoped by // checking if the metadata.namespace is configured. @@ -133,13 +132,13 @@ func FindAllNamespaces(objects []*fn.KubeObject) ([]string, map[string]int) { nsObjCounter := map[string]int{} namespaces := sets.NewString() VisitNamespaces(objects, func(ns *Namespace) { - if ns.Name == "" { + if *ns.Ptr == "" { return } if ns.IsNamespace { - nsObjCounter[ns.Name] += 1 + nsObjCounter[*ns.Ptr] += 1 } - namespaces.Insert(ns.Name) + namespaces.Insert(*ns.Ptr) }) return namespaces.List(), nsObjCounter } @@ -147,11 +146,11 @@ func FindAllNamespaces(objects []*fn.KubeObject) ([]string, map[string]int) { // ReplaceNamespace iterates the `objects` to replace the `OldNs` with `newNs` on namespace field. func ReplaceNamespace(objects []*fn.KubeObject, oldNs, newNs string) { VisitNamespaces(objects, func(ns *Namespace) { - if ns.Name == "" { + if *ns.Ptr == "" { return } - if ns.Name == oldNs { - ns.Set(newNs) + if *ns.Ptr == oldNs { + *ns.Ptr = newNs } }) } @@ -232,10 +231,7 @@ type NamespaceTransformer struct { Errors []string } -func NewNamespace(obj *fn.KubeObject, path []string) *Namespace { - setter := func(newNs string) { - _ = obj.Set(newNs, path...) - } +func NewNamespace(obj *fn.KubeObject, namespacePtr *string) *Namespace { annotationSetter := func(newAnnotation string) { obj.SetAnnotation(dependsOnAnnotation, newAnnotation) } @@ -247,28 +243,22 @@ func NewNamespace(obj *fn.KubeObject, path []string) *Namespace { return dependsOnKeyPattern(group, obj.GetKind(), obj.GetName()) } return &Namespace{ - Name: obj.GetStringOrDie(path...), + Ptr: namespacePtr, // obj.GetStringOrDie(path...), IsNamespace: obj.IsGVK("v1", "Namespace"), DependsOnAnnotation: obj.GetAnnotations()[dependsOnAnnotation], - setter: setter, annotationGetter: annotationGetter, annotationSetter: annotationSetter, } } type Namespace struct { - Name string + Ptr *string IsNamespace bool DependsOnAnnotation string - setter func(newNs string) annotationGetter func() string annotationSetter func(newDependsOnAnnotation string) } -func (n *Namespace) Set(newNs string) { - n.setter(newNs) -} - func (n *Namespace) SetDependsOnAnnotation(newDependsOn string) { n.annotationSetter(newDependsOn) } From 38ddcdb63deed80bb00cb6a216d58cb85611e061 Mon Sep 17 00:00:00 2001 From: Sunil Arora Date: Mon, 4 Apr 2022 20:12:09 -0700 Subject: [PATCH 5/7] Handle kpt fn behavior change (#796) * updated behavior and tests for ensure-name-substring * adjusted fix-simple test to not specify include-meta-resources * kubeval-simple: skip Kptfile validation * adjusted starlark tests/examples to handle Kptfile and StarlarkRun files * adjusted search-replace tests to match kpt behavior to include meta resources by default * adjusted create-setters-simple test to match kpt behavior * adjusted set-project-id to match the kpt fn behavior * adjusted generate-kpt-pkg-docs-simple test to match kpt behavior * adjusted set-annotations tests to match new kpt fn behavior * adjusted set-labels test to match new kpt fn behavior * adjusted the golden file for generate-folders function * using kpt@main --- .../.expected/diff.patch | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/examples/set-labels-imperative/.expected/diff.patch b/examples/set-labels-imperative/.expected/diff.patch index 8fe95f062..a2c2b88dc 100644 --- a/examples/set-labels-imperative/.expected/diff.patch +++ b/examples/set-labels-imperative/.expected/diff.patch @@ -1,19 +1,24 @@ diff --git a/app.yaml b/app.yaml -index d67a0d2..bf55161 100644 +index 1e641f7..bb4be90 100644 --- a/app.yaml +++ b/app.yaml -@@ -9,7 +9,7 @@ apiVersion: v1 - kind: Service +@@ -2,6 +2,9 @@ apiVersion: v1 + kind: ConfigMap + metadata: + name: the-map ++ labels: ++ color: orange ++ fruit: apple + data: + some-key: some-value + --- +@@ -10,6 +13,9 @@ kind: MyResource metadata: name: the-service -- namespace: example -+ namespace: new-ns + namespace: the-namespace ++ labels: ++ color: orange ++ fruit: apple spec: - ports: - - name: etcd-server-ssl -@@ -34,4 +34,4 @@ spec: - apiVersion: v1 - kind: Namespace - metadata: -- name: example -+ name: new-ns \ No newline at end of file + selector: + labels: From b526ca4f4894a3b1fcebc498d6bcbc1c61e08314 Mon Sep 17 00:00:00 2001 From: Yuwen Ma Date: Tue, 5 Apr 2022 16:30:26 -0700 Subject: [PATCH 6/7] Rolebinding does not need to update the subjects ns --- functions/go/set-namespace/transformer/namespace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/functions/go/set-namespace/transformer/namespace.go b/functions/go/set-namespace/transformer/namespace.go index e27b60428..2f5279550 100644 --- a/functions/go/set-namespace/transformer/namespace.go +++ b/functions/go/set-namespace/transformer/namespace.go @@ -103,7 +103,7 @@ func VisitNamespaces(objects []*fn.KubeObject, visitor func(namespace *Namespace namespace := o.GetStringOrDie("spec", "service", "namespace") visitor(NewNamespace(o, &namespace)) o.SetOrDie(&namespace, "spec", "service", "namespace") - case o.GetKind() == "ClusterRoleBinding" || o.GetKind() == "RoleBinding": + case o.GetKind() == "ClusterRoleBinding": subjects := o.GetSlice("subjects") for _, s := range subjects { var ns string From 15165949f80f85e7ed1b49875dddf43328eb49c3 Mon Sep 17 00:00:00 2001 From: Yuwen Ma Date: Tue, 5 Apr 2022 18:34:05 -0700 Subject: [PATCH 7/7] resolve comments --- functions/go/set-namespace/README.md | 28 +++++++++---------- functions/go/set-namespace/generated/docs.go | 10 +++---- .../go/set-namespace/transformer/namespace.go | 24 ++++++++-------- 3 files changed, 30 insertions(+), 32 deletions(-) diff --git a/functions/go/set-namespace/README.md b/functions/go/set-namespace/README.md index bae3a734c..848f3592c 100644 --- a/functions/go/set-namespace/README.md +++ b/functions/go/set-namespace/README.md @@ -36,21 +36,21 @@ This function replaces the KRM resources existing namespace to a new value. This function supports the default `ConfigMap` as function config and a custom `SetNamespace`. See below examples -ConfigMap as functionConfig +`ConfigMap` as functionConfig ```yaml apiVersion: v1 kind: ConfigMap data: namespace: newNamespace # required - namespaceSelector: example # update namespace whose value is "example" to "newNamespace" + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" ``` -SetNamespace as functionConfig +`SetNamespace` as functionConfig ```yaml apiVersion: fn.kpt.dev/v1alpha1 kind: SetNamespace namespace: newNamespace # required -namespaceSelector: example # update namespace whose value is "example" to "newNamespace" +namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" ``` @@ -61,7 +61,7 @@ This function supports three modes to flexibly choose and update the target name ##### Restrict Mode All target KRM resources namespace has to have the same value. All namespace will be updated to the new value. -ConfigMap as functionConfig +`ConfigMap` as functionConfig ```yaml apiVersion: v1 kind: ConfigMap @@ -71,9 +71,9 @@ data: ##### DefaultNamespace Mode -The input `resourcelist.items` contains one and only one namespace object. The function matches the namespace `metadata.name` -with all other KRM resources, and only update the namespace if it matches the namespace object. -If more than one namespace objects are found, raise errors; +The input `resourcelist.items` contains one and only one `Namespace` object. The function matches the namespace `metadata.name` +with all other KRM resources, and only update the namespace if it matches the `Namespace` object. +If more than one `Namespace` objects are found, raise errors; ```yaml kind: ResourceList @@ -99,31 +99,31 @@ items: namespace: irrelevant # skip since namespace does not match "example". ``` -##### Selector Mode +##### Matcher Mode Only updates the namespace which matches a given value. The "oldNamespace" refers to the argument in FunctionConfig -ConfigMap as functionConfig +`ConfigMap` as functionConfig ```yaml apiVersion: v1 kind: ConfigMap data: namespace: newNamespace - namespaceSelector: example # update namespace whose value is "example" to "newNamespace" + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" ``` -SetNamespace as functionConfig +`SetNamespace` as functionConfig ```yaml apiVersion: fn.kpt.dev/v1alpha1 kind: SetNamespace namespace: newNamespace -namespaceSelector: example # update namespace whose value is "example" to "newNamespace" +namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" ``` ### DependsOn annotation DependsOn annotation is a [kpt feature](https://kpt.dev/reference/annotations/depends-on/). This function updates the -namespace segment in a depends-on annotation if matches oldNs +namespace segment in a depends-on annotation if the namespace matches the `Namespace` object or `namespaceMatcher` field. diff --git a/functions/go/set-namespace/generated/docs.go b/functions/go/set-namespace/generated/docs.go index 6f20c8f0a..f2f87c540 100644 --- a/functions/go/set-namespace/generated/docs.go +++ b/functions/go/set-namespace/generated/docs.go @@ -1,5 +1,3 @@ - - // Code generated by "mdtogo"; DO NOT EDIT. package generated @@ -32,13 +30,13 @@ ConfigMap as functionConfig kind: ConfigMap data: namespace: newNamespace # required - namespaceSelector: example # update namespace whose value is "example" to "newNamespace" + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" SetNamespace as functionConfig apiVersion: fn.kpt.dev/v1alpha1 kind: SetNamespace namespace: newNamespace # required - namespaceSelector: example # update namespace whose value is "example" to "newNamespace" + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" ### Three updating modes @@ -91,13 +89,13 @@ ConfigMap as functionConfig kind: ConfigMap data: namespace: newNamespace - namespaceSelector: example # update namespace whose value is "example" to "newNamespace" + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" SetNamespace as functionConfig apiVersion: fn.kpt.dev/v1alpha1 kind: SetNamespace namespace: newNamespace - namespaceSelector: example # update namespace whose value is "example" to "newNamespace" + namespaceMatcher: example # update namespace whose value is "example" to "newNamespace" ### DependsOn annotation diff --git a/functions/go/set-namespace/transformer/namespace.go b/functions/go/set-namespace/transformer/namespace.go index 2f5279550..afd2fe8c2 100644 --- a/functions/go/set-namespace/transformer/namespace.go +++ b/functions/go/set-namespace/transformer/namespace.go @@ -58,13 +58,13 @@ func (p *NamespaceTransformer) Config(o *fn.KubeObject) error { return fmt.Errorf("`data.namespace` should not be empty") } } - p.namespaceSelector = o.GetStringOrDie("data", "namespaceSelector") + p.NamespaceMatcher = o.GetStringOrDie("data", "namespaceMatcher") case o.IsGVK(fnConfigAPIVersion, fnConfigKind): p.NewNamespace = o.GetStringOrDie("namespace") if p.NewNamespace == "" { return fmt.Errorf("`namespace` should not be empty") } - p.namespaceSelector = o.GetStringOrDie("data", "namespaceSelector") + p.NamespaceMatcher = o.GetStringOrDie("data", "namespaceMatcher") default: return fmt.Errorf("unknown functionConfig Kind=%v ApiVersion=%v, expect `%v` or `ConfigMap`", o.GetKind(), o.GetAPIVersion(), fnConfigKind) @@ -186,17 +186,17 @@ func UpdateAnnotation(objects []*fn.KubeObject, oldNs, newNs string, dependsOnMa // GetOldNamespace finds the existing namespace and make sure the input resourceList.items satisfy the requirements. // - no more than one Namespace Object can exist in the input resource.items // - If Namespace object exists, its name is the `oldNs` -// - If `namespaceSelector` is given, its value is the `oldNs` -// - If neither Namespace object nor `namespaceSelector` found, all resources should have the same namespace value and +// - If `namespaceMatcher` is given, its value is the `oldNs` +// - If neither Namespace object nor `namespaceMatcher` found, all resources should have the same namespace value and // this value is teh `oldNs` func (p *NamespaceTransformer) GetOldNamespace(fromResources []string, nsCount map[string]int) (string, bool) { - if p.namespaceSelector != "" { + if p.NamespaceMatcher != "" { if len(nsCount) == 0 { - return p.namespaceSelector, true + return p.NamespaceMatcher, true } p.Errors = append(p.Errors, "found Namespace objects from the input resources, "+ - "you cannot use `namespaceSelector` in FunctionConfig together with Namespace objects") + "you cannot use `namespaceMatcher` in FunctionConfig together with Namespace objects") return "", false } if len(nsCount) > 1 { @@ -206,7 +206,7 @@ func (p *NamespaceTransformer) GetOldNamespace(fromResources []string, nsCount m return "", false } if len(nsCount) == 1 { - // Use the namespace object as the matching namespace if `namespaceSelector` is not given. + // Use the namespace object as the matching namespace if `namespaceMatcher` is not given. oldNs := reflect.ValueOf(nsCount).MapKeys()[0].String() if nsCount[oldNs] > 1 { msg := fmt.Sprintf("found more than one Namespace objects of the same name %v", oldNs) @@ -225,10 +225,10 @@ func (p *NamespaceTransformer) GetOldNamespace(fromResources []string, nsCount m } type NamespaceTransformer struct { - NewNamespace string - namespaceSelector string - DependsOnMap map[string]bool - Errors []string + NewNamespace string + NamespaceMatcher string + DependsOnMap map[string]bool + Errors []string } func NewNamespace(obj *fn.KubeObject, namespacePtr *string) *Namespace {