mirror of https://github.com/kubevela/kubevela.git
Feat: Support kruise rollout (#4243)
* Feat: support kruise rollout Signed-off-by: Somefive <yd219913@alibaba-inc.com> resolve roll back fix add tests Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> small fix * fix rollback Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> topology filter by owner reference Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> fix ci Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> add comments Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> fix imports Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> fix lint * rollback related tests Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> rename the operator Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> fix bugs Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> fix test Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> fix test * clean args before start Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> fix test * remove replace go mod Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> * fix operation tests Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com> Co-authored-by: Somefive <yd219913@alibaba-inc.com>
This commit is contained in:
parent
dc660fc97d
commit
c4e1f39d28
20
go.mod
20
go.mod
|
|
@ -105,6 +105,18 @@ require (
|
||||||
sigs.k8s.io/yaml v1.3.0
|
sigs.k8s.io/yaml v1.3.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||||
|
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||||
|
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||||
|
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||||
|
github.com/openkruise/rollouts v0.1.1-0.20220622054609-149e5a48da5e
|
||||||
|
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20220516155154-20f960328961 // indirect
|
||||||
|
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||||
|
google.golang.org/protobuf v1.28.0 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/compute v1.6.1 // indirect
|
cloud.google.com/go/compute v1.6.1 // indirect
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||||
|
|
@ -148,7 +160,6 @@ require (
|
||||||
github.com/creack/pty v1.1.11 // indirect
|
github.com/creack/pty v1.1.11 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||||
github.com/docker/cli v20.10.16+incompatible // indirect
|
github.com/docker/cli v20.10.16+incompatible // indirect
|
||||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
|
||||||
github.com/docker/docker v20.10.16+incompatible // indirect
|
github.com/docker/docker v20.10.16+incompatible // indirect
|
||||||
github.com/docker/docker-credential-helpers v0.6.4 // indirect
|
github.com/docker/docker-credential-helpers v0.6.4 // indirect
|
||||||
github.com/docker/go-connections v0.4.0 // indirect
|
github.com/docker/go-connections v0.4.0 // indirect
|
||||||
|
|
@ -190,8 +201,6 @@ require (
|
||||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
|
||||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/huandu/xstrings v1.3.2 // indirect
|
github.com/huandu/xstrings v1.3.2 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
|
|
@ -201,7 +210,6 @@ require (
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
|
||||||
github.com/klauspost/compress v1.15.4 // indirect
|
github.com/klauspost/compress v1.15.4 // indirect
|
||||||
github.com/kr/pretty v0.3.0 // indirect
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
github.com/kr/pty v1.1.8 // indirect
|
github.com/kr/pty v1.1.8 // indirect
|
||||||
|
|
@ -254,7 +262,6 @@ require (
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.0 // indirect
|
github.com/tidwall/pretty v1.2.0 // indirect
|
||||||
github.com/tjfoc/gmsm v1.3.2 // indirect
|
github.com/tjfoc/gmsm v1.3.2 // indirect
|
||||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
|
||||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||||
github.com/xdg-go/scram v1.0.2 // indirect
|
github.com/xdg-go/scram v1.0.2 // indirect
|
||||||
github.com/xdg-go/stringprep v1.0.2 // indirect
|
github.com/xdg-go/stringprep v1.0.2 // indirect
|
||||||
|
|
@ -281,16 +288,13 @@ require (
|
||||||
go.uber.org/atomic v1.7.0 // indirect
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
go.uber.org/multierr v1.6.0 // indirect
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||||
golang.org/x/net v0.0.0-20220516155154-20f960328961 // indirect
|
|
||||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
|
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect
|
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
|
||||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3 // indirect
|
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3 // indirect
|
||||||
google.golang.org/grpc v1.45.0 // indirect
|
google.golang.org/grpc v1.45.0 // indirect
|
||||||
google.golang.org/protobuf v1.28.0 // indirect
|
|
||||||
gopkg.in/gorp.v1 v1.7.2 // indirect
|
gopkg.in/gorp.v1 v1.7.2 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||||
|
|
|
||||||
33
go.sum
33
go.sum
|
|
@ -1608,6 +1608,8 @@ github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvw
|
||||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||||
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||||
github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
|
github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
|
||||||
|
|
@ -1627,6 +1629,7 @@ github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDs
|
||||||
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
|
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
|
||||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||||
github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||||
|
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||||
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||||
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
|
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
|
||||||
|
|
@ -1662,8 +1665,11 @@ github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqi
|
||||||
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
|
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
|
||||||
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
|
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
|
||||||
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||||
|
github.com/openkruise/kruise-api v1.0.0/go.mod h1:kxV/UA/vrf/hz3z+kL21c0NOawC6K1ZjaKcJFgiOwsE=
|
||||||
github.com/openkruise/kruise-api v1.1.0 h1:ZRhV0FnxUp4XHc60YPkUqj2LJD4GRFB92qhtdgU6Zhc=
|
github.com/openkruise/kruise-api v1.1.0 h1:ZRhV0FnxUp4XHc60YPkUqj2LJD4GRFB92qhtdgU6Zhc=
|
||||||
github.com/openkruise/kruise-api v1.1.0/go.mod h1:kxV/UA/vrf/hz3z+kL21c0NOawC6K1ZjaKcJFgiOwsE=
|
github.com/openkruise/kruise-api v1.1.0/go.mod h1:kxV/UA/vrf/hz3z+kL21c0NOawC6K1ZjaKcJFgiOwsE=
|
||||||
|
github.com/openkruise/rollouts v0.1.1-0.20220622054609-149e5a48da5e h1:jUMEDsA0OOpp0262pK8MV8M2glac+jIjx+q5Aydn6G0=
|
||||||
|
github.com/openkruise/rollouts v0.1.1-0.20220622054609-149e5a48da5e/go.mod h1:SORsT96ssCqMJYSVA90v6Z52utlV2jxPlyGh4czRfHA=
|
||||||
github.com/openshift/api v0.0.0-20210915110300-3cd8091317c4/go.mod h1:RsQCVJu4qhUawxxDP7pGlwU3IA4F01wYm3qKEu29Su8=
|
github.com/openshift/api v0.0.0-20210915110300-3cd8091317c4/go.mod h1:RsQCVJu4qhUawxxDP7pGlwU3IA4F01wYm3qKEu29Su8=
|
||||||
github.com/openshift/api v0.0.0-20211209135129-c58d9f695577/go.mod h1:DoslCwtqUpr3d/gsbq4ZlkaMEdYqKxuypsDjorcHhME=
|
github.com/openshift/api v0.0.0-20211209135129-c58d9f695577/go.mod h1:DoslCwtqUpr3d/gsbq4ZlkaMEdYqKxuypsDjorcHhME=
|
||||||
github.com/openshift/build-machinery-go v0.0.0-20210115170933-e575b44a7a94/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE=
|
github.com/openshift/build-machinery-go v0.0.0-20210115170933-e575b44a7a94/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE=
|
||||||
|
|
@ -2199,6 +2205,7 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||||
|
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||||
go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
|
go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
|
||||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||||
golang.org/x/arch v0.0.0-20180920145803-b19384d3c130/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8=
|
golang.org/x/arch v0.0.0-20180920145803-b19384d3c130/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8=
|
||||||
|
|
@ -2375,6 +2382,7 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211215060638-4ddde0e984e9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211215060638-4ddde0e984e9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
|
@ -2547,6 +2555,7 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
|
@ -3073,7 +3082,10 @@ k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s=
|
||||||
k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU=
|
k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU=
|
||||||
k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg=
|
k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg=
|
||||||
k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY=
|
k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY=
|
||||||
|
k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8=
|
||||||
k8s.io/api v0.22.4/go.mod h1:Rgs+9gIGYC5laXQSZZ9JqT5NevNgoGiOdVWi1BAB3qk=
|
k8s.io/api v0.22.4/go.mod h1:Rgs+9gIGYC5laXQSZZ9JqT5NevNgoGiOdVWi1BAB3qk=
|
||||||
|
k8s.io/api v0.22.4/go.mod h1:Rgs+9gIGYC5laXQSZZ9JqT5NevNgoGiOdVWi1BAB3qk=
|
||||||
|
k8s.io/api v0.22.6/go.mod h1:q1F7IfaNrbi/83ebLy3YFQYLjPSNyunZ/IXQxMmbwCg=
|
||||||
k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg=
|
k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg=
|
||||||
k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo=
|
k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo=
|
||||||
k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
|
k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
|
||||||
|
|
@ -3089,7 +3101,9 @@ k8s.io/apiextensions-apiserver v0.18.6/go.mod h1:lv89S7fUysXjLZO7ke783xOwVTm6lKi
|
||||||
k8s.io/apiextensions-apiserver v0.21.2/go.mod h1:+Axoz5/l3AYpGLlhJDfcVQzCerVYq3K3CvDMvw6X1RA=
|
k8s.io/apiextensions-apiserver v0.21.2/go.mod h1:+Axoz5/l3AYpGLlhJDfcVQzCerVYq3K3CvDMvw6X1RA=
|
||||||
k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE=
|
k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE=
|
||||||
k8s.io/apiextensions-apiserver v0.22.1/go.mod h1:HeGmorjtRmRLE+Q8dJu6AYRoZccvCMsghwS8XTUYb2c=
|
k8s.io/apiextensions-apiserver v0.22.1/go.mod h1:HeGmorjtRmRLE+Q8dJu6AYRoZccvCMsghwS8XTUYb2c=
|
||||||
|
k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA=
|
||||||
k8s.io/apiextensions-apiserver v0.22.4/go.mod h1:kH9lxD8dbJ+k0ZizGET55lFgdGjO8t45fgZnCVdZEpw=
|
k8s.io/apiextensions-apiserver v0.22.4/go.mod h1:kH9lxD8dbJ+k0ZizGET55lFgdGjO8t45fgZnCVdZEpw=
|
||||||
|
k8s.io/apiextensions-apiserver v0.22.6/go.mod h1:wNsLwy8mfIkGThiv4Qq/Hy4qRazViKXqmH5pfYiRKyY=
|
||||||
k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4=
|
k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4=
|
||||||
k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ=
|
k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ=
|
||||||
k8s.io/apiextensions-apiserver v0.23.6 h1:v58cQ6Z0/GK1IXYr+oW0fnYl52o9LTY0WgoWvI8uv5Q=
|
k8s.io/apiextensions-apiserver v0.23.6 h1:v58cQ6Z0/GK1IXYr+oW0fnYl52o9LTY0WgoWvI8uv5Q=
|
||||||
|
|
@ -3119,7 +3133,9 @@ k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswP
|
||||||
k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM=
|
k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM=
|
||||||
k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI=
|
k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI=
|
||||||
k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
|
k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
|
||||||
|
k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
|
||||||
k8s.io/apimachinery v0.22.4/go.mod h1:yU6oA6Gnax9RrxGzVvPFFJ+mpnW6PBSqp0sx0I0HHW0=
|
k8s.io/apimachinery v0.22.4/go.mod h1:yU6oA6Gnax9RrxGzVvPFFJ+mpnW6PBSqp0sx0I0HHW0=
|
||||||
|
k8s.io/apimachinery v0.22.6/go.mod h1:ZvVLP5iLhwVFg2Yx9Gh5W0um0DUauExbRhe+2Z8I1EU=
|
||||||
k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc=
|
k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc=
|
||||||
k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno=
|
k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno=
|
||||||
k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
||||||
|
|
@ -3139,7 +3155,10 @@ k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
|
||||||
k8s.io/apiserver v0.21.2/go.mod h1:lN4yBoGyiNT7SC1dmNk0ue6a5Wi6O3SWOIw91TsucQw=
|
k8s.io/apiserver v0.21.2/go.mod h1:lN4yBoGyiNT7SC1dmNk0ue6a5Wi6O3SWOIw91TsucQw=
|
||||||
k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU=
|
k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU=
|
||||||
k8s.io/apiserver v0.22.1/go.mod h1:2mcM6dzSt+XndzVQJX21Gx0/Klo7Aen7i0Ai6tIa400=
|
k8s.io/apiserver v0.22.1/go.mod h1:2mcM6dzSt+XndzVQJX21Gx0/Klo7Aen7i0Ai6tIa400=
|
||||||
|
k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI=
|
||||||
k8s.io/apiserver v0.22.4/go.mod h1:38WmcUZiiy41A7Aty8/VorWRa8vDGqoUzDf2XYlku0E=
|
k8s.io/apiserver v0.22.4/go.mod h1:38WmcUZiiy41A7Aty8/VorWRa8vDGqoUzDf2XYlku0E=
|
||||||
|
k8s.io/apiserver v0.22.4/go.mod h1:38WmcUZiiy41A7Aty8/VorWRa8vDGqoUzDf2XYlku0E=
|
||||||
|
k8s.io/apiserver v0.22.6/go.mod h1:OlL1rGa2kKWGj2JEXnwBcul/BwC9Twe95gm4ohtiIIs=
|
||||||
k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4=
|
k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4=
|
||||||
k8s.io/apiserver v0.23.1/go.mod h1:Bqt0gWbeM2NefS8CjWswwd2VNAKN6lUKR85Ft4gippY=
|
k8s.io/apiserver v0.23.1/go.mod h1:Bqt0gWbeM2NefS8CjWswwd2VNAKN6lUKR85Ft4gippY=
|
||||||
k8s.io/apiserver v0.23.5/go.mod h1:7wvMtGJ42VRxzgVI7jkbKvMbuCbVbgsWFT7RyXiRNTw=
|
k8s.io/apiserver v0.23.5/go.mod h1:7wvMtGJ42VRxzgVI7jkbKvMbuCbVbgsWFT7RyXiRNTw=
|
||||||
|
|
@ -3173,7 +3192,9 @@ k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs=
|
||||||
k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA=
|
k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA=
|
||||||
k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU=
|
k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU=
|
||||||
k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk=
|
k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk=
|
||||||
|
k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U=
|
||||||
k8s.io/client-go v0.22.4/go.mod h1:Yzw4e5e7h1LNHA4uqnMVrpEpUs1hJOiuBsJKIlRCHDA=
|
k8s.io/client-go v0.22.4/go.mod h1:Yzw4e5e7h1LNHA4uqnMVrpEpUs1hJOiuBsJKIlRCHDA=
|
||||||
|
k8s.io/client-go v0.22.6/go.mod h1:TffU4AV2idZGeP+g3kdFZP+oHVHWPL1JYFySOALriw0=
|
||||||
k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA=
|
k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA=
|
||||||
k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0=
|
k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0=
|
||||||
k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4=
|
k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4=
|
||||||
|
|
@ -3189,10 +3210,13 @@ k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRV
|
||||||
k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c=
|
k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c=
|
||||||
k8s.io/code-generator v0.20.0/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg=
|
k8s.io/code-generator v0.20.0/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg=
|
||||||
k8s.io/code-generator v0.20.10/go.mod h1:i6FmG+QxaLxvJsezvZp0q/gAEzzOz3U53KFibghWToU=
|
k8s.io/code-generator v0.20.10/go.mod h1:i6FmG+QxaLxvJsezvZp0q/gAEzzOz3U53KFibghWToU=
|
||||||
|
k8s.io/code-generator v0.20.10/go.mod h1:i6FmG+QxaLxvJsezvZp0q/gAEzzOz3U53KFibghWToU=
|
||||||
k8s.io/code-generator v0.21.2/go.mod h1:8mXJDCB7HcRo1xiEQstcguZkbxZaqeUOrO9SsicWs3U=
|
k8s.io/code-generator v0.21.2/go.mod h1:8mXJDCB7HcRo1xiEQstcguZkbxZaqeUOrO9SsicWs3U=
|
||||||
k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo=
|
k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo=
|
||||||
k8s.io/code-generator v0.22.1/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
|
k8s.io/code-generator v0.22.1/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
|
||||||
|
k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
|
||||||
k8s.io/code-generator v0.22.4/go.mod h1:qjYl54pQ/emhkT0UxbufbREYJMWsHNNV/jSVwhYZQGw=
|
k8s.io/code-generator v0.22.4/go.mod h1:qjYl54pQ/emhkT0UxbufbREYJMWsHNNV/jSVwhYZQGw=
|
||||||
|
k8s.io/code-generator v0.22.6/go.mod h1:iOZwYADSgFPNGWfqHFfg1V0TNJnl1t0WyZluQp4baqU=
|
||||||
k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE=
|
k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE=
|
||||||
k8s.io/code-generator v0.23.1/go.mod h1:V7yn6VNTCWW8GqodYCESVo95fuiEg713S8B7WacWZDA=
|
k8s.io/code-generator v0.23.1/go.mod h1:V7yn6VNTCWW8GqodYCESVo95fuiEg713S8B7WacWZDA=
|
||||||
k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
||||||
|
|
@ -3213,7 +3237,9 @@ k8s.io/component-base v0.20.10/go.mod h1:ZKOEin1xu68aJzxgzl5DZSp5J1IrjAOPlPN90/t
|
||||||
k8s.io/component-base v0.21.2/go.mod h1:9lvmIThzdlrJj5Hp8Z/TOgIkdfsNARQ1pT+3PByuiuc=
|
k8s.io/component-base v0.21.2/go.mod h1:9lvmIThzdlrJj5Hp8Z/TOgIkdfsNARQ1pT+3PByuiuc=
|
||||||
k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ=
|
k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ=
|
||||||
k8s.io/component-base v0.22.1/go.mod h1:0D+Bl8rrnsPN9v0dyYvkqFfBeAd4u7n77ze+p8CMiPo=
|
k8s.io/component-base v0.22.1/go.mod h1:0D+Bl8rrnsPN9v0dyYvkqFfBeAd4u7n77ze+p8CMiPo=
|
||||||
|
k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug=
|
||||||
k8s.io/component-base v0.22.4/go.mod h1:MrSaQy4a3tFVViff8TZL6JHYSewNCLshZCwHYM58v5A=
|
k8s.io/component-base v0.22.4/go.mod h1:MrSaQy4a3tFVViff8TZL6JHYSewNCLshZCwHYM58v5A=
|
||||||
|
k8s.io/component-base v0.22.6/go.mod h1:ngHLefY4J5fq2fApNdbWyj4yh0lvw36do4aAjNN8rc8=
|
||||||
k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI=
|
k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI=
|
||||||
k8s.io/component-base v0.23.1/go.mod h1:6llmap8QtJIXGDd4uIWJhAq0Op8AtQo6bDW2RrNMTeo=
|
k8s.io/component-base v0.23.1/go.mod h1:6llmap8QtJIXGDd4uIWJhAq0Op8AtQo6bDW2RrNMTeo=
|
||||||
k8s.io/component-base v0.23.5/go.mod h1:c5Nq44KZyt1aLl0IpHX82fhsn84Sb0jjzwjpcA42bY0=
|
k8s.io/component-base v0.23.5/go.mod h1:c5Nq44KZyt1aLl0IpHX82fhsn84Sb0jjzwjpcA42bY0=
|
||||||
|
|
@ -3262,6 +3288,7 @@ k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAG
|
||||||
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
|
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
|
||||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||||
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||||
|
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
|
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
|
||||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
||||||
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd/go.mod h1:9ehGcuUGjXVZh0qbYSB0vvofQw2JQe6c6cO0k4wu/Oo=
|
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd/go.mod h1:9ehGcuUGjXVZh0qbYSB0vvofQw2JQe6c6cO0k4wu/Oo=
|
||||||
|
|
@ -3287,6 +3314,7 @@ k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
|
||||||
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
|
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
k8s.io/utils v0.0.0-20211208161948-7d6a63dca704/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20211208161948-7d6a63dca704/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
|
|
@ -3330,6 +3358,7 @@ sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2
|
||||||
sigs.k8s.io/controller-runtime v0.6.2/go.mod h1:vhcq/rlnENJ09SIRp3EveTaZ0yqH526hjf9iJdbUJ/E=
|
sigs.k8s.io/controller-runtime v0.6.2/go.mod h1:vhcq/rlnENJ09SIRp3EveTaZ0yqH526hjf9iJdbUJ/E=
|
||||||
sigs.k8s.io/controller-runtime v0.9.2/go.mod h1:TxzMCHyEUpaeuOiZx/bIdc2T81vfs/aKdvJt9wuu0zk=
|
sigs.k8s.io/controller-runtime v0.9.2/go.mod h1:TxzMCHyEUpaeuOiZx/bIdc2T81vfs/aKdvJt9wuu0zk=
|
||||||
sigs.k8s.io/controller-runtime v0.9.5/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA=
|
sigs.k8s.io/controller-runtime v0.9.5/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA=
|
||||||
|
sigs.k8s.io/controller-runtime v0.10.3/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY=
|
||||||
sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
|
sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
|
||||||
sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
|
sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
|
||||||
sigs.k8s.io/controller-runtime v0.11.2 h1:H5GTxQl0Mc9UjRJhORusqfJCIjBO8UtUxGggCwL1rLA=
|
sigs.k8s.io/controller-runtime v0.11.2 h1:H5GTxQl0Mc9UjRJhORusqfJCIjBO8UtUxGggCwL1rLA=
|
||||||
|
|
@ -3370,7 +3399,11 @@ sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.0/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.0/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||||
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||||
|
sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w=
|
||||||
sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w=
|
sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w=
|
||||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||||
|
|
|
||||||
|
|
@ -280,6 +280,9 @@ func (h *AppHandler) collectHealthStatus(ctx context.Context, wl *appfile.Worklo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, errors.WithMessagef(err, "app=%s, comp=%s, trait=%s, evaluate status message error", appName, wl.Name, tr.Name)
|
return nil, false, errors.WithMessagef(err, "app=%s, comp=%s, trait=%s, evaluate status message error", appName, wl.Name, tr.Name)
|
||||||
}
|
}
|
||||||
|
if status.Message == "" && traitStatus.Message != "" {
|
||||||
|
status.Message = traitStatus.Message
|
||||||
|
}
|
||||||
traitStatusList = append(traitStatusList, traitStatus)
|
traitStatusList = append(traitStatusList, traitStatus)
|
||||||
namespace = appRev.GetNamespace()
|
namespace = appRev.GetNamespace()
|
||||||
wl.Ctx.SetCtx(context.WithValue(wl.Ctx.GetCtx(), multicluster.ClusterContextKey, status.Cluster))
|
wl.Ctx.SetCtx(context.WithValue(wl.Ctx.GetCtx(), multicluster.ClusterContextKey, status.Cluster))
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,200 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 The KubeVela 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 rollout
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/client-go/util/retry"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
kruisev1alpha1 "github.com/openkruise/rollouts/api/v1alpha1"
|
||||||
|
|
||||||
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/resourcetracker"
|
||||||
|
velaerrors "github.com/oam-dev/kubevela/pkg/utils/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClusterRollout rollout in specified cluster
|
||||||
|
type ClusterRollout struct {
|
||||||
|
*kruisev1alpha1.Rollout
|
||||||
|
Cluster string
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAssociatedRollouts(ctx context.Context, cli client.Client, app *v1beta1.Application, withHistoryRTs bool) ([]*ClusterRollout, error) {
|
||||||
|
rootRT, currentRT, historyRTs, _, err := resourcetracker.ListApplicationResourceTrackers(ctx, cli, app)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to list resource trackers")
|
||||||
|
}
|
||||||
|
if !withHistoryRTs {
|
||||||
|
historyRTs = []*v1beta1.ResourceTracker{}
|
||||||
|
}
|
||||||
|
var rollouts []*ClusterRollout
|
||||||
|
for _, rt := range append(historyRTs, rootRT, currentRT) {
|
||||||
|
if rt == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, mr := range rt.Spec.ManagedResources {
|
||||||
|
if mr.APIVersion == kruisev1alpha1.SchemeGroupVersion.String() && mr.Kind == "Rollout" {
|
||||||
|
rollout := &kruisev1alpha1.Rollout{}
|
||||||
|
if err = cli.Get(multicluster.ContextWithClusterName(ctx, mr.Cluster), k8stypes.NamespacedName{Namespace: mr.Namespace, Name: mr.Name}, rollout); err != nil {
|
||||||
|
if multicluster.IsNotFoundOrClusterNotExists(err) || velaerrors.IsCRDNotExists(err) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil, errors.Wrapf(err, "failed to get kruise rollout %s/%s in cluster %s", mr.Namespace, mr.Name, mr.Cluster)
|
||||||
|
}
|
||||||
|
rollouts = append(rollouts, &ClusterRollout{Rollout: rollout, Cluster: mr.Cluster})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rollouts, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SuspendRollout find all rollouts associated with the application (including history RTs) and resume them
|
||||||
|
func SuspendRollout(ctx context.Context, cli client.Client, app *v1beta1.Application, writer io.Writer) error {
|
||||||
|
rollouts, err := getAssociatedRollouts(ctx, cli, app, true)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i := range rollouts {
|
||||||
|
rollout := rollouts[i]
|
||||||
|
if rollout.Status.Phase == kruisev1alpha1.RolloutPhaseProgressing && !rollout.Spec.Strategy.Paused {
|
||||||
|
_ctx := multicluster.ContextWithClusterName(ctx, rollout.Cluster)
|
||||||
|
rolloutKey := client.ObjectKeyFromObject(rollout.Rollout)
|
||||||
|
if err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||||
|
if err = cli.Get(_ctx, rolloutKey, rollout.Rollout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if rollout.Status.Phase == kruisev1alpha1.RolloutPhaseProgressing && !rollout.Spec.Strategy.Paused {
|
||||||
|
rollout.Spec.Strategy.Paused = true
|
||||||
|
if err = cli.Update(_ctx, rollout.Rollout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if writer != nil {
|
||||||
|
_, _ = writer.Write([]byte(fmt.Sprintf("Rollout %s/%s in cluster %s suspended.\n", rollout.Namespace, rollout.Name, rollout.Cluster)))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to suspend rollout %s/%s in cluster %s", rollout.Namespace, rollout.Name, rollout.Cluster)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResumeRollout find all rollouts associated with the application (in the current RT) and resume them
|
||||||
|
func ResumeRollout(ctx context.Context, cli client.Client, app *v1beta1.Application, writer io.Writer) (bool, error) {
|
||||||
|
rollouts, err := getAssociatedRollouts(ctx, cli, app, false)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
modified := false
|
||||||
|
for i := range rollouts {
|
||||||
|
rollout := rollouts[i]
|
||||||
|
if rollout.Spec.Strategy.Paused || (rollout.Status.CanaryStatus != nil && rollout.Status.CanaryStatus.CurrentStepState == kruisev1alpha1.CanaryStepStatePaused) {
|
||||||
|
_ctx := multicluster.ContextWithClusterName(ctx, rollout.Cluster)
|
||||||
|
rolloutKey := client.ObjectKeyFromObject(rollout.Rollout)
|
||||||
|
resumed := false
|
||||||
|
if err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||||
|
if err = cli.Get(_ctx, rolloutKey, rollout.Rollout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if rollout.Spec.Strategy.Paused {
|
||||||
|
rollout.Spec.Strategy.Paused = false
|
||||||
|
if err = cli.Update(_ctx, rollout.Rollout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resumed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return false, errors.Wrapf(err, "failed to resume rollout %s/%s in cluster %s", rollout.Namespace, rollout.Name, rollout.Cluster)
|
||||||
|
}
|
||||||
|
if err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||||
|
if err = cli.Get(_ctx, rolloutKey, rollout.Rollout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if rollout.Status.CanaryStatus != nil && rollout.Status.CanaryStatus.CurrentStepState == kruisev1alpha1.CanaryStepStatePaused {
|
||||||
|
rollout.Status.CanaryStatus.CurrentStepState = kruisev1alpha1.CanaryStepStateReady
|
||||||
|
if err = cli.Status().Update(_ctx, rollout.Rollout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resumed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return false, errors.Wrapf(err, "failed to resume rollout %s/%s in cluster %s", rollout.Namespace, rollout.Name, rollout.Cluster)
|
||||||
|
}
|
||||||
|
if resumed {
|
||||||
|
modified = true
|
||||||
|
if writer != nil {
|
||||||
|
_, _ = writer.Write([]byte(fmt.Sprintf("Rollout %s/%s in cluster %s resumed.\n", rollout.Namespace, rollout.Name, rollout.Cluster)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modified, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RollbackRollout find all rollouts associated with the application (in the current RT) and disable the pause field.
|
||||||
|
func RollbackRollout(ctx context.Context, cli client.Client, app *v1beta1.Application, writer io.Writer) (bool, error) {
|
||||||
|
rollouts, err := getAssociatedRollouts(ctx, cli, app, false)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
modified := false
|
||||||
|
for i := range rollouts {
|
||||||
|
rollout := rollouts[i]
|
||||||
|
if rollout.Spec.Strategy.Paused || (rollout.Status.CanaryStatus != nil && rollout.Status.CanaryStatus.CurrentStepState == kruisev1alpha1.CanaryStepStatePaused) {
|
||||||
|
_ctx := multicluster.ContextWithClusterName(ctx, rollout.Cluster)
|
||||||
|
rolloutKey := client.ObjectKeyFromObject(rollout.Rollout)
|
||||||
|
resumed := false
|
||||||
|
if err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||||
|
if err = cli.Get(_ctx, rolloutKey, rollout.Rollout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if rollout.Spec.Strategy.Paused {
|
||||||
|
rollout.Spec.Strategy.Paused = false
|
||||||
|
if err = cli.Update(_ctx, rollout.Rollout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
resumed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return false, errors.Wrapf(err, "failed to rollback rollout %s/%s in cluster %s", rollout.Namespace, rollout.Name, rollout.Cluster)
|
||||||
|
}
|
||||||
|
if resumed {
|
||||||
|
modified = true
|
||||||
|
if writer != nil {
|
||||||
|
_, _ = writer.Write([]byte(fmt.Sprintf("Rollout %s/%s in cluster %s rollback.\n", rollout.Namespace, rollout.Name, rollout.Cluster)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return modified, nil
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 The KubeVela 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 rollout
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
kruisev1alpha1 "github.com/openkruise/rollouts/api/v1alpha1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||||
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Kruise rollout test", func() {
|
||||||
|
ctx := context.Background()
|
||||||
|
BeforeEach(func() {
|
||||||
|
Expect(k8sClient.Create(ctx, rollout.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
|
||||||
|
Expect(k8sClient.Create(ctx, rt.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
|
||||||
|
Expect(k8sClient.Create(ctx, app.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("test get associated rollout func", func() {
|
||||||
|
rollouts, err := getAssociatedRollouts(ctx, k8sClient, &app, false)
|
||||||
|
Expect(err).Should(BeNil())
|
||||||
|
Expect(len(rollouts)).Should(BeEquivalentTo(1))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Suspend rollout", func() {
|
||||||
|
r := kruisev1alpha1.Rollout{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "my-rollout"}, &r)).Should(BeNil())
|
||||||
|
r.Status.Phase = kruisev1alpha1.RolloutPhaseProgressing
|
||||||
|
Expect(k8sClient.Status().Update(ctx, &r)).Should(BeNil())
|
||||||
|
Expect(SuspendRollout(ctx, k8sClient, &app, nil))
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "my-rollout"}, &r))
|
||||||
|
Expect(r.Spec.Strategy.Paused).Should(BeEquivalentTo(true))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Resume rollout", func() {
|
||||||
|
r := kruisev1alpha1.Rollout{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "my-rollout"}, &r)).Should(BeNil())
|
||||||
|
Expect(r.Spec.Strategy.Paused).Should(BeEquivalentTo(true))
|
||||||
|
Expect(ResumeRollout(ctx, k8sClient, &app, nil))
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "my-rollout"}, &r))
|
||||||
|
Expect(r.Spec.Strategy.Paused).Should(BeEquivalentTo(false))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Rollback rollout", func() {
|
||||||
|
r := kruisev1alpha1.Rollout{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "my-rollout"}, &r)).Should(BeNil())
|
||||||
|
r.Spec.Strategy.Paused = true
|
||||||
|
Expect(k8sClient.Update(ctx, &r)).Should(BeNil())
|
||||||
|
Expect(RollbackRollout(ctx, k8sClient, &app, nil))
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "my-rollout"}, &r))
|
||||||
|
Expect(r.Spec.Strategy.Paused).Should(BeEquivalentTo(false))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
var app = v1beta1.Application{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: "core.oam.dev/v1beta1",
|
||||||
|
Kind: "Application",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "rollout-app",
|
||||||
|
Namespace: "default",
|
||||||
|
Generation: 1,
|
||||||
|
},
|
||||||
|
Spec: v1beta1.ApplicationSpec{
|
||||||
|
Components: []common.ApplicationComponent{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var rt = v1beta1.ResourceTracker{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: "core.oam.dev/v1beta1",
|
||||||
|
Kind: "ResourceTracker",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "rollout-app",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"app.oam.dev/appRevision": "rollout-app-v1",
|
||||||
|
"app.oam.dev/name": "rollout-app",
|
||||||
|
"app.oam.dev/namespace": "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: v1beta1.ResourceTrackerSpec{
|
||||||
|
ApplicationGeneration: 1,
|
||||||
|
Type: v1beta1.ResourceTrackerTypeVersioned,
|
||||||
|
ManagedResources: []v1beta1.ManagedResource{
|
||||||
|
{
|
||||||
|
ClusterObjectReference: common.ClusterObjectReference{
|
||||||
|
ObjectReference: v1.ObjectReference{
|
||||||
|
APIVersion: "rollouts.kruise.io/v1alpha1",
|
||||||
|
Kind: "Rollout",
|
||||||
|
Name: "my-rollout",
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OAMObjectReference: common.OAMObjectReference{
|
||||||
|
Component: "my-rollout",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var rollout = kruisev1alpha1.Rollout{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: "rollouts.kruise.io/v1alpha1",
|
||||||
|
Kind: "Rollout",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "my-rollout",
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
Spec: kruisev1alpha1.RolloutSpec{
|
||||||
|
ObjectRef: kruisev1alpha1.ObjectRef{
|
||||||
|
WorkloadRef: &kruisev1alpha1.WorkloadRef{
|
||||||
|
APIVersion: "appsv1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
Name: "canary-demo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Strategy: kruisev1alpha1.RolloutStrategy{
|
||||||
|
Canary: &kruisev1alpha1.CanaryStrategy{
|
||||||
|
Steps: []kruisev1alpha1.CanaryStep{
|
||||||
|
{
|
||||||
|
Weight: 30,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Paused: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 The KubeVela 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 rollout
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/client-go/discovery"
|
||||||
|
ocmclusterv1 "open-cluster-management.io/api/cluster/v1"
|
||||||
|
ocmclusterv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
|
||||||
|
ocmworkv1 "open-cluster-management.io/api/work/v1"
|
||||||
|
|
||||||
|
v12 "k8s.io/api/core/v1"
|
||||||
|
crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
|
||||||
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||||
|
|
||||||
|
kruisev1alpha1 "github.com/openkruise/rollouts/api/v1alpha1"
|
||||||
|
|
||||||
|
coreoam "github.com/oam-dev/kubevela/apis/core.oam.dev"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/cue/packages"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||||
|
// +kubebuilder:scaffold:imports
|
||||||
|
)
|
||||||
|
|
||||||
|
var cfg *rest.Config
|
||||||
|
var scheme *runtime.Scheme
|
||||||
|
var k8sClient client.Client
|
||||||
|
var testEnv *envtest.Environment
|
||||||
|
var dm discoverymapper.DiscoveryMapper
|
||||||
|
var pd *packages.PackageDiscover
|
||||||
|
var testns string
|
||||||
|
var dc *discovery.DiscoveryClient
|
||||||
|
|
||||||
|
func TestAddon(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecsWithDefaultAndCustomReporters(t,
|
||||||
|
"Kruise rollout Suite test",
|
||||||
|
[]Reporter{printer.NewlineReporter{}})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = BeforeSuite(func(done Done) {
|
||||||
|
logf.SetLogger(zap.New(zap.UseDevMode(true), zap.WriteTo(GinkgoWriter)))
|
||||||
|
By("bootstrapping test environment")
|
||||||
|
useExistCluster := false
|
||||||
|
testEnv = &envtest.Environment{
|
||||||
|
ControlPlaneStartTimeout: time.Minute,
|
||||||
|
ControlPlaneStopTimeout: time.Minute,
|
||||||
|
CRDDirectoryPaths: []string{filepath.Join("..", "..", "charts", "vela-core", "crds"), filepath.Join("", "testdata")},
|
||||||
|
UseExistingCluster: &useExistCluster,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
cfg, err = testEnv.Start()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(cfg).ToNot(BeNil())
|
||||||
|
scheme = runtime.NewScheme()
|
||||||
|
Expect(coreoam.AddToScheme(scheme)).NotTo(HaveOccurred())
|
||||||
|
Expect(clientgoscheme.AddToScheme(scheme)).NotTo(HaveOccurred())
|
||||||
|
Expect(crdv1.AddToScheme(scheme)).NotTo(HaveOccurred())
|
||||||
|
_ = ocmclusterv1alpha1.Install(scheme)
|
||||||
|
_ = ocmclusterv1.Install(scheme)
|
||||||
|
_ = ocmworkv1.Install(scheme)
|
||||||
|
_ = kruisev1alpha1.AddToScheme(scheme)
|
||||||
|
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(k8sClient).ToNot(BeNil())
|
||||||
|
|
||||||
|
dc, err = discovery.NewDiscoveryClientForConfig(cfg)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(dc).ShouldNot(BeNil())
|
||||||
|
|
||||||
|
dm, err = discoverymapper.New(cfg)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(dm).ToNot(BeNil())
|
||||||
|
pd, err = packages.NewPackageDiscover(cfg)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(pd).ToNot(BeNil())
|
||||||
|
testns = "vela-system"
|
||||||
|
Expect(k8sClient.Create(context.Background(),
|
||||||
|
&v12.Namespace{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Namespace"}, ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: testns,
|
||||||
|
}}))
|
||||||
|
|
||||||
|
close(done)
|
||||||
|
}, 120)
|
||||||
|
|
||||||
|
var _ = AfterSuite(func() {
|
||||||
|
By("tearing down the test environment")
|
||||||
|
err := testEnv.Stop()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,290 @@
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.7.0
|
||||||
|
creationTimestamp: null
|
||||||
|
name: rollouts.rollouts.kruise.io
|
||||||
|
spec:
|
||||||
|
group: rollouts.kruise.io
|
||||||
|
names:
|
||||||
|
kind: Rollout
|
||||||
|
listKind: RolloutList
|
||||||
|
plural: rollouts
|
||||||
|
singular: rollout
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- additionalPrinterColumns:
|
||||||
|
- description: The rollout status phase
|
||||||
|
jsonPath: .status.phase
|
||||||
|
name: STATUS
|
||||||
|
type: string
|
||||||
|
- description: The rollout canary status step
|
||||||
|
jsonPath: .status.canaryStatus.currentStepIndex
|
||||||
|
name: CANARY_STEP
|
||||||
|
type: integer
|
||||||
|
- description: The rollout canary status step state
|
||||||
|
jsonPath: .status.canaryStatus.currentStepState
|
||||||
|
name: CANARY_STATE
|
||||||
|
type: string
|
||||||
|
- description: The rollout canary status message
|
||||||
|
jsonPath: .status.message
|
||||||
|
name: MESSAGE
|
||||||
|
type: string
|
||||||
|
- jsonPath: .metadata.creationTimestamp
|
||||||
|
name: AGE
|
||||||
|
type: date
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: Rollout is the Schema for the rollouts API
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: 'APIVersion defines the versioned schema of this representation
|
||||||
|
of an object. Servers should convert recognized schemas to the latest
|
||||||
|
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: 'Kind is a string value representing the REST resource this
|
||||||
|
object represents. Servers may infer this from the endpoint the client
|
||||||
|
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||||
|
type: string
|
||||||
|
metadata:
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
description: RolloutSpec defines the desired state of Rollout
|
||||||
|
properties:
|
||||||
|
objectRef:
|
||||||
|
description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
||||||
|
Important: Run "make" to regenerate code after modifying this file
|
||||||
|
ObjectRef indicates workload'
|
||||||
|
properties:
|
||||||
|
workloadRef:
|
||||||
|
description: WorkloadRef contains enough information to let you
|
||||||
|
identify a workload for Rollout Batch release of the bypass
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: API Version of the referent
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: Kind of the referent
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: Name of the referent
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- apiVersion
|
||||||
|
- kind
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
strategy:
|
||||||
|
description: rollout strategy
|
||||||
|
properties:
|
||||||
|
canary:
|
||||||
|
description: CanaryStrategy defines parameters for a Replica Based
|
||||||
|
Canary
|
||||||
|
properties:
|
||||||
|
steps:
|
||||||
|
description: Steps define the order of phases to execute release
|
||||||
|
in batches(20%, 40%, 60%, 80%, 100%)
|
||||||
|
items:
|
||||||
|
description: CanaryStep defines a step of a canary workload.
|
||||||
|
properties:
|
||||||
|
pause:
|
||||||
|
description: Pause defines a pause stage for a rollout,
|
||||||
|
manual or auto
|
||||||
|
properties:
|
||||||
|
duration:
|
||||||
|
description: Duration the amount of time to wait
|
||||||
|
before moving to the next step.
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
replicas:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
description: 'Replicas is the number of expected canary
|
||||||
|
pods in this batch it can be an absolute number (ex:
|
||||||
|
5) or a percentage of total pods.'
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
weight:
|
||||||
|
description: SetWeight sets what percentage of the canary
|
||||||
|
pods should receive
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
trafficRoutings:
|
||||||
|
description: TrafficRoutings hosts all the supported service
|
||||||
|
meshes supported to enable more fine-grained traffic routing
|
||||||
|
todo current only support one
|
||||||
|
items:
|
||||||
|
description: TrafficRouting hosts all the different configuration
|
||||||
|
for supported service meshes to enable more fine-grained
|
||||||
|
traffic routing
|
||||||
|
properties:
|
||||||
|
gracePeriodSeconds:
|
||||||
|
description: Optional duration in seconds the traffic
|
||||||
|
provider(e.g. nginx ingress controller) consumes the
|
||||||
|
service, ingress configuration changes gracefully.
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
ingress:
|
||||||
|
description: Ingress holds Ingress specific configuration
|
||||||
|
to route traffic, e.g. Nginx, Alb.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name refers to the name of an `Ingress`
|
||||||
|
resource in the same namespace as the `Rollout`
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
service:
|
||||||
|
description: Service holds the name of a service which
|
||||||
|
selects pods with stable version and don't select
|
||||||
|
any pods with canary version.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: nginx, alb, istio etc.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- service
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
paused:
|
||||||
|
description: Paused indicates that the Rollout is paused. Default
|
||||||
|
value is false
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- objectRef
|
||||||
|
- strategy
|
||||||
|
type: object
|
||||||
|
status:
|
||||||
|
description: RolloutStatus defines the observed state of Rollout
|
||||||
|
properties:
|
||||||
|
canaryStatus:
|
||||||
|
description: Canary describes the state of the canary rollout
|
||||||
|
properties:
|
||||||
|
canaryReadyReplicas:
|
||||||
|
description: CanaryReadyReplicas the numbers of ready canary revision
|
||||||
|
pods
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
canaryReplicas:
|
||||||
|
description: CanaryReplicas the numbers of canary revision pods
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
canaryRevision:
|
||||||
|
description: CanaryRevision is calculated by rollout based on
|
||||||
|
podTemplateHash, and the internal logic flow uses It may be
|
||||||
|
different from rs podTemplateHash in different k8s versions,
|
||||||
|
so it cannot be used as service selector label
|
||||||
|
type: string
|
||||||
|
canaryService:
|
||||||
|
description: CanaryService holds the name of a service which selects
|
||||||
|
pods with canary version and don't select any pods with stable
|
||||||
|
version.
|
||||||
|
type: string
|
||||||
|
currentStepIndex:
|
||||||
|
description: CurrentStepIndex defines the current step of the
|
||||||
|
rollout is on. If the current step index is null, the controller
|
||||||
|
will execute the rollout.
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
currentStepState:
|
||||||
|
type: string
|
||||||
|
lastReadyTime:
|
||||||
|
description: The last time this step pods is ready.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
observedWorkloadGeneration:
|
||||||
|
description: observedWorkloadGeneration is the most recent generation
|
||||||
|
observed for this Rollout ref workload generation.
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
podTemplateHash:
|
||||||
|
description: pod template hash is used as service selector label
|
||||||
|
type: string
|
||||||
|
rolloutHash:
|
||||||
|
description: RolloutHash from rollout.spec object
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- canaryReadyReplicas
|
||||||
|
- canaryReplicas
|
||||||
|
- canaryService
|
||||||
|
- currentStepState
|
||||||
|
- podTemplateHash
|
||||||
|
type: object
|
||||||
|
conditions:
|
||||||
|
description: Conditions a list of conditions a rollout can have.
|
||||||
|
items:
|
||||||
|
description: RolloutCondition describes the state of a rollout at
|
||||||
|
a certain point.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: Last time the condition transitioned from one status
|
||||||
|
to another.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
lastUpdateTime:
|
||||||
|
description: The last time this condition was updated.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: A human readable message indicating details about
|
||||||
|
the transition.
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: The reason for the condition's last transition.
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: Phase of the condition, one of True, False, Unknown.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: Type of rollout condition.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
message:
|
||||||
|
description: Message provides details on why the rollout is in its
|
||||||
|
current phase
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: observedGeneration is the most recent generation observed
|
||||||
|
for this Rollout.
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
phase:
|
||||||
|
description: BlueGreenStatus *BlueGreenStatus `json:"blueGreenStatus,omitempty"`
|
||||||
|
Phase is the rollout phase.
|
||||||
|
type: string
|
||||||
|
stableRevision:
|
||||||
|
description: CanaryRevision the hash of the canary pod template CanaryRevision
|
||||||
|
string `json:"canaryRevision,omitempty"` StableRevision indicates
|
||||||
|
the revision pods that has successfully rolled out
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
status:
|
||||||
|
acceptedNames:
|
||||||
|
kind: ""
|
||||||
|
plural: ""
|
||||||
|
conditions: []
|
||||||
|
storedVersions: []
|
||||||
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/hashicorp/hcl/v2/hclparse"
|
"github.com/hashicorp/hcl/v2/hclparse"
|
||||||
"github.com/oam-dev/terraform-config-inspect/tfconfig"
|
"github.com/oam-dev/terraform-config-inspect/tfconfig"
|
||||||
kruise "github.com/openkruise/kruise-api/apps/v1alpha1"
|
kruise "github.com/openkruise/kruise-api/apps/v1alpha1"
|
||||||
|
kruisev1alpha1 "github.com/openkruise/rollouts/api/v1alpha1"
|
||||||
errors2 "github.com/pkg/errors"
|
errors2 "github.com/pkg/errors"
|
||||||
certmanager "github.com/wonderflow/cert-manager-api/pkg/apis/certmanager/v1"
|
certmanager "github.com/wonderflow/cert-manager-api/pkg/apis/certmanager/v1"
|
||||||
istioclientv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
|
istioclientv1beta1 "istio.io/client-go/pkg/apis/networking/v1beta1"
|
||||||
|
|
@ -102,6 +103,7 @@ func init() {
|
||||||
_ = ocmworkv1.Install(Scheme)
|
_ = ocmworkv1.Install(Scheme)
|
||||||
_ = clustergatewayapi.AddToScheme(Scheme)
|
_ = clustergatewayapi.AddToScheme(Scheme)
|
||||||
_ = metricsV1beta1api.AddToScheme(Scheme)
|
_ = metricsV1beta1api.AddToScheme(Scheme)
|
||||||
|
_ = kruisev1alpha1.AddToScheme(Scheme)
|
||||||
_ = prismclusterv1alpha1.AddToScheme(Scheme)
|
_ = prismclusterv1alpha1.AddToScheme(Scheme)
|
||||||
// +kubebuilder:scaffold:scheme
|
// +kubebuilder:scaffold:scheme
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ func init() {
|
||||||
{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "RoleBinding"}: nil,
|
{APIVersion: "rbac.authorization.k8s.io/v1", Kind: "RoleBinding"}: nil,
|
||||||
},
|
},
|
||||||
DefaultGenListOptionFunc: helmRelease2AnyListOption,
|
DefaultGenListOptionFunc: helmRelease2AnyListOption,
|
||||||
|
DisableFilterByOwnerReference: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,6 +118,8 @@ type ChildrenResourcesRule struct {
|
||||||
CareResource map[ResourceType]genListOptionFunc
|
CareResource map[ResourceType]genListOptionFunc
|
||||||
// if specified genListOptionFunc is nil will use use default genListOptionFunc to generate listOption.
|
// if specified genListOptionFunc is nil will use use default genListOptionFunc to generate listOption.
|
||||||
DefaultGenListOptionFunc genListOptionFunc
|
DefaultGenListOptionFunc genListOptionFunc
|
||||||
|
// DisableFilterByOwnerReference means don't use parent resource's UID filter the result.
|
||||||
|
DisableFilterByOwnerReference bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type genListOptionFunc func(unstructured.Unstructured) (client.ListOptions, error)
|
type genListOptionFunc func(unstructured.Unstructured) (client.ListOptions, error)
|
||||||
|
|
@ -618,7 +621,7 @@ func fetchObjectWithResourceTreeNode(ctx context.Context, cluster string, k8sCli
|
||||||
}
|
}
|
||||||
|
|
||||||
func listItemByRule(clusterCTX context.Context, k8sClient client.Client, resource ResourceType,
|
func listItemByRule(clusterCTX context.Context, k8sClient client.Client, resource ResourceType,
|
||||||
parentObject unstructured.Unstructured, specifiedFunc genListOptionFunc, defaultFunc genListOptionFunc) ([]unstructured.Unstructured, error) {
|
parentObject unstructured.Unstructured, specifiedFunc genListOptionFunc, defaultFunc genListOptionFunc, disableFilterByOwner bool) ([]unstructured.Unstructured, error) {
|
||||||
|
|
||||||
itemList := unstructured.UnstructuredList{}
|
itemList := unstructured.UnstructuredList{}
|
||||||
itemList.SetAPIVersion(resource.APIVersion)
|
itemList.SetAPIVersion(resource.APIVersion)
|
||||||
|
|
@ -657,6 +660,20 @@ func listItemByRule(clusterCTX context.Context, k8sClient client.Client, resourc
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if !disableFilterByOwner {
|
||||||
|
var res []unstructured.Unstructured
|
||||||
|
for _, item := range itemList.Items {
|
||||||
|
if len(item.GetOwnerReferences()) == 0 {
|
||||||
|
res = append(res, item)
|
||||||
|
}
|
||||||
|
for _, reference := range item.GetOwnerReferences() {
|
||||||
|
if reference.UID == parentObject.GetUID() {
|
||||||
|
res = append(res, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
return itemList.Items, nil
|
return itemList.Items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -676,7 +693,7 @@ func iteratorChildResources(ctx context.Context, cluster string, k8sClient clien
|
||||||
var resList []*types.ResourceTreeNode
|
var resList []*types.ResourceTreeNode
|
||||||
for resource, specifiedFunc := range rules.CareResource {
|
for resource, specifiedFunc := range rules.CareResource {
|
||||||
clusterCTX := multicluster.ContextWithClusterName(ctx, cluster)
|
clusterCTX := multicluster.ContextWithClusterName(ctx, cluster)
|
||||||
items, err := listItemByRule(clusterCTX, k8sClient, resource, *parentObject, specifiedFunc, rules.DefaultGenListOptionFunc)
|
items, err := listItemByRule(clusterCTX, k8sClient, resource, *parentObject, specifiedFunc, rules.DefaultGenListOptionFunc, rules.DisableFilterByOwnerReference)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if meta.IsNoMatchError(err) || runtime.IsNotRegisteredError(err) {
|
if meta.IsNoMatchError(err) || runtime.IsNotRegisteredError(err) {
|
||||||
log.Logger.Errorf("error to list subresources: %s err: %v", resource.Kind, err)
|
log.Logger.Errorf("error to list subresources: %s err: %v", resource.Kind, err)
|
||||||
|
|
|
||||||
|
|
@ -1266,14 +1266,14 @@ var _ = Describe("unit-test to e2e test", func() {
|
||||||
u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deploy1.DeepCopy())
|
u, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deploy1.DeepCopy())
|
||||||
Expect(err).Should(BeNil())
|
Expect(err).Should(BeNil())
|
||||||
items, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "apps/v1", Kind: "ReplicaSet"}, unstructured.Unstructured{Object: u},
|
items, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "apps/v1", Kind: "ReplicaSet"}, unstructured.Unstructured{Object: u},
|
||||||
deploy2RsLabelListOption, nil)
|
deploy2RsLabelListOption, nil, true)
|
||||||
Expect(err).Should(BeNil())
|
Expect(err).Should(BeNil())
|
||||||
Expect(len(items)).Should(BeEquivalentTo(2))
|
Expect(len(items)).Should(BeEquivalentTo(2))
|
||||||
|
|
||||||
u2, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deploy2.DeepCopy())
|
u2, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deploy2.DeepCopy())
|
||||||
Expect(err).Should(BeNil())
|
Expect(err).Should(BeNil())
|
||||||
items2, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "apps/v1", Kind: "ReplicaSet"}, unstructured.Unstructured{Object: u2},
|
items2, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "apps/v1", Kind: "ReplicaSet"}, unstructured.Unstructured{Object: u2},
|
||||||
nil, deploy2RsLabelListOption)
|
nil, deploy2RsLabelListOption, true)
|
||||||
Expect(len(items2)).Should(BeEquivalentTo(1))
|
Expect(len(items2)).Should(BeEquivalentTo(1))
|
||||||
|
|
||||||
// test use ownerReference UId to filter
|
// test use ownerReference UId to filter
|
||||||
|
|
@ -1285,7 +1285,7 @@ var _ = Describe("unit-test to e2e test", func() {
|
||||||
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: u3.GetNamespace(), Name: u3.GetName()}, &u3))
|
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: u3.GetNamespace(), Name: u3.GetName()}, &u3))
|
||||||
Expect(err).Should(BeNil())
|
Expect(err).Should(BeNil())
|
||||||
items3, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "v1", Kind: "Pod"}, u3,
|
items3, err := listItemByRule(ctx, k8sClient, ResourceType{APIVersion: "v1", Kind: "Pod"}, u3,
|
||||||
nil, nil)
|
nil, nil, true)
|
||||||
Expect(err).Should(BeNil())
|
Expect(err).Should(BeNil())
|
||||||
Expect(len(items3)).Should(BeEquivalentTo(1))
|
Expect(len(items3)).Should(BeEquivalentTo(1))
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,289 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 The KubeVela 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 operation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"k8s.io/client-go/util/retry"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
|
||||||
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||||
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/apiserver/domain/service"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2/application"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/controller/utils"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/oam"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/resourcetracker"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/rollout"
|
||||||
|
errors3 "github.com/oam-dev/kubevela/pkg/utils/errors"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// WorkflowOperator is opratior handler for workflow's resume/rollback/restart
|
||||||
|
type WorkflowOperator interface {
|
||||||
|
Suspend(ctx context.Context, app *v1beta1.Application) error
|
||||||
|
Resume(ctx context.Context, app *v1beta1.Application) error
|
||||||
|
Rollback(ctx context.Context, app *v1beta1.Application) error
|
||||||
|
Restart(ctx context.Context, app *v1beta1.Application) error
|
||||||
|
Terminate(ctx context.Context, app *v1beta1.Application) error
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewWorkflowOperator get an workflow operator with k8sClient and ioWriter(optional, useful for cli)
|
||||||
|
func NewWorkflowOperator(cli client.Client, w io.Writer) WorkflowOperator {
|
||||||
|
return wfOperator{cli: cli, outputWriter: w}
|
||||||
|
}
|
||||||
|
|
||||||
|
type wfOperator struct {
|
||||||
|
cli client.Client
|
||||||
|
outputWriter io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Suspend a running workflow
|
||||||
|
func (wo wfOperator) Suspend(ctx context.Context, app *v1beta1.Application) error {
|
||||||
|
if app.Status.Workflow == nil {
|
||||||
|
return fmt.Errorf("the workflow in application is not running")
|
||||||
|
}
|
||||||
|
var err error
|
||||||
|
if err = rollout.SuspendRollout(context.Background(), wo.cli, app, wo.outputWriter); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
appKey := client.ObjectKeyFromObject(app)
|
||||||
|
if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||||
|
if err := wo.cli.Get(ctx, appKey, app); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// set the workflow suspend to true
|
||||||
|
app.Status.Workflow.Suspend = true
|
||||||
|
return wo.cli.Status().Patch(ctx, app, client.Merge)
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return wo.writeOutputF("Successfully suspend workflow: %s\n", app.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resume a suspending workflow
|
||||||
|
func (wo wfOperator) Resume(ctx context.Context, app *v1beta1.Application) error {
|
||||||
|
if app.Status.Workflow == nil {
|
||||||
|
return fmt.Errorf("the workflow in application is not running")
|
||||||
|
}
|
||||||
|
if app.Status.Workflow.Terminated {
|
||||||
|
return fmt.Errorf("can not resume a terminated workflow")
|
||||||
|
}
|
||||||
|
|
||||||
|
var rolloutResumed bool
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if rolloutResumed, err = rollout.ResumeRollout(context.Background(), wo.cli, app, wo.outputWriter); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !rolloutResumed && !app.Status.Workflow.Suspend {
|
||||||
|
return wo.writeOutput("the workflow is not suspending")
|
||||||
|
}
|
||||||
|
|
||||||
|
if app.Status.Workflow.Suspend {
|
||||||
|
if err = service.ResumeWorkflow(ctx, wo.cli, app); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rollback a running in middle state workflow.
|
||||||
|
//nolint
|
||||||
|
func (wo wfOperator) Rollback(ctx context.Context, app *v1beta1.Application) error {
|
||||||
|
if oam.GetPublishVersion(app) == "" {
|
||||||
|
return fmt.Errorf("app without public version cannot rollback")
|
||||||
|
}
|
||||||
|
|
||||||
|
appRevs, err := application.GetSortedAppRevisions(ctx, wo.cli, app.Name, app.Namespace)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to list revisions for application %s/%s", app.Namespace, app.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// find succeeded revision to rollback
|
||||||
|
var rev *v1beta1.ApplicationRevision
|
||||||
|
var outdatedRev []*v1beta1.ApplicationRevision
|
||||||
|
for i := range appRevs {
|
||||||
|
candidate := appRevs[len(appRevs)-i-1]
|
||||||
|
_rev := candidate.DeepCopy()
|
||||||
|
if !candidate.Status.Succeeded || oam.GetPublishVersion(_rev) == "" {
|
||||||
|
outdatedRev = append(outdatedRev, _rev)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rev = _rev
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if rev == nil {
|
||||||
|
return errors.Errorf("failed to find previous succeeded revision for application %s/%s", app.Namespace, app.Name)
|
||||||
|
}
|
||||||
|
publishVersion := oam.GetPublishVersion(rev)
|
||||||
|
revisionNumber, err := utils.ExtractRevision(rev.Name)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to extract revision number from revision %s", rev.Name)
|
||||||
|
}
|
||||||
|
_, currentRT, historyRTs, _, err := resourcetracker.ListApplicationResourceTrackers(ctx, wo.cli, app)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to list resource trackers for application %s/%s", app.Namespace, app.Name)
|
||||||
|
}
|
||||||
|
var matchRT *v1beta1.ResourceTracker
|
||||||
|
for _, rt := range append(historyRTs, currentRT) {
|
||||||
|
if rt == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
labels := rt.GetLabels()
|
||||||
|
if labels != nil && labels[oam.LabelAppRevision] == rev.Name {
|
||||||
|
matchRT = rt.DeepCopy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if matchRT == nil {
|
||||||
|
return errors.Errorf("cannot find resource tracker for previous revision %s, unable to rollback", rev.Name)
|
||||||
|
}
|
||||||
|
if matchRT.DeletionTimestamp != nil {
|
||||||
|
return errors.Errorf("previous revision %s is being recycled, unable to rollback", rev.Name)
|
||||||
|
}
|
||||||
|
err = wo.writeOutput("Find succeeded application revision %s (PublishVersion: %s) to rollback.\n")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
appKey := client.ObjectKeyFromObject(app)
|
||||||
|
// rollback application spec and freeze
|
||||||
|
controllerRequirement, err := utils.FreezeApplication(ctx, wo.cli, app, func() {
|
||||||
|
app.Spec = rev.Spec.Application.Spec
|
||||||
|
oam.SetPublishVersion(app, publishVersion)
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to rollback application spec to revision %s (PublishVersion: %s)", rev.Name, publishVersion)
|
||||||
|
}
|
||||||
|
err = wo.writeOutput("Application spec rollback successfully.\n")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// rollback application status
|
||||||
|
if err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||||
|
if err = wo.cli.Get(ctx, appKey, app); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
app.Status.Workflow = rev.Status.Workflow
|
||||||
|
app.Status.Services = []common.ApplicationComponentStatus{}
|
||||||
|
app.Status.AppliedResources = []common.ClusterObjectReference{}
|
||||||
|
for _, rsc := range matchRT.Spec.ManagedResources {
|
||||||
|
app.Status.AppliedResources = append(app.Status.AppliedResources, rsc.ClusterObjectReference)
|
||||||
|
}
|
||||||
|
app.Status.LatestRevision = &common.Revision{
|
||||||
|
Name: rev.Name,
|
||||||
|
Revision: int64(revisionNumber),
|
||||||
|
RevisionHash: rev.GetLabels()[oam.LabelAppRevisionHash],
|
||||||
|
}
|
||||||
|
return wo.cli.Status().Update(ctx, app)
|
||||||
|
}); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to rollback application status to revision %s (PublishVersion: %s)", rev.Name, publishVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
err = wo.writeOutput("Application status rollback successfully.\n")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// update resource tracker generation
|
||||||
|
matchRTKey := client.ObjectKeyFromObject(matchRT)
|
||||||
|
if err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||||
|
if err = wo.cli.Get(ctx, matchRTKey, matchRT); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
matchRT.Spec.ApplicationGeneration = app.Generation
|
||||||
|
return wo.cli.Update(ctx, matchRT)
|
||||||
|
}); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to update application generation in resource tracker")
|
||||||
|
}
|
||||||
|
|
||||||
|
// unfreeze application
|
||||||
|
if err = utils.UnfreezeApplication(ctx, wo.cli, app, nil, controllerRequirement); err != nil {
|
||||||
|
return errors.Wrapf(err, "failed to resume application to restart")
|
||||||
|
}
|
||||||
|
|
||||||
|
rollback, err := rollout.RollbackRollout(ctx, wo.cli, app, wo.outputWriter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if rollback {
|
||||||
|
err = wo.writeOutput("Successfully rollback rollout")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clean up outdated revisions
|
||||||
|
var errs errors3.ErrorList
|
||||||
|
for _, _rev := range outdatedRev {
|
||||||
|
if err = wo.cli.Delete(ctx, _rev); err != nil {
|
||||||
|
errs = append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if errs.HasError() {
|
||||||
|
return errors.Wrapf(errs, "failed to clean up outdated revisions")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = wo.writeOutput("Application outdated revision cleaned up.\n")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restart a terminated or finished workflow.
|
||||||
|
func (wo wfOperator) Restart(ctx context.Context, app *v1beta1.Application) error {
|
||||||
|
if app.Status.Workflow == nil {
|
||||||
|
return fmt.Errorf("the workflow in application is not running")
|
||||||
|
}
|
||||||
|
// reset the workflow status to restart the workflow
|
||||||
|
app.Status.Workflow = nil
|
||||||
|
|
||||||
|
if err := wo.cli.Status().Update(context.TODO(), app); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return wo.writeOutputF("Successfully restart workflow: %s\n", app.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wo wfOperator) Terminate(ctx context.Context, app *v1beta1.Application) error {
|
||||||
|
if err := service.TerminateWorkflow(context.TODO(), wo.cli, app); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wo wfOperator) writeOutput(str string) error {
|
||||||
|
if wo.outputWriter == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err := wo.outputWriter.Write([]byte(str))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (wo wfOperator) writeOutputF(format string, a ...interface{}) error {
|
||||||
|
if wo.outputWriter == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
_, err := wo.outputWriter.Write([]byte(fmt.Sprintf(format, a...)))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,215 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 The KubeVela 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 operation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
kruisev1alpha1 "github.com/openkruise/rollouts/api/v1alpha1"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
|
||||||
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||||
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/oam"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Kruise rollout test", func() {
|
||||||
|
ctx := context.Background()
|
||||||
|
BeforeEach(func() {
|
||||||
|
Expect(k8sClient.Create(ctx, myRollout.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
|
||||||
|
Expect(k8sClient.Create(ctx, rt.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
|
||||||
|
Expect(k8sClient.Create(ctx, app.DeepCopy())).Should(SatisfyAny(BeNil(), util.AlreadyExistMatcher{}))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Suspend workflow", func() {
|
||||||
|
checkApp := v1beta1.Application{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app"}, &checkApp)).Should(BeNil())
|
||||||
|
checkApp.Status.Workflow = &common.WorkflowStatus{Suspend: false, StartTime: metav1.Now()}
|
||||||
|
Expect(k8sClient.Status().Update(ctx, &checkApp)).Should(BeNil())
|
||||||
|
operator := NewWorkflowOperator(k8sClient, nil)
|
||||||
|
checkApp = v1beta1.Application{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app"}, &checkApp)).Should(BeNil())
|
||||||
|
Expect(operator.Suspend(ctx, checkApp.DeepCopy())).Should(BeNil())
|
||||||
|
checkApp = v1beta1.Application{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app"}, &checkApp)).Should(BeNil())
|
||||||
|
Expect(checkApp.Status.Workflow.Suspend).Should(BeEquivalentTo(true))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Resume workflow", func() {
|
||||||
|
checkApp := v1beta1.Application{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app"}, &checkApp)).Should(BeNil())
|
||||||
|
operator := NewWorkflowOperator(k8sClient, nil)
|
||||||
|
Expect(operator.Resume(ctx, &checkApp)).Should(BeNil())
|
||||||
|
checkApp = v1beta1.Application{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app"}, &checkApp)).Should(BeNil())
|
||||||
|
Expect(checkApp.Status.Workflow.Suspend).Should(BeEquivalentTo(false))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Terminate workflow", func() {
|
||||||
|
checkApp := v1beta1.Application{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app"}, &checkApp)).Should(BeNil())
|
||||||
|
operator := NewWorkflowOperator(k8sClient, nil)
|
||||||
|
Expect(operator.Terminate(ctx, &checkApp)).Should(BeNil())
|
||||||
|
checkApp = v1beta1.Application{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app"}, &checkApp)).Should(BeNil())
|
||||||
|
Expect(checkApp.Status.Workflow.Terminated).Should(BeEquivalentTo(true))
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Restart workflow", func() {
|
||||||
|
checkApp := v1beta1.Application{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app"}, &checkApp)).Should(BeNil())
|
||||||
|
operator := NewWorkflowOperator(k8sClient, nil)
|
||||||
|
Expect(operator.Restart(ctx, &checkApp)).Should(BeNil())
|
||||||
|
checkApp = v1beta1.Application{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app"}, &checkApp)).Should(BeNil())
|
||||||
|
Expect(checkApp.Status.Workflow).Should(BeNil())
|
||||||
|
})
|
||||||
|
|
||||||
|
It("Rollback workflow", func() {
|
||||||
|
Expect(k8sClient.Create(ctx, &appRev)).Should(BeNil())
|
||||||
|
checkAppRev := v1beta1.ApplicationRevision{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app-v1"}, &checkAppRev)).Should(BeNil())
|
||||||
|
checkAppRev.Status.Succeeded = true
|
||||||
|
Expect(k8sClient.Status().Update(ctx, checkAppRev.DeepCopy())).Should(BeNil())
|
||||||
|
|
||||||
|
checkApp := v1beta1.Application{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app"}, &checkApp)).Should(BeNil())
|
||||||
|
checkApp.Annotations = map[string]string{
|
||||||
|
oam.AnnotationPublishVersion: "v2",
|
||||||
|
}
|
||||||
|
operator := NewWorkflowOperator(k8sClient, nil)
|
||||||
|
Expect(operator.Rollback(ctx, checkApp.DeepCopy())).Should(BeNil())
|
||||||
|
|
||||||
|
checkApp = v1beta1.Application{}
|
||||||
|
Expect(k8sClient.Get(ctx, types.NamespacedName{Namespace: "default", Name: "opt-app"}, &checkApp)).Should(BeNil())
|
||||||
|
// must rollback to v1
|
||||||
|
Expect(oam.GetPublishVersion(&checkApp)).Should(BeEquivalentTo("v1"))
|
||||||
|
Expect(checkApp.Status.LatestRevision.Name).Should(BeEquivalentTo("opt-app-v1"))
|
||||||
|
Expect(checkApp.Status.LatestRevision.Revision).Should(BeEquivalentTo(1))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
var app = v1beta1.Application{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: "core.oam.dev/v1beta1",
|
||||||
|
Kind: "Application",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "opt-app",
|
||||||
|
Namespace: "default",
|
||||||
|
Generation: 1,
|
||||||
|
Labels: map[string]string{
|
||||||
|
oam.AnnotationPublishVersion: "v2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: v1beta1.ApplicationSpec{
|
||||||
|
Components: []common.ApplicationComponent{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var rt = v1beta1.ResourceTracker{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: "core.oam.dev/v1beta1",
|
||||||
|
Kind: "ResourceTracker",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "rollout-app",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"app.oam.dev/appRevision": "opt-app-v1",
|
||||||
|
"app.oam.dev/name": "opt-app",
|
||||||
|
"app.oam.dev/namespace": "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: v1beta1.ResourceTrackerSpec{
|
||||||
|
ApplicationGeneration: 1,
|
||||||
|
Type: v1beta1.ResourceTrackerTypeVersioned,
|
||||||
|
ManagedResources: []v1beta1.ManagedResource{
|
||||||
|
{
|
||||||
|
ClusterObjectReference: common.ClusterObjectReference{
|
||||||
|
ObjectReference: v1.ObjectReference{
|
||||||
|
APIVersion: "rollouts.kruise.io/v1alpha1",
|
||||||
|
Kind: "Rollout",
|
||||||
|
Name: "my-rollout",
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OAMObjectReference: common.OAMObjectReference{
|
||||||
|
Component: "my-rollout",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var appRev = v1beta1.ApplicationRevision{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: "core.oam.dev/v1beta1",
|
||||||
|
Kind: "ApplicationRevision",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "opt-app-v1",
|
||||||
|
Namespace: "default",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"app.oam.dev/name": "opt-app",
|
||||||
|
},
|
||||||
|
Annotations: map[string]string{
|
||||||
|
oam.AnnotationPublishVersion: "v1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: v1beta1.ApplicationRevisionSpec{
|
||||||
|
Application: v1beta1.Application{
|
||||||
|
Spec: v1beta1.ApplicationSpec{
|
||||||
|
Components: []common.ApplicationComponent{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var myRollout = kruisev1alpha1.Rollout{
|
||||||
|
TypeMeta: metav1.TypeMeta{
|
||||||
|
APIVersion: "rollouts.kruise.io/v1alpha1",
|
||||||
|
Kind: "Rollout",
|
||||||
|
},
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "my-rollout",
|
||||||
|
Namespace: "default",
|
||||||
|
},
|
||||||
|
Spec: kruisev1alpha1.RolloutSpec{
|
||||||
|
ObjectRef: kruisev1alpha1.ObjectRef{
|
||||||
|
WorkloadRef: &kruisev1alpha1.WorkloadRef{
|
||||||
|
APIVersion: "appsv1",
|
||||||
|
Kind: "Deployment",
|
||||||
|
Name: "canary-demo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Strategy: kruisev1alpha1.RolloutStrategy{
|
||||||
|
Canary: &kruisev1alpha1.CanaryStrategy{
|
||||||
|
Steps: []kruisev1alpha1.CanaryStep{
|
||||||
|
{
|
||||||
|
Weight: 30,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Paused: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
Copyright 2021 The KubeVela 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 operation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"k8s.io/client-go/discovery"
|
||||||
|
ocmclusterv1 "open-cluster-management.io/api/cluster/v1"
|
||||||
|
ocmclusterv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
|
||||||
|
ocmworkv1 "open-cluster-management.io/api/work/v1"
|
||||||
|
|
||||||
|
v12 "k8s.io/api/core/v1"
|
||||||
|
crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
|
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||||
|
"k8s.io/client-go/rest"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/envtest/printer"
|
||||||
|
logf "sigs.k8s.io/controller-runtime/pkg/log"
|
||||||
|
"sigs.k8s.io/controller-runtime/pkg/log/zap"
|
||||||
|
|
||||||
|
kruisev1alpha1 "github.com/openkruise/rollouts/api/v1alpha1"
|
||||||
|
|
||||||
|
coreoam "github.com/oam-dev/kubevela/apis/core.oam.dev"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/cue/packages"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||||
|
// +kubebuilder:scaffold:imports
|
||||||
|
)
|
||||||
|
|
||||||
|
var cfg *rest.Config
|
||||||
|
var scheme *runtime.Scheme
|
||||||
|
var k8sClient client.Client
|
||||||
|
var testEnv *envtest.Environment
|
||||||
|
var dm discoverymapper.DiscoveryMapper
|
||||||
|
var pd *packages.PackageDiscover
|
||||||
|
var testns string
|
||||||
|
var dc *discovery.DiscoveryClient
|
||||||
|
|
||||||
|
func TestAddon(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecsWithDefaultAndCustomReporters(t,
|
||||||
|
"Kruise rollout Suite test",
|
||||||
|
[]Reporter{printer.NewlineReporter{}})
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = BeforeSuite(func(done Done) {
|
||||||
|
logf.SetLogger(zap.New(zap.UseDevMode(true), zap.WriteTo(GinkgoWriter)))
|
||||||
|
By("bootstrapping test environment")
|
||||||
|
useExistCluster := false
|
||||||
|
testEnv = &envtest.Environment{
|
||||||
|
ControlPlaneStartTimeout: time.Minute,
|
||||||
|
ControlPlaneStopTimeout: time.Minute,
|
||||||
|
CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "charts", "vela-core", "crds"), filepath.Join("", "testdata")},
|
||||||
|
UseExistingCluster: &useExistCluster,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
cfg, err = testEnv.Start()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(cfg).ToNot(BeNil())
|
||||||
|
scheme = runtime.NewScheme()
|
||||||
|
Expect(coreoam.AddToScheme(scheme)).NotTo(HaveOccurred())
|
||||||
|
Expect(clientgoscheme.AddToScheme(scheme)).NotTo(HaveOccurred())
|
||||||
|
Expect(crdv1.AddToScheme(scheme)).NotTo(HaveOccurred())
|
||||||
|
_ = ocmclusterv1alpha1.Install(scheme)
|
||||||
|
_ = ocmclusterv1.Install(scheme)
|
||||||
|
_ = ocmworkv1.Install(scheme)
|
||||||
|
_ = kruisev1alpha1.AddToScheme(scheme)
|
||||||
|
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme})
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(k8sClient).ToNot(BeNil())
|
||||||
|
|
||||||
|
dc, err = discovery.NewDiscoveryClientForConfig(cfg)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(dc).ShouldNot(BeNil())
|
||||||
|
|
||||||
|
dm, err = discoverymapper.New(cfg)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(dm).ToNot(BeNil())
|
||||||
|
pd, err = packages.NewPackageDiscover(cfg)
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
Expect(pd).ToNot(BeNil())
|
||||||
|
testns = "vela-system"
|
||||||
|
Expect(k8sClient.Create(context.Background(),
|
||||||
|
&v12.Namespace{TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Namespace"}, ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: testns,
|
||||||
|
}}))
|
||||||
|
|
||||||
|
close(done)
|
||||||
|
}, 120)
|
||||||
|
|
||||||
|
var _ = AfterSuite(func() {
|
||||||
|
By("tearing down the test environment")
|
||||||
|
err := testEnv.Stop()
|
||||||
|
Expect(err).ToNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,290 @@
|
||||||
|
apiVersion: apiextensions.k8s.io/v1
|
||||||
|
kind: CustomResourceDefinition
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
controller-gen.kubebuilder.io/version: v0.7.0
|
||||||
|
creationTimestamp: null
|
||||||
|
name: rollouts.rollouts.kruise.io
|
||||||
|
spec:
|
||||||
|
group: rollouts.kruise.io
|
||||||
|
names:
|
||||||
|
kind: Rollout
|
||||||
|
listKind: RolloutList
|
||||||
|
plural: rollouts
|
||||||
|
singular: rollout
|
||||||
|
scope: Namespaced
|
||||||
|
versions:
|
||||||
|
- additionalPrinterColumns:
|
||||||
|
- description: The rollout status phase
|
||||||
|
jsonPath: .status.phase
|
||||||
|
name: STATUS
|
||||||
|
type: string
|
||||||
|
- description: The rollout canary status step
|
||||||
|
jsonPath: .status.canaryStatus.currentStepIndex
|
||||||
|
name: CANARY_STEP
|
||||||
|
type: integer
|
||||||
|
- description: The rollout canary status step state
|
||||||
|
jsonPath: .status.canaryStatus.currentStepState
|
||||||
|
name: CANARY_STATE
|
||||||
|
type: string
|
||||||
|
- description: The rollout canary status message
|
||||||
|
jsonPath: .status.message
|
||||||
|
name: MESSAGE
|
||||||
|
type: string
|
||||||
|
- jsonPath: .metadata.creationTimestamp
|
||||||
|
name: AGE
|
||||||
|
type: date
|
||||||
|
name: v1alpha1
|
||||||
|
schema:
|
||||||
|
openAPIV3Schema:
|
||||||
|
description: Rollout is the Schema for the rollouts API
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: 'APIVersion defines the versioned schema of this representation
|
||||||
|
of an object. Servers should convert recognized schemas to the latest
|
||||||
|
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: 'Kind is a string value representing the REST resource this
|
||||||
|
object represents. Servers may infer this from the endpoint the client
|
||||||
|
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
|
||||||
|
type: string
|
||||||
|
metadata:
|
||||||
|
type: object
|
||||||
|
spec:
|
||||||
|
description: RolloutSpec defines the desired state of Rollout
|
||||||
|
properties:
|
||||||
|
objectRef:
|
||||||
|
description: 'INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
|
||||||
|
Important: Run "make" to regenerate code after modifying this file
|
||||||
|
ObjectRef indicates workload'
|
||||||
|
properties:
|
||||||
|
workloadRef:
|
||||||
|
description: WorkloadRef contains enough information to let you
|
||||||
|
identify a workload for Rollout Batch release of the bypass
|
||||||
|
properties:
|
||||||
|
apiVersion:
|
||||||
|
description: API Version of the referent
|
||||||
|
type: string
|
||||||
|
kind:
|
||||||
|
description: Kind of the referent
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
description: Name of the referent
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- apiVersion
|
||||||
|
- kind
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
strategy:
|
||||||
|
description: rollout strategy
|
||||||
|
properties:
|
||||||
|
canary:
|
||||||
|
description: CanaryStrategy defines parameters for a Replica Based
|
||||||
|
Canary
|
||||||
|
properties:
|
||||||
|
steps:
|
||||||
|
description: Steps define the order of phases to execute release
|
||||||
|
in batches(20%, 40%, 60%, 80%, 100%)
|
||||||
|
items:
|
||||||
|
description: CanaryStep defines a step of a canary workload.
|
||||||
|
properties:
|
||||||
|
pause:
|
||||||
|
description: Pause defines a pause stage for a rollout,
|
||||||
|
manual or auto
|
||||||
|
properties:
|
||||||
|
duration:
|
||||||
|
description: Duration the amount of time to wait
|
||||||
|
before moving to the next step.
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
replicas:
|
||||||
|
anyOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
description: 'Replicas is the number of expected canary
|
||||||
|
pods in this batch it can be an absolute number (ex:
|
||||||
|
5) or a percentage of total pods.'
|
||||||
|
x-kubernetes-int-or-string: true
|
||||||
|
weight:
|
||||||
|
description: SetWeight sets what percentage of the canary
|
||||||
|
pods should receive
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
trafficRoutings:
|
||||||
|
description: TrafficRoutings hosts all the supported service
|
||||||
|
meshes supported to enable more fine-grained traffic routing
|
||||||
|
todo current only support one
|
||||||
|
items:
|
||||||
|
description: TrafficRouting hosts all the different configuration
|
||||||
|
for supported service meshes to enable more fine-grained
|
||||||
|
traffic routing
|
||||||
|
properties:
|
||||||
|
gracePeriodSeconds:
|
||||||
|
description: Optional duration in seconds the traffic
|
||||||
|
provider(e.g. nginx ingress controller) consumes the
|
||||||
|
service, ingress configuration changes gracefully.
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
ingress:
|
||||||
|
description: Ingress holds Ingress specific configuration
|
||||||
|
to route traffic, e.g. Nginx, Alb.
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
description: Name refers to the name of an `Ingress`
|
||||||
|
resource in the same namespace as the `Rollout`
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
type: object
|
||||||
|
service:
|
||||||
|
description: Service holds the name of a service which
|
||||||
|
selects pods with stable version and don't select
|
||||||
|
any pods with canary version.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: nginx, alb, istio etc.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- service
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
paused:
|
||||||
|
description: Paused indicates that the Rollout is paused. Default
|
||||||
|
value is false
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- objectRef
|
||||||
|
- strategy
|
||||||
|
type: object
|
||||||
|
status:
|
||||||
|
description: RolloutStatus defines the observed state of Rollout
|
||||||
|
properties:
|
||||||
|
canaryStatus:
|
||||||
|
description: Canary describes the state of the canary rollout
|
||||||
|
properties:
|
||||||
|
canaryReadyReplicas:
|
||||||
|
description: CanaryReadyReplicas the numbers of ready canary revision
|
||||||
|
pods
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
canaryReplicas:
|
||||||
|
description: CanaryReplicas the numbers of canary revision pods
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
canaryRevision:
|
||||||
|
description: CanaryRevision is calculated by rollout based on
|
||||||
|
podTemplateHash, and the internal logic flow uses It may be
|
||||||
|
different from rs podTemplateHash in different k8s versions,
|
||||||
|
so it cannot be used as service selector label
|
||||||
|
type: string
|
||||||
|
canaryService:
|
||||||
|
description: CanaryService holds the name of a service which selects
|
||||||
|
pods with canary version and don't select any pods with stable
|
||||||
|
version.
|
||||||
|
type: string
|
||||||
|
currentStepIndex:
|
||||||
|
description: CurrentStepIndex defines the current step of the
|
||||||
|
rollout is on. If the current step index is null, the controller
|
||||||
|
will execute the rollout.
|
||||||
|
format: int32
|
||||||
|
type: integer
|
||||||
|
currentStepState:
|
||||||
|
type: string
|
||||||
|
lastReadyTime:
|
||||||
|
description: The last time this step pods is ready.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
observedWorkloadGeneration:
|
||||||
|
description: observedWorkloadGeneration is the most recent generation
|
||||||
|
observed for this Rollout ref workload generation.
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
podTemplateHash:
|
||||||
|
description: pod template hash is used as service selector label
|
||||||
|
type: string
|
||||||
|
rolloutHash:
|
||||||
|
description: RolloutHash from rollout.spec object
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- canaryReadyReplicas
|
||||||
|
- canaryReplicas
|
||||||
|
- canaryService
|
||||||
|
- currentStepState
|
||||||
|
- podTemplateHash
|
||||||
|
type: object
|
||||||
|
conditions:
|
||||||
|
description: Conditions a list of conditions a rollout can have.
|
||||||
|
items:
|
||||||
|
description: RolloutCondition describes the state of a rollout at
|
||||||
|
a certain point.
|
||||||
|
properties:
|
||||||
|
lastTransitionTime:
|
||||||
|
description: Last time the condition transitioned from one status
|
||||||
|
to another.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
lastUpdateTime:
|
||||||
|
description: The last time this condition was updated.
|
||||||
|
format: date-time
|
||||||
|
type: string
|
||||||
|
message:
|
||||||
|
description: A human readable message indicating details about
|
||||||
|
the transition.
|
||||||
|
type: string
|
||||||
|
reason:
|
||||||
|
description: The reason for the condition's last transition.
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
description: Phase of the condition, one of True, False, Unknown.
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
description: Type of rollout condition.
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- message
|
||||||
|
- reason
|
||||||
|
- status
|
||||||
|
- type
|
||||||
|
type: object
|
||||||
|
type: array
|
||||||
|
message:
|
||||||
|
description: Message provides details on why the rollout is in its
|
||||||
|
current phase
|
||||||
|
type: string
|
||||||
|
observedGeneration:
|
||||||
|
description: observedGeneration is the most recent generation observed
|
||||||
|
for this Rollout.
|
||||||
|
format: int64
|
||||||
|
type: integer
|
||||||
|
phase:
|
||||||
|
description: BlueGreenStatus *BlueGreenStatus `json:"blueGreenStatus,omitempty"`
|
||||||
|
Phase is the rollout phase.
|
||||||
|
type: string
|
||||||
|
stableRevision:
|
||||||
|
description: CanaryRevision the hash of the canary pod template CanaryRevision
|
||||||
|
string `json:"canaryRevision,omitempty"` StableRevision indicates
|
||||||
|
the revision pods that has successfully rolled out
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
served: true
|
||||||
|
storage: true
|
||||||
|
subresources:
|
||||||
|
status: {}
|
||||||
|
status:
|
||||||
|
acceptedNames:
|
||||||
|
kind: ""
|
||||||
|
plural: ""
|
||||||
|
conditions: []
|
||||||
|
storedVersions: []
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,8 @@
|
||||||
|
apiVersion: v2
|
||||||
|
appVersion: 1.0.1
|
||||||
|
description: This is a test sample addon
|
||||||
|
home: https://terraform.io/
|
||||||
|
icon: https://www.terraform.io/assets/images/logo-text-8c3ba8a6.svg
|
||||||
|
name: sample
|
||||||
|
type: library
|
||||||
|
version: 1.0.1
|
||||||
|
|
@ -20,23 +20,16 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
k8stypes "k8s.io/apimachinery/pkg/types"
|
k8stypes "k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/client-go/util/retry"
|
|
||||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
||||||
|
|
||||||
oamcommon "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
|
||||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||||
"github.com/oam-dev/kubevela/apis/types"
|
"github.com/oam-dev/kubevela/apis/types"
|
||||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/service"
|
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||||
"github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2/application"
|
|
||||||
"github.com/oam-dev/kubevela/pkg/controller/utils"
|
|
||||||
"github.com/oam-dev/kubevela/pkg/oam"
|
"github.com/oam-dev/kubevela/pkg/oam"
|
||||||
"github.com/oam-dev/kubevela/pkg/resourcetracker"
|
|
||||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||||
velaerrors "github.com/oam-dev/kubevela/pkg/utils/errors"
|
|
||||||
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
|
||||||
|
"github.com/oam-dev/kubevela/pkg/workflow/operation"
|
||||||
"github.com/oam-dev/kubevela/references/appfile"
|
"github.com/oam-dev/kubevela/references/appfile"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -79,18 +72,19 @@ func NewWorkflowSuspendCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if app.Status.Workflow == nil {
|
|
||||||
return fmt.Errorf("the workflow in application is not running")
|
config, err := c.GetConfig()
|
||||||
}
|
|
||||||
client, err := c.GetClient()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = suspendWorkflow(client, app)
|
config.Wrap(multicluster.NewSecretModeMultiClusterRoundTripper)
|
||||||
|
cli, err := c.GetClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
wo := operation.NewWorkflowOperator(cli, cmd.OutOrStdout())
|
||||||
|
return wo.Suspend(context.Background(), app)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
addNamespaceAndEnvArg(cmd)
|
addNamespaceAndEnvArg(cmd)
|
||||||
|
|
@ -116,29 +110,19 @@ func NewWorkflowResumeCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if app.Status.Workflow == nil {
|
|
||||||
return fmt.Errorf("the workflow in application is not running")
|
config, err := c.GetConfig()
|
||||||
}
|
|
||||||
if app.Status.Workflow.Terminated {
|
|
||||||
return fmt.Errorf("can not resume a terminated workflow")
|
|
||||||
}
|
|
||||||
if !app.Status.Workflow.Suspend {
|
|
||||||
_, err := ioStream.Out.Write([]byte("the workflow is not suspending\n"))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
config.Wrap(multicluster.NewSecretModeMultiClusterRoundTripper)
|
||||||
}
|
cli, err := c.GetClient()
|
||||||
client, err := c.GetClient()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = resumeWorkflow(client, app)
|
wo := operation.NewWorkflowOperator(cli, cmd.OutOrStdout())
|
||||||
if err != nil {
|
return wo.Resume(context.Background(), app)
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
addNamespaceAndEnvArg(cmd)
|
addNamespaceAndEnvArg(cmd)
|
||||||
|
|
@ -167,15 +151,12 @@ func NewWorkflowTerminateCommand(c common.Args, ioStream cmdutil.IOStreams) *cob
|
||||||
if app.Status.Workflow == nil {
|
if app.Status.Workflow == nil {
|
||||||
return fmt.Errorf("the workflow in application is not running")
|
return fmt.Errorf("the workflow in application is not running")
|
||||||
}
|
}
|
||||||
client, err := c.GetClient()
|
cli, err := c.GetClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = terminateWorkflow(client, app)
|
wo := operation.NewWorkflowOperator(cli, cmd.OutOrStdout())
|
||||||
if err != nil {
|
return wo.Terminate(context.Background(), app)
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
addNamespaceAndEnvArg(cmd)
|
addNamespaceAndEnvArg(cmd)
|
||||||
|
|
@ -201,19 +182,18 @@ func NewWorkflowRestartCommand(c common.Args, ioStream cmdutil.IOStreams) *cobra
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if app.Status.Workflow == nil {
|
config, err := c.GetConfig()
|
||||||
return fmt.Errorf("the workflow in application is not running")
|
if err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
client, err := c.GetClient()
|
config.Wrap(multicluster.NewSecretModeMultiClusterRoundTripper)
|
||||||
|
cli, err := c.GetClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = restartWorkflow(client, app)
|
wo := operation.NewWorkflowOperator(cli, cmd.OutOrStdout())
|
||||||
if err != nil {
|
return wo.Restart(context.Background(), app)
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
addNamespaceAndEnvArg(cmd)
|
addNamespaceAndEnvArg(cmd)
|
||||||
|
|
@ -239,205 +219,40 @@ func NewWorkflowRollbackCommand(c common.Args, ioStream cmdutil.IOStreams) *cobr
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
config, err := c.GetConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
config.Wrap(multicluster.NewSecretModeMultiClusterRoundTripper)
|
||||||
|
cli, err := c.GetClient()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if app.Status.Workflow != nil && !app.Status.Workflow.Terminated && !app.Status.Workflow.Suspend && !app.Status.Workflow.Finished {
|
if app.Status.Workflow != nil && !app.Status.Workflow.Terminated && !app.Status.Workflow.Suspend && !app.Status.Workflow.Finished {
|
||||||
return fmt.Errorf("can not rollback a running workflow")
|
return fmt.Errorf("can not rollback a running workflow")
|
||||||
}
|
}
|
||||||
client, err := c.GetClient()
|
if oam.GetPublishVersion(app) == "" {
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = rollbackWorkflow(cmd, client, app)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
},
|
|
||||||
}
|
|
||||||
addNamespaceAndEnvArg(cmd)
|
|
||||||
return cmd
|
|
||||||
}
|
|
||||||
|
|
||||||
func suspendWorkflow(kubecli client.Client, app *v1beta1.Application) error {
|
|
||||||
appKey := client.ObjectKeyFromObject(app)
|
|
||||||
ctx := context.Background()
|
|
||||||
if err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
|
||||||
if err := kubecli.Get(ctx, appKey, app); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// set the workflow suspend to true
|
|
||||||
app.Status.Workflow.Suspend = true
|
|
||||||
return kubecli.Status().Patch(ctx, app, client.Merge)
|
|
||||||
}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("Successfully suspend workflow: %s\n", app.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func resumeWorkflow(kubecli client.Client, app *v1beta1.Application) error {
|
|
||||||
if err := service.ResumeWorkflow(context.TODO(), kubecli, app); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Successfully resume workflow: %s\n", app.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func terminateWorkflow(kubecli client.Client, app *v1beta1.Application) error {
|
|
||||||
if err := service.TerminateWorkflow(context.TODO(), kubecli, app); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Successfully terminate workflow: %s\n", app.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func restartWorkflow(kubecli client.Client, app *v1beta1.Application) error {
|
|
||||||
// reset the workflow status to restart the workflow
|
|
||||||
app.Status.Workflow = nil
|
|
||||||
|
|
||||||
if err := kubecli.Status().Update(context.TODO(), app); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("Successfully restart workflow: %s\n", app.Name)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func rollbackWorkflow(cmd *cobra.Command, kubecli client.Client, app *v1beta1.Application) error {
|
|
||||||
if oam.GetPublishVersion(app) != "" {
|
|
||||||
return rollbackApplicationWithPublishVersion(cmd, kubecli, app)
|
|
||||||
}
|
|
||||||
if app.Status.LatestRevision == nil || app.Status.LatestRevision.Name == "" {
|
if app.Status.LatestRevision == nil || app.Status.LatestRevision.Name == "" {
|
||||||
return fmt.Errorf("the latest revision is not set: %s", app.Name)
|
return fmt.Errorf("the latest revision is not set: %s", app.Name)
|
||||||
}
|
}
|
||||||
// get the last revision
|
// get the last revision
|
||||||
revision := &v1beta1.ApplicationRevision{}
|
revision := &v1beta1.ApplicationRevision{}
|
||||||
if err := kubecli.Get(context.TODO(), k8stypes.NamespacedName{Name: app.Status.LatestRevision.Name, Namespace: app.Namespace}, revision); err != nil {
|
if err := cli.Get(context.TODO(), k8stypes.NamespacedName{Name: app.Status.LatestRevision.Name, Namespace: app.Namespace}, revision); err != nil {
|
||||||
return fmt.Errorf("failed to get the latest revision: %w", err)
|
return fmt.Errorf("failed to get the latest revision: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Spec = revision.Spec.Application.Spec
|
app.Spec = revision.Spec.Application.Spec
|
||||||
if err := kubecli.Status().Update(context.TODO(), app); err != nil {
|
if err := cli.Status().Update(context.TODO(), app); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Successfully rollback workflow to the latest revision: %s\n", app.Name)
|
fmt.Printf("Successfully rollback workflow to the latest revision: %s\n", app.Name)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
wo := operation.NewWorkflowOperator(cli, cmd.OutOrStdout())
|
||||||
func rollbackApplicationWithPublishVersion(cmd *cobra.Command, cli client.Client, app *v1beta1.Application) error {
|
return wo.Rollback(context.Background(), app)
|
||||||
ctx := context.Background()
|
},
|
||||||
appRevs, err := application.GetSortedAppRevisions(ctx, cli, app.Name, app.Namespace)
|
}
|
||||||
if err != nil {
|
addNamespaceAndEnvArg(cmd)
|
||||||
return errors.Wrapf(err, "failed to list revisions for application %s/%s", app.Namespace, app.Name)
|
return cmd
|
||||||
}
|
|
||||||
|
|
||||||
// find succeeded revision to rollback
|
|
||||||
var rev *v1beta1.ApplicationRevision
|
|
||||||
var outdatedRev []*v1beta1.ApplicationRevision
|
|
||||||
for i := range appRevs {
|
|
||||||
candidate := appRevs[len(appRevs)-i-1]
|
|
||||||
_rev := candidate.DeepCopy()
|
|
||||||
if !candidate.Status.Succeeded || oam.GetPublishVersion(_rev) == "" {
|
|
||||||
outdatedRev = append(outdatedRev, _rev)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
rev = _rev
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if rev == nil {
|
|
||||||
return errors.Errorf("failed to find previous succeeded revision for application %s/%s", app.Namespace, app.Name)
|
|
||||||
}
|
|
||||||
publishVersion := oam.GetPublishVersion(rev)
|
|
||||||
revisionNumber, err := utils.ExtractRevision(rev.Name)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to extract revision number from revision %s", rev.Name)
|
|
||||||
}
|
|
||||||
_, currentRT, historyRTs, _, err := resourcetracker.ListApplicationResourceTrackers(ctx, cli, app)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to list resource trackers for application %s/%s", app.Namespace, app.Name)
|
|
||||||
}
|
|
||||||
var matchRT *v1beta1.ResourceTracker
|
|
||||||
for _, rt := range append(historyRTs, currentRT) {
|
|
||||||
if rt == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
labels := rt.GetLabels()
|
|
||||||
if labels != nil && labels[oam.LabelAppRevision] == rev.Name {
|
|
||||||
matchRT = rt.DeepCopy()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if matchRT == nil {
|
|
||||||
return errors.Errorf("cannot find resource tracker for previous revision %s, unable to rollback", rev.Name)
|
|
||||||
}
|
|
||||||
if matchRT.DeletionTimestamp != nil {
|
|
||||||
return errors.Errorf("previous revision %s is being recycled, unable to rollback", rev.Name)
|
|
||||||
}
|
|
||||||
cmd.Printf("Find succeeded application revision %s (PublishVersion: %s) to rollback.\n", rev.Name, publishVersion)
|
|
||||||
|
|
||||||
appKey := client.ObjectKeyFromObject(app)
|
|
||||||
// rollback application spec and freeze
|
|
||||||
controllerRequirement, err := utils.FreezeApplication(ctx, cli, app, func() {
|
|
||||||
app.Spec = rev.Spec.Application.Spec
|
|
||||||
oam.SetPublishVersion(app, publishVersion)
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to rollback application spec to revision %s (PublishVersion: %s)", rev.Name, publishVersion)
|
|
||||||
}
|
|
||||||
cmd.Printf("Application spec rollback successfully.\n")
|
|
||||||
|
|
||||||
// rollback application status
|
|
||||||
if err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
|
||||||
if err = cli.Get(ctx, appKey, app); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
app.Status.Workflow = rev.Status.Workflow
|
|
||||||
app.Status.Services = []oamcommon.ApplicationComponentStatus{}
|
|
||||||
app.Status.AppliedResources = []oamcommon.ClusterObjectReference{}
|
|
||||||
for _, rsc := range matchRT.Spec.ManagedResources {
|
|
||||||
app.Status.AppliedResources = append(app.Status.AppliedResources, rsc.ClusterObjectReference)
|
|
||||||
}
|
|
||||||
app.Status.LatestRevision = &oamcommon.Revision{
|
|
||||||
Name: rev.Name,
|
|
||||||
Revision: int64(revisionNumber),
|
|
||||||
RevisionHash: rev.GetLabels()[oam.LabelAppRevisionHash],
|
|
||||||
}
|
|
||||||
return cli.Status().Update(ctx, app)
|
|
||||||
}); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to rollback application status to revision %s (PublishVersion: %s)", rev.Name, publishVersion)
|
|
||||||
}
|
|
||||||
cmd.Printf("Application status rollback successfully.\n")
|
|
||||||
|
|
||||||
// update resource tracker generation
|
|
||||||
matchRTKey := client.ObjectKeyFromObject(matchRT)
|
|
||||||
if err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
|
||||||
if err = cli.Get(ctx, matchRTKey, matchRT); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
matchRT.Spec.ApplicationGeneration = app.Generation
|
|
||||||
return cli.Update(ctx, matchRT)
|
|
||||||
}); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to update application generation in resource tracker")
|
|
||||||
}
|
|
||||||
|
|
||||||
// unfreeze application
|
|
||||||
if err = utils.UnfreezeApplication(ctx, cli, app, nil, controllerRequirement); err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to resume application to restart")
|
|
||||||
}
|
|
||||||
cmd.Printf("Application rollback completed.\n")
|
|
||||||
|
|
||||||
// clean up outdated revisions
|
|
||||||
var errs velaerrors.ErrorList
|
|
||||||
for _, _rev := range outdatedRev {
|
|
||||||
if err = cli.Delete(ctx, _rev); err != nil {
|
|
||||||
errs = append(errs, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if errs.HasError() {
|
|
||||||
return errors.Wrapf(errs, "failed to clean up outdated revisions")
|
|
||||||
}
|
|
||||||
cmd.Printf("Application outdated revision cleaned up.\n")
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,8 @@ func TestWorkflowResume(t *testing.T) {
|
||||||
r := require.New(t)
|
r := require.New(t)
|
||||||
cmd := NewWorkflowResumeCommand(c, ioStream)
|
cmd := NewWorkflowResumeCommand(c, ioStream)
|
||||||
initCommand(cmd)
|
initCommand(cmd)
|
||||||
|
// clean up the arguments before start
|
||||||
|
cmd.SetArgs([]string{})
|
||||||
client, err := c.GetClient()
|
client, err := c.GetClient()
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
if tc.app != nil {
|
if tc.app != nil {
|
||||||
|
|
@ -352,6 +354,8 @@ func TestWorkflowTerminate(t *testing.T) {
|
||||||
r := require.New(t)
|
r := require.New(t)
|
||||||
cmd := NewWorkflowTerminateCommand(c, ioStream)
|
cmd := NewWorkflowTerminateCommand(c, ioStream)
|
||||||
initCommand(cmd)
|
initCommand(cmd)
|
||||||
|
// clean up the arguments before start
|
||||||
|
cmd.SetArgs([]string{})
|
||||||
client, err := c.GetClient()
|
client, err := c.GetClient()
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
if tc.app != nil {
|
if tc.app != nil {
|
||||||
|
|
@ -444,6 +448,8 @@ func TestWorkflowRestart(t *testing.T) {
|
||||||
r := require.New(t)
|
r := require.New(t)
|
||||||
cmd := NewWorkflowRestartCommand(c, ioStream)
|
cmd := NewWorkflowRestartCommand(c, ioStream)
|
||||||
initCommand(cmd)
|
initCommand(cmd)
|
||||||
|
// clean up the arguments before start
|
||||||
|
cmd.SetArgs([]string{})
|
||||||
client, err := c.GetClient()
|
client, err := c.GetClient()
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
if tc.app != nil {
|
if tc.app != nil {
|
||||||
|
|
@ -567,6 +573,8 @@ func TestWorkflowRollback(t *testing.T) {
|
||||||
r := require.New(t)
|
r := require.New(t)
|
||||||
cmd := NewWorkflowRollbackCommand(c, ioStream)
|
cmd := NewWorkflowRollbackCommand(c, ioStream)
|
||||||
initCommand(cmd)
|
initCommand(cmd)
|
||||||
|
// clean up the arguments before start
|
||||||
|
cmd.SetArgs([]string{})
|
||||||
client, err := c.GetClient()
|
client, err := c.GetClient()
|
||||||
r.NoError(err)
|
r.NoError(err)
|
||||||
if tc.app != nil {
|
if tc.app != nil {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue