diff --git a/Gopkg.lock b/Gopkg.lock index aaad8169e..7c4d43c05 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,34 +2,27 @@ [[projects]] - digest = "1:e4549155be72f065cf860ada7148bbeb0857360e81da2d5e28b799bd8720f1bc" name = "cloud.google.com/go" packages = ["compute/metadata"] - pruneopts = "T" revision = "0ebda48a7f143b1cce9eb37a8c1106ac762a3430" version = "v0.34.0" [[projects]] - digest = "1:b92928b73320648b38c93cacb9082c0fe3f8ac3383ad9bd537eef62c380e0e7a" name = "contrib.go.opencensus.io/exporter/ocagent" packages = ["."] - pruneopts = "T" revision = "00af367e65149ff1f2f4b93bbfbb84fd9297170d" version = "v0.2.0" [[projects]] branch = "master" - digest = "1:6da51e5ec493ad2b44cb04129e2d0a068c8fb9bd6cb5739d199573558696bb94" name = "github.com/Azure/go-ansiterm" packages = [ ".", - "winterm", + "winterm" ] - pruneopts = "T" revision = "d6e3b3328b783f23731bc4d058875b0371ff8109" [[projects]] - digest = "1:4827c7440869600b1e44806702a649c5055692063056e165026d46518e33db12" name = "github.com/Azure/go-autorest" packages = [ "autorest", @@ -37,158 +30,122 @@ "autorest/azure", "autorest/date", "logger", - "tracing", + "tracing" ] - pruneopts = "T" revision = "f401b1ccc8eb505927fae7a0c7f6406d37ca1c7e" version = "v11.2.8" [[projects]] - digest = "1:147748cfa709da38076c3df47f6bca6814c8ced6cba510065ec03f2120cc4819" name = "github.com/BurntSushi/toml" packages = ["."] - pruneopts = "T" revision = "3012a1dbe2e4bd1391d42b32f0577cb7bbc7f005" version = "v0.3.1" [[projects]] branch = "master" - digest = "1:414b0f57170d23e2941aa5cd393e99d0ab7a639e27d9784ef3949eae6cddfdb3" name = "github.com/MakeNowJust/heredoc" packages = ["."] - pruneopts = "T" revision = "e9091a26100e9cfb2b6a8f470085bfa541931a91" [[projects]] - digest = "1:3b10c6fd33854dc41de2cf78b7bae105da94c2789b6fa5b9ac9e593ea43484ac" name = "github.com/Masterminds/goutils" packages = ["."] - pruneopts = "T" revision = "41ac8693c5c10a92ea1ff5ac3a7f95646f6123b0" version = "v1.1.0" [[projects]] - digest = "1:55388fd080150b9a072912f97b1f5891eb0b50df43401f8b75fb4273d3fec9fc" name = "github.com/Masterminds/semver" packages = ["."] - pruneopts = "T" revision = "c7af12943936e8c39859482e61f0574c2fd7fc75" version = "v1.4.2" [[projects]] - digest = "1:167d20f2417c3188e4f4d02a8870ac65b4d4f9fe0ac6f450873fcffa39623a37" name = "github.com/Masterminds/sprig" packages = ["."] - pruneopts = "T" revision = "258b00ffa7318e8b109a141349980ffbd30a35db" version = "v2.20.0" [[projects]] - digest = "1:74334b154a542b15a7391df3db5428675fdaa56b4d3f3de7b750289b9500d70e" name = "github.com/Masterminds/vcs" packages = ["."] - pruneopts = "T" revision = "b4f55832432b95a611cf1495272b5c8e24952a1a" version = "v1.13.0" [[projects]] - digest = "1:ef2f0eff765cd6c60594654adc602ac5ba460462ac395c6f3c144e5bea24babe" name = "github.com/Microsoft/go-winio" packages = ["."] - pruneopts = "T" revision = "1a8911d1ed007260465c3bfbbc785ac6915a0bb8" version = "v0.4.12" [[projects]] branch = "master" - digest = "1:3721a10686511b80c052323423f0de17a8c06d417dbdd3b392b1578432a33aae" name = "github.com/Nvveen/Gotty" packages = ["."] - pruneopts = "T" revision = "cd527374f1e5bff4938207604a14f2e38a9cf512" [[projects]] - digest = "1:352fc094dbd1438593b64251de6788bffdf30f9925cf763c7f62e1fd27142b76" name = "github.com/PuerkitoBio/purell" packages = ["."] - pruneopts = "T" revision = "0bcb03f4b4d0a9428594752bd2a3b9aa0a9d4bd4" version = "v1.1.0" [[projects]] branch = "master" - digest = "1:c739832d67eb1e9cc478a19cc1a1ccd78df0397bf8a32978b759152e205f644b" name = "github.com/PuerkitoBio/urlesc" packages = ["."] - pruneopts = "T" revision = "de5bf2ad457846296e2031421a34e2568e304e35" [[projects]] branch = "master" - digest = "1:5b8a3b9e8d146a93f6d0538d3be408c9adff07fd694d4094b814a376b4727b14" name = "github.com/Shopify/logrus-bugsnag" packages = ["."] - pruneopts = "T" revision = "577dee27f20dd8f1a529f82210094af593be12bd" [[projects]] - digest = "1:297a3c21bf1d3b4695a222e43e982bb52b4b9e156ca2eadbe32b898d0a1ae551" name = "github.com/asaskevich/govalidator" packages = ["."] - pruneopts = "T" revision = "ccb8e960c48f04d6935e72476ae4a51028f9e22f" version = "v9" [[projects]] branch = "master" - digest = "1:ad4589ec239820ee99eb01c1ad47ebc5f8e02c4f5103a9b210adff9696d89f36" name = "github.com/beorn7/perks" packages = ["quantile"] - pruneopts = "T" revision = "3a771d992973f24aa725d07868b467d1ddfceafb" [[projects]] - digest = "1:7b81d2ed76bf960333a8020c4b8c22abd6072f0b54ad31c66e90e6a17a19315a" name = "github.com/bshuster-repo/logrus-logstash-hook" packages = ["."] - pruneopts = "T" revision = "dbc1e22735aa6ed7bd9579a407c17bc7c4a4e046" version = "v0.4.1" [[projects]] - digest = "1:f18852f146423bf4c60dcd2f84e8819cfeabac15a875d7ea49daddb2d021f9d5" name = "github.com/bugsnag/bugsnag-go" packages = [ ".", - "errors", + "errors" ] - pruneopts = "T" revision = "3f5889f222e9c07aa1f62c5e8c202e402ce574cd" version = "v1.3.2" [[projects]] - digest = "1:3049c43c6d1cfaa347acd27d6342187f8f38d9f416bbba7b02b43f82848302d2" name = "github.com/bugsnag/panicwrap" packages = ["."] - pruneopts = "T" revision = "4009b2b7c78d820cc4a2e42f035bb557ce4ae45b" version = "v1.2.0" [[projects]] - digest = "1:0b2d5839372f6dc106fcaa70b6bd5832789a633c4e470540f76c2ec6c560e1c1" name = "github.com/census-instrumentation/opencensus-proto" packages = [ "gen-go/agent/common/v1", "gen-go/agent/trace/v1", "gen-go/resource/v1", - "gen-go/trace/v1", + "gen-go/trace/v1" ] - pruneopts = "T" revision = "7f2434bc10da710debe5c4315ed6d4df454b4024" version = "v0.1.0" [[projects]] - digest = "1:b5f139796b532342966b835fb26fe41b6b488e94b914f1af1aba4cd3a9fee6dc" name = "github.com/containerd/containerd" packages = [ "content", @@ -198,73 +155,59 @@ "platforms", "reference", "remotes", - "remotes/docker", + "remotes/docker" ] - pruneopts = "T" revision = "894b81a4b802e4eb2a91d1ce216b8817763c29fb" version = "v1.2.6" [[projects]] branch = "master" - digest = "1:1271f7f8cc5f5b2eb0c683f92c7adf8fca1813b9da5218d6df1c9cf4bdc3f8d5" name = "github.com/containerd/continuity" packages = ["pathdriver"] - pruneopts = "T" revision = "004b46473808b3e7a4a3049c20e4376c91eb966d" [[projects]] - digest = "1:607c4f1f646bfe5ec1a4eac4a505608f280829550ed546a243698a525d3c5fe8" name = "github.com/cpuguy83/go-md2man" packages = ["md2man"] - pruneopts = "T" revision = "20f5889cbdc3c73dbd2862796665e7c465ade7d1" version = "v1.0.8" [[projects]] - digest = "1:9f42202ac457c462ad8bb9642806d275af9ab4850cf0b1960b9c6f083d4a309a" name = "github.com/davecgh/go-spew" packages = ["spew"] - pruneopts = "T" revision = "8991bc29aa16c548c550c7ff78260e27b9ab7c73" version = "v1.1.1" [[projects]] - digest = "1:7dd5499cbbbb141b28c7b98bcf9a14af1ca69d368796096784ccef3292407a52" name = "github.com/deislabs/oras" packages = [ "pkg/auth", "pkg/auth/docker", "pkg/content", "pkg/context", - "pkg/oras", + "pkg/oras" ] - pruneopts = "T" revision = "b3b6ce7eeb31a5c0d891d33f585c84ae3dcc9046" version = "v0.5.0" [[projects]] - digest = "1:6b014c67cb522566c30ef02116f9acb50cd60954708cf92c6654e2985696db18" name = "github.com/dgrijalva/jwt-go" packages = ["."] - pruneopts = "T" revision = "06ea1031745cb8b3dab3f6a236daf2b0aa468b7e" version = "v3.2.0" [[projects]] - digest = "1:82905edd0b7a5bca3774725e162e1befecd500cd95df2c9909358d4835d36310" name = "github.com/docker/cli" packages = [ "cli/config", "cli/config/configfile", "cli/config/credentials", - "cli/config/types", + "cli/config/types" ] - pruneopts = "T" revision = "f28d9cc92972044feb72ab6833699102992d40a2" version = "v19.03.0-beta3" [[projects]] - digest = "1:bd3ffa8395e5f3cee7a1d38a7f4de0df088301e25c4e6910fc53936c4be09278" name = "github.com/docker/distribution" packages = [ ".", @@ -306,15 +249,13 @@ "registry/storage/driver/inmemory", "registry/storage/driver/middleware", "uuid", - "version", + "version" ] - pruneopts = "T" revision = "40b7b5830a2337bb07627617740c0e39eb92800c" version = "v2.7.0" [[projects]] branch = "master" - digest = "1:3d23e50eab6b3aa4ced1b1cc8b5c40534b9c9a54b0f5648a2e76d72599134e4e" name = "github.com/docker/docker" packages = [ "api/types", @@ -341,157 +282,123 @@ "pkg/term", "pkg/term/windows", "registry", - "registry/resumable", + "registry/resumable" ] - pruneopts = "T" revision = "2cb26cfe9cbf8a64c5046c74d65f4528b22e67f4" [[projects]] - digest = "1:523611f6876df8a1fd1aea07499e6ae33585238e8fdd8793f48a2441438a12d6" name = "github.com/docker/docker-credential-helpers" packages = [ "client", - "credentials", + "credentials" ] - pruneopts = "T" revision = "5241b46610f2491efdf9d1c85f1ddf5b02f6d962" version = "v0.6.1" [[projects]] - digest = "1:b64eea95d41af3792092af9c951efcd2d8d8bfd2335c851f7afaf54d6be12c66" name = "github.com/docker/go-connections" packages = [ "nat", "sockets", - "tlsconfig", + "tlsconfig" ] - pruneopts = "T" revision = "7395e3f8aa162843a74ed6d48e79627d9792ac55" version = "v0.4.0" [[projects]] branch = "master" - digest = "1:2b126e77be4ab4b92cdb3924c87894dd76bf365ba282f358a13133e848aa0059" name = "github.com/docker/go-metrics" packages = ["."] - pruneopts = "T" revision = "b84716841b82eab644a0c64fc8b42d480e49add5" [[projects]] - digest = "1:6f82cacd0af5921e99bf3f46748705239b36489464f4529a1589bc895764fb18" name = "github.com/docker/go-units" packages = ["."] - pruneopts = "T" revision = "47565b4f722fb6ceae66b95f853feed578a4a51c" version = "v0.3.3" [[projects]] branch = "master" - digest = "1:46cb138b11721830161dd8293356e3dc5dd7ec774825b7fc5f2bf2fbbf2bed33" name = "github.com/docker/libtrust" packages = ["."] - pruneopts = "T" revision = "aabc10ec26b754e797f9028f4589c5b7bd90dc20" [[projects]] branch = "master" - digest = "1:0d4540d92fd82f9957e1f718e2b1e5f2d301ed8169e2923bba23558fbbbd08a1" name = "github.com/docker/spdystream" packages = [ ".", - "spdy", + "spdy" ] - pruneopts = "T" revision = "6480d4af844c189cf5dd913db24ddd339d3a4f85" [[projects]] - digest = "1:0ffd93121f3971aea43f6a26b3eaaa64c8af20fb0ff0731087d8dab7164af5a8" name = "github.com/emicklei/go-restful" packages = [ ".", - "log", + "log" ] - pruneopts = "T" revision = "3eb9738c1697594ea6e71a7156a9bb32ed216cf0" version = "v2.8.0" [[projects]] - digest = "1:75c3d1e7907ed7a800afd0569783a99a2b6421b634c404565de537b224826703" name = "github.com/evanphx/json-patch" packages = ["."] - pruneopts = "T" revision = "afac545df32f2287a079e2dfb7ba2745a643747e" version = "v3.0.0" [[projects]] branch = "master" - digest = "1:5e0da1aba1a7b125f46e6ddca43e98b40cf6eaea3322b016c331cf6afe53c30a" name = "github.com/exponent-io/jsonpath" packages = ["."] - pruneopts = "T" revision = "d6023ce2651d8eafb5c75bb0c7167536102ec9f5" [[projects]] - digest = "1:bbc4aacabe6880bdbce849c64cb061b7eddf39f132af4ea2853ddd32f85fbec3" name = "github.com/fatih/camelcase" packages = ["."] - pruneopts = "T" revision = "44e46d280b43ec1531bb25252440e34f1b800b65" version = "v1.0.0" [[projects]] - digest = "1:30c81df6bc8e5518535aee2b1eacb1a9dab172ee608eeadb40f4db30f007027e" name = "github.com/garyburd/redigo" packages = [ "internal", - "redis", + "redis" ] - pruneopts = "T" revision = "a69d19351219b6dd56f274f96d85a7014a2ec34e" version = "v1.6.0" [[projects]] - digest = "1:2cd7915ab26ede7d95b8749e6b1f933f1c6d5398030684e6505940a10f31cfda" name = "github.com/ghodss/yaml" packages = ["."] - pruneopts = "T" revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" version = "v1.0.0" [[projects]] - digest = "1:701ec53dfa0182bf25e5c09e664906f11d697e779b59461a2607dbd4dc75a4f9" name = "github.com/go-openapi/jsonpointer" packages = ["."] - pruneopts = "T" revision = "ef5f0afec364d3b9396b7b77b43dbe26bf1f8004" version = "v0.17.2" [[projects]] - digest = "1:3f17ebd557845adeb347c9e398394e96ebc18e0ec94cc04972be87851a4679e0" name = "github.com/go-openapi/jsonreference" packages = ["."] - pruneopts = "T" revision = "8483a886a90412cd6858df4ea3483dce9c8e35a3" version = "v0.17.2" [[projects]] - digest = "1:76b8b440ca412e287dff607469a5a40a9445fe7168ad1fb85916d87c66011c83" name = "github.com/go-openapi/spec" packages = ["."] - pruneopts = "T" revision = "5bae59e25b21498baea7f9d46e9c147ec106a42e" version = "v0.17.2" [[projects]] - digest = "1:0d8057a212a27a625bb8e57b1e25fb8e8e4a0feb0b7df543fd46d8d15c31d870" name = "github.com/go-openapi/swag" packages = ["."] - pruneopts = "T" revision = "5899d5c5e619fda5fa86e14795a835f473ca284c" version = "v0.17.2" [[projects]] - digest = "1:0a5d2a670ac050354afcf572e65aceabefdebdbb90973ea729d8640fa211a9e2" name = "github.com/gobwas/glob" packages = [ ".", @@ -501,33 +408,27 @@ "syntax/ast", "syntax/lexer", "util/runes", - "util/strings", + "util/strings" ] - pruneopts = "T" revision = "5ccd90ef52e1e632236f7326478d4faa74f99438" version = "v0.2.3" [[projects]] - digest = "1:f5ccd717b5f093cbabc51ee2e7a5979b92f17d217f9031d6d64f337101c408e4" name = "github.com/gogo/protobuf" packages = [ "proto", - "sortkeys", + "sortkeys" ] - pruneopts = "T" revision = "4cbf7e384e768b4e01799441fdf2a706a5635ae7" version = "v1.2.0" [[projects]] branch = "master" - digest = "1:8f3489cb7352125027252a6517757cbd1706523119f1e14e20741ae8d2f70428" name = "github.com/golang/groupcache" packages = ["lru"] - pruneopts = "T" revision = "c65c006176ff7ff98bb916961c7abbc6b0afc0aa" [[projects]] - digest = "1:a2ecb56e5053d942aafc86738915fb94c9131bac848c543b8b6764365fd69080" name = "github.com/golang/protobuf" packages = [ "proto", @@ -535,65 +436,53 @@ "ptypes/any", "ptypes/duration", "ptypes/timestamp", - "ptypes/wrappers", + "ptypes/wrappers" ] - pruneopts = "T" revision = "aa810b61a9c79d51363740d207bb46cf8e620ed5" version = "v1.2.0" [[projects]] branch = "master" - digest = "1:0bfbe13936953a98ae3cfe8ed6670d396ad81edf069a806d2f6515d7bb6950df" name = "github.com/google/btree" packages = ["."] - pruneopts = "T" revision = "4030bb1f1f0c35b30ca7009e9ebd06849dd45306" [[projects]] - digest = "1:ec7c114271a6226a146c64cb0d95348ac85350fde7dbb2564a1911165aa63ced" name = "github.com/google/go-cmp" packages = [ "cmp", "cmp/internal/diff", "cmp/internal/flags", "cmp/internal/function", - "cmp/internal/value", + "cmp/internal/value" ] - pruneopts = "T" revision = "6f77996f0c42f7b84e5a2b252227263f93432e9b" version = "v0.3.0" [[projects]] branch = "master" - digest = "1:3ee90c0d94da31b442dde97c99635aaafec68d0b8a3c12ee2075c6bdabeec6bb" name = "github.com/google/gofuzz" packages = ["."] - pruneopts = "T" revision = "24818f796faf91cd76ec7bddd72458fbced7a6c1" [[projects]] - digest = "1:236d7e1bdb50d8f68559af37dbcf9d142d56b431c9b2176d41e2a009b664cda8" name = "github.com/google/uuid" packages = ["."] - pruneopts = "T" revision = "9b3b1e0f5f99ae461456d768e7d301a7acdaa2d8" version = "v1.1.0" [[projects]] - digest = "1:35735e2255fa34521c2a1355fb2a3a2300bc9949f487be1c1ce8ee8efcfa2d04" name = "github.com/googleapis/gnostic" packages = [ "OpenAPIv2", "compiler", - "extensions", + "extensions" ] - pruneopts = "T" revision = "7c663266750e7d82587642f65e60bc4083f1f84e" version = "v0.2.0" [[projects]] branch = "master" - digest = "1:115dd91e62130f4751ab7bf3f9e892bc3b46670a99d5f680128082fe470cbcf4" name = "github.com/gophercloud/gophercloud" packages = [ ".", @@ -602,383 +491,297 @@ "openstack/identity/v2/tokens", "openstack/identity/v3/tokens", "openstack/utils", - "pagination", + "pagination" ] - pruneopts = "T" revision = "94924357ebf6c7d448c70d65082ff7ca6f78ddc5" [[projects]] - digest = "1:664d37ea261f0fc73dd17f4a1f5f46d01fbb0b0d75f6375af064824424109b7d" name = "github.com/gorilla/handlers" packages = ["."] - pruneopts = "T" revision = "7e0847f9db758cdebd26c149d0ae9d5d0b9c98ce" version = "v1.4.0" [[projects]] - digest = "1:03e234a7f71e1bab87804517e5f729b4cc3534cabd2b7cc692052282f6215192" name = "github.com/gorilla/mux" packages = ["."] - pruneopts = "T" revision = "a7962380ca08b5a188038c69871b8d3fbdf31e89" version = "v1.7.0" [[projects]] branch = "master" - digest = "1:fae5efc46b655e70e982e4d8b6af5a829333bc98edfaa91dde5ac608f142c00c" name = "github.com/gosuri/uitable" packages = [ ".", "util/strutil", - "util/wordwrap", + "util/wordwrap" ] - pruneopts = "T" revision = "36ee7e946282a3fb1cfecd476ddc9b35d8847e42" [[projects]] branch = "master" - digest = "1:8c0ceab65d43f49dce22aac0e8f670c170fc74dcf2dfba66d3a89516f7ae2c15" name = "github.com/gregjones/httpcache" packages = [ ".", - "diskcache", + "diskcache" ] - pruneopts = "T" revision = "c63ab54fda8f77302f8d414e19933f2b6026a089" [[projects]] - digest = "1:8ec8d88c248041a6df5f6574b87bc00e7e0b493881dad2e7ef47b11dc69093b5" name = "github.com/hashicorp/golang-lru" packages = [ ".", - "simplelru", + "simplelru" ] - pruneopts = "T" revision = "20f1fb78b0740ba8c3cb143a61e86ba5c8669768" version = "v0.5.0" [[projects]] - digest = "1:f9a5e090336881be43cfc1cf468330c1bdd60abdc9dd194e0b1ab69f4b94dd7c" name = "github.com/huandu/xstrings" packages = ["."] - pruneopts = "T" revision = "f02667b379e2fb5916c3cda2cf31e0eb885d79f8" version = "v1.2.0" [[projects]] - digest = "1:3477d9dd8c135faab978bac762eaeafb31f28d6da97ef500d5c271966f74140a" name = "github.com/imdario/mergo" packages = ["."] - pruneopts = "T" revision = "9f23e2d6bd2a77f959b2bf6acdbefd708a83a4a4" version = "v0.3.6" [[projects]] - digest = "1:870d441fe217b8e689d7949fef6e43efbc787e50f200cb1e70dbca9204a1d6be" name = "github.com/inconshreveable/mousetrap" packages = ["."] - pruneopts = "T" revision = "76626ae9c91c4f2a10f34cad8ce83ea42c93bb75" version = "v1.0" [[projects]] - digest = "1:5d713dbcad44f3358fec51fd5573d4f733c02cac5a40dcb177787ad5ffe9272f" name = "github.com/json-iterator/go" packages = ["."] - pruneopts = "T" revision = "1624edc4454b8682399def8740d46db5e4362ba4" version = "v1.1.5" [[projects]] branch = "master" - digest = "1:caf6db28595425c0e0f2301a00257d11712f65c1878e12cffc42f6b9a9cf3f23" name = "github.com/kardianos/osext" packages = ["."] - pruneopts = "T" revision = "ae77be60afb1dcacde03767a8c37337fad28ac14" [[projects]] - digest = "1:0a69a1c0db3591fcefb47f115b224592c8dfa4368b7ba9fae509d5e16cdc95c8" name = "github.com/konsorten/go-windows-terminal-sequences" packages = ["."] - pruneopts = "T" revision = "5c8c8bd35d3832f5d134ae1e1e375b69a4d25242" version = "v1.0.1" [[projects]] branch = "master" - digest = "1:4be65cb3a11626a0d89fc72b34f62a8768040512d45feb086184ac30fdfbef65" name = "github.com/mailru/easyjson" packages = [ "buffer", "jlexer", - "jwriter", + "jwriter" ] - pruneopts = "T" revision = "60711f1a8329503b04e1c88535f419d0bb440bff" [[projects]] - digest = "1:0356f3312c9bd1cbeda81505b7fd437501d8e778ab66998ef69f00d7f9b3a0d7" name = "github.com/mattn/go-runewidth" packages = ["."] - pruneopts = "T" revision = "3ee7d812e62a0804a7d0a324e0249ca2db3476d3" version = "v0.0.4" [[projects]] - digest = "1:7efe48dea4db6b35dcc15e15394b627247e5b3fb814242de986b746ba8e0abf0" name = "github.com/mattn/go-shellwords" packages = ["."] - pruneopts = "T" revision = "02e3cf038dcea8290e44424da473dd12be796a8a" version = "v1.0.3" [[projects]] - digest = "1:a8e3d14801bed585908d130ebfc3b925ba642208e6f30d879437ddfc7bb9b413" name = "github.com/matttproud/golang_protobuf_extensions" packages = ["pbutil"] - pruneopts = "T" revision = "c12348ce28de40eed0136aa2b644d0ee0650e56c" version = "v1.0.1" [[projects]] - digest = "1:ceb81990372dadfe39e96b9b3df793d4838bbc21cfa02d2f34e7fcbbed227f37" name = "github.com/miekg/dns" packages = ["."] - pruneopts = "T" revision = "0d29b283ac0f967dd3a02739bf26a22702210d7a" [[projects]] - digest = "1:abf08734a6527df70ed361d7c369fb580e6840d8f7a6012e5f609fdfd93b4e48" name = "github.com/mitchellh/go-wordwrap" packages = ["."] - pruneopts = "T" revision = "9e67c67572bc5dd02aef930e2b0ae3c02a4b5a5c" version = "v1.0.0" [[projects]] - digest = "1:33422d238f147d247752996a26574ac48dcf472976eda7f5134015f06bf16563" name = "github.com/modern-go/concurrent" packages = ["."] - pruneopts = "T" revision = "bacd9c7ef1dd9b15be4a9909b8ac7a4e313eec94" version = "1.0.3" [[projects]] - digest = "1:e32bdbdb7c377a07a9a46378290059822efdce5c8d96fe71940d87cb4f918855" name = "github.com/modern-go/reflect2" packages = ["."] - pruneopts = "T" revision = "4b7aa43c6742a2c18fdef89dd197aaae7dac7ccd" version = "1.0.1" [[projects]] - digest = "1:ee4d4af67d93cc7644157882329023ce9a7bcfce956a079069a9405521c7cc8d" name = "github.com/opencontainers/go-digest" packages = ["."] - pruneopts = "T" revision = "279bed98673dd5bef374d3b6e4b09e2af76183bf" version = "v1.0.0-rc1" [[projects]] - digest = "1:eb47da2fdabb69f64ce3a42a1790ec0ed9da6718c8378f3fdc41cbe6af184519" name = "github.com/opencontainers/image-spec" packages = [ "specs-go", - "specs-go/v1", + "specs-go/v1" ] - pruneopts = "T" revision = "d60099175f88c47cd379c4738d158884749ed235" version = "v1.0.1" [[projects]] - digest = "1:52254f0d6ce1358972c08cb1ecd91a449af3a7f927f829abec962613fb167403" name = "github.com/opencontainers/runc" packages = ["libcontainer/user"] - pruneopts = "T" revision = "baf6536d6259209c3edfa2b22237af82942d3dfa" version = "v0.1.1" [[projects]] branch = "master" - digest = "1:0c29d499ffc3b9f33e7136444575527d0c3a9463a89b3cbeda0523b737f910b3" name = "github.com/petar/GoLLRB" packages = ["llrb"] - pruneopts = "T" revision = "53be0d36a84c2a886ca057d34b6aa4468df9ccb4" [[projects]] - digest = "1:598241bd36d3a5f6d9102a306bd9bf78f3bc253672460d92ac70566157eae648" name = "github.com/peterbourgon/diskv" packages = ["."] - pruneopts = "T" revision = "5f041e8faa004a95c88a202771f4cc3e991971e6" version = "v2.0.1" [[projects]] - digest = "1:40e195917a951a8bf867cd05de2a46aaf1806c50cf92eebf4c16f78cd196f747" name = "github.com/pkg/errors" packages = ["."] - pruneopts = "T" revision = "645ef00459ed84a119197bfb8d8205042c6df63d" version = "v0.8.0" [[projects]] - digest = "1:22aa691fe0213cb5c07d103f9effebcb7ad04bee45a0ce5fe5369d0ca2ec3a1f" name = "github.com/pmezard/go-difflib" packages = ["difflib"] - pruneopts = "T" revision = "792786c7400a136282c1664665ae0a8db921c6c2" version = "v1.0.0" [[projects]] - digest = "1:3b5729e3fc486abc6fc16ce026331c3d196e788c3b973081ecf5d28ae3e1050d" name = "github.com/prometheus/client_golang" packages = [ "prometheus", "prometheus/internal", - "prometheus/promhttp", + "prometheus/promhttp" ] - pruneopts = "T" revision = "505eaef017263e299324067d40ca2c48f6a2cf50" version = "v0.9.2" [[projects]] branch = "master" - digest = "1:cd67319ee7536399990c4b00fae07c3413035a53193c644549a676091507cadc" name = "github.com/prometheus/client_model" packages = ["go"] - pruneopts = "T" revision = "fd36f4220a901265f90734c3183c5f0c91daa0b8" [[projects]] - digest = "1:1688d03416102590c2a93f23d44e4297cb438bff146830aae35e66b33c9af114" name = "github.com/prometheus/common" packages = [ "expfmt", "internal/bitbucket.org/ww/goautoneg", - "model", + "model" ] - pruneopts = "T" revision = "cfeb6f9992ffa54aaa4f2170ade4067ee478b250" version = "v0.2.0" [[projects]] branch = "master" - digest = "1:eb94fa4ad4d1e3c7a084f6f19d60a7dbafa3194147655e2b5db14e8bc9dcef74" name = "github.com/prometheus/procfs" packages = [ ".", "internal/util", "nfs", - "xfs", + "xfs" ] - pruneopts = "T" revision = "316cf8ccfec56d206735d46333ca162eb374da8b" [[projects]] - digest = "1:40e527269f1feb16b3069bfe80ff05a462d190eacfe07eb0a59fa25c381db7af" name = "github.com/russross/blackfriday" packages = ["."] - pruneopts = "T" revision = "05f3235734ad95d0016f6a23902f06461fcf567a" version = "v1.5.2" [[projects]] - digest = "1:c3498d1186a4f84897812aa2dccfbd5d805955846f2cd020aa384bf0b218e9e9" name = "github.com/sirupsen/logrus" packages = ["."] - pruneopts = "T" revision = "8bdbc7bcc01dcbb8ec23dc8a28e332258d25251f" version = "v1.4.1" [[projects]] - digest = "1:674fedb5641490b913f0f01e4f97f3f578f7a1c5f106cd47cfd5394eca8155db" name = "github.com/spf13/cobra" packages = [ ".", - "doc", + "doc" ] - pruneopts = "T" revision = "67fc4837d267bc9bfd6e47f77783fcc3dffc68de" version = "v0.0.4" [[projects]] - digest = "1:0f775ea7a72e30d5574267692aaa9ff265aafd15214a7ae7db26bc77f2ca04dc" name = "github.com/spf13/pflag" packages = ["."] - pruneopts = "T" revision = "298182f68c66c05229eb03ac171abe6e309ee79a" version = "v1.0.3" [[projects]] - digest = "1:17c4ccf5cdb1627aaaeb5c1725cb13aec97b63ea2033d4a6824dcaedf94223dc" name = "github.com/stretchr/testify" packages = [ "assert", "require", - "suite", + "suite" ] - pruneopts = "T" revision = "ffdc059bfe9ce6a4e144ba849dbedead332c6053" version = "v1.3.0" [[projects]] branch = "master" - digest = "1:f4e5276a3b356f4692107047fd2890f2fe534f4feeb6b1fd2f6dfbd87f1ccf54" name = "github.com/xeipuuv/gojsonpointer" packages = ["."] - pruneopts = "T" revision = "4e3ac2762d5f479393488629ee9370b50873b3a6" [[projects]] branch = "master" - digest = "1:dc6a6c28ca45d38cfce9f7cb61681ee38c5b99ec1425339bfc1e1a7ba769c807" name = "github.com/xeipuuv/gojsonreference" packages = ["."] - pruneopts = "T" revision = "bd5ef7bd5415a7ac448318e64f11a24cd21e594b" [[projects]] - digest = "1:6d01aadbf9c582bc90c520707fcab1e63af19649218d785c49d6aa561c8948a8" name = "github.com/xeipuuv/gojsonschema" packages = ["."] - pruneopts = "T" revision = "f971f3cd73b2899de6923801c147f075263e0c50" version = "v1.1.0" [[projects]] - digest = "1:89d64b91ff6c1ede3cbc3f3ff6ac101977ee5e56547aebb85af5504adbdb4c63" name = "github.com/xenolf/lego" packages = ["acme"] - pruneopts = "T" revision = "a9d8cec0e6563575e5868a005359ac97911b5985" [[projects]] branch = "master" - digest = "1:f5abbb52b11b97269d74b7ebf9e057e8e34d477eedd171741fe21cc190bedb02" name = "github.com/yvasiyarov/go-metrics" packages = ["."] - pruneopts = "T" revision = "c25f46c4b94079672242ec48a545e7ca9ebe3aec" [[projects]] - digest = "1:6ce16ef7a4c7f60d648676d2c1fbf142c6dbdb96624743472078260150d519c2" name = "github.com/yvasiyarov/gorelic" packages = ["."] - pruneopts = "T" revision = "4dc1bb7ab951bc884feb2c009092b1a454152355" version = "v0.0.6" [[projects]] - digest = "1:c20b060d66ecf0fe4dfbef1bc7d314b352289b8f6cd37069abb5ba6a0f8e0b91" name = "github.com/yvasiyarov/newrelic_platform_go" packages = ["."] - pruneopts = "T" revision = "b21fdbd4370f3717f3bbd2bf41c223bc273068e6" [[projects]] - digest = "1:b6f574d818cb549185939ce3c228983b339eeba4aee229c74c5848ff9e806836" name = "go.opencensus.io" packages = [ ".", @@ -995,15 +798,13 @@ "trace", "trace/internal", "trace/propagation", - "trace/tracestate", + "trace/tracestate" ] - pruneopts = "T" revision = "b7bf3cdb64150a8c8c53b769fdeb2ba581bd4d4b" version = "v0.18.0" [[projects]] branch = "master" - digest = "1:d470cb69884835b1800e93ceceb85afcf981ea647e61d99398a76af7a95bad6a" name = "golang.org/x/crypto" packages = [ "bcrypt", @@ -1021,14 +822,12 @@ "openpgp/s2k", "pbkdf2", "scrypt", - "ssh/terminal", + "ssh/terminal" ] - pruneopts = "T" revision = "505ab145d0a99da450461ae2c1a9f6cd10d1f447" [[projects]] branch = "master" - digest = "1:6a668f89e7e121bf970a6dc37c729f05f5261ae64e27945326d896ad158e5a10" name = "golang.org/x/net" packages = [ "bpf", @@ -1046,49 +845,41 @@ "ipv6", "proxy", "publicsuffix", - "trace", + "trace" ] - pruneopts = "T" revision = "927f97764cc334a6575f4b7a1584a147864d5723" [[projects]] branch = "master" - digest = "1:320e5ba9ea8000060bec710764b8b26c251ee28f6012422b669cb8cb100c9815" name = "golang.org/x/oauth2" packages = [ ".", "google", "internal", "jws", - "jwt", + "jwt" ] - pruneopts = "T" revision = "d668ce993890a79bda886613ee587a69dd5da7a6" [[projects]] branch = "master" - digest = "1:6932d1ef4294f3ea819748e89d1003f5df3804b20b84b5f1c60f8f1d7c933e2d" name = "golang.org/x/sync" packages = [ "errgroup", - "semaphore", + "semaphore" ] - pruneopts = "T" revision = "37e7f081c4d4c64e13b10787722085407fe5d15f" [[projects]] branch = "master" - digest = "1:50eb9e3f847dc29971fecac71bf84a32e9d756dd34216cf9219c50bd3801b4c4" name = "golang.org/x/sys" packages = [ "unix", - "windows", + "windows" ] - pruneopts = "T" revision = "b4a75ba826a64a70990f11a225237acd6ef35c9f" [[projects]] - digest = "1:6164911cb5e94e8d8d5131d646613ff82c14f5a8ce869de2f6d80d9889df8c5a" name = "golang.org/x/text" packages = [ "collate", @@ -1111,30 +902,24 @@ "unicode/cldr", "unicode/norm", "unicode/rangetable", - "width", + "width" ] - pruneopts = "T" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] branch = "master" - digest = "1:077216d94c076b8cd7bd057cb6f7c6d224970cc991bdfe49c0c7a24e8e39ee33" name = "golang.org/x/time" packages = ["rate"] - pruneopts = "T" revision = "85acf8d2951cb2a3bde7632f9ff273ef0379bcbd" [[projects]] branch = "master" - digest = "1:9eaf0fc3f9a9b24531d89e1e0adf916e0d3f5ac7d3ce61f520af19212b1798b0" name = "google.golang.org/api" packages = ["support/bundler"] - pruneopts = "T" revision = "65a46cafb132eff435c7d1e0f439cc73c8eebb85" [[projects]] - digest = "1:1469235a5a8e192cfe6a99c4804b883a02f0ff96a693cd1660515a3a3b94d5ac" name = "google.golang.org/appengine" packages = [ ".", @@ -1146,22 +931,18 @@ "internal/modules", "internal/remote_api", "internal/urlfetch", - "urlfetch", + "urlfetch" ] - pruneopts = "T" revision = "e9657d882bb81064595ca3b56cbe2546bbabf7b1" version = "v1.4.0" [[projects]] branch = "master" - digest = "1:8c7bf8f974d0b63a83834e83b6dd39c2b40d61d409d76172c81d67eba8fee4a8" name = "google.golang.org/genproto" packages = ["googleapis/rpc/status"] - pruneopts = "T" revision = "bd9b4fb69e2ffd37621a6caa54dcbead29b546f2" [[projects]] - digest = "1:c32026b4d2b9f7240ad72edf0dffca4e5863d5edc1ea25416d64929926b5ac67" name = "google.golang.org/grpc" packages = [ ".", @@ -1194,60 +975,50 @@ "resolver/passthrough", "stats", "status", - "tap", + "tap" ] - pruneopts = "T" revision = "df014850f6dee74ba2fc94874043a9f3f75fbfd8" version = "v1.17.0" [[projects]] - digest = "1:2d1fbdc6777e5408cabeb02bf336305e724b925ff4546ded0fa8715a7267922a" name = "gopkg.in/inf.v0" packages = ["."] - pruneopts = "T" revision = "d2d2541c53f18d2a059457998ce2876cc8e67cbf" source = "https://github.com/go-inf/inf.git" version = "v0.9.1" [[projects]] - digest = "1:12f4009e9a437d974387eaf60699ac6a401d146fe8560b01c16478c629af59b4" name = "gopkg.in/square/go-jose.v1" packages = [ ".", "cipher", - "json", + "json" ] - pruneopts = "T" revision = "56062818b5e15ee405eb8363f9498c7113e98337" source = "https://github.com/square/go-jose.git" version = "v1.1.2" [[projects]] - digest = "1:3effe4e6f8af2d27c9cd6070c7c332344490cbeeaa5476ae2bc9e05eb1079f0c" name = "gopkg.in/square/go-jose.v2" packages = [ ".", "cipher", "json", - "jwt", + "jwt" ] - pruneopts = "T" revision = "628223f44a71f715d2881ea69afc795a1e9c01be" source = "https://github.com/square/go-jose.git" version = "v2.3.0" [[projects]] - digest = "1:4d2e5a73dc1500038e504a8d78b986630e3626dc027bc030ba5c75da257cdb96" name = "gopkg.in/yaml.v2" packages = ["."] - pruneopts = "T" revision = "51d6538a90f86fe93ac480b35f37b2be17fef232" source = "https://github.com/go-yaml/yaml" version = "v2.2.2" [[projects]] branch = "release-1.15" - digest = "1:0f34ccf9357fb875ee20b8ba48a240576dfbb1a247d0f1c763f2fec6e93d2e32" name = "k8s.io/api" packages = [ "admission/v1beta1", @@ -1287,22 +1058,18 @@ "settings/v1alpha1", "storage/v1", "storage/v1alpha1", - "storage/v1beta1", + "storage/v1beta1" ] - pruneopts = "T" revision = "1634385ce4626e4da21367d139c4ee5d72437e3b" [[projects]] branch = "release-1.15" - digest = "1:dffbde7aabb4d8c613f9dd53317fd5b3aa0b2722cd4d7159772be68637116793" name = "k8s.io/apiextensions-apiserver" packages = ["pkg/features"] - pruneopts = "T" revision = "23f08c7096c0273b53178de488b95473d5cd3808" [[projects]] branch = "release-1.15" - digest = "1:2656a0f23465fb97265dd7dc176fada8e954dd191f198aa32e6bb52597514aa4" name = "k8s.io/apimachinery" packages = [ "pkg/api/equality", @@ -1357,28 +1124,24 @@ "pkg/watch", "third_party/forked/golang/json", "third_party/forked/golang/netutil", - "third_party/forked/golang/reflect", + "third_party/forked/golang/reflect" ] - pruneopts = "T" revision = "1799e75a07195de9460b8ef7300883499f12127b" [[projects]] branch = "release-1.15" - digest = "1:9e18a8310252d4101ea877fb517b52ca76975742065d86e9cf525f3ddda38b7e" name = "k8s.io/apiserver" packages = [ "pkg/authentication/authenticator", "pkg/authentication/serviceaccount", "pkg/authentication/user", "pkg/features", - "pkg/util/feature", + "pkg/util/feature" ] - pruneopts = "T" revision = "07da2c5601ffacb40aecb4ad92adea2c775d1dd9" [[projects]] branch = "master" - digest = "1:cd2774546a9f0db8e29e6a9792a1b5a7fabf7c0091f7b2845ad048652d74fcc2" name = "k8s.io/cli-runtime" packages = [ "pkg/genericclioptions", @@ -1392,13 +1155,11 @@ "pkg/kustomize/k8sdeps/transformer/patch", "pkg/kustomize/k8sdeps/validator", "pkg/printers", - "pkg/resource", + "pkg/resource" ] - pruneopts = "T" revision = "44a48934c135b31e4f1c0d12e91d384e1cb2304c" [[projects]] - digest = "1:0b9d76929add96339229991d4aeabf4ad1dc716bc8e1353e17a3d3d543480070" name = "k8s.io/client-go" packages = [ "discovery", @@ -1612,44 +1373,36 @@ "util/homedir", "util/jsonpath", "util/keyutil", - "util/retry", + "util/retry" ] - pruneopts = "T" revision = "8e956561bbf57253b1d19c449d0f24e8cb18d467" version = "kubernetes-1.15.1" [[projects]] branch = "master" - digest = "1:bde2bf8d78ad97dbe011a98ed73e0706f2e2d8c80e80caf90f35c6a9620af623" name = "k8s.io/component-base" packages = ["featuregate"] - pruneopts = "T" revision = "b4f50308a6168b3e1e8687b3fb46e9bf1a112ee5" [[projects]] - digest = "1:7a3ef99d492d30157b8e933624a8f0292b4cee5934c23269f7640c8030eb83cd" name = "k8s.io/klog" packages = ["."] - pruneopts = "T" revision = "a5bc97fbc634d635061f3146511332c7e313a55a" version = "v0.1.0" [[projects]] branch = "master" - digest = "1:90f16a49f856e6d94089444e487c535f4cd41f59a1e90c51deb9dcf965f3c50b" name = "k8s.io/kube-openapi" packages = [ "pkg/common", "pkg/util/proto", "pkg/util/proto/testing", - "pkg/util/proto/validation", + "pkg/util/proto/validation" ] - pruneopts = "T" revision = "0317810137be915b9cf888946c6e115c1bfac693" [[projects]] branch = "release-1.15" - digest = "1:06497e8bfb946cef502730eb1ab10dc4e60bac72123f634eef162aaf44999474" name = "k8s.io/kubernetes" packages = [ "pkg/api/legacyscheme", @@ -1703,14 +1456,12 @@ "pkg/util/hash", "pkg/util/labels", "pkg/util/parsers", - "pkg/util/taints", + "pkg/util/taints" ] - pruneopts = "T" revision = "92b2e906d7aa618588167817feaed137a44e6d92" [[projects]] branch = "master" - digest = "1:50d36d11cbcdc86bca9c3eede8bf7bee9947e2f350b3013a28282edf8d6e8b58" name = "k8s.io/utils" packages = [ "buffer", @@ -1719,22 +1470,18 @@ "net", "path", "pointer", - "trace", + "trace" ] - pruneopts = "T" revision = "21c4ce38f2a793ec01e925ddc31216500183b773" [[projects]] branch = "master" - digest = "1:15fbb9f95a13abe2be748b1159b491369d46a2ccc3f378e0f93c391f89608929" name = "rsc.io/letsencrypt" packages = ["."] - pruneopts = "T" revision = "1847a81d2087eba73081db43989e54dabe0768cd" source = "https://github.com/dmcgowan/letsencrypt.git" [[projects]] - digest = "1:663cc8454702691d4d089e6df5acc61d87b9c9a933a28b7615200e5b5a4f0cfd" name = "sigs.k8s.io/kustomize" packages = [ "pkg/commands/build", @@ -1758,103 +1505,20 @@ "pkg/transformers", "pkg/transformers/config", "pkg/transformers/config/defaultconfig", - "pkg/types", + "pkg/types" ] - pruneopts = "T" revision = "a6f65144121d1955266b0cd836ce954c04122dc8" version = "v2.0.3" [[projects]] - digest = "1:7719608fe0b52a4ece56c2dde37bedd95b938677d1ab0f84b8a7852e4c59f849" name = "sigs.k8s.io/yaml" packages = ["."] - pruneopts = "T" revision = "fd68e9863619f6ec2fdd8625fe1f02e7c877e480" version = "v1.1.0" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - input-imports = [ - "github.com/BurntSushi/toml", - "github.com/Masterminds/semver", - "github.com/Masterminds/sprig", - "github.com/Masterminds/vcs", - "github.com/asaskevich/govalidator", - "github.com/containerd/containerd/reference", - "github.com/containerd/containerd/remotes", - "github.com/deislabs/oras/pkg/auth", - "github.com/deislabs/oras/pkg/auth/docker", - "github.com/deislabs/oras/pkg/content", - "github.com/deislabs/oras/pkg/context", - "github.com/deislabs/oras/pkg/oras", - "github.com/docker/distribution/configuration", - "github.com/docker/distribution/registry", - "github.com/docker/distribution/registry/auth/htpasswd", - "github.com/docker/distribution/registry/storage/driver/inmemory", - "github.com/docker/docker/pkg/term", - "github.com/docker/go-units", - "github.com/evanphx/json-patch", - "github.com/gobwas/glob", - "github.com/gosuri/uitable", - "github.com/gosuri/uitable/util/strutil", - "github.com/mattn/go-shellwords", - "github.com/opencontainers/go-digest", - "github.com/opencontainers/image-spec/specs-go/v1", - "github.com/pkg/errors", - "github.com/sirupsen/logrus", - "github.com/spf13/cobra", - "github.com/spf13/cobra/doc", - "github.com/spf13/pflag", - "github.com/stretchr/testify/assert", - "github.com/stretchr/testify/require", - "github.com/stretchr/testify/suite", - "github.com/xeipuuv/gojsonschema", - "golang.org/x/crypto/bcrypt", - "golang.org/x/crypto/openpgp", - "golang.org/x/crypto/openpgp/clearsign", - "golang.org/x/crypto/openpgp/errors", - "golang.org/x/crypto/openpgp/packet", - "golang.org/x/crypto/ssh/terminal", - "gopkg.in/yaml.v2", - "k8s.io/api/apps/v1", - "k8s.io/api/apps/v1beta1", - "k8s.io/api/apps/v1beta2", - "k8s.io/api/batch/v1", - "k8s.io/api/core/v1", - "k8s.io/api/extensions/v1beta1", - "k8s.io/apimachinery/pkg/api/equality", - "k8s.io/apimachinery/pkg/api/errors", - "k8s.io/apimachinery/pkg/api/meta", - "k8s.io/apimachinery/pkg/apis/meta/v1", - "k8s.io/apimachinery/pkg/labels", - "k8s.io/apimachinery/pkg/runtime", - "k8s.io/apimachinery/pkg/runtime/schema", - "k8s.io/apimachinery/pkg/types", - "k8s.io/apimachinery/pkg/util/intstr", - "k8s.io/apimachinery/pkg/util/strategicpatch", - "k8s.io/apimachinery/pkg/util/validation", - "k8s.io/apimachinery/pkg/util/wait", - "k8s.io/apimachinery/pkg/watch", - "k8s.io/cli-runtime/pkg/genericclioptions", - "k8s.io/cli-runtime/pkg/resource", - "k8s.io/client-go/discovery", - "k8s.io/client-go/kubernetes", - "k8s.io/client-go/kubernetes/fake", - "k8s.io/client-go/kubernetes/scheme", - "k8s.io/client-go/kubernetes/typed/core/v1", - "k8s.io/client-go/plugin/pkg/client/auth", - "k8s.io/client-go/rest", - "k8s.io/client-go/rest/fake", - "k8s.io/client-go/tools/clientcmd", - "k8s.io/client-go/tools/watch", - "k8s.io/client-go/util/homedir", - "k8s.io/klog", - "k8s.io/kubernetes/pkg/controller/deployment/util", - "k8s.io/kubernetes/pkg/kubectl/cmd/testing", - "k8s.io/kubernetes/pkg/kubectl/cmd/util", - "k8s.io/kubernetes/pkg/kubectl/validation", - "sigs.k8s.io/yaml", - ] + inputs-digest = "41fffcba41c216580ccc31a7a09f407955aac28550c9fad6f05d44a5db9dc59b" solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index bdefca6f9..bd863f24a 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -58,6 +58,18 @@ name = "github.com/stretchr/testify" version = "^1.3.0" +[[constraint]] + name = "github.com/xeipuuv/gojsonschema" + version = "1.1.0" + +[[constraint]] + name = "github.com/spf13/cobra" + version = "0.0.4" + +[[constraint]] + name = "sigs.k8s.io/yaml" + version = "1.1.0" + [[override]] name = "sigs.k8s.io/kustomize" version = "2.0.3" @@ -104,15 +116,3 @@ [prune] go-tests = true - -[[constraint]] - name = "github.com/xeipuuv/gojsonschema" - version = "1.1.0" - -[[constraint]] - name = "github.com/spf13/cobra" - version = "0.0.4" - -[[constraint]] - name = "sigs.k8s.io/yaml" - version = "1.1.0" diff --git a/cmd/helm/helm.go b/cmd/helm/helm.go index 00933e03c..b47a91893 100644 --- a/cmd/helm/helm.go +++ b/cmd/helm/helm.go @@ -82,7 +82,7 @@ func initActionConfig(actionConfig *action.Configuration, allNamespaces bool) { kc := kube.New(kubeConfig()) kc.Log = logf - clientset, err := kc.KubernetesClientSet() + clientset, err := kc.Factory.KubernetesClientSet() if err != nil { // TODO return error log.Fatal(err) diff --git a/pkg/action/action.go b/pkg/action/action.go index 07aef4f4e..0e512cd27 100644 --- a/pkg/action/action.go +++ b/pkg/action/action.go @@ -24,6 +24,7 @@ import ( "github.com/pkg/errors" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/client-go/discovery" + "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "helm.sh/helm/pkg/chartutil" @@ -110,6 +111,15 @@ func (c *Configuration) getCapabilities() (*chartutil.Capabilities, error) { return c.Capabilities, nil } +func (c *Configuration) KubernetesClientSet() (kubernetes.Interface, error) { + conf, err := c.RESTClientGetter.ToRESTConfig() + if err != nil { + return nil, errors.Wrap(err, "unable to generate config for kubernetes client") + } + + return kubernetes.NewForConfig(conf) +} + // Now generates a timestamp // // If the configuration has a Timestamper on it, that will be used. diff --git a/pkg/action/hooks.go b/pkg/action/hooks.go index c896c415a..84cedead3 100644 --- a/pkg/action/hooks.go +++ b/pkg/action/hooks.go @@ -40,20 +40,21 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, sort.Sort(hookByWeight(executingHooks)) for _, h := range executingHooks { - if err := deleteHookByPolicy(cfg, h, release.HookBeforeHookCreation); err != nil { + if err := cfg.deleteHookByPolicy(h, release.HookBeforeHookCreation); err != nil { return err } - b := bytes.NewBufferString(h.Manifest) - if err := cfg.KubeClient.Create(b); err != nil { + resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest)) + if err != nil { + return errors.Wrapf(err, "unable to build kubernetes object for %s hook %s", hook, h.Path) + } + if _, err := cfg.KubeClient.Create(resources); err != nil { return errors.Wrapf(err, "warning: Hook %s %s failed", hook, h.Path) } - b.Reset() - b.WriteString(h.Manifest) // Get the time at which the hook was applied to the cluster start := time.Now() - err := cfg.KubeClient.WatchUntilReady(b, timeout) + err = cfg.KubeClient.WatchUntilReady(resources, timeout) h.LastRun = release.HookExecution{ StartedAt: start, CompletedAt: time.Now(), @@ -62,7 +63,7 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, if err != nil { // If a hook is failed, checkout the annotation of the hook to determine whether the hook should be deleted // under failed condition. If so, then clear the corresponding resource object in the hook - if err := deleteHookByPolicy(cfg, h, release.HookFailed); err != nil { + if err := cfg.deleteHookByPolicy(h, release.HookFailed); err != nil { return err } return err @@ -72,7 +73,7 @@ func (cfg *Configuration) execHook(rl *release.Release, hook release.HookEvent, // If all hooks are succeeded, checkout the annotation of each hook to determine whether the hook should be deleted // under succeeded condition. If so, then clear the corresponding resource object in each hook for _, h := range executingHooks { - if err := deleteHookByPolicy(cfg, h, release.HookSucceeded); err != nil { + if err := cfg.deleteHookByPolicy(h, release.HookSucceeded); err != nil { return err } } @@ -93,10 +94,14 @@ func (x hookByWeight) Less(i, j int) bool { } // deleteHookByPolicy deletes a hook if the hook policy instructs it to -func deleteHookByPolicy(cfg *Configuration, h *release.Hook, policy release.HookDeletePolicy) error { +func (cfg *Configuration) deleteHookByPolicy(h *release.Hook, policy release.HookDeletePolicy) error { if hookHasDeletePolicy(h, policy) { - b := bytes.NewBufferString(h.Manifest) - return cfg.KubeClient.Delete(b) + resources, err := cfg.KubeClient.Build(bytes.NewBufferString(h.Manifest)) + if err != nil { + return errors.Wrapf(err, "unable to build kubernetes object for deleting hook %s", h.Path) + } + _, errs := cfg.KubeClient.Delete(resources) + return errors.New(joinErrors(errs)) } return nil } diff --git a/pkg/action/install.go b/pkg/action/install.go index d02f0929f..495545426 100644 --- a/pkg/action/install.go +++ b/pkg/action/install.go @@ -19,7 +19,6 @@ package action import ( "bytes" "fmt" - "io" "io/ioutil" "net/url" "os" @@ -168,8 +167,10 @@ func (i *Install) Run(chrt *chart.Chart) (*release.Release, error) { // Mark this release as in-progress rel.SetStatus(release.StatusPendingInstall, "Initial install underway") - if err := i.validateManifest(manifestDoc); err != nil { - return rel, err + + resources, err := i.cfg.KubeClient.Build(bytes.NewBufferString(rel.Manifest)) + if err != nil { + return nil, errors.Wrap(err, "unable to build kubernetes objects from release manifest") } // Bail out here if it is a dry run @@ -204,14 +205,12 @@ func (i *Install) Run(chrt *chart.Chart) (*release.Release, error) { // At this point, we can do the install. Note that before we were detecting whether to // do an update, but it's not clear whether we WANT to do an update if the re-use is set // to true, since that is basically an upgrade operation. - buf := bytes.NewBufferString(rel.Manifest) - if err := i.cfg.KubeClient.Create(buf); err != nil { + if _, err := i.cfg.KubeClient.Create(resources); err != nil { return i.failRelease(rel, err) } if i.Wait { - buf := bytes.NewBufferString(rel.Manifest) - if err := i.cfg.KubeClient.Wait(buf, i.Timeout); err != nil { + if err := i.cfg.KubeClient.Wait(resources, i.Timeout); err != nil { return i.failRelease(rel, err) } @@ -457,12 +456,6 @@ func ensureDirectoryForFile(file string) error { return os.MkdirAll(baseDir, defaultDirectoryPermission) } -// validateManifest checks to see whether the given manifest is valid for the current Kubernetes -func (i *Install) validateManifest(manifest io.Reader) error { - _, err := i.cfg.KubeClient.BuildUnstructured(manifest) - return err -} - // NameAndChart returns the name and chart that should be used. // // This will read the flags and handle name generation if necessary. diff --git a/pkg/action/rollback.go b/pkg/action/rollback.go index 850b70d2a..42807335b 100644 --- a/pkg/action/rollback.go +++ b/pkg/action/rollback.go @@ -130,12 +130,20 @@ func (r *Rollback) prepareRollback(name string) (*release.Release, *release.Rele } func (r *Rollback) performRollback(currentRelease, targetRelease *release.Release) (*release.Release, error) { - if r.DryRun { r.cfg.Log("dry run for %s", targetRelease.Name) return targetRelease, nil } + current, err := r.cfg.KubeClient.Build(bytes.NewBufferString(currentRelease.Manifest)) + if err != nil { + return targetRelease, errors.Wrap(err, "unable to build kubernetes objects from current release manifest") + } + target, err := r.cfg.KubeClient.Build(bytes.NewBufferString(targetRelease.Manifest)) + if err != nil { + return targetRelease, errors.Wrap(err, "unable to build kubernetes objects from new release manifest") + } + // pre-rollback hooks if !r.DisableHooks { if err := r.cfg.execHook(targetRelease, release.HookPreRollback, r.Timeout); err != nil { @@ -145,10 +153,9 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas r.cfg.Log("rollback hooks disabled for %s", targetRelease.Name) } - cr := bytes.NewBufferString(currentRelease.Manifest) - tr := bytes.NewBufferString(targetRelease.Manifest) + results, err := r.cfg.KubeClient.Update(current, target, r.Force) - if err := r.cfg.KubeClient.Update(cr, tr, r.Force, r.Recreate); err != nil { + if err != nil { msg := fmt.Sprintf("Rollback %q failed: %s", targetRelease.Name, err) r.cfg.Log("warning: %s", msg) currentRelease.Info.Status = release.StatusSuperseded @@ -159,9 +166,18 @@ func (r *Rollback) performRollback(currentRelease, targetRelease *release.Releas return targetRelease, err } + if r.Recreate { + // NOTE: Because this is not critical for a release to succeed, we just + // log if an error occurs and continue onward. If we ever introduce log + // levels, we should make these error level logs so users are notified + // that they'll need to go do the cleanup on their own + if err := recreate(r.cfg, results.Updated); err != nil { + r.cfg.Log(err.Error()) + } + } + if r.Wait { - buf := bytes.NewBufferString(targetRelease.Manifest) - if err := r.cfg.KubeClient.Wait(buf, r.Timeout); err != nil { + if err := r.cfg.KubeClient.Wait(target, r.Timeout); err != nil { targetRelease.SetStatus(release.StatusFailed, fmt.Sprintf("Release %q failed: %s", targetRelease.Name, err.Error())) r.cfg.recordRelease(currentRelease) r.cfg.recordRelease(targetRelease) diff --git a/pkg/action/uninstall.go b/pkg/action/uninstall.go index a15fc188d..6dec73e40 100644 --- a/pkg/action/uninstall.go +++ b/pkg/action/uninstall.go @@ -17,13 +17,11 @@ limitations under the License. package action import ( - "bytes" "strings" "time" "github.com/pkg/errors" - "helm.sh/helm/pkg/kube" "helm.sh/helm/pkg/release" "helm.sh/helm/pkg/releaseutil" ) @@ -160,7 +158,7 @@ func joinErrors(errs []error) string { } // deleteRelease deletes the release and returns manifests that were kept in the deletion process -func (u *Uninstall) deleteRelease(rel *release.Release) (kept string, errs []error) { +func (u *Uninstall) deleteRelease(rel *release.Release) (string, []error) { caps, err := u.cfg.getCapabilities() if err != nil { return rel.Manifest, []error{errors.Wrap(err, "could not get apiVersions from Kubernetes")} @@ -177,23 +175,20 @@ func (u *Uninstall) deleteRelease(rel *release.Release) (kept string, errs []err } filesToKeep, filesToDelete := filterManifestsToKeep(files) + var kept string for _, f := range filesToKeep { kept += f.Name + "\n" } + var builder strings.Builder for _, file := range filesToDelete { - b := bytes.NewBufferString(strings.TrimSpace(file.Content)) - if b.Len() == 0 { - continue - } - if err := u.cfg.KubeClient.Delete(b); err != nil { - u.cfg.Log("uninstall: Failed deletion of %q: %s", rel.Name, err) - if err == kube.ErrNoObjectsVisited { - // Rewrite the message from "no objects visited" - err = errors.New("object not found, skipping delete") - } - errs = append(errs, err) - } + builder.WriteString("\n---\n" + file.Content) } + resources, err := u.cfg.KubeClient.Build(strings.NewReader(builder.String())) + if err != nil { + return "", []error{errors.Wrap(err, "unable to build kubernetes objects for delete")} + } + + _, errs := u.cfg.KubeClient.Delete(resources) return kept, errs } diff --git a/pkg/action/upgrade.go b/pkg/action/upgrade.go index aff9f40ac..3d2731bfb 100644 --- a/pkg/action/upgrade.go +++ b/pkg/action/upgrade.go @@ -23,6 +23,8 @@ import ( "github.com/pkg/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "helm.sh/helm/pkg/chart" "helm.sh/helm/pkg/chartutil" "helm.sh/helm/pkg/kube" @@ -74,7 +76,7 @@ func (u *Upgrade) Run(name string, chart *chart.Chart) (*release.Release, error) u.Wait = u.Wait || u.Atomic if err := validateReleaseName(name); err != nil { - return nil, errors.Errorf("upgradeRelease: Release name is invalid: %s", name) + return nil, errors.Errorf("release name is invalid: %s", name) } u.cfg.Log("preparing upgrade for %s", name) currentRelease, upgradedRelease, err := u.prepareUpgrade(name, chart) @@ -197,6 +199,15 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea return upgradedRelease, nil } + current, err := u.cfg.KubeClient.Build(bytes.NewBufferString(originalRelease.Manifest)) + if err != nil { + return upgradedRelease, errors.Wrap(err, "unable to build kubernetes objects from current release manifest") + } + target, err := u.cfg.KubeClient.Build(bytes.NewBufferString(upgradedRelease.Manifest)) + if err != nil { + return upgradedRelease, errors.Wrap(err, "unable to build kubernetes objects from new release manifest") + } + // pre-upgrade hooks if !u.DisableHooks { if err := u.cfg.execHook(upgradedRelease, release.HookPreUpgrade, u.Timeout); err != nil { @@ -205,14 +216,25 @@ func (u *Upgrade) performUpgrade(originalRelease, upgradedRelease *release.Relea } else { u.cfg.Log("upgrade hooks disabled for %s", upgradedRelease.Name) } - if err := u.upgradeRelease(originalRelease, upgradedRelease); err != nil { + + results, err := u.cfg.KubeClient.Update(current, target, u.Force) + if err != nil { u.cfg.recordRelease(originalRelease) return u.failRelease(upgradedRelease, err) } + if u.Recreate { + // NOTE: Because this is not critical for a release to succeed, we just + // log if an error occurs and continue onward. If we ever introduce log + // levels, we should make these error level logs so users are notified + // that they'll need to go do the cleanup on their own + if err := recreate(u.cfg, results.Updated); err != nil { + u.cfg.Log(err.Error()) + } + } + if u.Wait { - buf := bytes.NewBufferString(upgradedRelease.Manifest) - if err := u.cfg.KubeClient.Wait(buf, u.Timeout); err != nil { + if err := u.cfg.KubeClient.Wait(target, u.Timeout); err != nil { u.cfg.recordRelease(originalRelease) return u.failRelease(upgradedRelease, err) } @@ -280,14 +302,6 @@ func (u *Upgrade) failRelease(rel *release.Release, err error) (*release.Release return rel, err } -// upgradeRelease performs an upgrade from current to target release -func (u *Upgrade) upgradeRelease(current, target *release.Release) error { - cm := bytes.NewBufferString(current.Manifest) - tm := bytes.NewBufferString(target.Manifest) - // TODO add wait - return u.cfg.KubeClient.Update(cm, tm, u.Force, u.Recreate) -} - // reuseValues copies values from the current release to a new release if the // new release does not have any values. // @@ -331,3 +345,39 @@ func validateManifest(c kube.Interface, manifest []byte) error { _, err := c.Build(bytes.NewReader(manifest)) return err } + +// recreate captures all the logic for recreating pods for both upgrade and +// rollback. If we end up refactoring rollback to use upgrade, this can just be +// made an unexported method on the upgrade action. +func recreate(cfg *Configuration, resources kube.ResourceList) error { + for _, res := range resources { + versioned := kube.AsVersioned(res) + selector, err := kube.SelectorsForObject(versioned) + if err != nil { + // If no selector is returned, it means this object is + // definitely not a pod, so continue onward + continue + } + + client, err := cfg.KubernetesClientSet() + if err != nil { + return errors.Wrapf(err, "unable to recreate pods for object %s/%s because an error occurred", res.Namespace, res.Name) + } + + pods, err := client.CoreV1().Pods(res.Namespace).List(metav1.ListOptions{ + LabelSelector: selector.String(), + }) + if err != nil { + return errors.Wrapf(err, "unable to recreate pods for object %s/%s because an error occurred", res.Namespace, res.Name) + } + + // Restart pods + for _, pod := range pods.Items { + // Delete each pod for get them restarted with changed spec. + if err := client.CoreV1().Pods(pod.Namespace).Delete(pod.Name, metav1.NewPreconditionDeleteOptions(string(pod.UID))); err != nil { + return errors.Wrapf(err, "unable to recreate pods for object %s/%s because an error occurred", res.Namespace, res.Name) + } + } + } + return nil +} diff --git a/pkg/kube/client.go b/pkg/kube/client.go index e633a0dc0..6176ad0d0 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -38,8 +38,6 @@ import ( "k8s.io/apimachinery/pkg/watch" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/resource" - "k8s.io/client-go/kubernetes" - "k8s.io/client-go/kubernetes/scheme" watchtools "k8s.io/client-go/tools/watch" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" ) @@ -64,32 +62,20 @@ func New(getter genericclioptions.RESTClientGetter) *Client { } } -// KubernetesClientSet returns a client set from the client factory. -func (c *Client) KubernetesClientSet() (*kubernetes.Clientset, error) { - return c.Factory.KubernetesClientSet() -} - var nopLogger = func(_ string, _ ...interface{}) {} -// Create creates Kubernetes resources from an io.reader. -// -// Namespace will set the namespace. -func (c *Client) Create(reader io.Reader) error { - c.Log("building resources from manifest") - infos, err := c.BuildUnstructured(reader) - if err != nil { - return err +// Create creates Kubernetes resources specified in the resource list. +func (c *Client) Create(resources ResourceList) (*Result, error) { + c.Log("creating %d resource(s)", len(resources)) + if err := perform(resources, createResource); err != nil { + return nil, err } - c.Log("creating %d resource(s)", len(infos)) - return perform(infos, createResource) + return &Result{Created: resources}, nil } -func (c *Client) Wait(reader io.Reader, timeout time.Duration) error { - infos, err := c.BuildUnstructured(reader) - if err != nil { - return err - } - cs, err := c.KubernetesClientSet() +// Wait up to the given timeout for the specified resources to be ready +func (c *Client) Wait(resources ResourceList, timeout time.Duration) error { + cs, err := c.Factory.KubernetesClientSet() if err != nil { return err } @@ -98,7 +84,7 @@ func (c *Client) Wait(reader io.Reader, timeout time.Duration) error { log: c.Log, timeout: timeout, } - return w.waitForResources(infos) + return w.waitForResources(resources) } func (c *Client) namespace() string { @@ -117,16 +103,8 @@ func (c *Client) newBuilder() *resource.Builder { Flatten() } -func (c *Client) validator() resource.ContentValidator { - schema, err := c.Factory.Validator(true) - if err != nil { - c.Log("warning: failed to load schema: %s", err) - } - return schema -} - -// BuildUnstructured validates for Kubernetes objects and returns unstructured infos. -func (c *Client) BuildUnstructured(reader io.Reader) (Result, error) { +// Build validates for Kubernetes objects and returns unstructured infos. +func (c *Client) Build(reader io.Reader) (ResourceList, error) { result, err := c.newBuilder(). Unstructured(). Stream(reader, ""). @@ -134,39 +112,16 @@ func (c *Client) BuildUnstructured(reader io.Reader) (Result, error) { return result, scrubValidationError(err) } -// Build validates for Kubernetes objects and returns resource Infos from a io.Reader. -func (c *Client) Build(reader io.Reader) (Result, error) { - result, err := c.newBuilder(). - WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...). - Schema(c.validator()). - Stream(reader, ""). - Do(). - Infos() - return result, scrubValidationError(err) -} - // Update reads in the current configuration and a target configuration from io.reader // and creates resources that don't already exists, updates resources that have been modified // in the target configuration and deletes resources from the current configuration that are // not present in the target configuration. -// -// Namespace will set the namespaces. -func (c *Client) Update(originalReader, targetReader io.Reader, force, recreate bool) error { - original, err := c.BuildUnstructured(originalReader) - if err != nil { - return errors.Wrap(err, "failed decoding reader into objects") - } - - c.Log("building resources from updated manifest") - target, err := c.BuildUnstructured(targetReader) - if err != nil { - return errors.Wrap(err, "failed decoding reader into objects") - } - +func (c *Client) Update(original, target ResourceList, force bool) (*Result, error) { updateErrors := []string{} + res := &Result{} c.Log("checking %d resources for changes", len(target)) - err = target.Visit(func(info *resource.Info, err error) error { + err := target.Visit(func(info *resource.Info, err error) error { if err != nil { return err } @@ -182,6 +137,9 @@ func (c *Client) Update(originalReader, targetReader io.Reader, force, recreate return errors.Wrap(err, "failed to create resource") } + // Append the created resource to the results + res.Created = append(res.Created, info) + kind := info.Mapping.GroupVersionKind.Kind c.Log("Created a new %s called %q\n", kind, info.Name) return nil @@ -193,43 +151,64 @@ func (c *Client) Update(originalReader, targetReader io.Reader, force, recreate return errors.Errorf("no %s with the name %q found", kind, info.Name) } - if err := updateResource(c, info, originalInfo.Object, force, recreate); err != nil { + if err := updateResource(c, info, originalInfo.Object, force); err != nil { c.Log("error updating the resource %q:\n\t %v", info.Name, err) updateErrors = append(updateErrors, err.Error()) } + // Because we check for errors later, append the info regardless + res.Updated = append(res.Updated, info) return nil }) switch { case err != nil: - return err + return nil, err case len(updateErrors) != 0: - return errors.Errorf(strings.Join(updateErrors, " && ")) + return nil, errors.Errorf(strings.Join(updateErrors, " && ")) } for _, info := range original.Difference(target) { c.Log("Deleting %q in %s...", info.Name, info.Namespace) if err := deleteResource(info); err != nil { c.Log("Failed to delete %q, err: %s", info.Name, err) + } else { + // Only append ones we succeeded in deleting + res.Deleted = append(res.Deleted, info) } } - return nil + return res, nil } -// Delete deletes Kubernetes resources from an io.reader. -// -// Namespace will set the namespace. -func (c *Client) Delete(reader io.Reader) error { - infos, err := c.BuildUnstructured(reader) - if err != nil { - return err - } - return perform(infos, func(info *resource.Info) error { +// Delete deletes Kubernetes resources specified in the resources list. It will +// attempt to delete all resources even if one or more fail and collect any +// errors. All successfully deleted items will be returned in the `Deleted` +// ResourceList that is part of the result. +func (c *Client) Delete(resources ResourceList) (*Result, []error) { + var errs []error + res := &Result{} + err := perform(resources, func(info *resource.Info) error { c.Log("Starting delete for %q %s", info.Name, info.Mapping.GroupVersionKind.Kind) - err := deleteResource(info) - return c.skipIfNotFound(err) + if err := c.skipIfNotFound(deleteResource(info)); err != nil { + // Collect the error and continue on + errs = append(errs, err) + } else { + res.Deleted = append(res.Deleted, info) + } + return nil }) + if err != nil { + // Rewrite the message from "no objects visited" if that is what we got + // back + if err == ErrNoObjectsVisited { + err = errors.New("object not found, skipping delete") + } + errs = append(errs, err) + } + if errs != nil { + return nil, errs + } + return res, nil } func (c *Client) skipIfNotFound(err error) error { @@ -246,7 +225,7 @@ func (c *Client) watchTimeout(t time.Duration) func(*resource.Info) error { } } -// WatchUntilReady watches the resource given in the reader, and waits until it is ready. +// WatchUntilReady watches the resources given and waits until it is ready. // // This function is mainly for hook implementations. It watches for a resource to // hit a particular milestone. The milestone depends on the Kind. @@ -256,21 +235,15 @@ func (c *Client) watchTimeout(t time.Duration) func(*resource.Info) error { // // - Jobs: A job is marked "Ready" when it has successfully completed. This is // ascertained by watching the Status fields in a job's output. -// - Pods: A pod is marked "Ready" when it has successfully completed. This is -// ascertained by watching the status.phase field in a pod's output. // // Handling for other kinds will be added as necessary. -func (c *Client) WatchUntilReady(reader io.Reader, timeout time.Duration) error { - infos, err := c.Build(reader) - if err != nil { - return err - } +func (c *Client) WatchUntilReady(resources ResourceList, timeout time.Duration) error { // For jobs, there's also the option to do poll c.Jobs(namespace).Get(): // https://github.com/adamreese/kubernetes/blob/master/test/e2e/job.go#L291-L300 - return perform(infos, c.watchTimeout(timeout)) + return perform(resources, c.watchTimeout(timeout)) } -func perform(infos Result, fn func(*resource.Info) error) error { +func perform(infos ResourceList, fn func(*resource.Info) error) error { if len(infos) == 0 { return ErrNoObjectsVisited } @@ -317,7 +290,7 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P } // Get a versioned object - versionedObject := asVersioned(target) + versionedObject := AsVersioned(target) // Unstructured objects, such as CRDs, may not have an not registered error // returned from ConvertToVersion. Anything that's unstructured should @@ -332,7 +305,7 @@ func createPatch(target *resource.Info, current runtime.Object) ([]byte, types.P return patch, types.StrategicMergePatchType, err } -func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, force, recreate bool) error { +func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, force bool) error { patch, patchType, err := createPatch(target, currentObj) if err != nil { return errors.Wrap(err, "failed to create patch") @@ -379,37 +352,6 @@ func updateResource(c *Client, target *resource.Info, currentObj runtime.Object, } } - if !recreate { - return nil - } - - versioned := asVersioned(target) - selector, err := selectorsForObject(versioned) - if err != nil { - return nil - } - - client, err := c.KubernetesClientSet() - if err != nil { - return err - } - - pods, err := client.CoreV1().Pods(target.Namespace).List(metav1.ListOptions{ - LabelSelector: selector.String(), - }) - if err != nil { - return err - } - - // Restart pods - for _, pod := range pods.Items { - c.Log("Restarting pod: %v/%v", pod.Namespace, pod.Name) - - // Delete each pod for get them restarted with changed spec. - if err := client.CoreV1().Pods(pod.Namespace).Delete(pod.Name, metav1.NewPreconditionDeleteOptions(string(pod.UID))); err != nil { - return err - } - } return nil } @@ -431,6 +373,9 @@ func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) err ctx, cancel := watchtools.ContextWithOptionalTimeout(context.Background(), timeout) defer cancel() _, err = watchtools.UntilWithoutRetry(ctx, w, func(e watch.Event) (bool, error) { + // Make sure the incoming object is versioned as we use unstructured + // objects when we build manifests + obj := convertWithMapper(e.Object, info.Mapping) switch e.Type { case watch.Added, watch.Modified: // For things like a secret or a config map, this is the best indicator @@ -438,11 +383,8 @@ func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) err // the status go into a good state. For other types, like ReplicaSet // we don't really do anything to support these as hooks. c.Log("Add/Modify event for %s: %v", info.Name, e.Type) - switch kind { - case "Job": - return c.waitForJob(e, info.Name) - case "Pod": - return c.waitForPodSuccess(e, info.Name) + if kind == "Job" { + return c.waitForJob(obj, info.Name) } return true, nil case watch.Deleted: @@ -462,10 +404,10 @@ func (c *Client) watchUntilReady(timeout time.Duration, info *resource.Info) err // waitForJob is a helper that waits for a job to complete. // // This operates on an event returned from a watcher. -func (c *Client) waitForJob(e watch.Event, name string) (bool, error) { - o, ok := e.Object.(*batch.Job) +func (c *Client) waitForJob(obj runtime.Object, name string) (bool, error) { + o, ok := obj.(*batch.Job) if !ok { - return true, errors.Errorf("expected %s to be a *batch.Job, got %T", name, e.Object) + return true, errors.Errorf("expected %s to be a *batch.Job, got %T", name, obj) } for _, c := range o.Status.Conditions { @@ -480,30 +422,6 @@ func (c *Client) waitForJob(e watch.Event, name string) (bool, error) { return false, nil } -// waitForPodSuccess is a helper that waits for a pod to complete. -// -// This operates on an event returned from a watcher. -func (c *Client) waitForPodSuccess(e watch.Event, name string) (bool, error) { - o, ok := e.Object.(*v1.Pod) - if !ok { - return true, errors.Errorf("expected %s to be a *v1.Pod, got %T", name, e.Object) - } - - switch o.Status.Phase { - case v1.PodSucceeded: - fmt.Printf("Pod %s succeeded\n", o.Name) - return true, nil - case v1.PodFailed: - return true, errors.Errorf("pod %s failed", o.Name) - case v1.PodPending: - fmt.Printf("Pod %s pending\n", o.Name) - case v1.PodRunning: - fmt.Printf("Pod %s running\n", o.Name) - } - - return false, nil -} - // scrubValidationError removes kubectl info from the message. func scrubValidationError(err error) error { if err == nil { @@ -516,3 +434,29 @@ func scrubValidationError(err error) error { } return err } + +// WaitAndGetCompletedPodPhase waits up to a timeout until a pod enters a completed phase +// and returns said phase (PodSucceeded or PodFailed qualify). +func (c *Client) WaitAndGetCompletedPodPhase(name string, timeout time.Duration) (v1.PodPhase, error) { + client, _ := c.Factory.KubernetesClientSet() + to := int64(timeout) + watcher, err := client.CoreV1().Pods(c.namespace()).Watch(metav1.ListOptions{ + FieldSelector: fmt.Sprintf("metadata.name=%s", name), + TimeoutSeconds: &to, + }) + + for event := range watcher.ResultChan() { + p, ok := event.Object.(*v1.Pod) + if !ok { + return v1.PodUnknown, fmt.Errorf("%s not a pod", name) + } + switch p.Status.Phase { + case v1.PodFailed: + return v1.PodFailed, nil + case v1.PodSucceeded: + return v1.PodSucceeded, nil + } + } + + return v1.PodUnknown, err +} diff --git a/pkg/kube/client_test.go b/pkg/kube/client_test.go index 01008c819..c9da5cc57 100644 --- a/pkg/kube/client_test.go +++ b/pkg/kube/client_test.go @@ -142,7 +142,16 @@ func TestUpdate(t *testing.T) { } }), } - if err := c.Update(objBody(&listA), objBody(&listB), false, false); err != nil { + first, err := c.Build(objBody(&listA)) + if err != nil { + t.Fatal(err) + } + second, err := c.Build(objBody(&listB)) + if err != nil { + t.Fatal(err) + } + + if _, err := c.Update(first, second, false); err != nil { t.Fatal(err) } // TODO: Find a way to test methods that use Client Set @@ -188,11 +197,6 @@ func TestBuild(t *testing.T) { namespace: "test", reader: strings.NewReader(guestbookManifest), count: 6, - }, { - name: "Invalid schema", - namespace: "test", - reader: strings.NewReader(testInvalidServiceManifest), - err: true, }, { name: "Valid input, deploying resources into different namespaces", namespace: "test", @@ -272,24 +276,41 @@ func TestPerform(t *testing.T) { func TestReal(t *testing.T) { t.Skip("This is a live test, comment this line to run") c := New(nil) - if err := c.Create(strings.NewReader(guestbookManifest)); err != nil { + resources, err := c.Build(strings.NewReader(guestbookManifest)) + if err != nil { + t.Fatal(err) + } + if _, err := c.Create(resources); err != nil { t.Fatal(err) } testSvcEndpointManifest := testServiceManifest + "\n---\n" + testEndpointManifest c = New(nil) - if err := c.Create(strings.NewReader(testSvcEndpointManifest)); err != nil { + resources, err = c.Build(strings.NewReader(testSvcEndpointManifest)) + if err != nil { + t.Fatal(err) + } + if _, err := c.Create(resources); err != nil { t.Fatal(err) } - if err := c.Delete(strings.NewReader(testEndpointManifest)); err != nil { + resources, err = c.Build(strings.NewReader(testEndpointManifest)) + if err != nil { t.Fatal(err) } - // ensures that delete does not fail if a resource is not found - if err := c.Delete(strings.NewReader(testSvcEndpointManifest)); err != nil { + if _, errs := c.Delete(resources); errs != nil { + t.Fatal(errs) + } + + resources, err = c.Build(strings.NewReader(testSvcEndpointManifest)) + if err != nil { t.Fatal(err) } + // ensures that delete does not fail if a resource is not found + if _, errs := c.Delete(resources); errs != nil { + t.Fatal(errs) + } } const testServiceManifest = ` @@ -306,14 +327,6 @@ spec: targetPort: 9376 ` -const testInvalidServiceManifest = ` -kind: Service -apiVersion: v1 -spec: - ports: - - port: "80" -` - const testEndpointManifest = ` kind: Endpoints apiVersion: v1 diff --git a/pkg/kube/converter.go b/pkg/kube/converter.go index eff61a530..d298ad623 100644 --- a/pkg/kube/converter.go +++ b/pkg/kube/converter.go @@ -17,19 +17,28 @@ limitations under the License. package kube // import "helm.sh/helm/pkg/kube" import ( + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/cli-runtime/pkg/resource" "k8s.io/client-go/kubernetes/scheme" ) -func asVersioned(info *resource.Info) runtime.Object { - gv := runtime.GroupVersioner(schema.GroupVersions(scheme.Scheme.PrioritizedVersionsAllGroups())) - if info.Mapping != nil { - gv = info.Mapping.GroupVersionKind.GroupVersion() +// AsVersioned converts the given info into a runtime.Object with the correct +// group and version set +func AsVersioned(info *resource.Info) runtime.Object { + return convertWithMapper(info.Object, info.Mapping) +} + +// convertWithMapper converts the given object with the optional provided +// RESTMapping. If no mapping is provided, the default schema versioner is used +func convertWithMapper(obj runtime.Object, mapping *meta.RESTMapping) runtime.Object { + var gv = runtime.GroupVersioner(schema.GroupVersions(scheme.Scheme.PrioritizedVersionsAllGroups())) + if mapping != nil { + gv = mapping.GroupVersionKind.GroupVersion() } - if obj, err := runtime.ObjectConvertor(scheme.Scheme).ConvertToVersion(info.Object, gv); err == nil { + if obj, err := runtime.ObjectConvertor(scheme.Scheme).ConvertToVersion(obj, gv); err == nil { return obj } - return info.Object + return obj } diff --git a/pkg/kube/fake/fake.go b/pkg/kube/fake/fake.go index 9d3a62069..bd2a9ccdc 100644 --- a/pkg/kube/fake/fake.go +++ b/pkg/kube/fake/fake.go @@ -21,6 +21,7 @@ import ( "io" "time" + v1 "k8s.io/api/core/v1" "k8s.io/cli-runtime/pkg/resource" "helm.sh/helm/pkg/kube" @@ -31,76 +32,68 @@ import ( // delegates all its calls to `PrintingKubeClient` type FailingKubeClient struct { PrintingKubeClient - DeleteError error - WatchUntilReadyError error - UpdateError error - BuildError error - BuildUnstructuredError error - CreateError error - WaitError error - GetError error + CreateError error + WaitError error + DeleteError error + WatchUntilReadyError error + UpdateError error + BuildError error + BuildUnstructuredError error + WaitAndGetCompletedPodPhaseError error } // Create returns the configured error if set or prints -func (f *FailingKubeClient) Create(r io.Reader) error { +func (f *FailingKubeClient) Create(resources kube.ResourceList) (*kube.Result, error) { if f.CreateError != nil { - return f.CreateError + return nil, f.CreateError } - return f.PrintingKubeClient.Create(r) + return f.PrintingKubeClient.Create(resources) } // Wait returns the configured error if set or prints -func (f *FailingKubeClient) Wait(r io.Reader, d time.Duration) error { +func (f *FailingKubeClient) Wait(resources kube.ResourceList, d time.Duration) error { if f.WaitError != nil { return f.WaitError } - return f.PrintingKubeClient.Wait(r, d) -} - -// Create returns the configured error if set or prints -func (f *FailingKubeClient) Get(r io.Reader) (string, error) { - if f.GetError != nil { - return "", f.GetError - } - return f.PrintingKubeClient.Get(r) + return f.PrintingKubeClient.Wait(resources, d) } // Delete returns the configured error if set or prints -func (f *FailingKubeClient) Delete(r io.Reader) error { +func (f *FailingKubeClient) Delete(resources kube.ResourceList) (*kube.Result, []error) { if f.DeleteError != nil { - return f.DeleteError + return nil, []error{f.DeleteError} } - return f.PrintingKubeClient.Delete(r) + return f.PrintingKubeClient.Delete(resources) } // WatchUntilReady returns the configured error if set or prints -func (f *FailingKubeClient) WatchUntilReady(r io.Reader, d time.Duration) error { +func (f *FailingKubeClient) WatchUntilReady(resources kube.ResourceList, d time.Duration) error { if f.WatchUntilReadyError != nil { return f.WatchUntilReadyError } - return f.PrintingKubeClient.WatchUntilReady(r, d) + return f.PrintingKubeClient.WatchUntilReady(resources, d) } // Update returns the configured error if set or prints -func (f *FailingKubeClient) Update(r, modifiedReader io.Reader, not, needed bool) error { +func (f *FailingKubeClient) Update(r, modified kube.ResourceList, ignoreMe bool) (*kube.Result, error) { if f.UpdateError != nil { - return f.UpdateError + return nil, f.UpdateError } - return f.PrintingKubeClient.Update(r, modifiedReader, not, needed) + return f.PrintingKubeClient.Update(r, modified, ignoreMe) } // Build returns the configured error if set or prints -func (f *FailingKubeClient) Build(r io.Reader) (kube.Result, error) { +func (f *FailingKubeClient) Build(r io.Reader) (kube.ResourceList, error) { if f.BuildError != nil { return []*resource.Info{}, f.BuildError } return f.PrintingKubeClient.Build(r) } -// BuildUnstructured returns the configured error if set or prints -func (f *FailingKubeClient) BuildUnstructured(r io.Reader) (kube.Result, error) { - if f.BuildUnstructuredError != nil { - return []*resource.Info{}, f.BuildUnstructuredError +// WaitAndGetCompletedPodPhase returns the configured error if set or prints +func (f *FailingKubeClient) WaitAndGetCompletedPodPhase(s string, d time.Duration) (v1.PodPhase, error) { + if f.WaitAndGetCompletedPodPhaseError != nil { + return v1.PodSucceeded, f.WaitAndGetCompletedPodPhaseError } - return f.PrintingKubeClient.Build(r) + return f.PrintingKubeClient.WaitAndGetCompletedPodPhase(s, d) } diff --git a/pkg/kube/fake/printer.go b/pkg/kube/fake/printer.go index cc21358f5..3d7a81d14 100644 --- a/pkg/kube/fake/printer.go +++ b/pkg/kube/fake/printer.go @@ -18,8 +18,10 @@ package fake import ( "io" + "strings" "time" + v1 "k8s.io/api/core/v1" "k8s.io/cli-runtime/pkg/resource" "helm.sh/helm/pkg/kube" @@ -32,47 +34,62 @@ type PrintingKubeClient struct { } // Create prints the values of what would be created with a real KubeClient. -func (p *PrintingKubeClient) Create(r io.Reader) error { - _, err := io.Copy(p.Out, r) - return err +func (p *PrintingKubeClient) Create(resources kube.ResourceList) (*kube.Result, error) { + _, err := io.Copy(p.Out, bufferize(resources)) + if err != nil { + return nil, err + } + return &kube.Result{Created: resources}, nil } -func (p *PrintingKubeClient) Wait(r io.Reader, _ time.Duration) error { - _, err := io.Copy(p.Out, r) +func (p *PrintingKubeClient) Wait(resources kube.ResourceList, _ time.Duration) error { + _, err := io.Copy(p.Out, bufferize(resources)) return err } -// Get prints the values of what would be created with a real KubeClient. -func (p *PrintingKubeClient) Get(r io.Reader) (string, error) { - _, err := io.Copy(p.Out, r) - return "", err -} - // Delete implements KubeClient delete. // // It only prints out the content to be deleted. -func (p *PrintingKubeClient) Delete(r io.Reader) error { - _, err := io.Copy(p.Out, r) - return err +func (p *PrintingKubeClient) Delete(resources kube.ResourceList) (*kube.Result, []error) { + _, err := io.Copy(p.Out, bufferize(resources)) + if err != nil { + return nil, []error{err} + } + return &kube.Result{Deleted: resources}, nil } // WatchUntilReady implements KubeClient WatchUntilReady. -func (p *PrintingKubeClient) WatchUntilReady(r io.Reader, _ time.Duration) error { - _, err := io.Copy(p.Out, r) +func (p *PrintingKubeClient) WatchUntilReady(resources kube.ResourceList, _ time.Duration) error { + _, err := io.Copy(p.Out, bufferize(resources)) return err } // Update implements KubeClient Update. -func (p *PrintingKubeClient) Update(_, modifiedReader io.Reader, _, _ bool) error { - _, err := io.Copy(p.Out, modifiedReader) - return err +func (p *PrintingKubeClient) Update(_, modified kube.ResourceList, _ bool) (*kube.Result, error) { + _, err := io.Copy(p.Out, bufferize(modified)) + if err != nil { + return nil, err + } + // TODO: This doesn't completely mock out have some that get created, + // updated, and deleted. I don't think these are used in any unit tests, but + // we may want to refactor a way to handle future tests + return &kube.Result{Updated: modified}, nil } // Build implements KubeClient Build. -func (p *PrintingKubeClient) Build(_ io.Reader) (kube.Result, error) { +func (p *PrintingKubeClient) Build(_ io.Reader) (kube.ResourceList, error) { return []*resource.Info{}, nil } -func (p *PrintingKubeClient) BuildUnstructured(_ io.Reader) (kube.Result, error) { - return p.Build(nil) +// WaitAndGetCompletedPodPhase implements KubeClient WaitAndGetCompletedPodPhase. +func (p *PrintingKubeClient) WaitAndGetCompletedPodPhase(_ string, _ time.Duration) (v1.PodPhase, error) { + return v1.PodSucceeded, nil +} + +func bufferize(resources kube.ResourceList) io.Reader { + var builder strings.Builder + for _, info := range resources { + builder.WriteString(info.String() + "\n") + } + return strings.NewReader(builder.String()) } diff --git a/pkg/kube/interface.go b/pkg/kube/interface.go index 53da50b8b..2069d8cdd 100644 --- a/pkg/kube/interface.go +++ b/pkg/kube/interface.go @@ -19,43 +19,42 @@ package kube import ( "io" "time" + + v1 "k8s.io/api/core/v1" ) -// Interface represents a client capable of communicating with the Kubernetes API. +// KubernetesClient represents a client capable of communicating with the Kubernetes API. // // A KubernetesClient must be concurrency safe. type Interface interface { // Create creates one or more resources. - // - // reader must contain a YAML stream (one or more YAML documents separated - // by "\n---\n"). - Create(reader io.Reader) error + Create(resources ResourceList) (*Result, error) - Wait(r io.Reader, timeout time.Duration) error + Wait(resources ResourceList, timeout time.Duration) error // Delete destroys one or more resources. - // - // reader must contain a YAML stream (one or more YAML documents separated - // by "\n---\n"). - Delete(io.Reader) error + Delete(resources ResourceList) (*Result, []error) - // Watch the resource in reader until it is "ready". + // Watch the resource in reader until it is "ready". This method // - // For Jobs, "ready" means the Job ran to completion (exited without error). - // For Pods, "ready" means the Pod phase is marked "succeeded". + // For Jobs, "ready" means the job ran to completion (excited without error). // For all other kinds, it means the kind was created or modified without // error. - WatchUntilReady(reader io.Reader, timeout time.Duration) error + WatchUntilReady(resources ResourceList, timeout time.Duration) error // Update updates one or more resources or creates the resource // if it doesn't exist. + Update(original, target ResourceList, force bool) (*Result, error) + + // Build creates a resource list from a Reader // // reader must contain a YAML stream (one or more YAML documents separated - // by "\n---\n"). - Update(originalReader, modifiedReader io.Reader, force bool, recreate bool) error + // by "\n---\n") + Build(reader io.Reader) (ResourceList, error) - Build(reader io.Reader) (Result, error) - BuildUnstructured(reader io.Reader) (Result, error) + // WaitAndGetCompletedPodPhase waits up to a timeout until a pod enters a completed phase + // and returns said phase (PodSucceeded or PodFailed qualify). + WaitAndGetCompletedPodPhase(name string, timeout time.Duration) (v1.PodPhase, error) } var _ Interface = (*Client)(nil) diff --git a/pkg/kube/resource.go b/pkg/kube/resource.go new file mode 100644 index 000000000..b61c6d198 --- /dev/null +++ b/pkg/kube/resource.go @@ -0,0 +1,85 @@ +/* +Copyright The Helm Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kube // import "helm.sh/helm/pkg/kube" + +import "k8s.io/cli-runtime/pkg/resource" + +// ResourceList provides convenience methods for comparing collections of Infos. +type ResourceList []*resource.Info + +// Append adds an Info to the Result. +func (r *ResourceList) Append(val *resource.Info) { + *r = append(*r, val) +} + +// Visit implements resource.Visitor. +func (r ResourceList) Visit(fn resource.VisitorFunc) error { + for _, i := range r { + if err := fn(i, nil); err != nil { + return err + } + } + return nil +} + +// Filter returns a new Result with Infos that satisfy the predicate fn. +func (r ResourceList) Filter(fn func(*resource.Info) bool) ResourceList { + var result ResourceList + for _, i := range r { + if fn(i) { + result.Append(i) + } + } + return result +} + +// Get returns the Info from the result that matches the name and kind. +func (r ResourceList) Get(info *resource.Info) *resource.Info { + for _, i := range r { + if isMatchingInfo(i, info) { + return i + } + } + return nil +} + +// Contains checks to see if an object exists. +func (r ResourceList) Contains(info *resource.Info) bool { + for _, i := range r { + if isMatchingInfo(i, info) { + return true + } + } + return false +} + +// Difference will return a new Result with objects not contained in rs. +func (r ResourceList) Difference(rs ResourceList) ResourceList { + return r.Filter(func(info *resource.Info) bool { + return !rs.Contains(info) + }) +} + +// Intersect will return a new Result with objects contained in both Results. +func (r ResourceList) Intersect(rs ResourceList) ResourceList { + return r.Filter(rs.Contains) +} + +// isMatchingInfo returns true if infos match on Name and GroupVersionKind. +func isMatchingInfo(a, b *resource.Info) bool { + return a.Name == b.Name && a.Mapping.GroupVersionKind.Kind == b.Mapping.GroupVersionKind.Kind +} diff --git a/pkg/kube/result_test.go b/pkg/kube/resource_test.go similarity index 95% rename from pkg/kube/result_test.go rename to pkg/kube/resource_test.go index 87d47597c..8bf8b0bf5 100644 --- a/pkg/kube/result_test.go +++ b/pkg/kube/resource_test.go @@ -24,7 +24,7 @@ import ( "k8s.io/cli-runtime/pkg/resource" ) -func TestResult(t *testing.T) { +func TestResourceList(t *testing.T) { mapping := &meta.RESTMapping{ Resource: schema.GroupVersionResource{Group: "group", Version: "version", Resource: "pod"}, } @@ -33,7 +33,7 @@ func TestResult(t *testing.T) { return &resource.Info{Name: name, Mapping: mapping} } - var r1, r2 Result + var r1, r2 ResourceList r1 = []*resource.Info{info("foo"), info("bar")} r2 = []*resource.Info{info("bar")} diff --git a/pkg/kube/result.go b/pkg/kube/result.go index a527727ca..c3e171c2e 100644 --- a/pkg/kube/result.go +++ b/pkg/kube/result.go @@ -14,72 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ -package kube // import "helm.sh/helm/pkg/kube" +package kube -import "k8s.io/cli-runtime/pkg/resource" - -// Result provides convenience methods for comparing collections of Infos. -type Result []*resource.Info - -// Append adds an Info to the Result. -func (r *Result) Append(val *resource.Info) { - *r = append(*r, val) -} - -// Visit implements resource.Visitor. -func (r Result) Visit(fn resource.VisitorFunc) error { - for _, i := range r { - if err := fn(i, nil); err != nil { - return err - } - } - return nil -} - -// Filter returns a new Result with Infos that satisfy the predicate fn. -func (r Result) Filter(fn func(*resource.Info) bool) Result { - var result Result - for _, i := range r { - if fn(i) { - result.Append(i) - } - } - return result -} - -// Get returns the Info from the result that matches the name and kind. -func (r Result) Get(info *resource.Info) *resource.Info { - for _, i := range r { - if isMatchingInfo(i, info) { - return i - } - } - return nil +// Result contains the information of created, updated, and deleted resources +// for various kube API calls along with helper methods for using those +// resources +type Result struct { + Created ResourceList + Updated ResourceList + Deleted ResourceList } -// Contains checks to see if an object exists. -func (r Result) Contains(info *resource.Info) bool { - for _, i := range r { - if isMatchingInfo(i, info) { - return true - } - } - return false -} - -// Difference will return a new Result with objects not contained in rs. -func (r Result) Difference(rs Result) Result { - return r.Filter(func(info *resource.Info) bool { - return !rs.Contains(info) - }) -} - -// Intersect will return a new Result with objects contained in both Results. -func (r Result) Intersect(rs Result) Result { - return r.Filter(rs.Contains) -} - -// isMatchingInfo returns true if infos match on Name and GroupVersionKind. -func isMatchingInfo(a, b *resource.Info) bool { - return a.Name == b.Name && a.Mapping.GroupVersionKind.Kind == b.Mapping.GroupVersionKind.Kind -} +// If needed, we can add methods to the Result type for things like diffing diff --git a/pkg/kube/wait.go b/pkg/kube/wait.go index d00d976bd..bf502baea 100644 --- a/pkg/kube/wait.go +++ b/pkg/kube/wait.go @@ -44,7 +44,7 @@ type waiter struct { // waitForResources polls to get the current status of all pods, PVCs, and Services // until all are ready or a timeout is reached -func (w *waiter) waitForResources(created Result) error { +func (w *waiter) waitForResources(created ResourceList) error { w.log("beginning wait for %d resources with timeout of %v", len(created), w.timeout) return wait.Poll(2*time.Second, w.timeout, func() (bool, error) { @@ -56,7 +56,7 @@ func (w *waiter) waitForResources(created Result) error { ok = true err error ) - switch value := asVersioned(v).(type) { + switch value := AsVersioned(v).(type) { case *corev1.Pod: pod, err := w.c.CoreV1().Pods(value.Namespace).Get(value.Name, metav1.GetOptions{}) if err != nil || !w.isPodReady(pod) { @@ -178,7 +178,7 @@ func (w *waiter) podsReadyForObject(namespace string, obj runtime.Object) (bool, } func (w *waiter) podsforObject(namespace string, obj runtime.Object) ([]corev1.Pod, error) { - selector, err := selectorsForObject(obj) + selector, err := SelectorsForObject(obj) if err != nil { return nil, err } @@ -300,10 +300,10 @@ func getPods(client kubernetes.Interface, namespace, selector string) ([]corev1. return list.Items, err } -// selectorsForObject returns the pod label selector for a given object +// SelectorsForObject returns the pod label selector for a given object // // Modified version of https://github.com/kubernetes/kubernetes/blob/v1.14.1/pkg/kubectl/polymorphichelpers/helpers.go#L84 -func selectorsForObject(object runtime.Object) (selector labels.Selector, err error) { +func SelectorsForObject(object runtime.Object) (selector labels.Selector, err error) { switch t := object.(type) { case *extensionsv1beta1.ReplicaSet: selector, err = metav1.LabelSelectorAsSelector(t.Spec.Selector)