mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-18 02:55:22 +00:00
Merge pull request #1818 from mortent/WaitStatus
Add APIs for computing status based on fetching resource info from a cluster
This commit is contained in:
@@ -4,13 +4,22 @@ go 1.12
|
||||
|
||||
require (
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/kr/pretty v0.1.0 // indirect
|
||||
github.com/onsi/ginkgo v1.10.1 // indirect
|
||||
github.com/onsi/gomega v1.7.0 // indirect
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
go.uber.org/atomic v1.4.0 // indirect
|
||||
go.uber.org/zap v1.10.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 // indirect
|
||||
golang.org/x/net v0.0.0-20190909003024-a7b16738d86b // indirect
|
||||
golang.org/x/sys v0.0.0-20190911201528-7ad0cfa0b7b5 // indirect
|
||||
golang.org/x/text v0.3.2 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
|
||||
k8s.io/api v0.0.0-20190918195907-bd6ac527cfd2
|
||||
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d
|
||||
k8s.io/client-go v0.0.0-20190918200256-06eb1244587a
|
||||
sigs.k8s.io/controller-runtime v0.3.0
|
||||
sigs.k8s.io/kustomize/pseudo/k8s v0.1.0
|
||||
sigs.k8s.io/yaml v1.1.0
|
||||
)
|
||||
|
||||
224
kstatus/go.sum
224
kstatus/go.sum
@@ -1,4 +1,6 @@
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
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=
|
||||
@@ -10,57 +12,147 @@ github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxB
|
||||
github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
|
||||
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
|
||||
github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
|
||||
github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/purell v1.1.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
||||
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/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
|
||||
github.com/coreos/bbolt v1.3.1-coreos.6/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-oidc v0.0.0-20180117170138-065b426bd416/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
|
||||
github.com/coreos/go-semver v0.0.0-20180108230905-e214231b295a/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
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/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
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/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/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/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680 h1:ZktWZesgun21uEDrwW7iEV1zPCGQldM2atlJZ3TdvVM=
|
||||
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg=
|
||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
||||
github.com/go-logr/zapr v0.1.0 h1:h+WVe9j6HAA01niTJPA/kKH0i7e0rLZBCwauQFcRE54=
|
||||
github.com/go-logr/zapr v0.1.0/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk=
|
||||
github.com/go-openapi/analysis v0.0.0-20180825180245-b006789cd277/go.mod h1:k70tL6pCuVxPJOHXQ+wIac1FUrvNkHolPie/cLEU6hI=
|
||||
github.com/go-openapi/analysis v0.17.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||
github.com/go-openapi/analysis v0.17.2/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpRoBWb8PVZO0ik=
|
||||
github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonpointer v0.19.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
|
||||
github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
|
||||
github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
|
||||
github.com/go-openapi/loads v0.17.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/loads v0.17.2/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf7AC+0+OOU=
|
||||
github.com/go-openapi/runtime v0.0.0-20180920151709-4f900dc2ade9/go.mod h1:6v9a6LTXWQCdL8k1AO3cvqx5OtZY/Y9wKTgaoP6YRfA=
|
||||
github.com/go-openapi/runtime v0.17.2/go.mod h1:QO936ZXeisByFmZEO1IS1Dqhtf4QV1sYYFtIq6Ld86Q=
|
||||
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
|
||||
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
|
||||
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
|
||||
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
|
||||
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/swag v0.17.2/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
|
||||
github.com/go-openapi/validate v0.17.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-openapi/validate v0.18.0/go.mod h1:Uh4HdOzKt19xGIGm1qHf/ofbX1YQ4Y+MYsct2VUrAJ4=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
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-20180513044358-24b0969c4cb7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
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=
|
||||
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/btree v0.0.0-20160524151835-7d79101e329e/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
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 v0.0.0-20170612174753-24818f796faf/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/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
|
||||
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
|
||||
github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
|
||||
github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20170330212424-2500245aa611/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/imdario/mergo v0.3.6 h1:xTNEAn+kxVO7dTZGu0CegyqKZmoWFI0rF8UxjlB2d28=
|
||||
github.com/imdario/mergo v0.3.6/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jonboulle/clockwork v0.0.0-20141017032234-72f9bd7c4e0c/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.6/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/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
@@ -69,69 +161,201 @@ 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/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=
|
||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||
github.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=
|
||||
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
|
||||
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=
|
||||
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
|
||||
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff h1:VARhShG49tiji6mdRNp7JTNDtJ0FhuprF93GBQ37xGU=
|
||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/xiang90/probing v0.0.0-20160813154853-07dd2e8dfe18/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
go.uber.org/atomic v0.0.0-20181018215023-8dc6146f7569/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.3.2 h1:2Oa65PReHzfn29GpvgsYwloV9AVFHPDk8tYxt2c2tr4=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0 h1:cxzIVoETapQEqDhQu3QfnvXAV4AlzcvUCxkVUFw3+EU=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v0.0.0-20180122172545-ddea229ff1df/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.1.0 h1:HoEmRHQPVSqub6w2z2d2EOVs2fjyFRGyofhKuyDq0QI=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v0.0.0-20180814183419-67bc79d13d15/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.9.1 h1:XCJQEf3W6eZaVwhRBof6ImoYGJSITeKWsyeh3HFu/5o=
|
||||
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.10.0 h1:ORx85nbTijNz8ljznvCMR1ZBIPKFn3jQrag10X2AsuM=
|
||||
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-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7 h1:0hQKqeLdqlt5iIwVOBErRisrHJAN57yOiPRQItI20fU=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/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-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-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190812203447-cdfb69ac37fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
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/oauth2 v0.0.0-20190402181905-9f3314589c9a/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
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/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/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-20190312061237-fead79001313 h1:pczuHS43Cp2ktBEEmLwScxgjWsBSzdaQiKzUyf3DTTc=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/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/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
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-20161028155119-f51c12702a4d/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
|
||||
gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
|
||||
gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
|
||||
gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0 h1:KxkO13IPW4Lslp2bz+KHP2E3gtFlrIGNThxkZQ3g+4c=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20170731182057-09f6ed296fc6/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0-20150622162204-20b71e5b60d7/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
||||
gopkg.in/square/go-jose.v2 v2.0.0-20180411045311-89060dee6a84/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
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.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
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=
|
||||
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
|
||||
k8s.io/api v0.0.0-20190918195907-bd6ac527cfd2 h1:bkwe5LsuANqyOwsBng5Qc4S91D2Tv0JHctAztt3YTQs=
|
||||
k8s.io/api v0.0.0-20190918195907-bd6ac527cfd2/go.mod h1:AOxZTnaXR/xiarlQL0JUfwQPxjmKDvVYoRp58cA7lUo=
|
||||
k8s.io/apiextensions-apiserver v0.0.0-20190918201827-3de75813f604 h1:Kl/sh+wWzYK2hWFZtwvuFECup1SbE2kXfMnhGZsoO5M=
|
||||
k8s.io/apiextensions-apiserver v0.0.0-20190918201827-3de75813f604/go.mod h1:7H8sjDlWQu89yWB3FhZfsLyRCRLuoXoCoY5qtwW1q6I=
|
||||
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d h1:7Kns6qqhMAQWvGkxYOLSLRZ5hJO0/5pcE5lPGP2fxUw=
|
||||
k8s.io/apimachinery v0.0.0-20190817020851-f2f3a405f61d/go.mod h1:3jediapYqJ2w1BFw7lAZPCx7scubsTfosqHkhXCWJKw=
|
||||
k8s.io/apiserver v0.0.0-20190918200908-1e17798da8c1/go.mod h1:4FuDU+iKPjdsdQSN3GsEKZLB/feQsj1y9dhhBDVV2Ns=
|
||||
k8s.io/client-go v0.0.0-20190918200256-06eb1244587a h1:huOvPq1vO7dkuw9rZPYsLGpFmyGvy6L8q6mDItgkdQ4=
|
||||
k8s.io/client-go v0.0.0-20190918200256-06eb1244587a/go.mod h1:3YAcTbI2ArBRmhHns5vlHRX8YQqvkVYpz+U/N5i1mVU=
|
||||
k8s.io/code-generator v0.0.0-20190612205613-18da4a14b22b/go.mod h1:G8bQwmHm2eafm5bgtX67XDZQ8CWKSGu9DekI+yN4Y5I=
|
||||
k8s.io/component-base v0.0.0-20190918200425-ed2f0867c778/go.mod h1:DFWQCXgXVLiWtzFaS17KxHdlUeUymP7FLxZSkmL9/jU=
|
||||
k8s.io/gengo v0.0.0-20190116091435-f8a0810f38af/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||
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=
|
||||
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.3.3/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
|
||||
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
|
||||
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-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
|
||||
k8s.io/utils v0.0.0-20190506122338-8fab8cb257d5/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
k8s.io/utils v0.0.0-20191030222137-2b95a09bc58d h1:1P0iBJsBzxRmR+dIFnM+Iu4aLxnoa7lBqozW/0uHbT8=
|
||||
k8s.io/utils v0.0.0-20191030222137-2b95a09bc58d/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
|
||||
modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
|
||||
modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
|
||||
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
|
||||
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
|
||||
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
|
||||
sigs.k8s.io/controller-runtime v0.3.0 h1:ZtdgqJXVHsIytjdmDuk0QjagnzyLq9FjojXRqIp+dU4=
|
||||
sigs.k8s.io/controller-runtime v0.3.0/go.mod h1:Cw6PkEg0Sa7dAYovGT4R0tRkGhHXpYijwNxYhAnAZZk=
|
||||
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-20190302045857-e85c7b244fd2/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
|
||||
sigs.k8s.io/testing_frameworks v0.1.1 h1:cP2l8fkA3O9vekpy5Ks8mmA0NW/F7yBdXf8brkWhVrs=
|
||||
sigs.k8s.io/testing_frameworks v0.1.1/go.mod h1:VVBKrHmJ6Ekkfz284YKhQePcdycOzNH9qL6ht1zEr/U=
|
||||
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
|
||||
@@ -6,8 +6,8 @@ package status
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
corev1 "sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1"
|
||||
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
// GetConditionsFn defines the signature for functions to compute the
|
||||
@@ -36,6 +36,8 @@ const (
|
||||
tooFewAvailable = "LessAvailable"
|
||||
tooFewUpdated = "LessUpdated"
|
||||
tooFewReplicas = "LessReplicas"
|
||||
|
||||
onDeleteUpdateStrategy = "OnDelete"
|
||||
)
|
||||
|
||||
// GetLegacyConditionsFn returns a function that can compute the status for the
|
||||
@@ -71,7 +73,7 @@ func stsConditions(u *unstructured.Unstructured) (*Result, error) {
|
||||
|
||||
// updateStrategy==ondelete is a user managed statefulset.
|
||||
updateStrategy := GetStringField(obj, ".spec.updateStrategy.type", "")
|
||||
if updateStrategy == "ondelete" {
|
||||
if updateStrategy == onDeleteUpdateStrategy {
|
||||
return &Result{
|
||||
Status: CurrentStatus,
|
||||
Message: "StatefulSet is using the ondelete update strategy",
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// Computing the status of a resources can be done by calling the
|
||||
// Compute function in the status package.
|
||||
// import (
|
||||
// "sigs.k8s.io/kustomize/kstatus/status
|
||||
// "sigs.k8s.io/kustomize/kstatus/status"
|
||||
// )
|
||||
// res, err := status.Compute(resource)
|
||||
//
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
. "sigs.k8s.io/kustomize/kstatus/status"
|
||||
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/yaml"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
corev1 "sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1"
|
||||
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
// checkGenericProperties looks at the properties that are available on
|
||||
|
||||
@@ -7,8 +7,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
corev1 "sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1"
|
||||
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -23,6 +23,7 @@ const (
|
||||
FailedStatus Status = "Failed"
|
||||
CurrentStatus Status = "Current"
|
||||
TerminatingStatus Status = "Terminating"
|
||||
UnknownStatus Status = "Unknown"
|
||||
)
|
||||
|
||||
// ConditionType defines the set of condition types allowed inside a Condition struct.
|
||||
@@ -81,8 +82,15 @@ type Condition struct {
|
||||
// a list of standard resources that would belong on the given resource.
|
||||
func Compute(u *unstructured.Unstructured) (*Result, error) {
|
||||
res, err := checkGenericProperties(u)
|
||||
if err != nil || res != nil {
|
||||
return res, err
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If res is not nil, it means the generic checks was able to determine
|
||||
// the status of the resource. We don't need to check the type-specific
|
||||
// rules.
|
||||
if res != nil {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
fn := GetLegacyConditionsFn(u)
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
corev1 "sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1"
|
||||
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
var pod = `
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
corev1 "sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1"
|
||||
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func y2u(t *testing.T, spec string) *unstructured.Unstructured {
|
||||
|
||||
@@ -6,9 +6,9 @@ package status
|
||||
import (
|
||||
"strings"
|
||||
|
||||
apiunstructured "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
corev1 "sigs.k8s.io/kustomize/pseudo/k8s/api/core/v1"
|
||||
apiunstructured "sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/kustomize/pseudo/k8s/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// newInProgressCondition creates an inProgress condition with the given
|
||||
|
||||
57
kstatus/wait/doc.go
Normal file
57
kstatus/wait/doc.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package wait contains functionality for getting the statuses
|
||||
// of a list of kubernetes resources. Unlike the status package,
|
||||
// the functions exposed in the wait package will talk to a
|
||||
// live kubernetes cluster to get the latest state of resources
|
||||
// and provides functionality for polling the cluster until the
|
||||
// resources reach the Current status.
|
||||
//
|
||||
// FetchAndResolve will fetch resources from a cluster, compute the
|
||||
// status for each of them and then return the results. The list of
|
||||
// resources is defined as a slice of ResourceIdentifier, which is
|
||||
// an interface that is implemented by the Unstructured type. It
|
||||
// only requires functions for getting the apiVersion, kind, name
|
||||
// and namespace of a resource.
|
||||
//
|
||||
// import (
|
||||
// "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
// "k8s.io/apimachinery/pkg/types"
|
||||
// "sigs.k8s.io/kustomize/kstatus/wait"
|
||||
// )
|
||||
//
|
||||
// key := types.NamespacedName{Name: "name", Namespace: "namespace"}
|
||||
// deployment := &unstructured.Unstructured{
|
||||
// Object: map[string]interface{}{
|
||||
// "apiVersion": "apps/v1",
|
||||
// "kind": "Deployment",
|
||||
// },
|
||||
// }
|
||||
// client.Get(context.Background(), key, deployment)
|
||||
// resourceIdentifiers := []wait.ResourceIdentifier{deployment}
|
||||
//
|
||||
// resolver := wait.NewResolver(client)
|
||||
// results := resolver.FetchAndResolve(context.Background(), resourceIdentifiers)
|
||||
//
|
||||
// WaitForStatus also looks up status for a list of resources, but it will
|
||||
// block until all the provided resources has reached the Current status or
|
||||
// the wait is cancelled through the passed-in context. The function returns
|
||||
// a channel that will provide updates as the status of the different
|
||||
// resources change.
|
||||
//
|
||||
// import (
|
||||
// "sigs.k8s.io/kustomize/kstatus/wait"
|
||||
// )
|
||||
// resolver := wait.NewResolver(client)
|
||||
// eventsChan := resolver.WaitForStatus(context.Background(), resourceIdentifiers, 2 * time.Second)
|
||||
// for {
|
||||
// select {
|
||||
// case event, ok := <-eventsChan:
|
||||
// if !ok {
|
||||
// return
|
||||
// }
|
||||
// fmt.Printf(event) // do something useful here.
|
||||
// }
|
||||
// }
|
||||
package wait
|
||||
28
kstatus/wait/util.go
Normal file
28
kstatus/wait/util.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package wait
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
)
|
||||
|
||||
// keyFromResourceIdentifier creates a resourceKey from a ResourceIdentifier.
|
||||
func keyFromResourceIdentifier(i ResourceIdentifier) resourceKey {
|
||||
return resourceKey{
|
||||
apiVersion: i.GetAPIVersion(),
|
||||
kind: i.GetKind(),
|
||||
name: i.GetName(),
|
||||
namespace: i.GetNamespace(),
|
||||
}
|
||||
}
|
||||
|
||||
// keyFromObject creates a resourceKey from an Object.
|
||||
func keyFromObject(obj runtime.Object) resourceKey {
|
||||
gvk := obj.GetObjectKind().GroupVersionKind()
|
||||
r := obj.(metav1.Object)
|
||||
return resourceKey{
|
||||
apiVersion: gvk.GroupVersion().String(),
|
||||
kind: gvk.Kind,
|
||||
name: r.GetName(),
|
||||
namespace: r.GetNamespace(),
|
||||
}
|
||||
}
|
||||
258
kstatus/wait/wait.go
Normal file
258
kstatus/wait/wait.go
Normal file
@@ -0,0 +1,258 @@
|
||||
// Copyright 2019 The Kubernetes Authors.
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package wait
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/kustomize/kstatus/status"
|
||||
)
|
||||
|
||||
// ResourceIdentifier defines the functions needed to identify
|
||||
// a resource in a cluster. This interface is implemented by
|
||||
// both unstructured.Unstructured and the standard Kubernetes types.
|
||||
type ResourceIdentifier interface {
|
||||
GetName() string
|
||||
GetNamespace() string
|
||||
GetAPIVersion() string
|
||||
GetKind() string
|
||||
}
|
||||
|
||||
// Resolver provides the functions for resolving status of a list of resources.
|
||||
type Resolver struct {
|
||||
// DynamicClient is the client used to talk
|
||||
// with the cluster
|
||||
client client.Reader
|
||||
|
||||
// statusComputeFunc defines which function should be used for computing
|
||||
// the status of a resource. This is available for testing purposes.
|
||||
statusComputeFunc func(u *unstructured.Unstructured) (*status.Result, error)
|
||||
|
||||
// pollInterval defines the frequency with which the resolver should poll
|
||||
// the cluster for the state of resources. More frequent polling will
|
||||
// lead to more load on the cluster.
|
||||
pollInterval time.Duration
|
||||
}
|
||||
|
||||
// NewResolver creates a new resolver with the provided client. Fetching
|
||||
// and polling of resources will be done using the provided client.
|
||||
func NewResolver(client client.Reader, pollInterval time.Duration) *Resolver {
|
||||
return &Resolver{
|
||||
client: client,
|
||||
statusComputeFunc: status.Compute,
|
||||
pollInterval: pollInterval,
|
||||
}
|
||||
}
|
||||
|
||||
// ResourceResult is the status result for a given resource. It provides
|
||||
// information about the resource if the request was successful and an
|
||||
// error if something went wrong.
|
||||
type ResourceResult struct {
|
||||
Result *status.Result
|
||||
|
||||
Resource ResourceIdentifier
|
||||
|
||||
Error error
|
||||
}
|
||||
|
||||
// FetchAndResolve returns the status for a list of resources. It will return
|
||||
// the status for each of them individually. The slice of ResourceIdentifiers will
|
||||
// only be used to get the information needed to fetch the updated state of
|
||||
// the resources from the cluster.
|
||||
func (r *Resolver) FetchAndResolve(ctx context.Context, resources []ResourceIdentifier) []ResourceResult {
|
||||
var results []ResourceResult
|
||||
|
||||
for _, resource := range resources {
|
||||
u, err := r.fetchResource(ctx, resource)
|
||||
if err != nil {
|
||||
if k8serrors.IsNotFound(errors.Cause(err)) {
|
||||
results = append(results, ResourceResult{
|
||||
Resource: resource,
|
||||
Result: &status.Result{
|
||||
Status: status.CurrentStatus,
|
||||
Message: "Resource does not exist",
|
||||
},
|
||||
})
|
||||
} else {
|
||||
results = append(results, ResourceResult{
|
||||
Result: &status.Result{
|
||||
Status: status.UnknownStatus,
|
||||
Message: fmt.Sprintf("Error fetching resource from cluster: %v", err),
|
||||
},
|
||||
Resource: resource,
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
continue
|
||||
}
|
||||
res, err := r.statusComputeFunc(u)
|
||||
results = append(results, ResourceResult{
|
||||
Result: res,
|
||||
Resource: resource,
|
||||
Error: err,
|
||||
})
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
// Event is returned through the channel returned after a call
|
||||
// to WaitForStatus. It contains an update to either an individual
|
||||
// resource or to the aggregate status for the set of resources.
|
||||
type Event struct {
|
||||
// Type defines which type of event this is.
|
||||
Type EventType
|
||||
|
||||
// AggregateStatus is the aggregated status for all the provided resources.
|
||||
AggregateStatus status.Status
|
||||
|
||||
// EventResource is information about the event to which this event pertains.
|
||||
// This is only populated for ResourceUpdate events.
|
||||
EventResource *EventResource
|
||||
}
|
||||
|
||||
type EventType string
|
||||
|
||||
const (
|
||||
// The status/message for a resource has changed. This also means the
|
||||
// aggregate status might have changed.
|
||||
ResourceUpdate EventType = "ResourceUpdate"
|
||||
|
||||
// All resources have reached the current status.
|
||||
Completed EventType = "Completed"
|
||||
|
||||
// The wait was stopped before all resources could reach the
|
||||
// Current status.
|
||||
Aborted EventType = "Aborted"
|
||||
)
|
||||
|
||||
// EventResource contains information about the resource for which
|
||||
// a specific Event pertains.
|
||||
type EventResource struct {
|
||||
// Identifier contains information that identifies which resource
|
||||
// this information is about.
|
||||
Identifier ResourceIdentifier
|
||||
|
||||
// Status is the latest status for the given resource.
|
||||
Status status.Status
|
||||
|
||||
// Message is more details about the status.
|
||||
Message string
|
||||
|
||||
// Error is set if there was a problem identifying the status
|
||||
// of the resource. For example, if polling the cluster for information
|
||||
// about the resource failed.
|
||||
Error error
|
||||
}
|
||||
|
||||
// WaitForStatus polls all the provided resources until all of them has
|
||||
// reached the Current status. Updates the channel as resources change their status and
|
||||
// when the wait is either completed or aborted.
|
||||
func (r *Resolver) WaitForStatus(ctx context.Context, resources []ResourceIdentifier) <-chan Event {
|
||||
eventChan := make(chan Event)
|
||||
|
||||
go func() {
|
||||
ticker := time.NewTicker(r.pollInterval)
|
||||
|
||||
defer func() {
|
||||
ticker.Stop()
|
||||
// Make sure the channel is closed so consumers can detect that
|
||||
// we have completed.
|
||||
close(eventChan)
|
||||
}()
|
||||
|
||||
// No need to wait if we have no resources. We consider
|
||||
// this a situation where the status is Current.
|
||||
if len(resources) == 0 {
|
||||
eventChan <- Event{
|
||||
Type: Completed,
|
||||
AggregateStatus: status.CurrentStatus,
|
||||
EventResource: nil,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Initiate a new waitStatus object to keep track of the
|
||||
// resources while polling the state.
|
||||
waitState := newWaitState(resources, r.statusComputeFunc)
|
||||
|
||||
// Loop until either all resources have reached the Current status
|
||||
// or until the wait is cancelled through the context. In both cases
|
||||
// we will break out of the loop by returning from the function.
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
// The context has been cancelled, so report the most recent
|
||||
// aggregate status, report it through the channel and then
|
||||
// break out of the loop (which will close the channel).
|
||||
eventChan <- Event{
|
||||
Type: Aborted,
|
||||
AggregateStatus: waitState.AggregateStatus(),
|
||||
}
|
||||
return
|
||||
case <-ticker.C:
|
||||
// Every time the ticker fires, fetch all resources from the cluster,
|
||||
// check if their status has changed and send an event for each resource
|
||||
// with a new status. In each event, we also include the latest aggregate
|
||||
// status. Finally, if the aggregate status becomes Current, send a final
|
||||
// Completed type event and then return.
|
||||
for id := range waitState.ResourceWaitStates {
|
||||
// Make sure we have a local copy since we are passing
|
||||
// pointers to this variable as parameters to functions
|
||||
identifier := id
|
||||
u, err := r.fetchResource(ctx, &identifier)
|
||||
eventResource, updateObserved := waitState.ResourceObserved(&identifier, u, err)
|
||||
// Find the aggregate status based on the new state for this resource.
|
||||
aggStatus := waitState.AggregateStatus()
|
||||
// We want events for changes in status for each resource, so send
|
||||
// an event for this resource before checking if the aggregate status
|
||||
// has become Current.
|
||||
if updateObserved {
|
||||
eventChan <- Event{
|
||||
Type: ResourceUpdate,
|
||||
AggregateStatus: aggStatus,
|
||||
EventResource: &eventResource,
|
||||
}
|
||||
}
|
||||
// If aggregate status is Current, we are done!
|
||||
if aggStatus == status.CurrentStatus {
|
||||
eventChan <- Event{
|
||||
Type: Completed,
|
||||
AggregateStatus: status.CurrentStatus,
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
return eventChan
|
||||
}
|
||||
|
||||
// fetchResource gets the resource given by the identifier from the cluster
|
||||
// through the client available in the Resolver. It returns the resource
|
||||
// as an Unstructured.
|
||||
func (r *Resolver) fetchResource(ctx context.Context, identifier ResourceIdentifier) (*unstructured.Unstructured, error) {
|
||||
key := types.NamespacedName{Name: identifier.GetName(), Namespace: identifier.GetNamespace()}
|
||||
u := &unstructured.Unstructured{
|
||||
Object: map[string]interface{}{
|
||||
"apiVersion": identifier.GetAPIVersion(),
|
||||
"kind": identifier.GetKind(),
|
||||
},
|
||||
}
|
||||
err := r.client.Get(ctx, key, u)
|
||||
//return u, err
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "error fetching resource from cluster")
|
||||
}
|
||||
return u, nil
|
||||
}
|
||||
561
kstatus/wait/wait_test.go
Normal file
561
kstatus/wait/wait_test.go
Normal file
@@ -0,0 +1,561 @@
|
||||
package wait
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes/scheme"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
"sigs.k8s.io/kustomize/kstatus/status"
|
||||
)
|
||||
|
||||
const (
|
||||
testTimeout = 1 * time.Minute
|
||||
testPollInterval = 1 * time.Second
|
||||
)
|
||||
|
||||
func TestFetchAndResolve(t *testing.T) {
|
||||
type result struct {
|
||||
status status.Status
|
||||
error bool
|
||||
}
|
||||
|
||||
testCases := map[string]struct {
|
||||
resources []runtime.Object
|
||||
expectedResults []result
|
||||
}{
|
||||
"no resources": {
|
||||
resources: []runtime.Object{},
|
||||
expectedResults: []result{},
|
||||
},
|
||||
"single resource": {
|
||||
resources: []runtime.Object{
|
||||
&appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Generation: 1,
|
||||
Name: "myDeployment",
|
||||
Namespace: "default",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResults: []result{
|
||||
{
|
||||
status: status.InProgressStatus,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
"multiple resources": {
|
||||
resources: []runtime.Object{
|
||||
&appsv1.StatefulSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "StatefulSet",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Generation: 1,
|
||||
Name: "myStatefulSet",
|
||||
Namespace: "default",
|
||||
},
|
||||
Spec: appsv1.StatefulSetSpec{
|
||||
UpdateStrategy: appsv1.StatefulSetUpdateStrategy{
|
||||
Type: appsv1.OnDeleteStatefulSetStrategyType,
|
||||
},
|
||||
},
|
||||
Status: appsv1.StatefulSetStatus{
|
||||
ObservedGeneration: 1,
|
||||
},
|
||||
},
|
||||
&corev1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Secret",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Generation: 1,
|
||||
Name: "mySecret",
|
||||
Namespace: "default",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResults: []result{
|
||||
{
|
||||
status: status.CurrentStatus,
|
||||
error: false,
|
||||
},
|
||||
{
|
||||
status: status.CurrentStatus,
|
||||
error: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme, tc.resources...)
|
||||
resolver := NewResolver(fakeClient, testPollInterval)
|
||||
resolver.statusComputeFunc = status.Compute
|
||||
|
||||
var identifiers []ResourceIdentifier
|
||||
for _, resource := range tc.resources {
|
||||
gvk := resource.GetObjectKind().GroupVersionKind()
|
||||
r := resource.(metav1.Object)
|
||||
identifiers = append(identifiers, &resourceKey{
|
||||
name: r.GetName(),
|
||||
namespace: r.GetNamespace(),
|
||||
apiVersion: gvk.GroupVersion().String(),
|
||||
kind: gvk.Kind,
|
||||
})
|
||||
}
|
||||
|
||||
results := resolver.FetchAndResolve(context.TODO(), identifiers)
|
||||
for i, res := range results {
|
||||
id := identifiers[i]
|
||||
expectedRes := tc.expectedResults[i]
|
||||
rid := fmt.Sprintf("%s/%s", id.GetNamespace(), id.GetName())
|
||||
if expectedRes.error {
|
||||
if res.Error == nil {
|
||||
t.Errorf("expected error for resource %s, but didn't get one", rid)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if res.Error != nil {
|
||||
t.Errorf("didn't expected error for resource %s, but got %v", rid, res.Error)
|
||||
}
|
||||
|
||||
if got, want := res.Result.Status, expectedRes.status; got != want {
|
||||
t.Errorf("expected status %s for resources %s, but got %s", want, rid, got)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchAndResolveUnknownResource(t *testing.T) {
|
||||
fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme)
|
||||
resolver := NewResolver(fakeClient, testPollInterval)
|
||||
results := resolver.FetchAndResolve(context.TODO(), []ResourceIdentifier{
|
||||
&resourceKey{
|
||||
apiVersion: "apps/v1",
|
||||
kind: "Deploymnet",
|
||||
name: "myDeployment",
|
||||
namespace: "default",
|
||||
},
|
||||
})
|
||||
|
||||
if want, got := 1, len(results); want != got {
|
||||
t.Errorf("expected %d results, but got %d", want, got)
|
||||
}
|
||||
|
||||
res := results[0]
|
||||
|
||||
if want, got := status.CurrentStatus, res.Result.Status; got != want {
|
||||
t.Errorf("expected status %s, but got %s", want, got)
|
||||
}
|
||||
|
||||
if res.Error != nil {
|
||||
t.Errorf("expected no error, but got %v", res.Error)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchAndResolveWithFetchError(t *testing.T) {
|
||||
expectedError := errors.New("failed to fetch resource")
|
||||
resolver := NewResolver(
|
||||
&fakeReader{
|
||||
Err: expectedError,
|
||||
},
|
||||
testPollInterval,
|
||||
)
|
||||
results := resolver.FetchAndResolve(context.TODO(), []ResourceIdentifier{
|
||||
&resourceKey{
|
||||
apiVersion: "apps/v1",
|
||||
kind: "Deploymnet",
|
||||
name: "myDeployment",
|
||||
namespace: "default",
|
||||
},
|
||||
})
|
||||
|
||||
if want, got := 1, len(results); want != got {
|
||||
t.Errorf("expected %d results, but got %d", want, got)
|
||||
}
|
||||
|
||||
res := results[0]
|
||||
|
||||
if want, got := status.UnknownStatus, res.Result.Status; got != want {
|
||||
t.Errorf("expected status %s, but got %s", want, got)
|
||||
}
|
||||
|
||||
if want, got := expectedError, errors.Cause(res.Error); got != want {
|
||||
t.Errorf("expected error %v, but got %v", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFetchAndResolveComputeStatusError(t *testing.T) {
|
||||
expectedError := errors.New("this is a test")
|
||||
resource := &appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Generation: 1,
|
||||
Name: "myDeployment",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
|
||||
fakeClient := fake.NewFakeClientWithScheme(scheme.Scheme, resource)
|
||||
resolver := NewResolver(fakeClient, testPollInterval)
|
||||
|
||||
resolver.statusComputeFunc = func(u *unstructured.Unstructured) (*status.Result, error) {
|
||||
return &status.Result{
|
||||
Status: status.UnknownStatus,
|
||||
Message: "Got an error",
|
||||
}, expectedError
|
||||
}
|
||||
results := resolver.FetchAndResolve(context.TODO(), []ResourceIdentifier{
|
||||
&resourceKey{
|
||||
apiVersion: resource.APIVersion,
|
||||
kind: resource.Kind,
|
||||
name: resource.GetName(),
|
||||
namespace: resource.GetNamespace(),
|
||||
},
|
||||
})
|
||||
|
||||
if want, got := 1, len(results); want != got {
|
||||
t.Errorf("expected %d results, but got %d", want, got)
|
||||
}
|
||||
|
||||
res := results[0]
|
||||
if want, got := expectedError, res.Error; got != want {
|
||||
t.Errorf("expected error %v, but got %v", want, got)
|
||||
}
|
||||
|
||||
if want, got := status.UnknownStatus, res.Result.Status; got != want {
|
||||
t.Errorf("expected status %s, but got %s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeReader struct {
|
||||
Called int
|
||||
Err error
|
||||
}
|
||||
|
||||
func (f *fakeReader) Get(ctx context.Context, key client.ObjectKey, obj runtime.Object) error {
|
||||
f.Called += 1
|
||||
return f.Err
|
||||
}
|
||||
|
||||
func (f *fakeReader) List(ctx context.Context, list runtime.Object, opts ...client.ListOption) error {
|
||||
return errors.New("list not used")
|
||||
}
|
||||
|
||||
func TestWaitForStatus(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
resources map[runtime.Object][]*status.Result
|
||||
expectedResourceStatuses map[runtime.Object][]status.Status
|
||||
expectedAggregateStatuses []status.Status
|
||||
}{
|
||||
"no resources": {
|
||||
resources: map[runtime.Object][]*status.Result{},
|
||||
expectedResourceStatuses: map[runtime.Object][]status.Status{},
|
||||
expectedAggregateStatuses: []status.Status{
|
||||
status.CurrentStatus,
|
||||
},
|
||||
},
|
||||
"single resource": {
|
||||
resources: map[runtime.Object][]*status.Result{
|
||||
deploymentResource: {
|
||||
{
|
||||
Status: status.InProgressStatus,
|
||||
Message: "FirstInProgress",
|
||||
},
|
||||
{
|
||||
Status: status.InProgressStatus,
|
||||
Message: "SecondInProgress",
|
||||
},
|
||||
{
|
||||
Status: status.CurrentStatus,
|
||||
Message: "CurrentProgress",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResourceStatuses: map[runtime.Object][]status.Status{
|
||||
deploymentResource: {
|
||||
status.InProgressStatus,
|
||||
status.InProgressStatus,
|
||||
status.CurrentStatus,
|
||||
},
|
||||
},
|
||||
expectedAggregateStatuses: []status.Status{
|
||||
status.InProgressStatus,
|
||||
status.InProgressStatus,
|
||||
status.CurrentStatus,
|
||||
status.CurrentStatus,
|
||||
},
|
||||
},
|
||||
"multiple resource": {
|
||||
resources: map[runtime.Object][]*status.Result{
|
||||
statefulSetResource: {
|
||||
{
|
||||
Status: status.InProgressStatus,
|
||||
Message: "FirstUnknown",
|
||||
},
|
||||
{
|
||||
Status: status.InProgressStatus,
|
||||
Message: "SecondInProgress",
|
||||
},
|
||||
{
|
||||
Status: status.CurrentStatus,
|
||||
Message: "CurrentProgress",
|
||||
},
|
||||
},
|
||||
serviceResource: {
|
||||
{
|
||||
Status: status.CurrentStatus,
|
||||
Message: "CurrentImmediately",
|
||||
},
|
||||
},
|
||||
},
|
||||
expectedResourceStatuses: map[runtime.Object][]status.Status{
|
||||
statefulSetResource: {
|
||||
status.InProgressStatus,
|
||||
status.InProgressStatus,
|
||||
status.CurrentStatus,
|
||||
},
|
||||
serviceResource: {
|
||||
status.CurrentStatus,
|
||||
},
|
||||
},
|
||||
expectedAggregateStatuses: []status.Status{
|
||||
status.UnknownStatus,
|
||||
status.InProgressStatus,
|
||||
status.InProgressStatus,
|
||||
status.CurrentStatus,
|
||||
status.CurrentStatus,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for tn, tc := range testCases {
|
||||
tc := tc
|
||||
t.Run(tn, func(t *testing.T) {
|
||||
var objs []runtime.Object
|
||||
statusResults := make(map[resourceKey][]*status.Result)
|
||||
var identifiers []ResourceIdentifier
|
||||
|
||||
for obj, statuses := range tc.resources {
|
||||
objs = append(objs, obj)
|
||||
identifier := keyFromObject(obj)
|
||||
identifiers = append(identifiers, &identifier)
|
||||
statusResults[identifier] = statuses
|
||||
}
|
||||
|
||||
statusComputer := statusComputer{
|
||||
results: statusResults,
|
||||
resourceCallCount: make(map[resourceKey]int),
|
||||
}
|
||||
|
||||
resolver := &Resolver{
|
||||
client: fake.NewFakeClientWithScheme(scheme.Scheme, objs...),
|
||||
statusComputeFunc: statusComputer.Compute,
|
||||
pollInterval: testPollInterval,
|
||||
}
|
||||
|
||||
eventChan := resolver.WaitForStatus(context.TODO(), identifiers)
|
||||
|
||||
var events []Event
|
||||
timer := time.NewTimer(testTimeout)
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-eventChan:
|
||||
if !ok {
|
||||
break loop
|
||||
}
|
||||
events = append(events, event)
|
||||
case <-timer.C:
|
||||
t.Fatalf("timeout waiting for resources to reach current status")
|
||||
}
|
||||
}
|
||||
|
||||
var aggregateStatuses []status.Status
|
||||
resourceStatuses := make(map[resourceKey][]status.Status)
|
||||
for _, e := range events {
|
||||
aggregateStatuses = append(aggregateStatuses, e.AggregateStatus)
|
||||
if e.EventResource != nil {
|
||||
identifier := keyFromResourceIdentifier(e.EventResource.Identifier)
|
||||
resourceStatuses[identifier] = append(resourceStatuses[identifier], e.EventResource.Status)
|
||||
}
|
||||
}
|
||||
|
||||
for resource, expectedStatuses := range tc.expectedResourceStatuses {
|
||||
identifier := keyFromObject(resource)
|
||||
actualStatuses := resourceStatuses[identifier]
|
||||
if !reflect.DeepEqual(expectedStatuses, actualStatuses) {
|
||||
t.Errorf("expected statuses %v for resource %s/%s, but got %v", expectedStatuses, identifier.namespace, identifier.name, actualStatuses)
|
||||
}
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(tc.expectedAggregateStatuses, aggregateStatuses) {
|
||||
t.Errorf("expected aggregate statuses %v, but got %v", tc.expectedAggregateStatuses, aggregateStatuses)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestWaitForStatusDeletedResources(t *testing.T) {
|
||||
statusComputer := statusComputer{
|
||||
results: make(map[resourceKey][]*status.Result),
|
||||
resourceCallCount: make(map[resourceKey]int),
|
||||
}
|
||||
|
||||
resolver := &Resolver{
|
||||
client: fake.NewFakeClientWithScheme(scheme.Scheme),
|
||||
statusComputeFunc: statusComputer.Compute,
|
||||
pollInterval: testPollInterval,
|
||||
}
|
||||
|
||||
depResourceIdentifier := keyFromObject(deploymentResource)
|
||||
serviceResourceIdentifier := keyFromObject(serviceResource)
|
||||
identifiers := []ResourceIdentifier{
|
||||
&depResourceIdentifier,
|
||||
&serviceResourceIdentifier,
|
||||
}
|
||||
|
||||
eventChan := resolver.WaitForStatus(context.TODO(), identifiers)
|
||||
|
||||
var events []Event
|
||||
timer := time.NewTimer(testTimeout)
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-eventChan:
|
||||
if !ok {
|
||||
break loop
|
||||
}
|
||||
events = append(events, event)
|
||||
case <-timer.C:
|
||||
t.Fatalf("timeout waiting for resources to reach current status")
|
||||
}
|
||||
}
|
||||
|
||||
expectedEvents := []struct {
|
||||
aggregateStatus status.Status
|
||||
hasResource bool
|
||||
resourceStatus status.Status
|
||||
}{
|
||||
{
|
||||
aggregateStatus: status.UnknownStatus,
|
||||
hasResource: true,
|
||||
resourceStatus: status.CurrentStatus,
|
||||
},
|
||||
{
|
||||
aggregateStatus: status.CurrentStatus,
|
||||
hasResource: true,
|
||||
resourceStatus: status.CurrentStatus,
|
||||
},
|
||||
{
|
||||
aggregateStatus: status.CurrentStatus,
|
||||
hasResource: false,
|
||||
},
|
||||
}
|
||||
|
||||
if want, got := len(expectedEvents), len(events); got != want {
|
||||
t.Errorf("expected %d events, but got %d", want, got)
|
||||
}
|
||||
|
||||
for i, e := range events {
|
||||
ee := expectedEvents[i]
|
||||
if want, got := ee.aggregateStatus, e.AggregateStatus; got != want {
|
||||
t.Errorf("expected event %d to be %s, but got %s", i, want, got)
|
||||
}
|
||||
|
||||
if ee.hasResource {
|
||||
if want, got := ee.resourceStatus, e.EventResource.Status; want != got {
|
||||
t.Errorf("expected resource event %d to be %s, but got %s", i, want, got)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type statusComputer struct {
|
||||
t *testing.T
|
||||
|
||||
results map[resourceKey][]*status.Result
|
||||
resourceCallCount map[resourceKey]int
|
||||
}
|
||||
|
||||
func (s *statusComputer) Compute(u *unstructured.Unstructured) (*status.Result, error) {
|
||||
identifier := resourceKey{
|
||||
apiVersion: u.GetAPIVersion(),
|
||||
kind: u.GetKind(),
|
||||
name: u.GetName(),
|
||||
namespace: u.GetNamespace(),
|
||||
}
|
||||
|
||||
resourceResults, ok := s.results[identifier]
|
||||
if !ok {
|
||||
s.t.Fatalf("No results available for resource %s/%s", u.GetNamespace(), u.GetName())
|
||||
}
|
||||
callCount := s.resourceCallCount[identifier]
|
||||
|
||||
var res *status.Result
|
||||
if len(resourceResults) <= callCount {
|
||||
res = resourceResults[len(resourceResults)-1]
|
||||
} else {
|
||||
res = resourceResults[callCount]
|
||||
}
|
||||
s.resourceCallCount[identifier] = callCount + 1
|
||||
return res, nil
|
||||
}
|
||||
|
||||
var deploymentResource = &appsv1.Deployment{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myDeployment",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
|
||||
var statefulSetResource = &appsv1.StatefulSet{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "StatefulSet",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myStatefulSet",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
|
||||
var serviceResource = &corev1.Service{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "v1",
|
||||
Kind: "Service",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "myService",
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
211
kstatus/wait/waitstate.go
Normal file
211
kstatus/wait/waitstate.go
Normal file
@@ -0,0 +1,211 @@
|
||||
package wait
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/kustomize/kstatus/status"
|
||||
)
|
||||
|
||||
// resourceKey is a minimal implementation of
|
||||
// the ResourceIdentifier interface.
|
||||
type resourceKey struct {
|
||||
name string
|
||||
namespace string
|
||||
apiVersion string
|
||||
kind string
|
||||
}
|
||||
|
||||
// GetName returns the name of the resource.
|
||||
func (r *resourceKey) GetName() string {
|
||||
return r.name
|
||||
}
|
||||
|
||||
// GetNamespace returns the namespace of the resource.
|
||||
func (r *resourceKey) GetNamespace() string {
|
||||
return r.namespace
|
||||
}
|
||||
|
||||
// GetAPIVersion returns the API version of the resource.
|
||||
func (r *resourceKey) GetAPIVersion() string {
|
||||
return r.apiVersion
|
||||
}
|
||||
|
||||
// GetKind returns the Kind of the resource.
|
||||
func (r *resourceKey) GetKind() string {
|
||||
return r.kind
|
||||
}
|
||||
|
||||
// waitState keeps the state about the resources and their last
|
||||
// observed state. This is used to determine any changes in state
|
||||
// so events can be sent when needed.
|
||||
type waitState struct {
|
||||
// ResourceWaitStates contains wait state for each of the resources.
|
||||
ResourceWaitStates map[resourceKey]*resourceWaitState
|
||||
|
||||
// statusComputeFunc defines the function used to compute the state of
|
||||
// a single resource. This is available for testing purposes.
|
||||
statusComputeFunc func(u *unstructured.Unstructured) (*status.Result, error)
|
||||
}
|
||||
|
||||
// resourceWaitState contains state information about an individual resource.
|
||||
type resourceWaitState struct {
|
||||
FirstSeenGeneration *int64
|
||||
HasBeenCurrent bool
|
||||
Observed bool
|
||||
|
||||
LastEvent *EventResource
|
||||
}
|
||||
|
||||
// newWaitState creates a new waitState object and initializes it with the
|
||||
// provided slice of resources and the provided statusComputeFunc.
|
||||
func newWaitState(resources []ResourceIdentifier, statusComputeFunc func(u *unstructured.Unstructured) (*status.Result, error)) *waitState {
|
||||
resourceWaitStates := make(map[resourceKey]*resourceWaitState)
|
||||
|
||||
for _, r := range resources {
|
||||
identifier := resourceKey{
|
||||
apiVersion: r.GetAPIVersion(),
|
||||
kind: r.GetKind(),
|
||||
name: r.GetName(),
|
||||
namespace: r.GetNamespace(),
|
||||
}
|
||||
resourceWaitStates[identifier] = &resourceWaitState{}
|
||||
}
|
||||
|
||||
return &waitState{
|
||||
ResourceWaitStates: resourceWaitStates,
|
||||
statusComputeFunc: statusComputeFunc,
|
||||
}
|
||||
}
|
||||
|
||||
// AggregateStatus computes the aggregate status for all the resources.
|
||||
// TODO: Ideally we would like this to be pluggable for different strategies.
|
||||
func (w *waitState) AggregateStatus() status.Status {
|
||||
allCurrent := true
|
||||
for _, rws := range w.ResourceWaitStates {
|
||||
if !rws.Observed {
|
||||
return status.UnknownStatus
|
||||
}
|
||||
if !rws.HasBeenCurrent {
|
||||
allCurrent = false
|
||||
}
|
||||
}
|
||||
if allCurrent {
|
||||
return status.CurrentStatus
|
||||
}
|
||||
return status.InProgressStatus
|
||||
}
|
||||
|
||||
// ResourceObserved notifies the waitState that we have new state for
|
||||
// a resource. This also accepts an error in case fetching the resource
|
||||
// from a cluster failed. It returns an EventResource object that contains
|
||||
// information about the observed resource, including the identifier and
|
||||
// the latest status for the resource. The function also returns a bool value
|
||||
// that will be true if the status of the observed resource has changed
|
||||
// since the previous observation and false it not. This is used to determine
|
||||
// whether a new event should be sent based on this observation.
|
||||
func (w *waitState) ResourceObserved(id ResourceIdentifier, resource *unstructured.Unstructured, err error) (EventResource, bool) {
|
||||
identifier := resourceKey{
|
||||
name: id.GetName(),
|
||||
namespace: id.GetNamespace(),
|
||||
apiVersion: id.GetAPIVersion(),
|
||||
kind: id.GetKind(),
|
||||
}
|
||||
|
||||
// Check for nil is not needed here as the id passed in comes
|
||||
// from iterating over the keys of the map.
|
||||
rws := w.ResourceWaitStates[identifier]
|
||||
|
||||
eventResource := w.getEventResource(identifier, resource, err)
|
||||
// If the new eventResource is identical to the previous one, we return
|
||||
// with the last return value indicating this is not a new event.
|
||||
if rws.LastEvent != nil && reflect.DeepEqual(eventResource, *rws.LastEvent) {
|
||||
return eventResource, false
|
||||
}
|
||||
rws.LastEvent = &eventResource
|
||||
return eventResource, true
|
||||
}
|
||||
|
||||
// getEventResource creates a new EventResource for the resource identified by
|
||||
// the provided resourceKey. The EventResource contains information about the
|
||||
// latest status for the given resource, so it computes status for the resource
|
||||
// as well as check for deletion.
|
||||
func (w *waitState) getEventResource(identifier resourceKey, resource *unstructured.Unstructured, err error) EventResource {
|
||||
// Get the resourceWaitState for this resource. It contains information
|
||||
// of the previous observed statuses. We don't need to check for nil here
|
||||
// as the identifier comes from iterating over the keys of the
|
||||
// ResourceWaitState map.
|
||||
r := w.ResourceWaitStates[identifier]
|
||||
|
||||
// If fetching the resource from the cluster failed, we don't really
|
||||
// know anything about the status of the resource, so simply
|
||||
// report the status as Unknown.
|
||||
if err != nil && !k8serrors.IsNotFound(errors.Cause(err)) {
|
||||
return EventResource{
|
||||
Identifier: &identifier,
|
||||
Status: status.UnknownStatus,
|
||||
Message: fmt.Sprintf("Error: %s", err),
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
|
||||
// If we get here, we have successfully fetched the resource from
|
||||
// the cluster, or discovered that it doesn't exist.
|
||||
r.Observed = true
|
||||
|
||||
// We treat a non-existent resource as Current. This is to properly
|
||||
// handle deletion scenarios.
|
||||
if k8serrors.IsNotFound(errors.Cause(err)) {
|
||||
r.HasBeenCurrent = true
|
||||
return EventResource{
|
||||
Identifier: &identifier,
|
||||
Status: status.CurrentStatus,
|
||||
Message: fmt.Sprintf("Resource has been deleted"),
|
||||
}
|
||||
}
|
||||
|
||||
// We want to capture the first seen generation of the resource. This
|
||||
// allows us to discover if a resource is updated while we are waiting
|
||||
// for it to become Current.
|
||||
if r.FirstSeenGeneration != nil {
|
||||
gen := resource.GetGeneration()
|
||||
r.FirstSeenGeneration = &gen
|
||||
}
|
||||
|
||||
if resource.GetDeletionTimestamp() != nil {
|
||||
return EventResource{
|
||||
Identifier: &identifier,
|
||||
Status: status.TerminatingStatus,
|
||||
Message: fmt.Sprintf("Resource is terminating"),
|
||||
}
|
||||
}
|
||||
|
||||
statusResult, err := w.statusComputeFunc(resource)
|
||||
// If we can't compute status for the resource, we report the status
|
||||
// as Unknown.
|
||||
if err != nil {
|
||||
return EventResource{
|
||||
Identifier: &identifier,
|
||||
Status: status.UnknownStatus,
|
||||
Message: fmt.Sprintf("Error: %s", err),
|
||||
Error: err,
|
||||
}
|
||||
}
|
||||
|
||||
// We record whether a resource has ever been Current. This makes
|
||||
// sure we can report a set of resources as being Current if all
|
||||
// of them has reached the Current status at some point, but not
|
||||
// necessarily at the same time.
|
||||
if statusResult.Status == status.CurrentStatus {
|
||||
r.HasBeenCurrent = true
|
||||
}
|
||||
|
||||
return EventResource{
|
||||
Identifier: &identifier,
|
||||
Status: statusResult.Status,
|
||||
Message: statusResult.Message,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user