From 4650aa2466d0599e249c3e7c0ff4abcf023563b4 Mon Sep 17 00:00:00 2001 From: Phillip Wittrock Date: Thu, 12 Dec 2019 10:20:36 -0800 Subject: [PATCH] support for inline substitutions --- api/internal/crawl/go.sum | 63 +++++ cmd/config/configcobra/cmds.go | 2 + cmd/config/docs/commands/sub.md | 98 +++++++ cmd/config/docs/commands/subset.md | 167 ++++++++++++ cmd/config/go.mod | 1 + cmd/config/go.sum | 4 + cmd/config/internal/commands/cmdsub.go | 165 ++++++++++++ cmd/config/internal/commands/cmdsubcreate.go | 93 +++++++ .../internal/generateddocs/commands/docs.go | 252 ++++++++++++++++++ cmd/config/internal/sub/addkio.go | 39 +++ cmd/config/internal/sub/addyaml.go | 105 ++++++++ cmd/config/internal/sub/dokio.go | 53 ++++ cmd/config/internal/sub/doyaml.go | 155 +++++++++++ cmd/config/internal/sub/lookupkio.go | 69 +++++ cmd/config/internal/sub/lookupyaml.go | 65 +++++ cmd/config/internal/sub/types.go | 29 ++ kustomize/go.sum | 4 + kyaml/fieldmeta/fieldmeta.go | 134 ++++++++++ 18 files changed, 1498 insertions(+) create mode 100644 cmd/config/docs/commands/sub.md create mode 100644 cmd/config/docs/commands/subset.md create mode 100644 cmd/config/internal/commands/cmdsub.go create mode 100644 cmd/config/internal/commands/cmdsubcreate.go create mode 100644 cmd/config/internal/sub/addkio.go create mode 100644 cmd/config/internal/sub/addyaml.go create mode 100644 cmd/config/internal/sub/dokio.go create mode 100644 cmd/config/internal/sub/doyaml.go create mode 100644 cmd/config/internal/sub/lookupkio.go create mode 100644 cmd/config/internal/sub/lookupyaml.go create mode 100644 cmd/config/internal/sub/types.go create mode 100644 kyaml/fieldmeta/fieldmeta.go diff --git a/api/internal/crawl/go.sum b/api/internal/crawl/go.sum index 6954125c691..16214211e01 100644 --- a/api/internal/crawl/go.sum +++ b/api/internal/crawl/go.sum @@ -1,5 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.2/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0= @@ -25,6 +26,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bombsimon/wsl v1.2.5/go.mod h1:43lEF/i0kpXbLCeDXL9LMT8c92HyBywXb0AsgMHYngM= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= @@ -41,13 +43,16 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= +github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/elastic/go-elasticsearch/v6 v6.8.2 h1:rp5DGrd63V5c6nHLjF6QEXUpZSvs0+QM3ld7m9VhV2g= github.com/elastic/go-elasticsearch/v6 v6.8.2/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI= +github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.6+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= +github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5IcNrDCXZ6OoTAWu7M= github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -87,14 +92,18 @@ github.com/go-toolsmith/pkgload v1.0.0/go.mod h1:5eFArkbO80v7Z0kdngIxsRXRMTaX4Il github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= github.com/go-toolsmith/typep v1.0.0/go.mod h1:JSQCQMUPdRlMZFswiq3TGpNp1GMktqkR2Ns5AIQkATU= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= +github.com/gofrs/flock v0.0.0-20190320160742-5135e617513b/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= +github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -107,9 +116,12 @@ github.com/golangci/go-misc v0.0.0-20180628070357-927a3d87b613/go.mod h1:SyvUF2N github.com/golangci/goconst v0.0.0-20180610141641-041c5f2b40f3/go.mod h1:JXrF4TWy4tXYn62/9x8Wm/K/dm06p8tCKwFRDPZG/1o= github.com/golangci/gocyclo v0.0.0-20180528134321-2becd97e67ee/go.mod h1:ozx7R9SIwqmqf5pRP90DhR2Oay2UIjGuKheCBCNwAYU= github.com/golangci/gofmt v0.0.0-20181222123516-0b8337e80d98/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= +github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU= github.com/golangci/golangci-lint v1.19.1/go.mod h1:2CEc4Fxx3vxDv7g8DyXkHCBF73AOzAymcJAprs2vCps= +github.com/golangci/golangci-lint v1.21.0/go.mod h1:phxpHK52q7SE+5KpPnti4oZTdFCEsn/tKN+nFvCKXfk= github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU= github.com/golangci/lint-1 v0.0.0-20190420132249-ee948d087217/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= +github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg= github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o= github.com/golangci/misspell v0.0.0-20180809174111-950f5d19e770/go.mod h1:dEbvlSfYbMQDtrpRMQU675gSDLDNa8sCPPChZ7PhiVA= github.com/golangci/prealloc v0.0.0-20180630174525-215b22d4de21/go.mod h1:tf5+bzsHdTM0bsB7+8mt0GUMvjCgwLpTapNZHU8AajI= @@ -117,18 +129,25 @@ github.com/golangci/revgrep v0.0.0-20180526074752-d9c87f5ffaf0/go.mod h1:qOQCunE github.com/golangci/unconvert v0.0.0-20180507085042-28b1c447d1f4/go.mod h1:Izgrg8RkN3rCIMLGE9CyYmU9pY2Jer6DgANEnZ/L/cQ= github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0= github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4= +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/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 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= github.com/googleapis/gnostic v0.3.0 h1:CcQijm0XKekKjP/YCz28LXVSpgguuB+nCxaSjCe09y0= github.com/googleapis/gnostic v0.3.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY= +github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8= github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM= github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= @@ -139,11 +158,14 @@ github.com/gorilla/sessions v0.0.0-20160922145804-ca9ada445741/go.mod h1:+WVp8kd github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.mod h1:eEOZF4jCKGi+aprrirO9e7WKB3beBRtWgqGunKl6pKE= +github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= @@ -154,6 +176,7 @@ github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22 github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= @@ -178,7 +201,9 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN 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/matoous/godox v0.0.0-20190910121045-032ad8106c86/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= +github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -193,6 +218,7 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/monopole/mdrip v1.0.0/go.mod h1:N1/ppRG9CaPeUKAUHZ3dUlfOT81lTpKZLkyhCvTETwM= +github.com/monopole/mdrip v1.0.1/go.mod h1:/7E04hlzRG9Jrp6WILZfYYm/REoJWL2l+MlsCO1eH74= github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -232,6 +258,7 @@ github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday v2.0.0+incompatible/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/securego/gosec v0.0.0-20190912120752-140048b2a218/go.mod h1:q6oYAujd2qyeU4cJqIri4LBIgdHXGvxWHZ1E29HNFRE= +github.com/securego/gosec v0.0.0-20191002120514-e680875ea14d/go.mod h1:w5+eXa0mYznDkHaMCXA4XYffjlH+cy1oyKbfzJXa2Do= github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc= github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc= github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= @@ -262,11 +289,14 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/timakin/bodyclose v0.0.0-20190721030226-87058b9bfcec/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= +github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ultraware/funlen v0.0.2/go.mod h1:Dp4UiAus7Wdb9KUZsYWZEWiRzGuM2kXM1lPbfaF6xhA= github.com/ultraware/whitespace v0.0.3/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= +github.com/ultraware/whitespace v0.0.4/go.mod h1:aVMh/gQve5Maj9hQ/hg+F75lr/X5A89uZnzAmWSineA= +github.com/uudashr/gocognit v0.0.0-20190926065955-1655d0de0517/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3cQMJ5JUM= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s= github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4= @@ -274,16 +304,23 @@ github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -294,6 +331,7 @@ golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= @@ -302,11 +340,15 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190909003024-a7b16738d86b h1:XfVGCX+0T4WOStkaOsJRllbsiImhB2jgVBGc9L0lPGc= golang.org/x/net v0.0.0-20190909003024-a7b16738d86b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 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= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -315,17 +357,22 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190911201528-7ad0cfa0b7b5 h1:SW/0nsKCUaozCUtZTakri5laocGx/5bkDSSLrFUsa5s= golang.org/x/sys v0.0.0-20190911201528-7ad0cfa0b7b5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -336,8 +383,10 @@ golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20181117154741-2ddaf7f79a09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190110163146-51295c7ec13a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311215038-5c2858a9cfe5/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190322203728-c1a832b0ad89/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190521203540-521d6ed310dd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= @@ -346,10 +395,16 @@ golang.org/x/tools v0.0.0-20190719005602-e377ae9d6386/go.mod h1:jcCCGcm9btYwXyDq golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911230505-6bfd74cf029c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190912215617-3720d1ec3678/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190930201159-7c411dea38b0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= @@ -363,6 +418,7 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= +gopkg.in/russross/blackfriday.v2 v2.0.0/go.mod h1:6sSBNz/GtOm/pJTuh5UmBK2ZHfmnxGbl2NZg1UliSOI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= @@ -371,7 +427,11 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI= +k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg= +k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k= k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk= @@ -380,11 +440,14 @@ k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU= k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E= k8s.io/utils v0.0.0-20191030222137-2b95a09bc58d/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= +k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew= mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc= mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4= mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw= sigs.k8s.io/kustomize/api v0.2.0 h1:e++6JpysnnlUbHmFrv6jvfF5rFlgQ103bS1DO7r5bWA= sigs.k8s.io/kustomize/api v0.2.0/go.mod h1:zVtMg179jW1gr74jo9fc2Ac9dLYLTZZThc3DDb9lDW4= +sigs.k8s.io/kustomize/api v0.3.0/go.mod h1:4jaPCtRzxfQLFdYq4gYo40dBGW1hyPp/f4AuiZB5dAQ= +sigs.k8s.io/kustomize/pluginator/v2 v2.0.0/go.mod h1:zrXhTv8BAKt0egmZX/8AtMOSFUSWM9YuoHvvqz8/eHE= sigs.k8s.io/kustomize/pseudo/k8s v0.1.0 h1:otg4dLFc03c3gzl+2CV8GPGcd1kk8wjXwD+UhhcCn5I= sigs.k8s.io/kustomize/pseudo/k8s v0.1.0/go.mod h1:bl/gVJgYYhJZCZdYU2BfnaKYAlqFkgbJEkpl302jEss= sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI= diff --git a/cmd/config/configcobra/cmds.go b/cmd/config/configcobra/cmds.go index f6c85122f9b..0fd9c86bd37 100644 --- a/cmd/config/configcobra/cmds.go +++ b/cmd/config/configcobra/cmds.go @@ -76,6 +76,8 @@ func NewConfigCommand(name string) *cobra.Command { root.AddCommand(commands.MergeCommand(name)) root.AddCommand(commands.CountCommand(name)) root.AddCommand(commands.RunFnCommand(name)) + root.AddCommand(commands.SubCommand(name)) + root.AddCommand(commands.SubSetCommand(name)) root.AddCommand(&cobra.Command{ Use: "docs-merge", diff --git a/cmd/config/docs/commands/sub.md b/cmd/config/docs/commands/sub.md new file mode 100644 index 00000000000..38540fe9f1c --- /dev/null +++ b/cmd/config/docs/commands/sub.md @@ -0,0 +1,98 @@ +## set + +[Alpha] Set values on Resources fields by substituting values. + +### Synopsis + +Set values on Resources fields by substituting predefined markers for new values. + +`set` looks for markers specified on Resource fields and substitute a new user defined +value for the existing value. + +`set` maybe be used to: + +- edit configuration programmatically from the cli or scripts +- create reusable bundles of configuration + + DIR + + A directory containing Resource configuration. + + NAME + + Optional. The name of the substitution to perform or display. + + VALUE + + Optional. The new value to substitute into the field. + + +To print the possible substitutions for the Resources in a directory, run `set` on +a directory -- e.g. `kustomize config set DIR/`. + +#### Tips + +- A description of the value may be specified with `--description`. +- An owner for the field's value may be defined with `--owned-by`. +- Prevent overriding previous substitutions with `--override=false`. +- Revert previous substitutions with `--revert`. +- Create substitutions on Kustomization.yaml's, patches, etc + +When overriding or reverting previous substitutions, the description and owner are left +unmodified unless specified with flags. + +To create a substitution for a field see: `kustomize help config set create` + +### Examples + + Resource YAML: Name substitution + + # dir/resources.yaml + ... + metadata: + name: PREFIX-app1 # {"substitutions":[{"name":"prefix","marker":"PREFIX-"}]} + ... + --- + ... + metadata: + name: PREFIX-app2 # {"substitutions":[{"name":"prefix","marker":"PREFIX-"}]} + ... + + Show substitutions: Show the possible substitutions + + $ config set dir + NAME DESCRIPTION VALUE TYPE COUNT SUBSTITUTED OWNER + prefix '' PREFIX- string 2 false + + Perform substitution: set a new value, owner and description + + $ config set dir prefix "test-" --description "test environment" --owned-by "dev" + performed 2 substitutions + + Show substitutions: Show the new values + + $ config set dir + NAME DESCRIPTION VALUE TYPE COUNT SUBSTITUTED OWNER + prefix 'test environment' test- string 2 true dev + + New Resource YAML: + + # dir/resources.yaml + ... + metadata: + name: test-app1 # {"substitutions":[{"name":"prefix","marker":"PREFIX-","value":"test-"}],"ownedBy":"dev","description":"test environment"} + ... + --- + ... + metadata: + name: test-app2 # {"substitutions":[{"name":"prefix","marker":"PREFIX-","value":"test-"}],"ownedBy":"dev","description":"test environment"} + ... + + Revert substitution: + + config set dir prefix --revert + performed 2 substitutions + + config set dir + NAME DESCRIPTION VALUE TYPE COUNT SUBSTITUTED OWNER + prefix 'test environment' PREFIX- string 2 false dev diff --git a/cmd/config/docs/commands/subset.md b/cmd/config/docs/commands/subset.md new file mode 100644 index 00000000000..1a3f5ca0050 --- /dev/null +++ b/cmd/config/docs/commands/subset.md @@ -0,0 +1,167 @@ +## sub-set-marker + +[Alpha] Create a new substitution for a Resource field + +### Synopsis + +Create a new substitution for a Resource field -- recognized by `kustomize config set`. + + DIR + + A directory containing Resource configuration. + + NAME + + The name of the substitution to create. + + VALUE + + The current value of the field, or a substring of the field. + +#### Tips: Picking Good Marker + +Substitutions may be defined by directly editing yaml **or** by running `kustomize config set create` +to create a new substitution. + +Given the YAML: + + # resource.yaml + apiVersion: v1 + kind: Service + metadata: + ... + spec: + ... + ports: + ... + - name: http + port: 8080 + ... + +Create a new set marker: + + # create a substitution for ports + $ kustomize config set create dir/ http-port 8080 --type "int" --field "port" + +Modified YAML: + + # resource.yaml + apiVersion: v1 + kind: Service + metadata: + ... + spec: + ... + ports: + ... + - name: http + port: 8080 # {"substitutions":[{"name":"port","marker":"[MARKER]"}],"type":"int"} + ... + +Change the value using the `set` command: + + # change the http-port value to 8081 + $ kustomize config set dir/ http-port 8081 + +Resources fields with a field name matching `--field` and field value matching `VALUE` will +have a line comment added marking this field as settable. + +Substitution markers may be: + +- valid field values (e.g. `8080` for a port) + - Note: `008080` would be preferred because it is more recognizable as a marker +- invalid values that adhere to the schema (e.g. `0000` for a port) +- values that do not adhere to the schema (e.g. `[PORT]` for port) + +Markers **SHOULD be clearly identifiable as a marker and either**: + +- **adhere to the field schema** -- e.g. use a valid value + + + port: 008080 # {"substitutions":[{"name":"port","marker":"008080"}],"type":"int"} + +- **be pre-filled in with a value** -- e.g. set the value when setting the marker + + + port: 8080 # {"substitutions":[{"name":"port","marker":"[MARKER]","value":"8080""}],"type":"int"} + +**Note:** The important thing is that in both cases the Resource configuration may be directly +applied to a cluster and validated by tools without the tool knowing about the substitution +marker. + +The difference between the preceding examples is that: + +- the former will be shown as `SUBSTITUTED=false` (`config sub dir/` exits non-0) +- the latter with show up as `SUBSTITUTED=true` (`config sub dir/` exits 0) + +When choosing the which to use, consider that checks for unsubstituted values MAY be +configured as pre-commit checks -- if you want to these checks to fail if the value +hasn't been substituted, then don't specify a `value`. + +Markers which are invalid field values MAY be chosen in cases where it is preferred to have +the create or update request fail rather than succeed if the substitution has not yet been +performed. + +A substitution may be a substring of the full field: + + $ kustomize config set create dir/ app-image-tag v1.0.01 --type "string" --field "image" + + image: gcr.io/example/app:v1.0.1 # {"substitutions":[{"name":"app-image-tag","marker":"[MARKER]","value":"v1.0.1"}]} + + +A single field value may have multiple substitutions applied to it: + + name: PREFIX-app-SUFFIX # {"substitutions":[{"name":"prefix","marker":"PREFIX-"},{"name":"suffix","marker":"-SUFFIX"}]} + +#### Substitution Format + +Substitutions are defined as json encoded FieldMeta comments on fields. + +FieldMeta Schema read by `sub`: + + { + "title": "FieldMeta", + "type": "object", + "properties": { + "substitutions": { + "type": "array", + "description": "Possible substitutions that may be performed against this field.", + "items": { + "type": "object", + "properties": { + "name": "Name of the substitution.", + "marker": "Marker for the value to be substituted.", + "value": "Current substituted value" + } + } + }, + "type": { + "type": "string", + "description": "The value type. Defaults to string." + "enum": ["string", "int", "float", "bool"] + }, + "description": { + "type": "string", + "description": "A description of the field's current value. Optional." + }, + "ownedBy": { + "type": "string", + "description": "The current owner of the field. Optional." + }, + } + } + +### Examples + + # set a substitution for port fields matching "8080" + kustomize config sub create dir/ port 8080 --type "int" --field port \ + --description "default port used by the app" + + # set a substitution for port fields matching "8080", using "0000" as a marker. + kustomize config sub dir/ port 8080 --marker "0000" --type "int" \ + --field port --description "default port used by the app" + + # substitute a substring of a field rather than the full field -- e.g. only the + # image tag, not the full image + kustomize config sub dir/ app-image-tag v1.0.1 --type "string" --substring \ + --field port --description "current stable release" \ No newline at end of file diff --git a/cmd/config/go.mod b/cmd/config/go.mod index 1378e602975..487ad6c862b 100644 --- a/cmd/config/go.mod +++ b/cmd/config/go.mod @@ -4,6 +4,7 @@ go 1.13 require ( github.com/go-errors/errors v1.0.1 + github.com/olekukonko/tablewriter v0.0.4 github.com/posener/complete/v2 v2.0.1-alpha.12 github.com/spf13/cobra v0.0.5 github.com/spf13/pflag v1.0.5 diff --git a/cmd/config/go.sum b/cmd/config/go.sum index a1843090719..6a2ddd5737b 100644 --- a/cmd/config/go.sum +++ b/cmd/config/go.sum @@ -61,6 +61,8 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= @@ -72,6 +74,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= +github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= diff --git a/cmd/config/internal/commands/cmdsub.go b/cmd/config/internal/commands/cmdsub.go new file mode 100644 index 00000000000..a3543380780 --- /dev/null +++ b/cmd/config/internal/commands/cmdsub.go @@ -0,0 +1,165 @@ +// Copyright 2019 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 commands + +import ( + "fmt" + "os" + + "github.com/olekukonko/tablewriter" + "github.com/spf13/cobra" + "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" + "sigs.k8s.io/kustomize/cmd/config/internal/sub" + "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/kio" +) + +// NewSubRunner returns a command runner. +func NewSubRunner(parent string) *SubRunner { + r := &SubRunner{} + c := &cobra.Command{ + Use: "set DIR [NAME] [VALUE]", + Args: cobra.RangeArgs(1, 3), + Short: commands.SubShort, + Long: commands.SubLong, + Example: commands.SubExamples, + Aliases: []string{"sub"}, + PreRunE: r.preRunE, + RunE: r.runE, + } + c.Flags().BoolVar(&r.Perform.Override, "override", true, + "override previously substituted values.") + c.Flags().BoolVar(&r.Perform.Revert, "revert", false, + "override previously substituted values.") + fixDocs(parent, c) + r.Command = c + c.AddCommand(SubSetCommand(parent)) + return r +} + +func SubCommand(parent string) *cobra.Command { + return NewSubRunner(parent).Command +} + +type SubRunner struct { + Command *cobra.Command + Lookup sub.LookupSubstitutions + Perform sub.PerformSubstitutions +} + +func (r *SubRunner) preRunE(c *cobra.Command, args []string) error { + if len(args) > 1 { + r.Perform.Name = args[1] + r.Lookup.Name = args[1] + } + if len(args) > 2 { + r.Perform.NewValue = args[2] + } + if len(args) < 2 && r.Perform.Revert { + return errors.Errorf("must specify NAME with --revert") + } + if len(args) < 3 && r.Perform.Override { + return errors.Errorf("must specify VALUE with --override") + } + + var mutex int + if r.Perform.Revert { + mutex++ + } + if r.Perform.Override { + mutex++ + } + if mutex > 1 { + return errors.Errorf("--revert, --override are mutually exclusive") + } + + return nil +} + +func (r *SubRunner) runE(c *cobra.Command, args []string) error { + + if len(args) == 3 { + return handleError(c, r.perform(c, args)) + } + if len(args) == 2 && r.Perform.Revert { + return handleError(c, r.perform(c, args)) + } + + return handleError(c, r.lookup(c, args)) +} + +func (r *SubRunner) lookup(c *cobra.Command, args []string) error { + // lookup the substitutions + err := kio.Pipeline{ + Inputs: []kio.Reader{&kio.LocalPackageReader{PackagePath: args[0]}}, + Filters: []kio.Filter{&r.Lookup}, + }.Execute() + if err != nil { + return err + } + + remaining := false + table := tablewriter.NewWriter(c.OutOrStdout()) + table.SetRowLine(false) + table.SetBorder(false) + table.SetHeaderLine(false) + table.SetColumnSeparator(" ") + table.SetCenterSeparator(" ") + table.SetAlignment(tablewriter.ALIGN_LEFT) + table.SetHeader([]string{ + "NAME", "DESCRIPTION", "VALUE", "TYPE", "COUNT", "SUBSTITUTED", "OWNER", + }) + for i := range r.Lookup.SubstitutionCounts { + s := r.Lookup.SubstitutionCounts[i] + remaining = remaining || s.Count > s.CountComplete + v := s.CurrentValue + if s.CurrentValue == "" { + v = s.Marker + } + table.Append([]string{ + s.Name, + "'" + s.Description + "'", + v, + fmt.Sprintf("%v", s.Type), + fmt.Sprintf("%d", s.Count), + fmt.Sprintf("%v", s.Count == s.CountComplete), + s.OwnedBy, + }) + } + table.Render() + + if remaining { + os.Exit(1) + } + return nil +} + +// perform the substitutions +func (r *SubRunner) perform(c *cobra.Command, args []string) error { + rw := &kio.LocalPackageReadWriter{ + PackagePath: args[0], + } + // perform the substitutions in the package + err := kio.Pipeline{ + Inputs: []kio.Reader{rw}, + Filters: []kio.Filter{&r.Perform}, + Outputs: []kio.Writer{rw}, + }.Execute() + if err != nil { + return err + } + fmt.Fprintf(c.OutOrStdout(), "performed %d substitutions\n", r.Perform.Count) + return nil +} diff --git a/cmd/config/internal/commands/cmdsubcreate.go b/cmd/config/internal/commands/cmdsubcreate.go new file mode 100644 index 00000000000..ee9378b6411 --- /dev/null +++ b/cmd/config/internal/commands/cmdsubcreate.go @@ -0,0 +1,93 @@ +// Copyright 2019 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 commands + +import ( + "github.com/spf13/cobra" + "sigs.k8s.io/kustomize/cmd/config/internal/generateddocs/commands" + "sigs.k8s.io/kustomize/cmd/config/internal/sub" + "sigs.k8s.io/kustomize/kyaml/kio" +) + +// NewSubSetRunner returns a command runner. +func NewSubSetRunner(parent string) *SubSetRunner { + r := &SubSetRunner{} + set := &cobra.Command{ + Use: "create PKG_DIR NAME [VALUE]", + Args: cobra.ExactArgs(3), + Short: commands.SubsetShort, + Long: commands.SubsetLong, + Example: commands.SubsetExamples, + PreRunE: r.preRunE, + RunE: r.runE, + } + set.Flags().StringVar(&r.Set.Marker.OwnedBy, "owned-by", "", + "set this owner on for the current value.") + set.Flags().StringVar(&r.Set.Marker.Description, "description", "", + "set this description for the current value description.") + set.Flags().StringVar(&r.Set.Marker.Substitution.Marker, "marker", "[MARKER]", + "use this marker.") + set.Flags().StringVar(&r.Set.Marker.Field, "field", "", + "name of the field to set -- e.g. --field port") + set.Flags().StringVar(&r.Set.ResourceMeta.Name, "name", "", + "name of the Resource on which to set the substitution.") + set.Flags().StringVar(&r.Set.ResourceMeta.Kind, "kind", "", + "kind of the Resource on which to set substitution.") + set.Flags().StringVar(&r.Set.Marker.Type, "type", "", + "field type -- e.g. int,float,bool,string.") + set.Flags().BoolVar(&r.Set.Marker.PartialMatch, "substring", false, + "if true, the value may be a substring of the current value.") + fixDocs(parent, set) + set.MarkFlagRequired("type") + set.MarkFlagRequired("field") + r.Command = set + return r +} + +func SubSetCommand(parent string) *cobra.Command { + return NewSubSetRunner(parent).Command +} + +type SubSetRunner struct { + Command *cobra.Command + Set sub.SetSubstitutionMarker +} + +func (r *SubSetRunner) runE(c *cobra.Command, args []string) error { + return handleError(c, r.set(c, args)) +} + +func (r *SubSetRunner) preRunE(c *cobra.Command, args []string) error { + r.Set.Marker.Substitution.Name = args[1] + r.Set.Marker.Substitution.Value = args[2] + return nil +} + +// perform the substitutions +func (r *SubSetRunner) set(c *cobra.Command, args []string) error { + rw := &kio.LocalPackageReadWriter{ + PackagePath: args[0], + } + // add the substitution marker to the Resource + err := kio.Pipeline{ + Inputs: []kio.Reader{rw}, + Filters: []kio.Filter{&r.Set}, + Outputs: []kio.Writer{rw}, + }.Execute() + if err != nil { + return err + } + return nil +} diff --git a/cmd/config/internal/generateddocs/commands/docs.go b/cmd/config/internal/generateddocs/commands/docs.go index fef935bfc9f..01e218d8fef 100644 --- a/cmd/config/internal/generateddocs/commands/docs.go +++ b/cmd/config/internal/generateddocs/commands/docs.go @@ -185,6 +185,258 @@ order they appear in the file). var RunFnsExamples = ` kustomize config run example/` +var SubShort = `[Alpha] Set values on Resources fields by substituting values.` +var SubLong = ` +Set values on Resources fields by substituting predefined markers for new values. + +` + "`" + `set` + "`" + ` looks for markers specified on Resource fields and substitute a new user defined +value for the existing value. + +` + "`" + `set` + "`" + ` maybe be used to: + +- edit configuration programmatically from the cli or scripts +- create reusable bundles of configuration + + DIR + + A directory containing Resource configuration. + + NAME + + Optional. The name of the substitution to perform or display. + + VALUE + + Optional. The new value to substitute into the field. + + +To print the possible substitutions for the Resources in a directory, run ` + "`" + `set` + "`" + ` on +a directory -- e.g. ` + "`" + `kustomize config set DIR/` + "`" + `. + +#### Tips + +- A description of the value may be specified with ` + "`" + `--description` + "`" + `. +- An owner for the field's value may be defined with ` + "`" + `--owned-by` + "`" + `. +- Prevent overriding previous substitutions with ` + "`" + `--override=false` + "`" + `. +- Revert previous substitutions with ` + "`" + `--revert` + "`" + `. +- Create substitutions on Kustomization.yaml's, patches, etc + +When overriding or reverting previous substitutions, the description and owner are left +unmodified unless specified with flags. + +To create a substitution for a field see: ` + "`" + `kustomize help config set create` + "`" + ` +` +var SubExamples = ` + Resource YAML: Name substitution + + # dir/resources.yaml + ... + metadata: + name: PREFIX-app1 # {"substitutions":[{"name":"prefix","marker":"PREFIX-"}]} + ... + --- + ... + metadata: + name: PREFIX-app2 # {"substitutions":[{"name":"prefix","marker":"PREFIX-"}]} + ... + + Show substitutions: Show the possible substitutions + + $ config set dir + NAME DESCRIPTION VALUE TYPE COUNT SUBSTITUTED OWNER + prefix '' PREFIX- string 2 false + + Perform substitution: set a new value, owner and description + + $ config set dir prefix "test-" --description "test environment" --owned-by "dev" + performed 2 substitutions + + Show substitutions: Show the new values + + $ config set dir + NAME DESCRIPTION VALUE TYPE COUNT SUBSTITUTED OWNER + prefix 'test environment' test- string 2 true dev + + New Resource YAML: + + # dir/resources.yaml + ... + metadata: + name: test-app1 # {"substitutions":[{"name":"prefix","marker":"PREFIX-","value":"test-"}],"ownedBy":"dev","description":"test environment"} + ... + --- + ... + metadata: + name: test-app2 # {"substitutions":[{"name":"prefix","marker":"PREFIX-","value":"test-"}],"ownedBy":"dev","description":"test environment"} + ... + + Revert substitution: + + config set dir prefix --revert + performed 2 substitutions + + config set dir + NAME DESCRIPTION VALUE TYPE COUNT SUBSTITUTED OWNER + prefix 'test environment' PREFIX- string 2 false dev ` + +var SubsetShort = `[Alpha] Create a new substitution for a Resource field` +var SubsetLong = ` +Create a new substitution for a Resource field -- recognized by ` + "`" + `kustomize config set` + "`" + `. + + DIR + + A directory containing Resource configuration. + + NAME + + The name of the substitution to create. + + VALUE + + The current value of the field, or a substring of the field. + +#### Tips: Picking Good Marker + +Substitutions may be defined by directly editing yaml **or** by running ` + "`" + `kustomize config set create` + "`" + ` +to create a new substitution. + +Given the YAML: + + # resource.yaml + apiVersion: v1 + kind: Service + metadata: + ... + spec: + ... + ports: + ... + - name: http + port: 8080 + ... + +Set with ` + "`" + `set` + "`" + ` command: + + # create a substitution for ports + $ kustomize config set create dir/ http-port 8080 --type "int" --field "port" + +Modified YAML: + + # resource.yaml + apiVersion: v1 + kind: Service + metadata: + ... + spec: + ... + ports: + ... + - name: http + port: 8080 # {"substitutions":[{"name":"port","marker":"[MARKER]"}],"type":"int"} + ... + +Resources fields with a field name matching ` + "`" + `--field` + "`" + ` and field value matching ` + "`" + `VALUE` + "`" + ` will +have a line comment added marking this field as settable. + +Substitution markers may be: + +- valid field values (e.g. ` + "`" + `8080` + "`" + ` for a port) + - Note: ` + "`" + `008080` + "`" + ` would be preferred because it is more recognizable as a marker +- invalid values that adhere to the schema (e.g. ` + "`" + `0000` + "`" + ` for a port) +- values that do not adhere to the schema (e.g. ` + "`" + `[PORT]` + "`" + ` for port) + +Markers **SHOULD be clearly identifiable as a marker and either**: + +- **adhere to the field schema** -- e.g. use a valid value + + + port: 008080 # {"substitutions":[{"name":"port","marker":"008080"}],"type":"int"} + +- **be pre-filled in with a value** -- e.g. set the value when setting the marker + + + port: 8080 # {"substitutions":[{"name":"port","marker":"[MARKER]","value":"8080""}],"type":"int"} + +**Note:** The important thing is that in both cases the Resource configuration may be directly +applied to a cluster and validated by tools without the tool knowing about the substitution +marker. + +The difference between the preceding examples is that: + +- the former will be shown as ` + "`" + `SUBSTITUTED=false` + "`" + ` (` + "`" + `config sub dir/` + "`" + ` exits non-0) +- the latter with show up as ` + "`" + `SUBSTITUTED=true` + "`" + ` (` + "`" + `config sub dir/` + "`" + ` exits 0) + +When choosing the which to use, consider that checks for unsubstituted values MAY be +configured as pre-commit checks -- if you want to these checks to fail if the value +hasn't been substituted, then don't specify a ` + "`" + `value` + "`" + `. + +Markers which are invalid field values MAY be chosen in cases where it is preferred to have +the create or update request fail rather than succeed if the substitution has not yet been +performed. + +A substitution may be a substring of the full field: + + $ kustomize config set create dir/ app-image-tag v1.0.01 --type "string" --field "image" + + image: gcr.io/example/app:v1.0.1 # {"substitutions":[{"name":"app-image-tag","marker":"[MARKER]","value":"v1.0.1"}]} + + +A single field value may have multiple substitutions applied to it: + + name: PREFIX-app-SUFFIX # {"substitutions":[{"name":"prefix","marker":"PREFIX-"},{"name":"suffix","marker":"-SUFFIX"}]} + +#### Substitution Format + +Substitutions are defined as json encoded FieldMeta comments on fields. + +FieldMeta Schema read by ` + "`" + `sub` + "`" + `: + + { + "title": "FieldMeta", + "type": "object", + "properties": { + "substitutions": { + "type": "array", + "description": "Possible substitutions that may be performed against this field.", + "items": { + "type": "object", + "properties": { + "name": "Name of the substitution.", + "marker": "Marker for the value to be substituted.", + "value": "Current substituted value" + } + } + }, + "type": { + "type": "string", + "description": "The value type. Defaults to string." + "enum": ["string", "int", "float", "bool"] + }, + "description": { + "type": "string", + "description": "A description of the field's current value. Optional." + }, + "ownedBy": { + "type": "string", + "description": "The current owner of the field. Optional." + }, + } + } +` +var SubsetExamples = ` + # set a substitution for port fields matching "8080" + kustomize config sub create dir/ port 8080 --type "int" --field port \ + --description "default port used by the app" + + # set a substitution for port fields matching "8080", using "0000" as a marker. + kustomize config sub dir/ port 8080 --marker "0000" --type "int" \ + --field port --description "default port used by the app" + + # substitute a substring of a field rather than the full field -- e.g. only the + # image tag, not the full image + kustomize config sub dir/ app-image-tag v1.0.1 --type "string" --substring \ + --field port --description "current stable release"` + var TreeShort = `[Alpha] Display Resource structure from a directory or stdin.` var TreeLong = ` [Alpha] Display Resource structure from a directory or stdin. diff --git a/cmd/config/internal/sub/addkio.go b/cmd/config/internal/sub/addkio.go new file mode 100644 index 00000000000..dff71f983a4 --- /dev/null +++ b/cmd/config/internal/sub/addkio.go @@ -0,0 +1,39 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package sub + +import ( + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +var _ kio.Filter = &SetSubstitutionMarker{} + +// Sub performs substitutions +type SetSubstitutionMarker struct { + // Marker is the marker to set + Marker Marker + + // ResourceMeta defines the Resource to set the marker on + ResourceMeta yaml.ResourceMeta +} + +func (s *SetSubstitutionMarker) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { + for i := range input { + m, err := input[i].GetMeta() + if err != nil { + return nil, err + } + if s.ResourceMeta.Name != "" && m.Name != s.ResourceMeta.Name { + continue + } + if s.ResourceMeta.Kind != "" && m.Kind != s.ResourceMeta.Kind { + continue + } + if err := input[i].PipeE(&s.Marker); err != nil { + return nil, err + } + } + return input, nil +} diff --git a/cmd/config/internal/sub/addyaml.go b/cmd/config/internal/sub/addyaml.go new file mode 100644 index 00000000000..118d054dade --- /dev/null +++ b/cmd/config/internal/sub/addyaml.go @@ -0,0 +1,105 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package sub + +import ( + "strings" + + "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/fieldmeta" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +var _ yaml.Filter = &Marker{} + +// substituteResource substitutes a Marker value on a field +type Marker struct { + // Path is the path of the field to add the substitution for + Field string + + // Substitution is the substitution to add + Substitution fieldmeta.Substitution + + // PartialMatch if true will match if the Substitution value is a substring of the current + // value. + PartialMatch bool + + Description string + OwnedBy string + Type string + + // currentFieldName is the name of the current field being processed + currentFieldName string +} + +// Filter performs the substitutions for a single object +func (m *Marker) Filter(object *yaml.RNode) (*yaml.RNode, error) { + switch object.YNode().Kind { + case yaml.DocumentNode: + return m.Filter(yaml.NewRNode(object.YNode().Content[0])) + case yaml.MappingNode: + return object, object.VisitFields(func(node *yaml.MapNode) error { + // set the current field name + n := m.currentFieldName + defer func() { m.currentFieldName = n }() + m.currentFieldName = node.Key.YNode().Value + _, err := m.Filter(node.Value) + return err + }) + case yaml.SequenceNode: + return object, object.VisitElements(func(node *yaml.RNode) error { + _, err := m.Filter(node) + return err + }) + case yaml.ScalarNode: + if m.currentFieldName != m.Field { + return object, nil + } + if err := m.createSub(object); err != nil { + return nil, err + } + return object, nil + default: + return object, nil + } +} + +func (as *Marker) createSub(field *yaml.RNode) error { + // doesn't match the supplied value + if field.YNode().Value != as.Substitution.Value { + if !as.PartialMatch || !strings.Contains(field.YNode().Value, as.Substitution.Value) { + return nil + } + } + + fm := fieldmeta.FieldMeta{} + if err := fm.Read(field); err != nil { + return errors.Wrap(err) + } + fm.OwnedBy = as.OwnedBy + fm.Description = as.Description + fm.Type = fieldmeta.FieldValueType(as.Type) + if as.Substitution.Marker == "" { + as.Substitution.Marker = "[MARKER]" + } + + found := false + for i := range fm.Substitutions { + s := fm.Substitutions[i] + if s.Name == as.Substitution.Name { + // update the substitution if we find it + found = true + fm.Substitutions[i] = as.Substitution + break + } + } + if !found { + // add the substitution if it wasn't found + fm.Substitutions = append(fm.Substitutions, as.Substitution) + } + if err := fm.Write(field); err != nil { + return errors.Wrap(err) + } + return nil +} diff --git a/cmd/config/internal/sub/dokio.go b/cmd/config/internal/sub/dokio.go new file mode 100644 index 00000000000..794283a8bf8 --- /dev/null +++ b/cmd/config/internal/sub/dokio.go @@ -0,0 +1,53 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package sub + +import ( + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +var _ kio.Filter = &PerformSubstitutions{} + +// Sub performs substitutions +type PerformSubstitutions struct { + // Name is the name of the substitution to perform + Name string + + // NewValue is the substitution value + NewValue string + + // Override if set to true will re-substitute already fields with a new value + Override bool + + // Revert if set to true will substitute fields back to the marker value + Revert bool + + // Description, if set will annotate the field with a description. + Description string + + // OwnedBy, if set will annotate the field with an owner. + OwnedBy string + + // Count is the number of substitutions performed by Filter. + Count int +} + +func (s *PerformSubstitutions) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { + for i := range input { + p := &performSubstitutions{ + Name: s.Name, + Override: s.Override, + Revert: s.Revert, + NewValue: s.NewValue, + OwnedBy: s.OwnedBy, + Description: s.Description, + } + if err := input[i].PipeE(p); err != nil { + return nil, err + } + s.Count += p.Count + } + return input, nil +} diff --git a/cmd/config/internal/sub/doyaml.go b/cmd/config/internal/sub/doyaml.go new file mode 100644 index 00000000000..19c2b5198b9 --- /dev/null +++ b/cmd/config/internal/sub/doyaml.go @@ -0,0 +1,155 @@ +// Copyright 2019 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 sub substitutes strings in fields +package sub + +import ( + "strings" + + "sigs.k8s.io/kustomize/kyaml/fieldmeta" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +var _ yaml.Filter = &performSubstitutions{} + +// substituteResource substitutes a Marker value on a field +type performSubstitutions struct { + // Name of the substitution to perform. + Name string + + // Override if set to true will replace previously substituted values + Override bool + + // Revert if set to true will undo previously substituted values + Revert bool + + // NewValue is the new value to set. Mutually exclusive with Revert. + NewValue string + + // Description, if set will annotate the field with a description. + Description string + + // OwnedBy, if set will annotate the field with an owner. + OwnedBy string + + // Count will be incremented for each substituted value. + Count int +} + +// Filter performs the substitutions for a single object +func (fs *performSubstitutions) Filter(object *yaml.RNode) (*yaml.RNode, error) { + switch object.YNode().Kind { + case yaml.DocumentNode: + return fs.Filter(yaml.NewRNode(object.YNode().Content[0])) + case yaml.MappingNode: + return object, object.VisitFields(func(node *yaml.MapNode) error { + _, err := fs.Filter(node.Value) + return err + }) + case yaml.SequenceNode: + return object, object.VisitElements(func(node *yaml.RNode) error { + _, err := fs.Filter(node) + return err + }) + case yaml.ScalarNode: + s, f, err := fs.findSub(object) + if err != nil { + return nil, err + } + if s == nil { + return object, nil + } + return object, fs.substitute(object, s, f) + default: + return object, nil + } +} + +// findSub finds the substitution matching the name if one exists +func (fs *performSubstitutions) findSub(field *yaml.RNode) ( + *fieldmeta.Substitution, *fieldmeta.FieldMeta, error) { + // check if there are any substitutions for this field + var fm = &fieldmeta.FieldMeta{} + if err := fm.Read(field); err != nil { + return nil, nil, err + } + if fs.OwnedBy != "" { + fm.OwnedBy = fs.OwnedBy + } + if fs.Description != "" { + fm.Description = fs.Description + } + + // check if there is a matching substitution + for i := range fm.Substitutions { + if fm.Substitutions[i].Name == fs.Name { + // validate the value if we are not reverting to the marker. + // markers are allowed to be invalid. + // only validate if there is a substitution matching the name + if !fs.Revert { + if err := fm.Type.Validate(fs.NewValue); err != nil { + return nil, nil, err + } + } + return &fm.Substitutions[i], fm, nil + } + } + return nil, nil, nil +} + +// substitute performs the substitution for the given field, substitution, and metadata +func (fs *performSubstitutions) substitute( + field *yaml.RNode, s *fieldmeta.Substitution, f *fieldmeta.FieldMeta) error { + // undo or override previous substitutions by substituting the marker back + // NOTE: check if s.Value != "" so we never try to substitute the empty string back + if (fs.Revert || fs.Override) && s.Value != "" { + // revert to the marker value + if strings.Contains(field.YNode().Value, s.Value) { + // revert the substitution + field.YNode().Value = strings.ReplaceAll(field.YNode().Value, s.Value, s.Marker) + // only use the tag matching the type if the marker parses to that type + field.YNode().Tag = f.Type.TagForValue(s.Marker) + // record that the config has been modified + } + } + if fs.Revert { + fs.Count++ + s.Value = "" // value has been cleared and replaced with marker + if err := f.Write(field); err != nil { + return err + } + return nil + } + + if s.Value == fs.NewValue || !strings.Contains(field.YNode().Value, s.Marker) { + // no substitutions necessary -- already substituted or doesn't have the marker + return nil + } + + // replace the marker with the new value + field.YNode().Value = strings.ReplaceAll(field.YNode().Value, s.Marker, fs.NewValue) + // be sure to set the tag so the yaml doesn't incorrectly quote ints, bools or floats + field.YNode().Tag = f.Type.Tag() + field.YNode().Style = 0 + // record that the config has been modified + fs.Count++ + + // update the comment on the field + s.Value = fs.NewValue + if err := f.Write(field); err != nil { + return err + } + return nil +} diff --git a/cmd/config/internal/sub/lookupkio.go b/cmd/config/internal/sub/lookupkio.go new file mode 100644 index 00000000000..76921c1190f --- /dev/null +++ b/cmd/config/internal/sub/lookupkio.go @@ -0,0 +1,69 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package sub + +import ( + "sort" + + "sigs.k8s.io/kustomize/kyaml/kio" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +var _ kio.Filter = &LookupSubstitutions{} + +// Sub performs substitutions +type LookupSubstitutions struct { + // Name is the name of the substitution to match. If unspecified, all substitutions will + // be matched. + Name string + + // SubstitutionCounts are the aggregate substitutions matched. + SubstitutionCounts []FieldSubstitutionCount +} + +type FieldSubstitutionCount struct { + // Count is the number of substitutions possible to perform + Count int + + // CountComplete is the number of substitutions that have already been performed + // independent of this object. + CountComplete int + + // FieldSubstitution is the substitution found + FieldSubstitution +} + +func (l *LookupSubstitutions) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) { + subs := map[string]*FieldSubstitutionCount{} + for i := range input { + // lookup substitutions for this object + ls := &lookupSubstitutions{Name: l.Name} + if err := input[i].PipeE(ls); err != nil { + return nil, err + } + + // aggregate counts for each substitution + for j := range ls.Substitutions { + sub := ls.Substitutions[j] + curr, found := subs[sub.Name] + if !found { + curr = &FieldSubstitutionCount{FieldSubstitution: sub} + subs[sub.Name] = curr + } + curr.Count++ + if sub.CurrentValue != "" { + curr.CountComplete++ + } + } + } + + // pull out and sort the results + for _, v := range subs { + l.SubstitutionCounts = append(l.SubstitutionCounts, *v) + } + sort.Slice(l.SubstitutionCounts, func(i, j int) bool { + return l.SubstitutionCounts[i].Name < l.SubstitutionCounts[j].Name + }) + return input, nil +} diff --git a/cmd/config/internal/sub/lookupyaml.go b/cmd/config/internal/sub/lookupyaml.go new file mode 100644 index 00000000000..dee2abf29c9 --- /dev/null +++ b/cmd/config/internal/sub/lookupyaml.go @@ -0,0 +1,65 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package sub + +import ( + "sigs.k8s.io/kustomize/kyaml/fieldmeta" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +var _ yaml.Filter = &lookupSubstitutions{} + +// substituteResource substitutes a Marker value on a field +type lookupSubstitutions struct { + // Name of the substitution to lookup. If unspecified lookup all substitutions. + Name string + + // FieldSubstitution is the list of substitutions that were found + Substitutions []FieldSubstitution +} + +func (ls *lookupSubstitutions) Filter(object *yaml.RNode) (*yaml.RNode, error) { + switch object.YNode().Kind { + case yaml.DocumentNode: + return ls.Filter(yaml.NewRNode(object.YNode().Content[0])) + case yaml.MappingNode: + return object, object.VisitFields(func(node *yaml.MapNode) error { + _, err := ls.Filter(node.Value) + return err + }) + case yaml.SequenceNode: + return object, object.VisitElements(func(node *yaml.RNode) error { + _, err := ls.Filter(node) + return err + }) + case yaml.ScalarNode: + return object, ls.lookup(object) + default: + return object, nil + } +} + +// lookup finds any substitutions for this field +func (ls *lookupSubstitutions) lookup(field *yaml.RNode) error { + // check if there is a substitution for this field + var fm = &fieldmeta.FieldMeta{} + if err := fm.Read(field); err != nil { + return err + } + + for i := range fm.Substitutions { + s := fm.Substitutions[i] + if ls.Name == "" || ls.Name == s.Name { + ls.Substitutions = append(ls.Substitutions, FieldSubstitution{ + Name: s.Name, + CurrentValue: s.Value, + Description: fm.Description, + Marker: s.Marker, + Type: fm.Type, + OwnedBy: fm.OwnedBy, + }) + } + } + return nil +} diff --git a/cmd/config/internal/sub/types.go b/cmd/config/internal/sub/types.go new file mode 100644 index 00000000000..f8b6a86b77a --- /dev/null +++ b/cmd/config/internal/sub/types.go @@ -0,0 +1,29 @@ +// Copyright 2019 The Kubernetes Authors. +// SPDX-License-Identifier: Apache-2.0 + +package sub + +import ( + "sigs.k8s.io/kustomize/kyaml/fieldmeta" +) + +// FieldSubstitution is a possible field substitution read from a field +type FieldSubstitution struct { + // Name is the name of the substitution + Name string + + // Description is a description of the fields current value + Description string + + // Value is the current substituted value for the field. + CurrentValue string + + // Type is the type of the substitution + Type fieldmeta.FieldValueType + + // Marker is the marker used + Marker string + + // OwnedBy, if set will annotate the field with an owner. + OwnedBy string +} diff --git a/kustomize/go.sum b/kustomize/go.sum index 0f4a2732dcf..02dc9555cbc 100644 --- a/kustomize/go.sum +++ b/kustomize/go.sum @@ -240,6 +240,8 @@ github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7 github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54= +github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -261,6 +263,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8= +github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA= github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= diff --git a/kyaml/fieldmeta/fieldmeta.go b/kyaml/fieldmeta/fieldmeta.go new file mode 100644 index 00000000000..7b47229db38 --- /dev/null +++ b/kyaml/fieldmeta/fieldmeta.go @@ -0,0 +1,134 @@ +package fieldmeta + +import ( + "bytes" + "encoding/json" + "strconv" + "strings" + + "sigs.k8s.io/kustomize/kyaml/errors" + "sigs.k8s.io/kustomize/kyaml/yaml" +) + +// FieldMeta contains metadata that may be attached to fields as comments +type FieldMeta struct { + // Substitutions are substitutions that may be performed against this field + Substitutions []Substitution `yaml:"substitutions,omitempty" json:"substitutions,omitempty"` + // OwnedBy records the owner of this field + OwnedBy string `yaml:"ownedBy,omitempty" json:"ownedBy,omitempty"` + // DefaultedBy records that this field was default, but may be changed by other owners + DefaultedBy string `yaml:"defaultedBy,omitempty" json:"defaultedBy,omitempty"` + // Description is a description of the current field value, e.g. why it was set + Description string `yaml:"description,omitempty" json:"description,omitempty"` + // Type is the type of the field value + Type FieldValueType `yaml:"type,omitempty" json:"type,omitempty"` +} + +// Substitution defines a substitution that may be performed against the field +type Substitution struct { + // Name is the name of the substitution and read by tools + Name string `yaml:"name,omitempty" json:"name,omitempty"` + // Marker is the marker used for replacement + Marker string `yaml:"marker,omitempty" json:"marker,omitempty"` + // Value is the current value that has been substituted for the Marker + Value string `yaml:"value,omitempty" json:"value,omitempty"` +} + +// Read reads the FieldMeta from a node +func (fm *FieldMeta) Read(n *yaml.RNode) error { + if n.YNode().LineComment != "" { + v := strings.TrimLeft(n.YNode().LineComment, "#") + // if it doesn't Unmarshal that is fine, it means there is no metadata + // other comments are valid, they just don't parse + d := yaml.NewDecoder(bytes.NewBuffer([]byte(v))) + d.KnownFields(false) + _ = d.Decode(fm) + } + return nil +} + +// Write writes the FieldMeta to a node +func (fm *FieldMeta) Write(n *yaml.RNode) error { + b, err := json.Marshal(fm) + if err != nil { + return err + } + n.YNode().LineComment = string(b) + return nil +} + +// FieldValueType defines the type of input to register +type FieldValueType string + +const ( + // String defines a string flag + String FieldValueType = "string" + // Bool defines a bool flag + Bool = "bool" + // Float defines a float flag + Float = "float" + // Int defines an int flag + Int = "int" +) + +func (it FieldValueType) String() string { + if it == "" { + return "string" + } + return string(it) +} + +func (it FieldValueType) Validate(value string) error { + switch it { + case Int: + if _, err := strconv.Atoi(value); err != nil { + return errors.WrapPrefixf(err, "value must be an int") + } + case Bool: + if _, err := strconv.ParseBool(value); err != nil { + return errors.WrapPrefixf(err, "value must be a bool") + } + case Float: + if _, err := strconv.ParseFloat(value, 64); err != nil { + return errors.WrapPrefixf(err, "value must be a float") + } + } + return nil +} + +func (it FieldValueType) Tag() string { + switch it { + case String: + return "!!str" + case Bool: + return "!!bool" + case Int: + return "!!int" + case Float: + return "!!float" + } + return "" +} + +func (it FieldValueType) TagForValue(value string) string { + switch it { + case String: + return "!!str" + case Bool: + if _, err := strconv.ParseBool(string(it)); err != nil { + return "" + } + return "!!bool" + case Int: + if _, err := strconv.ParseInt(string(it), 0, 32); err != nil { + return "" + } + return "!!int" + case Float: + if _, err := strconv.ParseFloat(string(it), 64); err != nil { + return "" + } + return "!!float" + } + return "" +}