Compare commits

...

59 Commits

Author SHA1 Message Date
Parship Chowdhury 87f7e652ab
Fix workload webhook filtering: patch label bug and add Kruise StatefulSet support (#299)
* Fix workload type label patching bug and add Kruise StatefulSet support

Signed-off-by: Parship Chowdhury <i.am.parship@gmail.com>

* added objectSelector to filter workloads by rollout label

Signed-off-by: Parship Chowdhury <i.am.parship@gmail.com>

* reverted the changes in manifest

Signed-off-by: Parship Chowdhury <i.am.parship@gmail.com>

---------

Signed-off-by: Parship Chowdhury <i.am.parship@gmail.com>
2025-07-28 10:47:58 +08:00
守辰 b2806f5dec dump rollout logs if e2e fail
Signed-off-by: 守辰 <shouchen.zz@alibaba-inc.com>
2025-07-23 13:24:18 +08:00
shouchen.zz 885497f5df fix golang-lint-error
Signed-off-by: 守辰 <shouchen.zz@alibaba-inc.com>
2025-07-23 13:24:18 +08:00
shouchen.zz 0c89ec8ca0 update dependency to 1.28
Signed-off-by: 守辰 <shouchen.zz@alibaba-inc.com>
2025-07-23 13:24:18 +08:00
守辰 087483f1ec remove runtime inject dependency
Signed-off-by: 守辰 <shouchen.zz@alibaba-inc.com>
2025-07-23 13:24:18 +08:00
PersistentJZH 0fbc3ed8c4
Change workload controller to use patch instead of update (#286)
* change workload controller to use patch instead of update

Signed-off-by: zhihao jian <zhihao.jian@shopee.com>

fix test

use MergeFrom func to patch data

get latest rs

fix unit test

fix lint

do not get latest status before patch

* use runtimeClient to operate deployment uniformly

Signed-off-by: zhihao jian <zhihao.jian@shopee.com>

remove dupl SetNewReplicaSetAnnotations

use UnsafeDisableDeepCopy to optimize performance

use optimisticLock for patch

fix patch extra status always failed

fix unit test

* use runtimeClient to operate deployment uniformly

Signed-off-by: zhihao jian <zhihao.jian@shopee.com>

remove dupl SetNewReplicaSetAnnotations

use UnsafeDisableDeepCopy to optimize performance

use optimisticLock for patch

fix patch extra status always failed

fix unit test

add comment

* combine patchExtraStatus and syncDeploymentStatus

Signed-off-by: zhihao jian <zhihao.jian@shopee.com>

---------

Signed-off-by: zhihao jian <zhihao.jian@shopee.com>
Co-authored-by: zhihao jian <zhihao.jian@shopee.com>
Co-authored-by: Zhen Zhang <furykerry@gmail.com>
2025-07-22 20:48:52 +08:00
Gautam Manchandani 561de4fcbb
added ut for releaseManager (#291)
Signed-off-by: GautamBytes <manchandanigautam@gmail.com>
2025-07-21 14:39:52 +08:00
Gautam Manchandani c19c76203e
added ut for v1alpha1 Rollout validation (#295)
Signed-off-by: GautamBytes <manchandanigautam@gmail.com>
2025-07-18 19:15:49 +08:00
Ai Ranthem deaa5f38b5
Fix: Webhook will take over Deployment even Rollout CR doesn't exist (#278)
Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2025-06-20 15:24:23 +08:00
Ai Ranthem 6554cfcf08
Changelog: v0.6.1 (#270)
Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2025-05-08 19:12:37 +08:00
Ai Ranthem 402cb9cd90
Chore: upgrade e2e ubuntu version from 20.04 to 22.04 (#268)
Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2025-05-08 12:41:00 +08:00
handagou 2aa692dc2f
Fix order of object in batchrelease event handler (#265)
Signed-off-by: z760087139 <z760087139@gmail.com>
2025-04-10 16:24:51 +08:00
Ai Ranthem ca0a71ff52
Chore: add e2e workflows for k8s 1.26 (#263)
* Chore: add e2e workflows for k8s 1.26

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>

* Chore: add e2e workflows for k8s 1.26

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>

* Chore: add e2e workflows for k8s 1.26

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>

---------

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2025-04-08 18:27:46 +08:00
Ai Ranthem 744430356d
Fix: blue-green batch-id e2e fails sometime (#261)
* Fix: blue-green batch-id e2e fails sometime

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2025-04-01 13:20:48 +08:00
PersistentJZH 6094e966ac
supoort patch batch id in cacary release (#251)
Signed-off-by: zhihao jian <zhihao.jian@shopee.com>
Co-authored-by: zhihao jian <zhihao.jian@shopee.com>
2025-04-01 10:09:45 +08:00
Ai Ranthem 3e66fa1ad8
Feature: support batch-id labeling for bluegreen strategy (#250)
* Feature: support batch-id labeling for blue-green strategy

---------

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2025-03-20 19:26:46 +08:00
liheng.zms 7baf47d70e v0.5.1 changelog
Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>
2025-03-20 18:03:41 +08:00
Ai Ranthem 334fa1cbf3
add docker-image workflow (#253)
* add docker-image workflow

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>

* add docker-image workflow

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>

* fix typo

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>

---------

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2025-02-07 11:16:27 +08:00
Ai Ranthem 3562934ae5
Release note 0.6.0 (#252)
Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2025-01-21 15:51:12 +08:00
zhihao jian faa2d03338 fix patch rollout batch id
Signed-off-by: zhihao jian <zhihao.jian@shopee.com>

add rollback prefix to identify in rollback pods

fix patch rollout id

fix test

fix

add prefix when rollout id is empty

fix test
2025-01-03 09:55:23 +08:00
yunbo 5bbbc046b0 fix the pod-recreate issue in partition style
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
2024-12-27 10:00:08 +08:00
myname4423 efbd8ba8f9
support bluegreen release: support workload of deployment and cloneSet (#238)
* support bluegreen release: Deployment and CloneSet

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

* support bluegreen release: webhook update

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

* add unit test & split workload mutating webhook

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

* fix a bug caused by previous merged PR

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

* improve some log information

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

* fix kruise version problem

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

---------

Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-12-24 19:38:52 +08:00
Jiajing LU 056c77dbd2
Patch canary service selector from PodTemplateMetadata (#243)
* patch canary service selector

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* check null

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* fix nil check

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* remove len check

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

---------

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>
2024-12-09 19:25:49 +08:00
yunbo 3f66aae0ae support bluegreen release: release logic
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
2024-11-13 11:26:44 +08:00
Ai Ranthem 09e01cb95b
upgrade: gateway-api(0.5.1=>0.7.1), along with controller-runtime(0.12.1=>0.14.6) (#237)
Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2024-11-13 09:38:49 +08:00
Jiajing LU 6854752435
Add composite provider to support multiple network providers (#224)
* add composite provider

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* fix nginx lua script and add E2E

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* fix test case

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* revert image

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* fix indent

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* follow latest interface change

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* move e2e to v1beta1 file and add workflow

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

---------

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>
2024-11-01 11:28:58 +08:00
ls-2018 f0363f28c0
fix: lua encode structural error (#209)
Signed-off-by: acejilam <acejilam@gmail.com>
2024-09-06 19:38:09 +08:00
myname4423 d2613132aa
improve finalising logic for canary release (#229)
improve finalising logic for canary release-2

Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-09-04 17:29:58 +08:00
myname4423 5378dc2cf7
refactor the grace system (#226)
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-08-13 15:17:38 +08:00
myname4423 78273c2998
add restriction for traffic configuration of partition-style step (#225)
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-08-02 13:42:28 +08:00
myname4423 16a3f0acc1
update runCanary traffic step for special cases (#219)
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-07-30 10:30:26 +08:00
Jiajing LU 6fae7085e5
* inject headerModifier to the luaData (#223)
* fix lua script and test case
* use ptr instead of struct
* add requestHeaderModifier to testcase debugging toolkit

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>
2024-07-22 10:47:18 +08:00
myname4423 e7652cbc7c
traffic: Refactor continous logic (#222)
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-07-15 11:18:11 +08:00
myname4423 db761a979c
add 2 fields to status to support showing result of kubectl get (#220)
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-06-25 14:58:53 +08:00
myname4423 aa28f4e12e
Allow to jump between steps (#218)
* allow jump between steps

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

allow jump between steps

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

allow jump among steps

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

safte index check

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

add e2e test for step jump

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

amend: style-agonstic reference for webhook

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

improve existing e2e logic to avoid unexpected behaviour

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

jump: nextStep Index default value from 0 to -1

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

after rebase

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

* jump: fix out of range

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

---------

Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-06-25 13:21:54 +08:00
myname4423 1e8af4a4c1
update api for future bluegreen (#214)
add status conversion



nextStepIndex default value from 0 to -1



restore the enableExtra field in BR

Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-06-12 13:27:41 +08:00
Jiajing LU 62794dc883
Support Path and QueryParams in http route matches (#204)
* support queryparams for gateway api

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* support mse

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* support path and queryParams

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* fix lint

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* fix testcase

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* fix manifests

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* do not provide default value for path

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* Allow Not generating Canary Service && Fixed a bug caused by NOT considering case-insensitivity. (#200)

* Fixed a bug caused by NOT considering case-insensitivity.

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

* add DisableGenerateCanaryService for CanaryStrategy

amend1: update crd yaml

amend2: add DisableGenerateCanaryService for v1alpha1

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

---------

Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* revert test images

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* polish comments

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* add gateway api tests

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* fix MSE cases

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* update golang lint ci

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* regenerate manifests

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* remove generic usage

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* update istio lua script

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* update v1alpha1 in e2e to v1beta1

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* fix cases

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* refactor istio case to include queryParams and path

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* fix cloneset issue

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* fix typo

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

* revert images

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>

---------

Signed-off-by: Megrez Lu <lujiajing1126@gmail.com>
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: myname4423 <57184070+myname4423@users.noreply.github.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-06-12 13:21:42 +08:00
myname4423 3eeb7b4ddc
modify the helm version from latest to v3.14.0 (#215)
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-05-25 09:45:24 +08:00
pnr 07c1731e8a
fix: don't check for strategy when finalize (#198)
Co-authored-by: nwaiyatharee <nattadej.waiyatharee@agoda.com>
2024-04-02 13:45:36 +08:00
myname4423 25b053b8be
update unit test for PR #200 (#206)
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-04-02 10:34:36 +08:00
myname4423 0ff23f6636
Allow Not generating Canary Service && Fixed a bug caused by NOT considering case-insensitivity. (#200)
* Fixed a bug caused by NOT considering case-insensitivity.

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

* add DisableGenerateCanaryService for CanaryStrategy

amend1: update crd yaml

amend2: add DisableGenerateCanaryService for v1alpha1

Signed-off-by: yunbo <yunbo10124scut@gmail.com>

---------

Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-03-12 16:37:29 +08:00
Wei-Xiang Sun 678d4d2b34
refresh observed rollout-id for BatchRelease (#193)
Signed-off-by: mingzhou.swx <mingzhou.swx@alibaba-inc.com>
Co-authored-by: mingzhou.swx <mingzhou.swx@alibaba-inc.com>
2023-12-27 11:16:07 +08:00
zhengjr9 1e84129ff1
bugfix: Filter rs that are not part of the current Deployement (#191)
Signed-off-by: zhengjr <zhengjiarui_pro@163.com>
2023-12-26 17:54:07 +08:00
berg 83eedb354e
rollout v0.5.0 changelog (#190)
* rollout v0.5.0 changelog

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>

* modify rollout types description

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>

* limit secret & configmaps namespace rbac

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>

* modify rollout v0.5.0 changelog

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>

---------

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>
2023-12-21 15:23:02 +08:00
Wei-Xiang Sun 862040870d
set default advanced deployment strategy (#176)
Signed-off-by: mingzhou.swx <mingzhou.swx@alibaba-inc.com>
Co-authored-by: mingzhou.swx <mingzhou.swx@alibaba-inc.com>
2023-12-19 13:23:00 +08:00
Wei-Xiang Sun e19a89c16e
wait grace period seconds after pod creation/upgrade (#185)
Signed-off-by: mingzhou.swx <mingzhou.swx@alibaba-inc.com>
Co-authored-by: mingzhou.swx <mingzhou.swx@alibaba-inc.com>
2023-12-19 11:22:00 +08:00
berg bc580a3ae7
fix gateway print log panic (#167)
Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>
2023-12-19 11:20:00 +08:00
berg 897b42292c
dump to v1beta1 gatewayapis (#189)
Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>
2023-12-18 15:30:00 +08:00
berg 75b1b90dc9
webhook validate v1beta1 rollout (#188)
Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>
2023-12-18 13:14:00 +08:00
berg 9dcf3659d2
new v1beta1 apis (#184)
Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>
2023-12-04 14:56:47 +08:00
Kuromesi 07b7f20f6a
add lua scripts for istio (#178)
* add lua scripts for istio

Signed-off-by: Kuromesi <blackfacepan@163.com>

* make some improvements for istio lua script

Signed-off-by: Kuromesi <blackfacepan@163.com>

---------

Signed-off-by: Kuromesi <blackfacepan@163.com>
2023-11-06 17:34:57 +08:00
berg d41b1fa7d7
rollout v1beta1 apis (#182)
Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>
2023-11-03 13:38:55 +08:00
Kuromesi a9a9430a9a
add e2e tests for custom network provider (#177)
Signed-off-by: Kuromesi <blackfacepan@163.com>
2023-10-27 14:16:48 +08:00
berg 23f1e97f4e
add changelog v0.4.0 (#160)
* add changelog v0.4.0

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>

* optimize webhook patchResponse function

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>

* modify makefile install helm

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>

* modify github workflow golang version 1.19

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>

* modify makefile kustomize version v4.5.5

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>

* go format

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>

---------

Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>
2023-10-27 11:56:48 +08:00
Kuromesi 57f9853f23
add support for custom network provider (part A) (#172)
* add support for custom network providers

Signed-off-by: Kuromesi <blackfacepan@163.com>

* make some improvements

Signed-off-by: Kuromesi <blackfacepan@163.com>

* log format updates

Signed-off-by: Kuromesi <blackfacepan@163.com>

* make some logic changes

Signed-off-by: Kuromesi <blackfacepan@163.com>

* remove roll back

Signed-off-by: Kuromesi <blackfacepan@163.com>

* add annotation for lua.go

Signed-off-by: Kuromesi <blackfacepan@163.com>

* store configuration when ensure routes

Signed-off-by: Kuromesi <blackfacepan@163.com>

* store configuration when ensure routes

Signed-off-by: Kuromesi <blackfacepan@163.com>

* make some improvements

Signed-off-by: Kuromesi <blackfacepan@163.com>

* move TestLuaScript to custom_network_provider_test

Signed-off-by: Kuromesi <blackfacepan@163.com>

---------

Signed-off-by: Kuromesi <blackfacepan@163.com>
2023-09-25 13:39:20 +08:00
Kuromesi 76d33b830a
set nodePort of canary service to be 0 (#170)
Signed-off-by: Kuromesi <blackfacepan@163.com>
2023-08-29 13:29:56 +08:00
likakuli 657c6d8079
clean: update rollout status log info (#164)
Signed-off-by: likakuli <1154584512@qq.com>
2023-08-15 20:23:43 +08:00
berg 29862589aa
optimize webhook patchResponse function (#165)
Signed-off-by: liheng.zms <liheng.zms@alibaba-inc.com>
2023-07-18 12:47:18 +08:00
Wei-Xiang Sun 72e1c0b936
Advanced deployment scale down old unhealthy pods firstly (#150)
* advanced deployment scale down old unhealthy pods firstly

Signed-off-by: mingzhou.swx <mingzhou.swx@alibaba-inc.com>

* add e2e for advanced deployment scale down old unhealthy pod first

Signed-off-by: mingzhou.swx <mingzhou.swx@alibaba-inc.com>

---------

Signed-off-by: mingzhou.swx <mingzhou.swx@alibaba-inc.com>
Co-authored-by: mingzhou.swx <mingzhou.swx@alibaba-inc.com>
2023-07-12 17:52:13 +08:00
245 changed files with 36090 additions and 9041 deletions

View File

@ -10,24 +10,24 @@ on:
env:
# Common versions
GO_VERSION: '1.17'
GOLANGCI_VERSION: 'v1.42'
GO_VERSION: '1.20'
GOLANGCI_VERSION: 'v2.1'
jobs:
golangci-lint:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Cache Go Dependencies
uses: actions/cache@v2
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
@ -36,25 +36,27 @@ jobs:
run: |
make generate
- name: Lint golang code
uses: golangci/golangci-lint-action@v2
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
with:
version: ${{ env.GOLANGCI_VERSION }}
args: --verbose
skip-pkg-cache: true
mod: readonly
unit-tests:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Fetch History
run: git fetch --prune --unshallow
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Cache Go Dependencies
uses: actions/cache@v2
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
@ -62,11 +64,12 @@ jobs:
- name: Run Unit Tests
run: |
make test
git status
[[ -z $(git status -s) ]] || (printf "Existing modified/untracked files.\nPlease run \"make generate manifests\" and push again.\n"; exit 1)
- name: Publish Unit Test Coverage
uses: codecov/codecov-action@v1
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
token: ${{ secrets.CODECOV_TOKEN }}
flags: unittests
file: cover.out
- name: Check diff
run: '[[ -z $(git status -s) ]] || (printf "Existing modified/untracked files.\nPlease run \"make generate manifests\" and push again.\n"; exit 1)'

28
.github/workflows/docker-image.yaml vendored Normal file
View File

@ -0,0 +1,28 @@
name: Docker Image CI
on:
workflow_dispatch:
# Declare default permissions as read only.
permissions: read-all
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.HUB_KRUISE }}
- name: Build the Docker image
run: |
docker buildx create --use --platform=linux/amd64,linux/arm64,linux/ppc64le --name multi-platform-builder
docker buildx ls
IMG=openkruise/kruise-rollout:${{ github.ref_name }} make docker-multiarch

View File

@ -0,0 +1,121 @@
name: E2E-Advanced-Deployment-1.24
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_CLUSTER_NAME: 'ci-testing'
KIND_VERSION: 'v0.14.0'
KIND_IMAGE: 'kindest/node:v1.24.6'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests For Advance Deployment
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Advanced Deployment' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal
- name: Run E2E Tests For Canary rollout of Advance Deployment
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Canary rollout with Ingress using advance deployment' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -0,0 +1,121 @@
name: E2E-Advanced-Deployment-1.26
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.18.0'
KIND_IMAGE: 'kindest/node:v1.26.3'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests For Deployment Controller
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Advanced Deployment' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal
- name: Run E2E Tests For Canary rollout of Advance Deployment
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Canary rollout with Ingress using advance deployment' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -0,0 +1,121 @@
name: E2E-Advanced-Deployment-1.28
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.22.0'
KIND_IMAGE: 'kindest/node:v1.28.7'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests For Deployment Controller
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Advanced Deployment' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal
- name: Run E2E Tests For Canary rollout of Advance Deployment
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Canary rollout with Ingress using advance deployment' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-CloneSet-1.23
name: E2E-CloneSet-1.24
on:
push:
@ -8,30 +8,35 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.23.3'
GO_VERSION: '1.20'
KIND_VERSION: 'v0.14.0'
KIND_IMAGE: 'kindest/node:v1.24.6'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +49,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -97,14 +102,8 @@ jobs:
set +e
./bin/ginkgo -timeout 60m -v --focus='CloneSet canary rollout with Ingress' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-CloneSet-1.19
name: E2E-CloneSet-1.26
on:
push:
@ -8,30 +8,34 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.19.16'
GO_VERSION: '1.20'
KIND_IMAGE: 'kindest/node:v1.26.3'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +48,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -97,14 +101,8 @@ jobs:
set +e
./bin/ginkgo -timeout 60m -v --focus='CloneSet canary rollout with Ingress' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

109
.github/workflows/e2e-cloneset-1.28.yaml vendored Normal file
View File

@ -0,0 +1,109 @@
name: E2E-CloneSet-1.28
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.22.0'
KIND_IMAGE: 'kindest/node:v1.28.7'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='CloneSet canary rollout with Ingress' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

84
.github/workflows/e2e-custom.yaml vendored Normal file
View File

@ -0,0 +1,84 @@
name: E2E-Custom
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.18.0'
KIND_IMAGE: 'kindest/node:v1.26.3'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
version: ${{ env.KIND_VERSION }}
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests
run: |
export KUBECONFIG=/home/runner/.kube/config
kubectl apply -f ./test/e2e/test_data/customNetworkProvider/istio_crd.yaml
kubectl apply -f ./test/e2e/test_data/customNetworkProvider/lua_script_configmap.yaml
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Canary rollout with custom network provider' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-DaemonSet-1.23
name: E2E-DaemonSet-1.24
on:
push:
@ -8,30 +8,35 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.23.3'
GO_VERSION: '1.20'
KIND_VERSION: 'v0.14.0'
KIND_IMAGE: 'kindest/node:v1.24.6'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +49,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -97,14 +102,8 @@ jobs:
set +e
./bin/ginkgo -timeout 60m -v --focus='DaemonSet canary rollout' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-DaemonSet-1.19
name: E2E-DaemonSet-1.26
on:
push:
@ -8,30 +8,34 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.19.16'
GO_VERSION: '1.20'
KIND_IMAGE: 'kindest/node:v1.26.3'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +48,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -97,14 +101,8 @@ jobs:
set +e
./bin/ginkgo -timeout 60m -v --focus='DaemonSet canary rollout' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -0,0 +1,109 @@
name: E2E-DaemonSet-1.28
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.22.0'
KIND_IMAGE: 'kindest/node:v1.28.7'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='DaemonSet canary rollout' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-Deployment-1.23
name: E2E-Deployment-1.24
on:
push:
@ -8,30 +8,35 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.23.3'
GO_VERSION: '1.20'
KIND_VERSION: 'v0.14.0'
KIND_IMAGE: 'kindest/node:v1.24.6'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +49,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -97,14 +102,8 @@ jobs:
set +e
./bin/ginkgo -timeout 60m -v --focus='Deployment canary rollout with Ingress' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-Deployment-1.19
name: E2E-Deployment-1.26
on:
push:
@ -8,30 +8,34 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.19.16'
GO_VERSION: '1.20'
KIND_IMAGE: 'kindest/node:v1.26.3'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +48,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -97,14 +101,8 @@ jobs:
set +e
./bin/ginkgo -timeout 60m -v --focus='Deployment canary rollout with Ingress' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -0,0 +1,109 @@
name: E2E-Deployment-1.28
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.22.0'
KIND_IMAGE: 'kindest/node:v1.28.7'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Deployment canary rollout with Ingress' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -8,30 +8,35 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.23.3'
GO_VERSION: '1.20'
KIND_VERSION: 'v0.14.0'
KIND_IMAGE: 'kindest/node:v1.24.6'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -70,14 +75,8 @@ jobs:
set +e
./bin/ginkgo -timeout 60m -v --focus='Canary rollout with Gateway API' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -0,0 +1,84 @@
name: E2E-Multiple-NetworkProvider
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.18.0'
KIND_IMAGE: 'kindest/node:v1.26.3'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
version: ${{ env.KIND_VERSION }}
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests
run: |
export KUBECONFIG=/home/runner/.kube/config
kubectl apply -f ./test/e2e/test_data/customNetworkProvider/istio_crd.yaml
kubectl apply -f ./test/e2e/test_data/customNetworkProvider/lua_script_configmap.yaml
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Canary rollout with multiple network providers' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-Others-1.23
name: E2E-Others-1.24
on:
push:
@ -8,30 +8,35 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.23.3'
GO_VERSION: '1.20'
KIND_VERSION: 'v0.14.0'
KIND_IMAGE: 'kindest/node:v1.24.6'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +49,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -97,14 +102,8 @@ jobs:
set +e
./bin/ginkgo -timeout 60m -v --focus='Others' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-Others-1.19
name: E2E-Others-1.26
on:
push:
@ -8,30 +8,34 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.19.16'
GO_VERSION: '1.20'
KIND_IMAGE: 'kindest/node:v1.26.3'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +48,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -97,14 +101,8 @@ jobs:
set +e
./bin/ginkgo -timeout 60m -v --focus='Others' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

109
.github/workflows/e2e-others-1.28.yaml vendored Normal file
View File

@ -0,0 +1,109 @@
name: E2E-Others-1.28
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.22.0'
KIND_IMAGE: 'kindest/node:v1.28.7'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Others' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-StatefulSet-1.23
name: E2E-StatefulSet-1.24
on:
push:
@ -8,30 +8,35 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.23.3'
GO_VERSION: '1.20'
KIND_VERSION: 'v0.14.0'
KIND_IMAGE: 'kindest/node:v1.24.6'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +49,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -97,14 +102,8 @@ jobs:
set +e
./bin/ginkgo -timeout 60m -v --focus='StatefulSet canary rollout with Ingress' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-StatefulSet-1.19
name: E2E-StatefulSet-1.28
on:
push:
@ -8,30 +8,34 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.19.16'
GO_VERSION: '1.20'
KIND_IMAGE: 'kindest/node:v1.26.3'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +48,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -97,14 +101,8 @@ jobs:
set +e
./bin/ginkgo -timeout 60m -v --focus='StatefulSet canary rollout with Ingress' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -0,0 +1,109 @@
name: E2E-StatefulSet-1.28
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.22.0'
KIND_IMAGE: 'kindest/node:v1.28.7'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='StatefulSet canary rollout with Ingress' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-Advanced-Deployment-1.19
name: E2E-V1Beta1-BlueGreen-1.24
on:
push:
@ -8,30 +8,35 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.19.16'
GO_VERSION: '1.20'
KIND_VERSION: 'v0.14.0'
KIND_IMAGE: 'kindest/node:v1.24.6'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +49,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -81,23 +86,23 @@ jobs:
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
kubectl get pod -n kruise-rollout --no-headers | awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
kubectl get pod -n kruise-rollout --no-headers | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
exit 1
fi
- name: Run E2E Tests For Deployment Controller
- name: Bluegreen Release Disable HPA
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Advanced Deployment' test/e2e
./bin/ginkgo -timeout 60m -v --focus='bluegreen disable hpa test case - autoscaling/v2 for v1.23' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
@ -108,14 +113,14 @@ jobs:
exit 1
fi
exit $retVal
- name: Run E2E Tests For Control Plane
- name: Deployment Bluegreen Release
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Advanced Deployment canary rollout with Ingress' test/e2e
./bin/ginkgo -timeout 60m -v --focus='Bluegreen Release - Deployment - Ingress' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
@ -126,3 +131,15 @@ jobs:
exit 1
fi
exit $retVal
- name: CloneSet Bluegreen Release
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Bluegreen Release - Cloneset - Ingress' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -1,4 +1,4 @@
name: E2E-Advanced-Deployment-1.23
name: E2E-V1Beta1-BlueGreen-1.26
on:
push:
@ -8,30 +8,34 @@ on:
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.17'
KIND_IMAGE: 'kindest/node:v1.23.3'
GO_VERSION: '1.20'
KIND_IMAGE: 'kindest/node:v1.26.3'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@v2
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@v1.2.0
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
@ -44,7 +48,7 @@ jobs:
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
@ -90,14 +94,14 @@ jobs:
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests For Deployment Controller
- name: Bluegreen Release Disable HPA
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Advanced Deployment' test/e2e
./bin/ginkgo -timeout 60m -v --focus='bluegreen disable hpa test case - autoscaling/v2 for v1.26' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
@ -108,14 +112,14 @@ jobs:
exit 1
fi
exit $retVal
- name: Run E2E Tests For Control Plane
- name: Deployment Bluegreen Release
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Advanced Deployment canary rollout with Ingress' test/e2e
./bin/ginkgo -timeout 60m -v --focus='Bluegreen Release - Deployment - Ingress' test/e2e
retVal=$?
# kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
@ -126,3 +130,15 @@ jobs:
exit 1
fi
exit $retVal
- name: CloneSet Bluegreen Release
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Bluegreen Release - Cloneset - Ingress' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -0,0 +1,145 @@
name: E2E-V1Beta1-BlueGreen-1.28
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.22.0'
KIND_IMAGE: 'kindest/node:v1.28.7'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Bluegreen Release Disable HPA
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='bluegreen disable hpa test case - autoscaling/v2 for v1.26' test/e2e
retVal=$?
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
fi
exit $retVal
- name: Deployment Bluegreen Release
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Bluegreen Release - Deployment - Ingress' test/e2e
retVal=$?
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
restartCount=$(kubectl get pod -n kruise-rollout --no-headers | awk '{print $4}')
if [ "${restartCount}" -eq "0" ];then
echo "Kruise-rollout has not restarted"
else
kubectl get pod -n kruise-rollout --no-headers
echo "Kruise-rollout has restarted, abort!!!"
kubectl get pod -n kruise-rollout --no-headers| awk '{print $1}' | xargs kubectl logs -p -n kruise-rollout
exit 1
fi
exit $retVal
- name: CloneSet Bluegreen Release
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Bluegreen Release - Cloneset - Ingress' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -0,0 +1,109 @@
name: E2E-V1Beta1-JUMP-1.24
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.14.0'
KIND_IMAGE: 'kindest/node:v1.24.6'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Step Jump' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -0,0 +1,108 @@
name: E2E-V1Beta1-JUMP-1.26
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
# Declare default permissions as read only.
permissions: read-all
env:
# Common versions
GO_VERSION: '1.20'
KIND_IMAGE: 'kindest/node:v1.26.3'
KIND_CLUSTER_NAME: 'ci-testing'
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Step Jump' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -0,0 +1,108 @@
name: E2E-V1Beta1-JUMP-1.28
on:
push:
branches:
- master
- release-*
pull_request: {}
workflow_dispatch: {}
env:
# Common versions
GO_VERSION: '1.20'
KIND_VERSION: 'v0.22.0'
KIND_IMAGE: 'kindest/node:v1.28.7'
KIND_CLUSTER_NAME: 'ci-testing'
# Declare default permissions as read only.
permissions: read-all
jobs:
rollout:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Setup Kind Cluster
uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 # v1.12.0
with:
node_image: ${{ env.KIND_IMAGE }}
cluster_name: ${{ env.KIND_CLUSTER_NAME }}
config: ./test/kind-conf.yaml
version: ${{ env.KIND_VERSION }}
- name: Build image
run: |
export IMAGE="openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID}"
docker build --pull --no-cache . -t $IMAGE
kind load docker-image --name=${KIND_CLUSTER_NAME} $IMAGE || { echo >&2 "kind not installed or error loading image: $IMAGE"; exit 1; }
- name: Install Kruise
run: |
set -ex
kubectl cluster-info
make helm
helm repo add openkruise https://openkruise.github.io/charts/
helm repo update
helm install kruise openkruise/kruise --version 1.7.0
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-system | grep '1/1' | grep kruise-controller-manager | wc -l)
set -e
if [ "$PODS" -eq "2" ]; then
echo "Wait for kruise-manager ready successfully"
else
echo "Timeout to wait for kruise-manager ready"
exit 1
fi
- name: Install Kruise Rollout
run: |
set -ex
kubectl cluster-info
IMG=openkruise/kruise-rollout:e2e-${GITHUB_RUN_ID} ./scripts/deploy_kind.sh
for ((i=1;i<10;i++));
do
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
set -e
if [ "$PODS" -eq "1" ]; then
break
fi
sleep 3
done
set +e
PODS=$(kubectl get pod -n kruise-rollout | grep '1/1' | wc -l)
kubectl get node -o yaml
kubectl get all -n kruise-rollout -o yaml
set -e
if [ "$PODS" -eq "1" ]; then
echo "Wait for kruise-rollout ready successfully"
else
echo "Timeout to wait for kruise-rollout ready"
exit 1
fi
- name: Run E2E Tests
run: |
export KUBECONFIG=/home/runner/.kube/config
make ginkgo
set +e
./bin/ginkgo -timeout 60m -v --focus='Step Jump' test/e2e
retVal=$?
if [ "${retVal}" -ne 0 ];then
echo "test fail, dump kruise-rollout logs"
kubectl get pod -n kruise-rollout --no-headers | grep manager | awk '{print $1}' | xargs kubectl logs -n kruise-rollout
fi
exit $retVal

View File

@ -10,12 +10,15 @@ on:
- master
- release-*
# Declare default permissions as read only.
permissions: read-all
jobs:
license_check:
runs-on: ubuntu-latest
name: Check for unapproved licenses
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:

2
.gitignore vendored
View File

@ -29,3 +29,5 @@ test/e2e/generated/bindata.go
.vscode
.DS_Store
lua_configuration/networking.istio.io/**/testdata/*.lua

View File

@ -1,79 +1,77 @@
# options for analysis running
version: "2"
run:
# default concurrency is a available CPU number
concurrency: 4
# timeout for analysis, e.g. 30s, 5m, default is 1m
deadline: 5m
# exit code when at least one issue was found, default is 1
issues-exit-code: 1
# include test files or not, default is true
tests: true
# list of build tags, all linters use it. Default is empty list.
#build-tags:
# - mytag
# which dirs to skip: they won't be analyzed;
# can use regexp here: generated.*, regexp is applied on full path;
# default value is empty list, but next dirs are always skipped independently
# from this option's value:
# third_party$, testdata$, examples$, Godeps$, builtin$
skip-dirs:
- vendor
# which files to skip: they will be analyzed, but issues from them
# won't be reported. Default value is empty list, but there is
# no need to include all autogenerated files, we confidently recognize
# autogenerated files. If it's not please let us know.
skip-files:
# - ".*\\.my\\.go$"
# - lib/bad.go
# output configuration options
output:
# colored-line-number|line-number|json|tab|checkstyle, default is "colored-line-number"
format: colored-line-number
# print lines of code with issue, default is true
print-issued-lines: true
# print linter name in the end of issue text, default is true
print-linter-name: true
# all available settings of specific linters
linters-settings:
golint:
# minimal confidence for issues, default is 0.8
min-confidence: 0.8
gofmt:
# simplify code: gofmt with `-s` option, true by default
simplify: true
goimports:
# put imports beginning with prefix after 3rd-party packages;
# it's a comma-separated list of prefixes
#local-prefixes: github.com/openkruise/rollouts
misspell:
# Correct spellings using locale preferences for US or UK.
# Default is to use a neutral variety of English.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
locale: default
#ignore-words:
# - someword
formats:
text:
path: stdout
colors: true
linters:
fast: false
disable-all: true
default: none
enable:
# TODO Enforce the below linters later
- gofmt
- goimports
- depguard
- govet
- ineffassign
- misspell
issues:
exclude:
# staticcheck
- 'SA1019: package github.com/golang/protobuf/proto is deprecated: Use the "google.golang.org/protobuf/proto" package instead'
- unconvert
- unused
settings:
misspell:
# Correct spellings using locale preferences for US or UK.
# Default is to use a neutral variety of English.
# Setting locale to US will correct the British spelling of 'colour' to 'color'.
locale: US
ignore-rules:
- finalise
- Finalising
- Cancelling
depguard:
rules:
forbid-pkg-errors:
deny:
- pkg: "github.com/pkg/errors"
desc: Should be replaced with standard lib errors or fmt.Errorf
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- path: (.+)\.go$
text: 'SA1019: package github.com/golang/protobuf/proto is deprecated: Use the "google.golang.org/protobuf/proto" package instead'
paths:
- third_party$
- builtin$
- examples$
- apis
- pkg/client
- vendor
- test
formatters:
enable:
- gofmt
- goimports
settings:
gofmt:
simplify: true
goimports:
# put imports beginning with prefix after 3rd-party packages;
local-prefixes:
- github.com/openkruise/rollouts
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
- apis
- pkg/client
- vendor
- test

View File

@ -1,5 +1,93 @@
# Change Log
## v0.6.1
### Key Features:
- Introduced `rollout-batch-id` labeling for blue-green and canary style releases ([#250](https://github.com/openkruise/rollouts/pull/250),([#251](https://github.com/openkruise/rollouts/pull/251),[#261](https://github.com/openkruise/rollouts/pull/261),[@PersistentJZH](https://github.com/PersistentJZH),[@AiRanthem](https://github.com/AiRanthem))
### Bugfix:
- The order of object in BatchRelease event handler is fixed ([#265](https://github.com/openkruise/rollouts/pull/265),[@z760087139](https://github.com/z760087139))
## v0.5.1
### Bugfix:
- Fix Rollout v1alpha1 and v1beta1 version conversions with incorrectly converted partition fields. ([#200](https://github.com/openkruise/rollouts/pull/200),[@myname4423](https://github.com/myname4423))
## v0.6.0
### Key Features:
- 🎊 Support for blue-green style releases has been added ([#214](https://github.com/openkruise/rollouts/pull/214),[#229](https://github.com/openkruise/rollouts/pull/229),[#238](https://github.com/openkruise/rollouts/pull/238),[#220](https://github.com/openkruise/rollouts/pull/220),[@myname4423](https://github.com/myname4423))
- ⭐ Traffic loss during rollouts in certain scenarios is avoided ([#226](https://github.com/openkruise/rollouts/pull/226),[#219](https://github.com/openkruise/rollouts/pull/219),[#222](https://github.com/openkruise/rollouts/pull/222),[@myname4423](https://github.com/myname4423))
### Other Features:
- Enhanced flexibility by allowing free navigation between different steps within a rollout ([#218](https://github.com/openkruise/rollouts/pull/218),[@myname4423](https://github.com/myname4423))
- Added support for HTTPQueryParamMatch and HTTPPathMatch of the Gateway API in traffic management ([#204](https://github.com/openkruise/rollouts/pull/204),[@lujiajing1126](https://github.com/lujiajing1126))
- Integrated RequestHeaderModifier into LuaData, facilitating its use with custom network references like Istio ([#223](https://github.com/openkruise/rollouts/pull/223),[@lujiajing1126](https://github.com/lujiajing1126))
- Introduced a composite provider to support multiple network providers ([#224](https://github.com/openkruise/rollouts/pull/224),[@lujiajing1126](https://github.com/lujiajing1126))
- Got the canary service selector patched from pod template metadata ([#243](https://github.com/openkruise/rollouts/pull/243),[@lujiajing1126](https://github.com/lujiajing1126))
- Patched label `rollout-batch-id` to pods even without `rollout-id` in the workload ([#248](https://github.com/openkruise/rollouts/pull/248),[@PersistentJZH](https://github.com/PersistentJZH))
- Upgraded Gateway API version from 0.5.1 to 0.7.1 and Kubernetes version from 1.24 to 1.26 ([#237](https://github.com/openkruise/rollouts/pull/237),[@AiRanthem](https://github.com/AiRanthem))
- Enabled the option to skip canary service generation when using `trafficRoutings.customNetworkRefs` ([#200](https://github.com/openkruise/rollouts/pull/200),[@myname4423](https://github.com/myname4423))
### Bugfix:
- Filtered out ReplicaSets not part of the current Deployment to prevent frequent scaling issues when multiple deployments share the same selectors ([#191](https://github.com/openkruise/rollouts/pull/191),[@zhengjr9](https://github.com/zhengjr9))
- Synced the observed `rollout-id` to the BatchRelease CR status ([#193](https://github.com/openkruise/rollouts/pull/193),[@veophi](https://github.com/veophi))
- Checked deployment strategy during finalization to prevent random stuck states when used with KubeVela ([#198](https://github.com/openkruise/rollouts/pull/198),[@phantomnat](https://github.com/phantomnat))
- Resolved a Lua encoding structural error ([#209](https://github.com/openkruise/rollouts/pull/209),[@ls-2018](https://github.com/ls-2018))
- Corrected batch ID labeling in partition-style releases when pod recreation happens ([#246](https://github.com/openkruise/rollouts/pull/246),[@myname4423](https://github.com/myname4423))
### Breaking Changes:
- Restricted the ability to set traffic percentage or match selectors in a partition-style release step when exceeding 30% replicas. Use the `rollouts.kruise.io/partition-replicas-limit` annotation to override this default threshold. Setting the threshold to 100% restores the previous behavior ([#225](https://github.com/openkruise/rollouts/pull/225),[@myname4423](https://github.com/myname4423))
## v0.5.0
### Resources Graduating to BETA
After more than a year of development, we have now decided to upgrade the following resources to v1beta1, as follows:
- Rollout
- BatchRelease
Please refer to the [community documentation](https://openkruise.io/rollouts/user-manuals/api-specifications) for detailed api definitions.
**Note:** The v1alpha1 api is still available, and you can still use the v1alpha1 api in v0.5.0.
But we still recommend that you migrate to v1beta1 gradually, as some of the new features will only be available in v1beta1,
e.g., [Extensible Traffic Routing Based on Lua Script](https://openkruise.io/rollouts/developer-manuals/custom-network-provider/).
### Bump To V1beta1 Gateway API
Support for GatewayAPI from v1alpha2 to v1beta1, you can use v1beta1 gateway API.
### Extensible Traffic Routing Based on Lua Script
The Gateway API is a standard gateway resource given by the K8S community, but there are still a large number of users in the community who are still using some customized gateway resources, such as VirtualService, Apisix, and so on.
In order to adapt to this behavior and meet the diverse demands of the community for gateway resources, we support a traffic routing scheme based on Lua scripts.
Kruise Rollout utilizes a Lua-script-based customization approach for API Gateway resources (Istio VirtualService, Apisix ApisixRoute, Kuma TrafficRoute and etc.).
Kruise Rollout involves invoking Lua scripts to retrieve and update the desired configurations of resources based on release strategies and the original configurations of API Gateway resources (including spec, labels, and annotations).
It enables users to easily adapt and integrate various types of API Gateway resources without modifying existing code and configurations.
By using Kruise Rollout, users can:
- Customize Lua scripts for handling API Gateway resources, allowing for flexible implementation of resource processing and providing support for a wider range of resources.
- Utilize a common Rollout configuration template to configure different resources, reducing configuration complexity and facilitating user configuration.
### Traffic Routing with Istio
Based on the lua script approach, now we add built-in support for Istio resources VirtualService,
you can directly use Kruise Rollout to achieve Istio scenarios Canary, A/B Testing release.
### Others
- Bug fix: wait grace period seconds after pod creation/upgrade. ([#185](https://github.com/openkruise/rollouts/pull/185), [@veophi](https://github.com/veophi))
## v0.4.0
### Kruise-Rollout-Controller
- Rollout Support Kruise Advanced DaemonSet. ([#134](https://github.com/openkruise/rollouts/pull/134), [@Yadan-Wei](https://github.com/Yadan-Wei))
- Rollout support end-to-end canary deployment. ([#153](https://github.com/openkruise/rollouts/pull/153), [@zmberg](https://github.com/zmberg))
- Rollout trafficTouting support requestHeaderModifier. ([#156](https://github.com/openkruise/rollouts/pull/156), [@zmberg](https://github.com/zmberg))
- Rollout support disabled for a rollout. ([#155](https://github.com/openkruise/rollouts/pull/155), [@Kuromesi](https://github.com/Kuromesi))
- Rollout support patch PodTemplateMetadata. ([#157](https://github.com/openkruise/rollouts/pull/157), [@zmberg](https://github.com/zmberg))
- Rollout only webhook workload which has rollout CR. ([#158](https://github.com/openkruise/rollouts/pull/158), [@zmberg](https://github.com/zmberg))
- Advanced deployment scale down old unhealthy pods firstly. ([#150](https://github.com/openkruise/rollouts/pull/150), [@veophi](https://github.com/veophi))
- Update k8s registry references to registry.k8s.io. ([#126](https://github.com/openkruise/rollouts/pull/126), [@asa3311](https://github.com/asa3311))
- When the data type of spec.replicas is int, cancel the upper 100 limit. ([#142](https://github.com/openkruise/rollouts/pull/142), [@MrSumeng](https://github.com/MrSumeng))
- Add e2e test for advanced daemonSet. ([#143](https://github.com/openkruise/rollouts/pull/143), [@Janice1457](https://github.com/Janice1457))
- Exclude workload deleted matching labels in webhook. ([#146](https://github.com/openkruise/rollouts/pull/146), [@wangyikewxgm](https://github.com/wangyikewxgm))
- Optimize the modification of rollout to GatewayAPI httpRoute header. ([#137](https://github.com/openkruise/rollouts/pull/137), [@ZhangSetSail](https://github.com/ZhangSetSail))
## v0.3.0
### Kruise-Rollout-Controller

View File

@ -1,5 +1,4 @@
# Build the manager binary
FROM golang:1.18 as builder
FROM golang:1.20.14-alpine3.19 as builder
WORKDIR /workspace

View File

@ -1,7 +1,7 @@
# Build the manager binary
ARG BASE_IMAGE=alpine
ARG BASE_IMAGE_VERION=3.17
FROM --platform=$BUILDPLATFORM golang:1.18-alpine3.17 as builder
FROM --platform=$BUILDPLATFORM golang:1.19-alpine3.17 as builder
WORKDIR /workspace
@ -23,12 +23,25 @@ ARG BASE_IMAGE
ARG BASE_IMAGE_VERION
FROM ${BASE_IMAGE}:${BASE_IMAGE_VERION}
RUN apk add --no-cache ca-certificates=~20220614-r4 bash=~5.2.15-r0 expat=~2.5.0-r0 \
&& rm -rf /var/cache/apk/*
RUN set -eux; \
apk --no-cache --update upgrade && \
apk --no-cache add ca-certificates && \
apk --no-cache add tzdata && \
rm -rf /var/cache/apk/* && \
update-ca-certificates && \
echo "only include root and nobody user" && \
echo -e "root:x:0:0:root:/root:/bin/ash\nnobody:x:65534:65534:nobody:/:/sbin/nologin" | tee /etc/passwd && \
echo -e "root:x:0:root\nnobody:x:65534:" | tee /etc/group && \
rm -rf /usr/local/sbin/* && \
rm -rf /usr/local/bin/* && \
rm -rf /usr/sbin/* && \
rm -rf /usr/bin/* && \
rm -rf /sbin/* && \
rm -rf /bin/*
WORKDIR /
COPY --from=builder /workspace/manager .
COPY lua_configuration /lua_configuration
USER 1000
USER 65534
ENTRYPOINT ["/manager"]

View File

@ -19,6 +19,24 @@ SHELL = /usr/bin/env bash -o pipefail
all: build
## Location to install dependencies to
TESTBIN ?= $(shell pwd)/testbin
$(TESTBIN):
mkdir -p $(TESTBIN)
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
# Run `setup-envtest list` to list available versions.
ENVTEST_K8S_VERSION ?= 1.28.0
ENVTEST ?= $(TESTBIN)/setup-envtest
.PHONY: envtest
envtest: $(ENVTEST) ## Download envtest-setup locally if necessary.
$(ENVTEST): $(TESTBIN)
ifeq (, $(shell ls $(TESTBIN)/setup-envtest 2>/dev/null))
GOBIN=$(TESTBIN) go install sigs.k8s.io/controller-runtime/tools/setup-envtest@c7e1dc9b5302d649d5531e19168dd7ea0013736d
endif
##@ General
# The help target prints out all targets with their descriptions organized
@ -51,10 +69,10 @@ vet: ## Run go vet against code.
go vet ./...
ENVTEST_ASSETS_DIR=$(shell pwd)/testbin
test: manifests generate fmt vet ## Run tests.
mkdir -p ${ENVTEST_ASSETS_DIR}
test -f ${ENVTEST_ASSETS_DIR}/setup-envtest.sh || curl -sSLo ${ENVTEST_ASSETS_DIR}/setup-envtest.sh https://raw.githubusercontent.com/kubernetes-sigs/controller-runtime/v0.8.3/hack/setup-envtest.sh
source ${ENVTEST_ASSETS_DIR}/setup-envtest.sh; fetch_envtest_tools $(ENVTEST_ASSETS_DIR); setup_envtest_env $(ENVTEST_ASSETS_DIR); go test ./pkg/... -coverprofile cover.out
test: manifests generate fmt vet envtest ## Run tests.
echo $(ENVTEST)
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -race ./pkg/... -coverprofile raw-cover.out
grep -v "pkg/client" raw-cover.out > cover.out
##@ Build
@ -91,16 +109,17 @@ undeploy: ## Undeploy controller from the K8s cluster specified in ~/.kube/confi
CONTROLLER_GEN = $(shell pwd)/bin/controller-gen
CONTROLLER_GEN_VERSION = v0.14.0
controller-gen: ## Download controller-gen locally if necessary.
ifeq ("$(shell $(CONTROLLER_GEN) --version)", "Version: v0.7.0")
ifeq ("$(shell $(CONTROLLER_GEN) --version)", "Version: ${CONTROLLER_GEN_VERSION}")
else
rm -rf $(CONTROLLER_GEN)
$(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@v0.7.0)
$(call go-get-tool,$(CONTROLLER_GEN),sigs.k8s.io/controller-tools/cmd/controller-gen@${CONTROLLER_GEN_VERSION})
endif
KUSTOMIZE = $(shell pwd)/bin/kustomize
kustomize: ## Download kustomize locally if necessary.
$(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v3@v3.8.7)
$(call go-get-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v4@v4.5.5)
GINKGO = $(shell pwd)/bin/ginkgo
ginkgo: ## Download ginkgo locally if necessary.
@ -108,7 +127,7 @@ ginkgo: ## Download ginkgo locally if necessary.
HELM = $(shell pwd)/bin/helm
helm: ## Download helm locally if necessary.
$(call go-get-tool,$(HELM),helm.sh/helm/v3@v3.8.1)
$(call go-get-tool,$(HELM),helm.sh/helm/v3/cmd/helm@v3.14.0)
# go-get-tool will 'go get' any package $2 and install it to $1.
PROJECT_DIR := $(shell dirname $(abspath $(lastword $(MAKEFILE_LIST))))
@ -119,7 +138,7 @@ TMP_DIR=$$(mktemp -d) ;\
cd $$TMP_DIR ;\
go mod init tmp ;\
echo "Downloading $(2)" ;\
GOBIN=$(PROJECT_DIR)/bin go get $(2) ;\
GOBIN=$(PROJECT_DIR)/bin go install $(2) ;\
rm -rf $$TMP_DIR ;\
}
endef

View File

@ -0,0 +1,26 @@
/*
Copyright 2023 The Kruise 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 apis
import (
"github.com/openkruise/rollouts/api/v1alpha1"
)
func init() {
// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme)
}

View File

@ -0,0 +1,26 @@
/*
Copyright 2023 The Kruise 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 apis
import (
"github.com/openkruise/rollouts/api/v1beta1"
)
func init() {
// Register the types with the Scheme so the components can map objects to GroupVersionKinds and back
AddToSchemes = append(AddToSchemes, v1beta1.SchemeBuilder.AddToScheme)
}

29
api/apis.go Normal file
View File

@ -0,0 +1,29 @@
/*
Copyright 2023 The Kruise 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 apis
import (
"k8s.io/apimachinery/pkg/runtime"
)
// AddToSchemes may be used to add all resources defined in the project to a Scheme
var AddToSchemes runtime.SchemeBuilder
// AddToScheme adds all Resources to the Scheme
func AddToScheme(s *runtime.Scheme) error {
return AddToSchemes.AddToScheme(s)
}

View File

@ -54,6 +54,16 @@ type ReleasePlan struct {
// only support for canary deployment
// +optional
PatchPodTemplateMetadata *PatchPodTemplateMetadata `json:"patchPodTemplateMetadata,omitempty"`
// RollingStyle can be "Canary", "Partiton" or "BlueGreen"
RollingStyle RollingStyleType `json:"rollingStyle,omitempty"`
// EnableExtraWorkloadForCanary indicates whether to create extra workload for canary
// True corresponds to RollingStyle "Canary".
// False corresponds to RollingStyle "Partiton".
// Ignored in BlueGreen-style.
// This field is about to deprecate, use RollingStyle instead.
// If both of them are set, controller will only consider this
// filed when RollingStyle is empty
EnableExtraWorkloadForCanary bool `json:"enableExtraWorkloadForCanary"`
}
type FinalizingPolicyType string
@ -142,6 +152,6 @@ const (
RolloutPhasePreparing RolloutPhase = "Preparing"
// RolloutPhaseFinalizing indicates a rollout is finalizing
RolloutPhaseFinalizing RolloutPhase = "Finalizing"
// RolloutPhaseCompleted indicates a rollout is completed/cancelled/terminated
// RolloutPhaseCompleted indicates a rollout is completed/canceled/terminated
RolloutPhaseCompleted RolloutPhase = "Completed"
)

478
api/v1alpha1/conversion.go Normal file
View File

@ -0,0 +1,478 @@
/*
Copyright 2023 The Kruise 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 v1alpha1
import (
"fmt"
"strings"
"k8s.io/apimachinery/pkg/util/intstr"
utilpointer "k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/conversion"
"github.com/openkruise/rollouts/api/v1beta1"
)
func (src *Rollout) ConvertTo(dst conversion.Hub) error {
switch t := dst.(type) {
case *v1beta1.Rollout:
obj := dst.(*v1beta1.Rollout)
obj.ObjectMeta = src.ObjectMeta
obj.Spec = v1beta1.RolloutSpec{}
srcSpec := src.Spec
obj.Spec.WorkloadRef = v1beta1.ObjectRef{
APIVersion: srcSpec.ObjectRef.WorkloadRef.APIVersion,
Kind: srcSpec.ObjectRef.WorkloadRef.Kind,
Name: srcSpec.ObjectRef.WorkloadRef.Name,
}
obj.Spec.Disabled = srcSpec.Disabled
obj.Spec.Strategy = v1beta1.RolloutStrategy{
Paused: srcSpec.Strategy.Paused,
Canary: &v1beta1.CanaryStrategy{
FailureThreshold: srcSpec.Strategy.Canary.FailureThreshold,
},
}
for _, step := range srcSpec.Strategy.Canary.Steps {
o := v1beta1.CanaryStep{
TrafficRoutingStrategy: ConversionToV1beta1TrafficRoutingStrategy(step.TrafficRoutingStrategy),
Replicas: step.Replicas,
Pause: v1beta1.RolloutPause{Duration: step.Pause.Duration},
}
if step.Replicas == nil && step.Weight != nil {
o.Replicas = &intstr.IntOrString{
Type: intstr.String,
StrVal: fmt.Sprintf("%d", *step.Weight) + "%",
}
}
obj.Spec.Strategy.Canary.Steps = append(obj.Spec.Strategy.Canary.Steps, o)
}
for _, ref := range srcSpec.Strategy.Canary.TrafficRoutings {
o := ConversionToV1beta1TrafficRoutingRef(ref)
obj.Spec.Strategy.Canary.TrafficRoutings = append(obj.Spec.Strategy.Canary.TrafficRoutings, o)
}
if srcSpec.Strategy.Canary.PatchPodTemplateMetadata != nil {
obj.Spec.Strategy.Canary.PatchPodTemplateMetadata = &v1beta1.PatchPodTemplateMetadata{
Annotations: map[string]string{},
Labels: map[string]string{},
}
for k, v := range srcSpec.Strategy.Canary.PatchPodTemplateMetadata.Annotations {
obj.Spec.Strategy.Canary.PatchPodTemplateMetadata.Annotations[k] = v
}
for k, v := range srcSpec.Strategy.Canary.PatchPodTemplateMetadata.Labels {
obj.Spec.Strategy.Canary.PatchPodTemplateMetadata.Labels[k] = v
}
}
if !strings.EqualFold(src.Annotations[RolloutStyleAnnotation], string(PartitionRollingStyle)) {
obj.Spec.Strategy.Canary.EnableExtraWorkloadForCanary = true
}
if src.Annotations[TrafficRoutingAnnotation] != "" {
obj.Spec.Strategy.Canary.TrafficRoutingRef = src.Annotations[TrafficRoutingAnnotation]
}
// status
obj.Status = v1beta1.RolloutStatus{
ObservedGeneration: src.Status.ObservedGeneration,
Phase: v1beta1.RolloutPhase(src.Status.Phase),
Message: src.Status.Message,
}
for _, cond := range src.Status.Conditions {
o := v1beta1.RolloutCondition{
Type: v1beta1.RolloutConditionType(cond.Type),
Status: cond.Status,
LastUpdateTime: cond.LastUpdateTime,
LastTransitionTime: cond.LastTransitionTime,
Reason: cond.Reason,
Message: cond.Message,
}
obj.Status.Conditions = append(obj.Status.Conditions, o)
}
if src.Status.CanaryStatus == nil {
return nil
}
obj.Status.CanaryStatus = &v1beta1.CanaryStatus{
CommonStatus: v1beta1.CommonStatus{
ObservedWorkloadGeneration: src.Status.CanaryStatus.ObservedWorkloadGeneration,
ObservedRolloutID: src.Status.CanaryStatus.ObservedRolloutID,
RolloutHash: src.Status.CanaryStatus.RolloutHash,
StableRevision: src.Status.CanaryStatus.StableRevision,
PodTemplateHash: src.Status.CanaryStatus.PodTemplateHash,
CurrentStepIndex: src.Status.CanaryStatus.CurrentStepIndex,
CurrentStepState: v1beta1.CanaryStepState(src.Status.CanaryStatus.CurrentStepState),
Message: src.Status.CanaryStatus.Message,
LastUpdateTime: src.Status.CanaryStatus.LastUpdateTime,
FinalisingStep: v1beta1.FinalisingStepType(src.Status.CanaryStatus.FinalisingStep),
NextStepIndex: src.Status.CanaryStatus.NextStepIndex,
},
CanaryRevision: src.Status.CanaryStatus.CanaryRevision,
CanaryReplicas: src.Status.CanaryStatus.CanaryReplicas,
CanaryReadyReplicas: src.Status.CanaryStatus.CanaryReadyReplicas,
}
return nil
default:
return fmt.Errorf("unsupported type %v", t)
}
}
func ConversionToV1beta1TrafficRoutingRef(src TrafficRoutingRef) (dst v1beta1.TrafficRoutingRef) {
dst.Service = src.Service
dst.GracePeriodSeconds = src.GracePeriodSeconds
if src.Ingress != nil {
dst.Ingress = &v1beta1.IngressTrafficRouting{
ClassType: src.Ingress.ClassType,
Name: src.Ingress.Name,
}
}
if src.Gateway != nil {
dst.Gateway = &v1beta1.GatewayTrafficRouting{
HTTPRouteName: src.Gateway.HTTPRouteName,
}
}
for _, ref := range src.CustomNetworkRefs {
obj := v1beta1.ObjectRef{
APIVersion: ref.APIVersion,
Kind: ref.Kind,
Name: ref.Name,
}
dst.CustomNetworkRefs = append(dst.CustomNetworkRefs, obj)
}
return dst
}
func ConversionToV1beta1TrafficRoutingStrategy(src TrafficRoutingStrategy) (dst v1beta1.TrafficRoutingStrategy) {
if src.Weight != nil {
dst.Traffic = utilpointer.String(fmt.Sprintf("%d", *src.Weight) + "%")
}
dst.RequestHeaderModifier = src.RequestHeaderModifier
for _, match := range src.Matches {
obj := v1beta1.HttpRouteMatch{
Headers: match.Headers,
}
dst.Matches = append(dst.Matches, obj)
}
return dst
}
func (dst *Rollout) ConvertFrom(src conversion.Hub) error {
switch t := src.(type) {
case *v1beta1.Rollout:
srcV1beta1 := src.(*v1beta1.Rollout)
dst.ObjectMeta = srcV1beta1.ObjectMeta
if !srcV1beta1.Spec.Strategy.IsCanaryStragegy() {
// only v1beta1 supports bluegreen strategy
// Don't log the message because it will print too often
return nil
}
// spec
dst.Spec = RolloutSpec{
ObjectRef: ObjectRef{
WorkloadRef: &WorkloadRef{
APIVersion: srcV1beta1.Spec.WorkloadRef.APIVersion,
Kind: srcV1beta1.Spec.WorkloadRef.Kind,
Name: srcV1beta1.Spec.WorkloadRef.Name,
},
},
Strategy: RolloutStrategy{
Paused: srcV1beta1.Spec.Strategy.Paused,
Canary: &CanaryStrategy{
FailureThreshold: srcV1beta1.Spec.Strategy.Canary.FailureThreshold,
},
},
Disabled: srcV1beta1.Spec.Disabled,
}
for _, step := range srcV1beta1.Spec.Strategy.Canary.Steps {
obj := CanaryStep{
TrafficRoutingStrategy: ConversionToV1alpha1TrafficRoutingStrategy(step.TrafficRoutingStrategy),
Replicas: step.Replicas,
Pause: RolloutPause{Duration: step.Pause.Duration},
}
dst.Spec.Strategy.Canary.Steps = append(dst.Spec.Strategy.Canary.Steps, obj)
}
for _, ref := range srcV1beta1.Spec.Strategy.Canary.TrafficRoutings {
obj := ConversionToV1alpha1TrafficRoutingRef(ref)
dst.Spec.Strategy.Canary.TrafficRoutings = append(dst.Spec.Strategy.Canary.TrafficRoutings, obj)
}
if srcV1beta1.Spec.Strategy.Canary.PatchPodTemplateMetadata != nil {
dst.Spec.Strategy.Canary.PatchPodTemplateMetadata = &PatchPodTemplateMetadata{
Annotations: map[string]string{},
Labels: map[string]string{},
}
for k, v := range srcV1beta1.Spec.Strategy.Canary.PatchPodTemplateMetadata.Annotations {
dst.Spec.Strategy.Canary.PatchPodTemplateMetadata.Annotations[k] = v
}
for k, v := range srcV1beta1.Spec.Strategy.Canary.PatchPodTemplateMetadata.Labels {
dst.Spec.Strategy.Canary.PatchPodTemplateMetadata.Labels[k] = v
}
}
if dst.Annotations == nil {
dst.Annotations = map[string]string{}
}
if srcV1beta1.Spec.Strategy.Canary.EnableExtraWorkloadForCanary {
dst.Annotations[RolloutStyleAnnotation] = strings.ToLower(string(CanaryRollingStyle))
} else {
dst.Annotations[RolloutStyleAnnotation] = strings.ToLower(string(PartitionRollingStyle))
}
if srcV1beta1.Spec.Strategy.Canary.TrafficRoutingRef != "" {
dst.Annotations[TrafficRoutingAnnotation] = srcV1beta1.Spec.Strategy.Canary.TrafficRoutingRef
}
// status
dst.Status = RolloutStatus{
ObservedGeneration: srcV1beta1.Status.ObservedGeneration,
Phase: RolloutPhase(srcV1beta1.Status.Phase),
Message: srcV1beta1.Status.Message,
}
for _, cond := range srcV1beta1.Status.Conditions {
obj := RolloutCondition{
Type: RolloutConditionType(cond.Type),
Status: cond.Status,
LastUpdateTime: cond.LastUpdateTime,
LastTransitionTime: cond.LastTransitionTime,
Reason: cond.Reason,
Message: cond.Message,
}
dst.Status.Conditions = append(dst.Status.Conditions, obj)
}
if srcV1beta1.Status.CanaryStatus == nil {
return nil
}
dst.Status.CanaryStatus = &CanaryStatus{
ObservedWorkloadGeneration: srcV1beta1.Status.CanaryStatus.ObservedWorkloadGeneration,
ObservedRolloutID: srcV1beta1.Status.CanaryStatus.ObservedRolloutID,
RolloutHash: srcV1beta1.Status.CanaryStatus.RolloutHash,
StableRevision: srcV1beta1.Status.CanaryStatus.StableRevision,
CanaryRevision: srcV1beta1.Status.CanaryStatus.CanaryRevision,
PodTemplateHash: srcV1beta1.Status.CanaryStatus.PodTemplateHash,
CanaryReplicas: srcV1beta1.Status.CanaryStatus.CanaryReplicas,
CanaryReadyReplicas: srcV1beta1.Status.CanaryStatus.CanaryReadyReplicas,
CurrentStepIndex: srcV1beta1.Status.CanaryStatus.CurrentStepIndex,
CurrentStepState: CanaryStepState(srcV1beta1.Status.CanaryStatus.CurrentStepState),
Message: srcV1beta1.Status.CanaryStatus.Message,
LastUpdateTime: srcV1beta1.Status.CanaryStatus.LastUpdateTime,
FinalisingStep: FinalizeStateType(srcV1beta1.Status.CanaryStatus.FinalisingStep),
NextStepIndex: srcV1beta1.Status.CanaryStatus.NextStepIndex,
}
return nil
default:
return fmt.Errorf("unsupported type %v", t)
}
}
func ConversionToV1alpha1TrafficRoutingStrategy(src v1beta1.TrafficRoutingStrategy) (dst TrafficRoutingStrategy) {
if src.Traffic != nil {
is := intstr.FromString(*src.Traffic)
weight, _ := intstr.GetScaledValueFromIntOrPercent(&is, 100, true)
dst.Weight = utilpointer.Int32(int32(weight))
}
dst.RequestHeaderModifier = src.RequestHeaderModifier
for _, match := range src.Matches {
obj := HttpRouteMatch{
Headers: match.Headers,
}
dst.Matches = append(dst.Matches, obj)
}
return dst
}
func ConversionToV1alpha1TrafficRoutingRef(src v1beta1.TrafficRoutingRef) (dst TrafficRoutingRef) {
dst.Service = src.Service
dst.GracePeriodSeconds = src.GracePeriodSeconds
if src.Ingress != nil {
dst.Ingress = &IngressTrafficRouting{
ClassType: src.Ingress.ClassType,
Name: src.Ingress.Name,
}
}
if src.Gateway != nil {
dst.Gateway = &GatewayTrafficRouting{
HTTPRouteName: src.Gateway.HTTPRouteName,
}
}
for _, ref := range src.CustomNetworkRefs {
obj := CustomNetworkRef{
APIVersion: ref.APIVersion,
Kind: ref.Kind,
Name: ref.Name,
}
dst.CustomNetworkRefs = append(dst.CustomNetworkRefs, obj)
}
return dst
}
func (src *BatchRelease) ConvertTo(dst conversion.Hub) error {
switch t := dst.(type) {
case *v1beta1.BatchRelease:
obj := dst.(*v1beta1.BatchRelease)
obj.ObjectMeta = src.ObjectMeta
obj.Spec = v1beta1.BatchReleaseSpec{}
srcSpec := src.Spec
obj.Spec.WorkloadRef = v1beta1.ObjectRef{
APIVersion: srcSpec.TargetRef.WorkloadRef.APIVersion,
Kind: srcSpec.TargetRef.WorkloadRef.Kind,
Name: srcSpec.TargetRef.WorkloadRef.Name,
}
obj.Spec.ReleasePlan = v1beta1.ReleasePlan{
BatchPartition: srcSpec.ReleasePlan.BatchPartition,
RolloutID: srcSpec.ReleasePlan.RolloutID,
FailureThreshold: srcSpec.ReleasePlan.FailureThreshold,
FinalizingPolicy: v1beta1.FinalizingPolicyType(srcSpec.ReleasePlan.FinalizingPolicy),
}
for _, batch := range srcSpec.ReleasePlan.Batches {
o := v1beta1.ReleaseBatch{
CanaryReplicas: batch.CanaryReplicas,
}
obj.Spec.ReleasePlan.Batches = append(obj.Spec.ReleasePlan.Batches, o)
}
if srcSpec.ReleasePlan.PatchPodTemplateMetadata != nil {
obj.Spec.ReleasePlan.PatchPodTemplateMetadata = &v1beta1.PatchPodTemplateMetadata{
Annotations: map[string]string{},
Labels: map[string]string{},
}
for k, v := range srcSpec.ReleasePlan.PatchPodTemplateMetadata.Annotations {
obj.Spec.ReleasePlan.PatchPodTemplateMetadata.Annotations[k] = v
}
for k, v := range srcSpec.ReleasePlan.PatchPodTemplateMetadata.Labels {
obj.Spec.ReleasePlan.PatchPodTemplateMetadata.Labels[k] = v
}
}
if strings.EqualFold(src.Annotations[RolloutStyleAnnotation], string(PartitionRollingStyle)) {
obj.Spec.ReleasePlan.RollingStyle = v1beta1.PartitionRollingStyle
}
if strings.EqualFold(src.Annotations[RolloutStyleAnnotation], string(CanaryRollingStyle)) {
obj.Spec.ReleasePlan.RollingStyle = v1beta1.CanaryRollingStyle
}
if strings.EqualFold(src.Annotations[RolloutStyleAnnotation], string(BlueGreenRollingStyle)) {
obj.Spec.ReleasePlan.RollingStyle = v1beta1.BlueGreenRollingStyle
}
obj.Spec.ReleasePlan.EnableExtraWorkloadForCanary = srcSpec.ReleasePlan.EnableExtraWorkloadForCanary
// status
obj.Status = v1beta1.BatchReleaseStatus{
StableRevision: src.Status.StableRevision,
UpdateRevision: src.Status.UpdateRevision,
ObservedGeneration: src.Status.ObservedGeneration,
ObservedRolloutID: src.Status.ObservedRolloutID,
ObservedWorkloadReplicas: src.Status.ObservedWorkloadReplicas,
ObservedReleasePlanHash: src.Status.ObservedReleasePlanHash,
CollisionCount: src.Status.CollisionCount,
Phase: v1beta1.RolloutPhase(src.Status.Phase),
}
for _, cond := range src.Status.Conditions {
o := v1beta1.RolloutCondition{
Type: v1beta1.RolloutConditionType(cond.Type),
Status: cond.Status,
LastUpdateTime: cond.LastUpdateTime,
LastTransitionTime: cond.LastTransitionTime,
Reason: cond.Reason,
Message: cond.Message,
}
obj.Status.Conditions = append(obj.Status.Conditions, o)
}
obj.Status.CanaryStatus = v1beta1.BatchReleaseCanaryStatus{
CurrentBatchState: v1beta1.BatchReleaseBatchStateType(src.Status.CanaryStatus.CurrentBatchState),
CurrentBatch: src.Status.CanaryStatus.CurrentBatch,
BatchReadyTime: src.Status.CanaryStatus.BatchReadyTime,
UpdatedReplicas: src.Status.CanaryStatus.UpdatedReplicas,
UpdatedReadyReplicas: src.Status.CanaryStatus.UpdatedReadyReplicas,
NoNeedUpdateReplicas: src.Status.CanaryStatus.NoNeedUpdateReplicas,
}
return nil
default:
return fmt.Errorf("unsupported type %v", t)
}
}
func (dst *BatchRelease) ConvertFrom(src conversion.Hub) error {
switch t := src.(type) {
case *v1beta1.BatchRelease:
srcV1beta1 := src.(*v1beta1.BatchRelease)
dst.ObjectMeta = srcV1beta1.ObjectMeta
dst.Spec = BatchReleaseSpec{}
srcSpec := srcV1beta1.Spec
dst.Spec.TargetRef.WorkloadRef = &WorkloadRef{
APIVersion: srcSpec.WorkloadRef.APIVersion,
Kind: srcSpec.WorkloadRef.Kind,
Name: srcSpec.WorkloadRef.Name,
}
dst.Spec.ReleasePlan = ReleasePlan{
BatchPartition: srcSpec.ReleasePlan.BatchPartition,
RolloutID: srcSpec.ReleasePlan.RolloutID,
FailureThreshold: srcSpec.ReleasePlan.FailureThreshold,
FinalizingPolicy: FinalizingPolicyType(srcSpec.ReleasePlan.FinalizingPolicy),
}
for _, batch := range srcSpec.ReleasePlan.Batches {
obj := ReleaseBatch{
CanaryReplicas: batch.CanaryReplicas,
}
dst.Spec.ReleasePlan.Batches = append(dst.Spec.ReleasePlan.Batches, obj)
}
if srcSpec.ReleasePlan.PatchPodTemplateMetadata != nil {
dst.Spec.ReleasePlan.PatchPodTemplateMetadata = &PatchPodTemplateMetadata{
Annotations: map[string]string{},
Labels: map[string]string{},
}
for k, v := range srcSpec.ReleasePlan.PatchPodTemplateMetadata.Annotations {
dst.Spec.ReleasePlan.PatchPodTemplateMetadata.Annotations[k] = v
}
for k, v := range srcSpec.ReleasePlan.PatchPodTemplateMetadata.Labels {
dst.Spec.ReleasePlan.PatchPodTemplateMetadata.Labels[k] = v
}
}
if dst.Annotations == nil {
dst.Annotations = map[string]string{}
}
dst.Annotations[RolloutStyleAnnotation] = strings.ToLower(string(srcV1beta1.Spec.ReleasePlan.RollingStyle))
dst.Spec.ReleasePlan.RollingStyle = RollingStyleType(srcV1beta1.Spec.ReleasePlan.RollingStyle)
dst.Spec.ReleasePlan.EnableExtraWorkloadForCanary = srcV1beta1.Spec.ReleasePlan.EnableExtraWorkloadForCanary
// status
dst.Status = BatchReleaseStatus{
StableRevision: srcV1beta1.Status.StableRevision,
UpdateRevision: srcV1beta1.Status.UpdateRevision,
ObservedGeneration: srcV1beta1.Status.ObservedGeneration,
ObservedRolloutID: srcV1beta1.Status.ObservedRolloutID,
ObservedWorkloadReplicas: srcV1beta1.Status.ObservedWorkloadReplicas,
ObservedReleasePlanHash: srcV1beta1.Status.ObservedReleasePlanHash,
CollisionCount: srcV1beta1.Status.CollisionCount,
Phase: RolloutPhase(srcV1beta1.Status.Phase),
}
for _, cond := range srcV1beta1.Status.Conditions {
obj := RolloutCondition{
Type: RolloutConditionType(cond.Type),
Status: cond.Status,
LastUpdateTime: cond.LastUpdateTime,
LastTransitionTime: cond.LastTransitionTime,
Reason: cond.Reason,
Message: cond.Message,
}
dst.Status.Conditions = append(dst.Status.Conditions, obj)
}
dst.Status.CanaryStatus = BatchReleaseCanaryStatus{
CurrentBatchState: BatchReleaseBatchStateType(srcV1beta1.Status.CanaryStatus.CurrentBatchState),
CurrentBatch: srcV1beta1.Status.CanaryStatus.CurrentBatch,
BatchReadyTime: srcV1beta1.Status.CanaryStatus.BatchReadyTime,
UpdatedReplicas: srcV1beta1.Status.CanaryStatus.UpdatedReplicas,
UpdatedReadyReplicas: srcV1beta1.Status.CanaryStatus.UpdatedReadyReplicas,
NoNeedUpdateReplicas: srcV1beta1.Status.CanaryStatus.NoNeedUpdateReplicas,
}
return nil
default:
return fmt.Errorf("unsupported type %v", t)
}
}

View File

@ -1,3 +1,19 @@
/*
Copyright 2023 The Kruise 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 v1alpha1
import (
@ -43,6 +59,8 @@ const (
PartitionRollingStyle RollingStyleType = "Partition"
// CanaryRollingStyle means rolling in canary way, and will create a canary Deployment.
CanaryRollingStyle RollingStyleType = "Canary"
// BlueGreenRollingStyle means rolling in blue-green way, and will NOT create a canary Deployment.
BlueGreenRollingStyle RollingStyleType = "BlueGreen"
)
// DeploymentExtraStatus is extra status field for Advanced Deployment
@ -58,7 +76,7 @@ type DeploymentExtraStatus struct {
}
func SetDefaultDeploymentStrategy(strategy *DeploymentStrategy) {
if strategy.RollingStyle == CanaryRollingStyle {
if strategy.RollingStyle != PartitionRollingStyle {
return
}
if strategy.RollingUpdate == nil {

View File

@ -20,7 +20,7 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
)
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
@ -121,6 +121,8 @@ type CanaryStrategy struct {
// only support for canary deployment
// +optional
PatchPodTemplateMetadata *PatchPodTemplateMetadata `json:"patchPodTemplateMetadata,omitempty"`
// canary service will not be generated if DisableGenerateCanaryService is true
DisableGenerateCanaryService bool `json:"disableGenerateCanaryService,omitempty"`
}
type PatchPodTemplateMetadata struct {
@ -146,7 +148,7 @@ type HttpRouteMatch struct {
// ANDed together, meaning, a request must match all the specified headers
// to select the route.
// +kubebuilder:validation:MaxItems=16
Headers []gatewayv1alpha2.HTTPHeaderMatch `json:"headers,omitempty"`
Headers []gatewayv1beta1.HTTPHeaderMatch `json:"headers,omitempty"`
}
// RolloutPause defines a pause stage for a rollout
@ -169,8 +171,6 @@ type RolloutStatus struct {
// Conditions a list of conditions a rollout can have.
// +optional
Conditions []RolloutCondition `json:"conditions,omitempty"`
// +optional
//BlueGreenStatus *BlueGreenStatus `json:"blueGreenStatus,omitempty"`
// Phase is the rollout phase.
Phase RolloutPhase `json:"phase,omitempty"`
// Message provides details on why the rollout is in its current phase
@ -240,16 +240,28 @@ type CanaryStatus struct {
CanaryReplicas int32 `json:"canaryReplicas"`
// CanaryReadyReplicas the numbers of ready canary revision pods
CanaryReadyReplicas int32 `json:"canaryReadyReplicas"`
// CurrentStepIndex defines the current step of the rollout is on. If the current step index is null, the
// controller will execute the rollout.
// NextStepIndex defines the next step of the rollout is on.
// In normal case, NextStepIndex is equal to CurrentStepIndex + 1
// If the current step is the last step, NextStepIndex is equal to -1
// Before the release, NextStepIndex is also equal to -1
// 0 is not used and won't appear in any case
// It is allowed to patch NextStepIndex by design,
// e.g. if CurrentStepIndex is 2, user can patch NextStepIndex to 3 (if exists) to
// achieve batch jump, or patch NextStepIndex to 1 to implement a re-execution of step 1
// Patching it with a non-positive value is meaningless, which will be corrected
// in the next reconciliation
// achieve batch jump, or patch NextStepIndex to 1 to implement a re-execution of step 1
NextStepIndex int32 `json:"nextStepIndex"`
// +optional
CurrentStepIndex int32 `json:"currentStepIndex"`
CurrentStepState CanaryStepState `json:"currentStepState"`
Message string `json:"message,omitempty"`
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
CurrentStepIndex int32 `json:"currentStepIndex"`
CurrentStepState CanaryStepState `json:"currentStepState"`
Message string `json:"message,omitempty"`
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
FinalisingStep FinalizeStateType `json:"finalisingStep"`
}
type CanaryStepState string
type FinalizeStateType string
const (
CanaryStepStateUpgrade CanaryStepState = "StepUpgrade"

View File

@ -18,7 +18,7 @@ package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
)
const (
@ -30,12 +30,15 @@ type TrafficRoutingRef struct {
// Service holds the name of a service which selects pods with stable version and don't select any pods with canary version.
Service string `json:"service"`
// Optional duration in seconds the traffic provider(e.g. nginx ingress controller) consumes the service, ingress configuration changes gracefully.
// +kubebuilder:default=3
GracePeriodSeconds int32 `json:"gracePeriodSeconds,omitempty"`
// Ingress holds Ingress specific configuration to route traffic, e.g. Nginx, Alb.
Ingress *IngressTrafficRouting `json:"ingress,omitempty"`
// Gateway holds Gateway specific configuration to route traffic
// Gateway configuration only supports >= v0.4.0 (v1alpha2).
Gateway *GatewayTrafficRouting `json:"gateway,omitempty"`
// CustomNetworkRefs hold a list of custom providers to route traffic
CustomNetworkRefs []CustomNetworkRef `json:"customNetworkRefs,omitempty"`
}
// IngressTrafficRouting configuration for ingress controller to control traffic routing
@ -87,7 +90,7 @@ type TrafficRoutingStrategy struct {
// my-header: bar
//
// +optional
RequestHeaderModifier *gatewayv1alpha2.HTTPRequestHeaderFilter `json:"requestHeaderModifier,omitempty"`
RequestHeaderModifier *gatewayv1beta1.HTTPHeaderFilter `json:"requestHeaderModifier,omitempty"`
// Matches define conditions used for matching the incoming HTTP requests to canary service.
// Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied.
// If Gateway API, current only support one match.
@ -149,6 +152,12 @@ type TrafficRoutingList struct {
Items []TrafficRouting `json:"items"`
}
type CustomNetworkRef struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Name string `json:"name"`
}
func init() {
SchemeBuilder.Register(&TrafficRouting{}, &TrafficRoutingList{})
}

View File

@ -1,8 +1,7 @@
//go:build !ignore_autogenerated
// +build !ignore_autogenerated
/*
Copyright 2022 The Kruise Authors.
Copyright 2023 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -25,7 +24,7 @@ import (
"k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"sigs.k8s.io/gateway-api/apis/v1alpha2"
"sigs.k8s.io/gateway-api/apis/v1beta1"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
@ -256,6 +255,21 @@ func (in *CanaryStrategy) DeepCopy() *CanaryStrategy {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CustomNetworkRef) DeepCopyInto(out *CustomNetworkRef) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CustomNetworkRef.
func (in *CustomNetworkRef) DeepCopy() *CustomNetworkRef {
if in == nil {
return nil
}
out := new(CustomNetworkRef)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeploymentExtraStatus) DeepCopyInto(out *DeploymentExtraStatus) {
*out = *in
@ -333,7 +347,7 @@ func (in *HttpRouteMatch) DeepCopyInto(out *HttpRouteMatch) {
*out = *in
if in.Headers != nil {
in, out := &in.Headers, &out.Headers
*out = make([]v1alpha2.HTTPHeaderMatch, len(*in))
*out = make([]v1beta1.HTTPHeaderMatch, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
@ -901,6 +915,11 @@ func (in *TrafficRoutingRef) DeepCopyInto(out *TrafficRoutingRef) {
*out = new(GatewayTrafficRouting)
(*in).DeepCopyInto(*out)
}
if in.CustomNetworkRefs != nil {
in, out := &in.CustomNetworkRefs, &out.CustomNetworkRefs
*out = make([]CustomNetworkRef, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficRoutingRef.
@ -961,7 +980,7 @@ func (in *TrafficRoutingStrategy) DeepCopyInto(out *TrafficRoutingStrategy) {
}
if in.RequestHeaderModifier != nil {
in, out := &in.RequestHeaderModifier, &out.RequestHeaderModifier
*out = new(v1alpha2.HTTPRequestHeaderFilter)
*out = new(v1beta1.HTTPHeaderFilter)
(*in).DeepCopyInto(*out)
}
if in.Matches != nil {

View File

@ -0,0 +1,159 @@
/*
Copyright 2023 The Kruise 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 v1beta1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
// ReleasePlan fines the details of the release plan
type ReleasePlan struct {
// Batches is the details on each batch of the ReleasePlan.
//Users can specify their batch plan in this field, such as:
// batches:
// - canaryReplicas: 1 # batches 0
// - canaryReplicas: 2 # batches 1
// - canaryReplicas: 5 # batches 2
// Not that these canaryReplicas should be a non-decreasing sequence.
// +optional
Batches []ReleaseBatch `json:"batches"`
// All pods in the batches up to the batchPartition (included) will have
// the target resource specification while the rest still is the stable revision.
// This is designed for the operators to manually rollout.
// Default is nil, which means no partition and will release all batches.
// BatchPartition start from 0.
// +optional
BatchPartition *int32 `json:"batchPartition,omitempty"`
// RolloutID indicates an id for each rollout progress
RolloutID string `json:"rolloutID,omitempty"`
// FailureThreshold indicates how many failed pods can be tolerated in all upgraded pods.
// Only when FailureThreshold are satisfied, Rollout can enter ready state.
// If FailureThreshold is nil, Rollout will use the MaxUnavailable of workload as its
// FailureThreshold.
// Defaults to nil.
FailureThreshold *intstr.IntOrString `json:"failureThreshold,omitempty"`
// FinalizingPolicy define the behavior of controller when phase enter Finalizing
// Defaults to "Immediate"
FinalizingPolicy FinalizingPolicyType `json:"finalizingPolicy,omitempty"`
// PatchPodTemplateMetadata indicates patch configuration(e.g. labels, annotations) to the canary deployment podTemplateSpec.metadata
// only support for canary deployment
// +optional
PatchPodTemplateMetadata *PatchPodTemplateMetadata `json:"patchPodTemplateMetadata,omitempty"`
// RollingStyle can be "Canary", "Partiton" or "BlueGreen"
RollingStyle RollingStyleType `json:"rollingStyle,omitempty"`
// EnableExtraWorkloadForCanary indicates whether to create extra workload for canary
// True corresponds to RollingStyle "Canary".
// False corresponds to RollingStyle "Partiton".
// Ignored in BlueGreen-style.
// This field is about to deprecate, use RollingStyle instead.
// If both of them are set, controller will only consider this
// filed when RollingStyle is empty
EnableExtraWorkloadForCanary bool `json:"enableExtraWorkloadForCanary"`
}
type FinalizingPolicyType string
const (
// WaitResumeFinalizingPolicyType will wait workload to be resumed, which means
// controller will be hold at Finalizing phase until all pods of workload is upgraded.
// WaitResumeFinalizingPolicyType only works in canary-style BatchRelease controller.
WaitResumeFinalizingPolicyType FinalizingPolicyType = "WaitResume"
// ImmediateFinalizingPolicyType will not to wait workload to be resumed.
ImmediateFinalizingPolicyType FinalizingPolicyType = "Immediate"
)
// ReleaseBatch is used to describe how each batch release should be
type ReleaseBatch struct {
// CanaryReplicas is the number of upgraded pods that should have in this batch.
// it can be an absolute number (ex: 5) or a percentage of workload replicas.
// batches[i].canaryReplicas should less than or equal to batches[j].canaryReplicas if i < j.
CanaryReplicas intstr.IntOrString `json:"canaryReplicas"`
}
// BatchReleaseStatus defines the observed state of a release plan
type BatchReleaseStatus struct {
// Conditions represents the observed process state of each phase during executing the release plan.
Conditions []RolloutCondition `json:"conditions,omitempty"`
// CanaryStatus describes the state of the canary rollout.
CanaryStatus BatchReleaseCanaryStatus `json:"canaryStatus,omitempty"`
// StableRevision is the pod-template-hash of stable revision pod template.
StableRevision string `json:"stableRevision,omitempty"`
// UpdateRevision is the pod-template-hash of update revision pod template.
UpdateRevision string `json:"updateRevision,omitempty"`
// ObservedGeneration is the most recent generation observed for this BatchRelease.
// It corresponds to this BatchRelease's generation, which is updated on mutation
// by the API Server, and only if BatchRelease Spec was changed, its generation will increase 1.
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// ObservedRolloutID is the most recent rollout-id observed for this BatchRelease.
// If RolloutID was changed, we will restart to roll out from batch 0,
// to ensure the batch-id and rollout-id labels of Pods are correct.
ObservedRolloutID string `json:"observedRolloutID,omitempty"`
// ObservedWorkloadReplicas is observed replicas of target referenced workload.
// This field is designed to deal with scaling event during rollout, if this field changed,
// it means that the workload is scaling during rollout.
ObservedWorkloadReplicas int32 `json:"observedWorkloadReplicas,omitempty"`
// Count of hash collisions for creating canary Deployment. The controller uses this
// field as a collision avoidance mechanism when it needs to create the name for the
// newest canary Deployment.
// +optional
CollisionCount *int32 `json:"collisionCount,omitempty"`
// ObservedReleasePlanHash is a hash code of observed itself spec.releasePlan.
ObservedReleasePlanHash string `json:"observedReleasePlanHash,omitempty"`
// Phase is the release plan phase, which indicates the current state of release
// plan state machine in BatchRelease controller.
Phase RolloutPhase `json:"phase,omitempty"`
// Message provides details on why the rollout is in its current phase
Message string `json:"message,omitempty"`
}
type BatchReleaseCanaryStatus struct {
// CurrentBatchState indicates the release state of the current batch.
CurrentBatchState BatchReleaseBatchStateType `json:"batchState,omitempty"`
// The current batch the rollout is working on/blocked, it starts from 0
CurrentBatch int32 `json:"currentBatch"`
// BatchReadyTime is the ready timestamp of the current batch or the last batch.
// This field is updated once a batch ready, and the batches[x].pausedSeconds
// relies on this field to calculate the real-time duration.
BatchReadyTime *metav1.Time `json:"batchReadyTime,omitempty"`
// UpdatedReplicas is the number of upgraded Pods.
UpdatedReplicas int32 `json:"updatedReplicas,omitempty"`
// UpdatedReadyReplicas is the number upgraded Pods that have a Ready Condition.
UpdatedReadyReplicas int32 `json:"updatedReadyReplicas,omitempty"`
// the number of pods that no need to rollback in rollback scene.
NoNeedUpdateReplicas *int32 `json:"noNeedUpdateReplicas,omitempty"`
}
type BatchReleaseBatchStateType string
const (
// UpgradingBatchState indicates that current batch is at upgrading pod state
UpgradingBatchState BatchReleaseBatchStateType = "Upgrading"
// VerifyingBatchState indicates that current batch is at verifying whether it's ready state
VerifyingBatchState BatchReleaseBatchStateType = "Verifying"
// ReadyBatchState indicates that current batch is at batch ready state
ReadyBatchState BatchReleaseBatchStateType = "Ready"
)
const (
// RolloutPhasePreparing indicates a rollout is preparing for next progress.
RolloutPhasePreparing RolloutPhase = "Preparing"
// RolloutPhaseFinalizing indicates a rollout is finalizing
RolloutPhaseFinalizing RolloutPhase = "Finalizing"
// RolloutPhaseCompleted indicates a rollout is completed/canceled/terminated
RolloutPhaseCompleted RolloutPhase = "Completed"
)

View File

@ -0,0 +1,61 @@
/*
Copyright 2023 The Kruise 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 v1beta1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// +genclient
// +k8s:openapi-gen=true
// +kubebuilder:object:root=true
// +kubebuilder:subresource:status
// +kubebuilder:storageversion
// +kubebuilder:printcolumn:name="KIND",type=string,JSONPath=`.spec.targetReference.workloadRef.kind`
// +kubebuilder:printcolumn:name="PHASE",type=string,JSONPath=`.status.phase`
// +kubebuilder:printcolumn:name="BATCH",type=integer,JSONPath=`.status.canaryStatus.currentBatch`
// +kubebuilder:printcolumn:name="BATCH-STATE",type=string,JSONPath=`.status.canaryStatus.batchState`
// +kubebuilder:printcolumn:name="AGE",type=date,JSONPath=".metadata.creationTimestamp"
type BatchRelease struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec BatchReleaseSpec `json:"spec,omitempty"`
Status BatchReleaseStatus `json:"status,omitempty"`
}
// BatchReleaseSpec defines how to describe an update between different compRevision
type BatchReleaseSpec struct {
// WorkloadRef contains enough information to let you identify a workload for Rollout
// Batch release of the bypass
WorkloadRef ObjectRef `json:"workloadRef,omitempty"`
// ReleasePlan is the details on how to rollout the resources
ReleasePlan ReleasePlan `json:"releasePlan"`
}
// BatchReleaseList contains a list of BatchRelease
// +kubebuilder:object:root=true
type BatchReleaseList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []BatchRelease `json:"items"`
}
func init() {
SchemeBuilder.Register(&BatchRelease{}, &BatchReleaseList{})
}

21
api/v1beta1/convertion.go Normal file
View File

@ -0,0 +1,21 @@
/*
Copyright 2023 The Kruise 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 v1beta1
func (*Rollout) Hub() {}
func (*BatchRelease) Hub() {}

View File

@ -0,0 +1,115 @@
/*
Copyright 2023 The Kruise 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 v1beta1
import (
apps "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)
const (
// DeploymentStrategyAnnotation is annotation for deployment,
// which is strategy fields of Advanced Deployment.
DeploymentStrategyAnnotation = "rollouts.kruise.io/deployment-strategy"
// DeploymentExtraStatusAnnotation is annotation for deployment,
// which is extra status field of Advanced Deployment.
DeploymentExtraStatusAnnotation = "rollouts.kruise.io/deployment-extra-status"
// DeploymentStableRevisionLabel is label for deployment,
// which record the stable revision during the current rolling process.
DeploymentStableRevisionLabel = "rollouts.kruise.io/stable-revision"
// AdvancedDeploymentControlLabel is label for deployment,
// which labels whether the deployment is controlled by advanced-deployment-controller.
AdvancedDeploymentControlLabel = "rollouts.kruise.io/controlled-by-advanced-deployment-controller"
// OriginalDeploymentStrategyAnnotation is annotation for workload in BlueGreen Release,
// it will store the original setting of the workload, which will be used to restore the workload
OriginalDeploymentStrategyAnnotation = "rollouts.kruise.io/original-deployment-strategy"
// MaxProgressSeconds is the value we set for ProgressDeadlineSeconds
// MaxReadySeconds is the value we set for MinReadySeconds, which is one less than ProgressDeadlineSeconds
// MaxInt32: 2147483647, ≈ 68 years
MaxProgressSeconds = 1<<31 - 1
MaxReadySeconds = MaxProgressSeconds - 1
)
// DeploymentStrategy is strategy field for Advanced Deployment
type DeploymentStrategy struct {
// RollingStyle define the behavior of rolling for deployment.
RollingStyle RollingStyleType `json:"rollingStyle,omitempty"`
// original deployment strategy rolling update fields
RollingUpdate *apps.RollingUpdateDeployment `json:"rollingUpdate,omitempty"`
// Paused = true will block the upgrade of Pods
Paused bool `json:"paused,omitempty"`
// Partition describe how many Pods should be updated during rollout.
// We use this field to implement partition-style rolling update.
Partition intstr.IntOrString `json:"partition,omitempty"`
}
type RollingStyleType string
const (
// PartitionRollingStyle means rolling in batches just like CloneSet, and will NOT create any extra Deployment;
PartitionRollingStyle RollingStyleType = "Partition"
// CanaryRollingStyle means rolling in canary way, and will create a canary Deployment.
CanaryRollingStyle RollingStyleType = "Canary"
// BlueGreenRollingStyle means rolling in blue-green way, and will NOT create a extra Deployment.
BlueGreenRollingStyle RollingStyleType = "BlueGreen"
)
// DeploymentExtraStatus is extra status field for Advanced Deployment
type DeploymentExtraStatus struct {
// UpdatedReadyReplicas the number of pods that has been updated and ready.
UpdatedReadyReplicas int32 `json:"updatedReadyReplicas,omitempty"`
// ExpectedUpdatedReplicas is an absolute number calculated based on Partition
// and Deployment.Spec.Replicas, means how many pods are expected be updated under
// current strategy.
// This field is designed to avoid users to fall into the details of algorithm
// for Partition calculation.
ExpectedUpdatedReplicas int32 `json:"expectedUpdatedReplicas,omitempty"`
}
func SetDefaultDeploymentStrategy(strategy *DeploymentStrategy) {
if strategy.RollingStyle != PartitionRollingStyle {
return
}
if strategy.RollingUpdate == nil {
strategy.RollingUpdate = &apps.RollingUpdateDeployment{}
}
if strategy.RollingUpdate.MaxUnavailable == nil {
// Set MaxUnavailable as 25% by default
maxUnavailable := intstr.FromString("25%")
strategy.RollingUpdate.MaxUnavailable = &maxUnavailable
}
if strategy.RollingUpdate.MaxSurge == nil {
// Set MaxSurge as 25% by default
maxSurge := intstr.FromString("25%")
strategy.RollingUpdate.MaxUnavailable = &maxSurge
}
// Cannot allow maxSurge==0 && MaxUnavailable==0, otherwise, no pod can be updated when rolling update.
maxSurge, _ := intstr.GetScaledValueFromIntOrPercent(strategy.RollingUpdate.MaxSurge, 100, true)
maxUnavailable, _ := intstr.GetScaledValueFromIntOrPercent(strategy.RollingUpdate.MaxUnavailable, 100, true)
if maxSurge == 0 && maxUnavailable == 0 {
strategy.RollingUpdate = &apps.RollingUpdateDeployment{
MaxSurge: &intstr.IntOrString{Type: intstr.Int, IntVal: 0},
MaxUnavailable: &intstr.IntOrString{Type: intstr.Int, IntVal: 1},
}
}
}

View File

@ -0,0 +1,43 @@
/*
Copyright 2023 The Kruise 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 v1beta1 contains API Schema definitions for the apps v1beta1 API group
// +kubebuilder:object:generate=true
// +groupName=rollouts.kruise.io
package v1beta1
import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)
var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "rollouts.kruise.io", Version: "v1beta1"}
// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}
// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
SchemeGroupVersion = GroupVersion
)
// Resource is required by pkg/client/listers/...
func Resource(resource string) schema.GroupResource {
return SchemeGroupVersion.WithResource(resource).GroupResource()
}

View File

@ -0,0 +1,622 @@
/*
Copyright 2023 The Kruise 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 v1beta1
import (
"reflect"
apps "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
)
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
const (
// RolloutIDLabel is set to workload labels.
// RolloutIDLabel is designed to distinguish each workload revision publications.
// The value of RolloutIDLabel corresponds Rollout.Spec.RolloutID.
RolloutIDLabel = "rollouts.kruise.io/rollout-id"
// RolloutBatchIDLabel is patched in pod labels.
// RolloutBatchIDLabel is the label key of batch id that will be patched to pods during rollout.
// Only when RolloutIDLabel is set, RolloutBatchIDLabel will be patched.
// Users can use RolloutIDLabel and RolloutBatchIDLabel to select the pods that are upgraded in some certain batch and release.
RolloutBatchIDLabel = "rollouts.kruise.io/rollout-batch-id"
// RollbackInBatchAnnotation is set to rollout annotations.
// RollbackInBatchAnnotation allow use disable quick rollback, and will roll back in batch style.
RollbackInBatchAnnotation = "rollouts.kruise.io/rollback-in-batch"
)
// RolloutSpec defines the desired state of Rollout
type RolloutSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file
// WorkloadRef contains enough information to let you identify a workload for Rollout
// Batch release of the bypass
WorkloadRef ObjectRef `json:"workloadRef"`
// rollout strategy
Strategy RolloutStrategy `json:"strategy"`
// if a rollout disabled, then the rollout would not watch changes of workload
//+kubebuilder:validation:Optional
//+kubebuilder:default=false
Disabled bool `json:"disabled"`
}
// ObjectRef holds a references to the Kubernetes object
type ObjectRef struct {
// API Version of the referent
APIVersion string `json:"apiVersion"`
// Kind of the referent
Kind string `json:"kind"`
// Name of the referent
Name string `json:"name"`
}
// RolloutStrategy defines strategy to apply during next rollout
type RolloutStrategy struct {
// Paused indicates that the Rollout is paused.
// Default value is false
Paused bool `json:"paused,omitempty"`
// +optional
Canary *CanaryStrategy `json:"canary,omitempty"`
// +optional
BlueGreen *BlueGreenStrategy `json:"blueGreen,omitempty" protobuf:"bytes,1,opt,name=blueGreen"`
}
// Get the rolling style based on the strategy
func (r *RolloutStrategy) GetRollingStyle() RollingStyleType {
if r.BlueGreen != nil {
return BlueGreenRollingStyle
}
//NOTE - even EnableExtraWorkloadForCanary is true, as long as it is not Deployment,
//we won't do canary release. BatchRelease will treat it as Partiton release
if r.Canary.EnableExtraWorkloadForCanary {
return CanaryRollingStyle
}
return PartitionRollingStyle
}
// using single field EnableExtraWorkloadForCanary to distinguish partition-style from canary-style
// is not enough, for example, a v1alaph1 Rollout can be converted to v1beta1 Rollout
// with EnableExtraWorkloadForCanary set as true, even the objectRef is cloneset (which doesn't support canary release)
func IsRealPartition(rollout *Rollout) bool {
if rollout.Spec.Strategy.IsEmptyRelease() {
return false
}
estimation := rollout.Spec.Strategy.GetRollingStyle()
if estimation == BlueGreenRollingStyle {
return false
}
targetRef := rollout.Spec.WorkloadRef
if targetRef.APIVersion == apps.SchemeGroupVersion.String() && targetRef.Kind == reflect.TypeOf(apps.Deployment{}).Name() &&
estimation == CanaryRollingStyle {
return false
}
return true
}
// r.GetRollingStyle() == BlueGreenRollingStyle
func (r *RolloutStrategy) IsBlueGreenRelease() bool {
return r.GetRollingStyle() == BlueGreenRollingStyle
}
// r.GetRollingStyle() == CanaryRollingStyle || r.GetRollingStyle() == PartitionRollingStyle
func (r *RolloutStrategy) IsCanaryStragegy() bool {
return r.GetRollingStyle() == CanaryRollingStyle || r.GetRollingStyle() == PartitionRollingStyle
}
func (r *RolloutStrategy) IsEmptyRelease() bool {
return r.BlueGreen == nil && r.Canary == nil
}
// Get the steps based on the rolling style
func (r *RolloutStrategy) GetSteps() []CanaryStep {
switch r.GetRollingStyle() {
case BlueGreenRollingStyle:
return r.BlueGreen.Steps
case CanaryRollingStyle, PartitionRollingStyle:
return r.Canary.Steps
default:
return nil
}
}
// Get the traffic routing based on the rolling style
func (r *RolloutStrategy) GetTrafficRouting() []TrafficRoutingRef {
switch r.GetRollingStyle() {
case BlueGreenRollingStyle:
return r.BlueGreen.TrafficRoutings
case CanaryRollingStyle, PartitionRollingStyle:
return r.Canary.TrafficRoutings
default:
return nil
}
}
// Check if there are traffic routings
func (r *RolloutStrategy) HasTrafficRoutings() bool {
return len(r.GetTrafficRouting()) > 0
}
// Check the value of DisableGenerateCanaryService
func (r *RolloutStrategy) DisableGenerateCanaryService() bool {
switch r.GetRollingStyle() {
case BlueGreenRollingStyle:
return r.BlueGreen.DisableGenerateCanaryService
case CanaryRollingStyle, PartitionRollingStyle:
return r.Canary.DisableGenerateCanaryService
default:
return false
}
}
// BlueGreenStrategy defines parameters for Blue Green Release
type BlueGreenStrategy struct {
// Steps define the order of phases to execute release in batches(20%, 40%, 60%, 80%, 100%)
// +kubebuilder:validation:MaxItems=50
// +optional
Steps []CanaryStep `json:"steps,omitempty"`
// TrafficRoutings support ingress, gateway api and custom network resource(e.g. istio, apisix) to enable more fine-grained traffic routing
// and current only support one TrafficRouting
TrafficRoutings []TrafficRoutingRef `json:"trafficRoutings,omitempty"`
// FailureThreshold indicates how many failed pods can be tolerated in all upgraded pods.
// Only when FailureThreshold are satisfied, Rollout can enter ready state.
// If FailureThreshold is nil, Rollout will use the MaxUnavailable of workload as its
// FailureThreshold.
// Defaults to nil.
FailureThreshold *intstr.IntOrString `json:"failureThreshold,omitempty"`
// TrafficRoutingRef is TrafficRouting's Name
TrafficRoutingRef string `json:"trafficRoutingRef,omitempty"`
// canary service will not be generated if DisableGenerateCanaryService is true
DisableGenerateCanaryService bool `json:"disableGenerateCanaryService,omitempty"`
}
// CanaryStrategy defines parameters for a Replica Based Canary
type CanaryStrategy struct {
// Steps define the order of phases to execute release in batches(20%, 40%, 60%, 80%, 100%)
// +kubebuilder:validation:MaxItems=50
// +optional
Steps []CanaryStep `json:"steps,omitempty"`
// TrafficRoutings support ingress, gateway api and custom network resource(e.g. istio, apisix) to enable more fine-grained traffic routing
// and current only support one TrafficRouting
TrafficRoutings []TrafficRoutingRef `json:"trafficRoutings,omitempty"`
// FailureThreshold indicates how many failed pods can be tolerated in all upgraded pods.
// Only when FailureThreshold are satisfied, Rollout can enter ready state.
// If FailureThreshold is nil, Rollout will use the MaxUnavailable of workload as its
// FailureThreshold.
// Defaults to nil.
FailureThreshold *intstr.IntOrString `json:"failureThreshold,omitempty"`
// PatchPodTemplateMetadata indicates patch configuration(e.g. labels, annotations) to the canary deployment podTemplateSpec.metadata
// only support for canary deployment
// +optional
PatchPodTemplateMetadata *PatchPodTemplateMetadata `json:"patchPodTemplateMetadata,omitempty"`
// If true, then it will create new deployment for canary, such as: workload-demo-canary.
// When user verifies that the canary version is ready, we will remove the canary deployment and release the deployment workload-demo in full.
// Current only support k8s native deployment
EnableExtraWorkloadForCanary bool `json:"enableExtraWorkloadForCanary,omitempty"`
// TrafficRoutingRef is TrafficRouting's Name
TrafficRoutingRef string `json:"trafficRoutingRef,omitempty"`
// canary service will not be generated if DisableGenerateCanaryService is true
DisableGenerateCanaryService bool `json:"disableGenerateCanaryService,omitempty"`
}
type PatchPodTemplateMetadata struct {
// annotations
Annotations map[string]string `json:"annotations,omitempty"`
// labels
Labels map[string]string `json:"labels,omitempty"`
}
// CanaryStep defines a step of a canary workload.
type CanaryStep struct {
TrafficRoutingStrategy `json:",inline"`
// 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.
Replicas *intstr.IntOrString `json:"replicas,omitempty"`
// Pause defines a pause stage for a rollout, manual or auto
// +optional
Pause RolloutPause `json:"pause,omitempty"`
}
type TrafficRoutingStrategy struct {
// Traffic indicate how many percentage of traffic the canary pods should receive
// Value is of string type and is a percentage, e.g. 5%.
// +optional
Traffic *string `json:"traffic,omitempty"`
// Set overwrites the request with the given header (name, value)
// before the action.
//
// Input:
// GET /foo HTTP/1.1
// my-header: foo
//
// requestHeaderModifier:
// set:
// - name: "my-header"
// value: "bar"
//
// Output:
// GET /foo HTTP/1.1
// my-header: bar
//
// +optional
RequestHeaderModifier *gatewayv1beta1.HTTPHeaderFilter `json:"requestHeaderModifier,omitempty"`
// Matches define conditions used for matching incoming HTTP requests to the canary service.
// Each match is independent, i.e. this rule will be matched as long as **any** one of the matches is satisfied.
//
// It cannot support Traffic (weight-based routing) and Matches simultaneously, if both are configured.
// In such cases, Matches takes precedence.
// +kubebuilder:validation:MaxItems=16
Matches []HttpRouteMatch `json:"matches,omitempty"`
}
type HttpRouteMatch struct {
// Path specifies a HTTP request path matcher.
// Supported list:
// - Istio: https://istio.io/latest/docs/reference/config/networking/virtual-service/#HTTPMatchRequest
// - GatewayAPI: If path is defined, the whole HttpRouteMatch will be used as a standalone matcher
//
// +optional
Path *gatewayv1beta1.HTTPPathMatch `json:"path,omitempty"`
// Headers specifies HTTP request header matchers. Multiple match values are
// ANDed together, meaning, a request must match all the specified headers
// to select the route.
//
// +listType=map
// +listMapKey=name
// +optional
// +kubebuilder:validation:MaxItems=16
Headers []gatewayv1beta1.HTTPHeaderMatch `json:"headers,omitempty"`
// QueryParams specifies HTTP query parameter matchers. Multiple match
// values are ANDed together, meaning, a request must match all the
// specified query parameters to select the route.
// Supported list:
// - Istio: https://istio.io/latest/docs/reference/config/networking/virtual-service/#HTTPMatchRequest
// - MSE Ingress: https://help.aliyun.com/zh/ack/ack-managed-and-ack-dedicated/user-guide/annotations-supported-by-mse-ingress-gateways-1
// Header/Cookie > QueryParams
// - Gateway API
//
// +listType=map
// +listMapKey=name
// +optional
// +kubebuilder:validation:MaxItems=16
QueryParams []gatewayv1beta1.HTTPQueryParamMatch `json:"queryParams,omitempty"`
}
// RolloutPause defines a pause stage for a rollout
type RolloutPause struct {
// Duration the amount of time to wait before moving to the next step.
// +optional
Duration *int32 `json:"duration,omitempty"`
}
// RolloutStatus defines the observed state of Rollout
type RolloutStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
// observedGeneration is the most recent generation observed for this Rollout.
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// Canary describes the state of the canary rollout
// +optional
CanaryStatus *CanaryStatus `json:"canaryStatus,omitempty"`
// BlueGreen describes the state of the blueGreen rollout
// +optional
BlueGreenStatus *BlueGreenStatus `json:"blueGreenStatus,omitempty"`
// Conditions a list of conditions a rollout can have.
// +optional
Conditions []RolloutCondition `json:"conditions,omitempty"`
// +optional
//BlueGreenStatus *BlueGreenStatus `json:"blueGreenStatus,omitempty"`
// Phase is the rollout phase.
Phase RolloutPhase `json:"phase,omitempty"`
// Message provides details on why the rollout is in its current phase
Message string `json:"message,omitempty"`
// These two values will be synchronized with the same fileds in CanaryStatus or BlueGreeenStatus
// mainly used to provide info for kubectl get command
CurrentStepIndex int32 `json:"currentStepIndex"`
CurrentStepState CanaryStepState `json:"currentStepState"`
}
// RolloutCondition describes the state of a rollout at a certain point.
type RolloutCondition struct {
// Type of rollout condition.
Type RolloutConditionType `json:"type"`
// Phase of the condition, one of True, False, Unknown.
Status corev1.ConditionStatus `json:"status"`
// The last time this condition was updated.
LastUpdateTime metav1.Time `json:"lastUpdateTime,omitempty"`
// Last time the condition transitioned from one status to another.
LastTransitionTime metav1.Time `json:"lastTransitionTime,omitempty"`
// The reason for the condition's last transition.
Reason string `json:"reason"`
// A human readable message indicating details about the transition.
Message string `json:"message"`
}
// RolloutConditionType defines the conditions of Rollout
type RolloutConditionType string
// These are valid conditions of a rollout.
//
//goland:noinspection GoUnusedConst
const (
// RolloutConditionProgressing means the rollout is progressing. Progress for a rollout is
// considered when a new replica set is created or adopted, when pods scale
// up or old pods scale down, or when the services are updated. Progress is not estimated
// for paused rollouts.
RolloutConditionProgressing RolloutConditionType = "Progressing"
// Progressing Reason
ProgressingReasonInitializing = "Initializing"
ProgressingReasonInRolling = "InRolling"
ProgressingReasonFinalising = "Finalising"
ProgressingReasonCompleted = "Completed"
ProgressingReasonCancelling = "Cancelling"
ProgressingReasonPaused = "Paused"
// RolloutConditionSucceeded indicates whether rollout is succeeded or failed.
RolloutConditionSucceeded RolloutConditionType = "Succeeded"
// Terminating condition
RolloutConditionTerminating RolloutConditionType = "Terminating"
// Terminating Reason
TerminatingReasonInTerminating = "InTerminating"
TerminatingReasonCompleted = "Completed"
// Finalise Reason
// Finalise when the last batch is released and all pods will update to new version
FinaliseReasonSuccess = "Success"
// Finalise when rollback detected
FinaliseReasonRollback = "Rollback"
// Finalise when Continuous Release detected
FinaliseReasonContinuous = "Continuous"
// Finalise when Rollout is disabling
FinaliseReasonDisalbed = "RolloutDisabled"
// Finalise when Rollout is deleting
FinaliseReasonDelete = "RolloutDeleting"
)
// fields in CommonStatus are shared between canary status and bluegreen status
// if a field is accessed in strategy-agnostic way, e.g. accessed from rollout_progressing.go, or rollout_status.go
// then it can be put into CommonStatus
// if a field is only accessed in strategy-specific way, e.g. accessed from rollout_canary.go or rollout_bluegreen.go
// then it should stay behind with CanaryStatus or BlueGreenStatus
type CommonStatus struct {
// observedWorkloadGeneration is the most recent generation observed for this Rollout ref workload generation.
ObservedWorkloadGeneration int64 `json:"observedWorkloadGeneration,omitempty"`
// ObservedRolloutID will record the newest spec.RolloutID if status.canaryRevision equals to workload.updateRevision
ObservedRolloutID string `json:"observedRolloutID,omitempty"`
// RolloutHash from rollout.spec object
RolloutHash string `json:"rolloutHash,omitempty"`
// StableRevision indicates the revision of stable pods
StableRevision string `json:"stableRevision,omitempty"`
// pod template hash is used as service selector label
PodTemplateHash string `json:"podTemplateHash"`
// CurrentStepIndex defines the current step of the rollout is on.
// +optional
CurrentStepIndex int32 `json:"currentStepIndex"`
// NextStepIndex defines the next step of the rollout is on.
// In normal case, NextStepIndex is equal to CurrentStepIndex + 1
// If the current step is the last step, NextStepIndex is equal to -1
// Before the release, NextStepIndex is also equal to -1
// 0 is not used and won't appear in any case
// It is allowed to patch NextStepIndex by design,
// e.g. if CurrentStepIndex is 2, user can patch NextStepIndex to 3 (if exists) to
// achieve batch jump, or patch NextStepIndex to 1 to implement a re-execution of step 1
// Patching it with a non-positive value is useless and meaningless, which will be corrected
// in the next reconciliation
NextStepIndex int32 `json:"nextStepIndex"`
// FinalisingStep the step of finalising
FinalisingStep FinalisingStepType `json:"finalisingStep"`
CurrentStepState CanaryStepState `json:"currentStepState"`
Message string `json:"message,omitempty"`
LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"`
}
// CanaryStatus status fields that only pertain to the canary rollout
type CanaryStatus struct {
// must be inline
CommonStatus `json:",inline"`
// 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
CanaryRevision string `json:"canaryRevision"`
// CanaryReplicas the numbers of canary revision pods
CanaryReplicas int32 `json:"canaryReplicas"`
// CanaryReadyReplicas the numbers of ready canary revision pods
CanaryReadyReplicas int32 `json:"canaryReadyReplicas"`
}
// BlueGreenStatus status fields that only pertain to the blueGreen rollout
type BlueGreenStatus struct {
CommonStatus `json:",inline"`
// UpdatedRevision 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
UpdatedRevision string `json:"updatedRevision"`
// UpdatedReplicas the numbers of updated pods
UpdatedReplicas int32 `json:"updatedReplicas"`
// UpdatedReadyReplicas the numbers of updated ready pods
UpdatedReadyReplicas int32 `json:"updatedReadyReplicas"`
}
// GetSubStatus returns the ethier canary or bluegreen status
func (r *RolloutStatus) GetSubStatus() *CommonStatus {
if r.CanaryStatus == nil && r.BlueGreenStatus == nil {
return nil
}
if r.CanaryStatus != nil {
return &r.CanaryStatus.CommonStatus
}
return &r.BlueGreenStatus.CommonStatus
}
func (r *RolloutStatus) IsSubStatusEmpty() bool {
return r.CanaryStatus == nil && r.BlueGreenStatus == nil
}
func (r *RolloutStatus) Clear() {
r.CanaryStatus = nil
r.BlueGreenStatus = nil
}
//TODO - the following functions seem awkward, is there better way for our case?
func (r *RolloutStatus) GetCanaryRevision() string {
if r.CanaryStatus != nil {
return r.CanaryStatus.CanaryRevision
}
if r.BlueGreenStatus != nil {
return r.BlueGreenStatus.UpdatedRevision
}
return ""
}
func (r *RolloutStatus) SetCanaryRevision(revision string) {
if r.CanaryStatus != nil {
r.CanaryStatus.CanaryRevision = revision
}
if r.BlueGreenStatus != nil {
r.BlueGreenStatus.UpdatedRevision = revision
}
}
func (r *RolloutStatus) GetCanaryReplicas() int32 {
if r.CanaryStatus != nil {
return r.CanaryStatus.CanaryReplicas
}
return r.BlueGreenStatus.UpdatedReplicas
}
func (r *RolloutStatus) SetCanaryReplicas(replicas int32) {
if r.CanaryStatus != nil {
r.CanaryStatus.CanaryReplicas = replicas
}
if r.BlueGreenStatus != nil {
r.BlueGreenStatus.UpdatedReplicas = replicas
}
}
func (r *RolloutStatus) GetCanaryReadyReplicas() int32 {
if r.CanaryStatus != nil {
return r.CanaryStatus.CanaryReadyReplicas
}
return r.BlueGreenStatus.UpdatedReadyReplicas
}
func (r *RolloutStatus) SetCanaryReadyReplicas(replicas int32) {
if r.CanaryStatus != nil {
r.CanaryStatus.CanaryReadyReplicas = replicas
}
if r.BlueGreenStatus != nil {
r.BlueGreenStatus.UpdatedReadyReplicas = replicas
}
}
type CanaryStepState string
const (
// the first step, handle some special cases before step upgrade, to prevent traffic loss
CanaryStepStateInit CanaryStepState = "BeforeStepUpgrade"
CanaryStepStateUpgrade CanaryStepState = "StepUpgrade"
CanaryStepStateTrafficRouting CanaryStepState = "StepTrafficRouting"
CanaryStepStateMetricsAnalysis CanaryStepState = "StepMetricsAnalysis"
CanaryStepStatePaused CanaryStepState = "StepPaused"
CanaryStepStateReady CanaryStepState = "StepReady"
CanaryStepStateCompleted CanaryStepState = "Completed"
)
// RolloutPhase are a set of phases that this rollout
type RolloutPhase string
const (
// RolloutPhaseInitial indicates a rollout is Initial
RolloutPhaseInitial RolloutPhase = "Initial"
// RolloutPhaseHealthy indicates a rollout is healthy
RolloutPhaseHealthy RolloutPhase = "Healthy"
// RolloutPhaseProgressing indicates a rollout is not yet healthy but still making progress towards a healthy state
RolloutPhaseProgressing RolloutPhase = "Progressing"
// RolloutPhaseTerminating indicates a rollout is terminated
RolloutPhaseTerminating RolloutPhase = "Terminating"
// RolloutPhaseDisabled indicates a rollout is disabled
RolloutPhaseDisabled RolloutPhase = "Disabled"
// RolloutPhaseDisabling indicates a rollout is disabling and releasing resources
RolloutPhaseDisabling RolloutPhase = "Disabling"
)
type FinalisingStepType string
//goland:noinspection GoUnusedConst
const (
// Route all traffic to new version (for bluegreen)
FinalisingStepRouteTrafficToNew FinalisingStepType = "FinalisingStepRouteTrafficToNew"
// Restore the GatewayAPI/Ingress/Istio
FinalisingStepRouteTrafficToStable FinalisingStepType = "FinalisingStepRouteTrafficToStable"
// Restore the stable Service, i.e. remove corresponding selector
FinalisingStepRestoreStableService FinalisingStepType = "RestoreStableService"
// Remove the Canary Service
FinalisingStepRemoveCanaryService FinalisingStepType = "RemoveCanaryService"
// Patch Batch Release to scale down (exception: the canary Deployment will be
// scaled down in FinalisingStepTypeDeleteBR step)
// For Both BlueGreenStrategy and CanaryStrategy:
// set workload.pause=false, set workload.partition=0
FinalisingStepResumeWorkload FinalisingStepType = "ResumeWorkload"
// Delete Batch Release
FinalisingStepReleaseWorkloadControl FinalisingStepType = "ReleaseWorkloadControl"
// All needed work done
FinalisingStepTypeEnd FinalisingStepType = "END"
// Only for debugging use
FinalisingStepWaitEndless FinalisingStepType = "WaitEndless"
)
// +genclient
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// +kubebuilder:storageversion
// +kubebuilder:printcolumn:name="STATUS",type="string",JSONPath=".status.phase",description="The rollout status phase"
// +kubebuilder:printcolumn:name="CANARY_STEP",type="integer",JSONPath=".status.currentStepIndex",description="The rollout canary status step"
// +kubebuilder:printcolumn:name="CANARY_STATE",type="string",JSONPath=".status.currentStepState",description="The rollout canary status step state"
// +kubebuilder:printcolumn:name="MESSAGE",type="string",JSONPath=".status.message",description="The rollout canary status message"
// +kubebuilder:printcolumn:name="AGE",type=date,JSONPath=".metadata.creationTimestamp"
// Rollout is the Schema for the rollouts API
type Rollout struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec RolloutSpec `json:"spec,omitempty"`
Status RolloutStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// RolloutList contains a list of Rollout
type RolloutList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Rollout `json:"items"`
}
func init() {
SchemeBuilder.Register(&Rollout{}, &RolloutList{})
}

View File

@ -0,0 +1,51 @@
/*
Copyright 2023 The Kruise 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 v1beta1
// TrafficRoutingRef hosts all the different configuration for supported service meshes to enable more fine-grained traffic routing
type TrafficRoutingRef struct {
// Service holds the name of a service which selects pods with stable version and don't select any pods with canary version.
Service string `json:"service"`
// Optional duration in seconds the traffic provider(e.g. nginx ingress controller) consumes the service, ingress configuration changes gracefully.
// +kubebuilder:default=3
GracePeriodSeconds int32 `json:"gracePeriodSeconds,omitempty"`
// Ingress holds Ingress specific configuration to route traffic, e.g. Nginx, Alb.
Ingress *IngressTrafficRouting `json:"ingress,omitempty"`
// Gateway holds Gateway specific configuration to route traffic
// Gateway configuration only supports >= v0.4.0 (v1alpha2).
Gateway *GatewayTrafficRouting `json:"gateway,omitempty"`
// CustomNetworkRefs hold a list of custom providers to route traffic
CustomNetworkRefs []ObjectRef `json:"customNetworkRefs,omitempty"`
}
// IngressTrafficRouting configuration for ingress controller to control traffic routing
type IngressTrafficRouting struct {
// ClassType refers to the type of `Ingress`.
// current support nginx, aliyun-alb. default is nginx.
// +optional
ClassType string `json:"classType,omitempty"`
// Name refers to the name of an `Ingress` resource in the same namespace as the `Rollout`
Name string `json:"name"`
}
// GatewayTrafficRouting configuration for gateway api
type GatewayTrafficRouting struct {
// HTTPRouteName refers to the name of an `HTTPRoute` resource in the same namespace as the `Rollout`
HTTPRouteName *string `json:"httpRouteName,omitempty"`
// TCPRouteName *string `json:"tcpRouteName,omitempty"`
// UDPRouteName *string `json:"udpRouteName,omitempty"`
}

View File

@ -0,0 +1,734 @@
//go:build !ignore_autogenerated
/*
Copyright 2023 The Kruise 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.
*/
// Code generated by controller-gen. DO NOT EDIT.
package v1beta1
import (
"k8s.io/api/apps/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
apisv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BatchRelease) DeepCopyInto(out *BatchRelease) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BatchRelease.
func (in *BatchRelease) DeepCopy() *BatchRelease {
if in == nil {
return nil
}
out := new(BatchRelease)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *BatchRelease) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BatchReleaseCanaryStatus) DeepCopyInto(out *BatchReleaseCanaryStatus) {
*out = *in
if in.BatchReadyTime != nil {
in, out := &in.BatchReadyTime, &out.BatchReadyTime
*out = (*in).DeepCopy()
}
if in.NoNeedUpdateReplicas != nil {
in, out := &in.NoNeedUpdateReplicas, &out.NoNeedUpdateReplicas
*out = new(int32)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BatchReleaseCanaryStatus.
func (in *BatchReleaseCanaryStatus) DeepCopy() *BatchReleaseCanaryStatus {
if in == nil {
return nil
}
out := new(BatchReleaseCanaryStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BatchReleaseList) DeepCopyInto(out *BatchReleaseList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]BatchRelease, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BatchReleaseList.
func (in *BatchReleaseList) DeepCopy() *BatchReleaseList {
if in == nil {
return nil
}
out := new(BatchReleaseList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *BatchReleaseList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BatchReleaseSpec) DeepCopyInto(out *BatchReleaseSpec) {
*out = *in
out.WorkloadRef = in.WorkloadRef
in.ReleasePlan.DeepCopyInto(&out.ReleasePlan)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BatchReleaseSpec.
func (in *BatchReleaseSpec) DeepCopy() *BatchReleaseSpec {
if in == nil {
return nil
}
out := new(BatchReleaseSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BatchReleaseStatus) DeepCopyInto(out *BatchReleaseStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]RolloutCondition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.CanaryStatus.DeepCopyInto(&out.CanaryStatus)
if in.CollisionCount != nil {
in, out := &in.CollisionCount, &out.CollisionCount
*out = new(int32)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BatchReleaseStatus.
func (in *BatchReleaseStatus) DeepCopy() *BatchReleaseStatus {
if in == nil {
return nil
}
out := new(BatchReleaseStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BlueGreenStatus) DeepCopyInto(out *BlueGreenStatus) {
*out = *in
in.CommonStatus.DeepCopyInto(&out.CommonStatus)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BlueGreenStatus.
func (in *BlueGreenStatus) DeepCopy() *BlueGreenStatus {
if in == nil {
return nil
}
out := new(BlueGreenStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *BlueGreenStrategy) DeepCopyInto(out *BlueGreenStrategy) {
*out = *in
if in.Steps != nil {
in, out := &in.Steps, &out.Steps
*out = make([]CanaryStep, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.TrafficRoutings != nil {
in, out := &in.TrafficRoutings, &out.TrafficRoutings
*out = make([]TrafficRoutingRef, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.FailureThreshold != nil {
in, out := &in.FailureThreshold, &out.FailureThreshold
*out = new(intstr.IntOrString)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BlueGreenStrategy.
func (in *BlueGreenStrategy) DeepCopy() *BlueGreenStrategy {
if in == nil {
return nil
}
out := new(BlueGreenStrategy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CanaryStatus) DeepCopyInto(out *CanaryStatus) {
*out = *in
in.CommonStatus.DeepCopyInto(&out.CommonStatus)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryStatus.
func (in *CanaryStatus) DeepCopy() *CanaryStatus {
if in == nil {
return nil
}
out := new(CanaryStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CanaryStep) DeepCopyInto(out *CanaryStep) {
*out = *in
in.TrafficRoutingStrategy.DeepCopyInto(&out.TrafficRoutingStrategy)
if in.Replicas != nil {
in, out := &in.Replicas, &out.Replicas
*out = new(intstr.IntOrString)
**out = **in
}
in.Pause.DeepCopyInto(&out.Pause)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryStep.
func (in *CanaryStep) DeepCopy() *CanaryStep {
if in == nil {
return nil
}
out := new(CanaryStep)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CanaryStrategy) DeepCopyInto(out *CanaryStrategy) {
*out = *in
if in.Steps != nil {
in, out := &in.Steps, &out.Steps
*out = make([]CanaryStep, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.TrafficRoutings != nil {
in, out := &in.TrafficRoutings, &out.TrafficRoutings
*out = make([]TrafficRoutingRef, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.FailureThreshold != nil {
in, out := &in.FailureThreshold, &out.FailureThreshold
*out = new(intstr.IntOrString)
**out = **in
}
if in.PatchPodTemplateMetadata != nil {
in, out := &in.PatchPodTemplateMetadata, &out.PatchPodTemplateMetadata
*out = new(PatchPodTemplateMetadata)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CanaryStrategy.
func (in *CanaryStrategy) DeepCopy() *CanaryStrategy {
if in == nil {
return nil
}
out := new(CanaryStrategy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *CommonStatus) DeepCopyInto(out *CommonStatus) {
*out = *in
if in.LastUpdateTime != nil {
in, out := &in.LastUpdateTime, &out.LastUpdateTime
*out = (*in).DeepCopy()
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CommonStatus.
func (in *CommonStatus) DeepCopy() *CommonStatus {
if in == nil {
return nil
}
out := new(CommonStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeploymentExtraStatus) DeepCopyInto(out *DeploymentExtraStatus) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentExtraStatus.
func (in *DeploymentExtraStatus) DeepCopy() *DeploymentExtraStatus {
if in == nil {
return nil
}
out := new(DeploymentExtraStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *DeploymentStrategy) DeepCopyInto(out *DeploymentStrategy) {
*out = *in
if in.RollingUpdate != nil {
in, out := &in.RollingUpdate, &out.RollingUpdate
*out = new(v1.RollingUpdateDeployment)
(*in).DeepCopyInto(*out)
}
out.Partition = in.Partition
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentStrategy.
func (in *DeploymentStrategy) DeepCopy() *DeploymentStrategy {
if in == nil {
return nil
}
out := new(DeploymentStrategy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *GatewayTrafficRouting) DeepCopyInto(out *GatewayTrafficRouting) {
*out = *in
if in.HTTPRouteName != nil {
in, out := &in.HTTPRouteName, &out.HTTPRouteName
*out = new(string)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayTrafficRouting.
func (in *GatewayTrafficRouting) DeepCopy() *GatewayTrafficRouting {
if in == nil {
return nil
}
out := new(GatewayTrafficRouting)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *HttpRouteMatch) DeepCopyInto(out *HttpRouteMatch) {
*out = *in
if in.Path != nil {
in, out := &in.Path, &out.Path
*out = new(apisv1beta1.HTTPPathMatch)
(*in).DeepCopyInto(*out)
}
if in.Headers != nil {
in, out := &in.Headers, &out.Headers
*out = make([]apisv1beta1.HTTPHeaderMatch, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.QueryParams != nil {
in, out := &in.QueryParams, &out.QueryParams
*out = make([]apisv1beta1.HTTPQueryParamMatch, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HttpRouteMatch.
func (in *HttpRouteMatch) DeepCopy() *HttpRouteMatch {
if in == nil {
return nil
}
out := new(HttpRouteMatch)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *IngressTrafficRouting) DeepCopyInto(out *IngressTrafficRouting) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressTrafficRouting.
func (in *IngressTrafficRouting) DeepCopy() *IngressTrafficRouting {
if in == nil {
return nil
}
out := new(IngressTrafficRouting)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ObjectRef) DeepCopyInto(out *ObjectRef) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectRef.
func (in *ObjectRef) DeepCopy() *ObjectRef {
if in == nil {
return nil
}
out := new(ObjectRef)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PatchPodTemplateMetadata) DeepCopyInto(out *PatchPodTemplateMetadata) {
*out = *in
if in.Annotations != nil {
in, out := &in.Annotations, &out.Annotations
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
if in.Labels != nil {
in, out := &in.Labels, &out.Labels
*out = make(map[string]string, len(*in))
for key, val := range *in {
(*out)[key] = val
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PatchPodTemplateMetadata.
func (in *PatchPodTemplateMetadata) DeepCopy() *PatchPodTemplateMetadata {
if in == nil {
return nil
}
out := new(PatchPodTemplateMetadata)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ReleaseBatch) DeepCopyInto(out *ReleaseBatch) {
*out = *in
out.CanaryReplicas = in.CanaryReplicas
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReleaseBatch.
func (in *ReleaseBatch) DeepCopy() *ReleaseBatch {
if in == nil {
return nil
}
out := new(ReleaseBatch)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ReleasePlan) DeepCopyInto(out *ReleasePlan) {
*out = *in
if in.Batches != nil {
in, out := &in.Batches, &out.Batches
*out = make([]ReleaseBatch, len(*in))
copy(*out, *in)
}
if in.BatchPartition != nil {
in, out := &in.BatchPartition, &out.BatchPartition
*out = new(int32)
**out = **in
}
if in.FailureThreshold != nil {
in, out := &in.FailureThreshold, &out.FailureThreshold
*out = new(intstr.IntOrString)
**out = **in
}
if in.PatchPodTemplateMetadata != nil {
in, out := &in.PatchPodTemplateMetadata, &out.PatchPodTemplateMetadata
*out = new(PatchPodTemplateMetadata)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReleasePlan.
func (in *ReleasePlan) DeepCopy() *ReleasePlan {
if in == nil {
return nil
}
out := new(ReleasePlan)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Rollout) DeepCopyInto(out *Rollout) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Rollout.
func (in *Rollout) DeepCopy() *Rollout {
if in == nil {
return nil
}
out := new(Rollout)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Rollout) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RolloutCondition) DeepCopyInto(out *RolloutCondition) {
*out = *in
in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime)
in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RolloutCondition.
func (in *RolloutCondition) DeepCopy() *RolloutCondition {
if in == nil {
return nil
}
out := new(RolloutCondition)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RolloutList) DeepCopyInto(out *RolloutList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Rollout, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RolloutList.
func (in *RolloutList) DeepCopy() *RolloutList {
if in == nil {
return nil
}
out := new(RolloutList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *RolloutList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RolloutPause) DeepCopyInto(out *RolloutPause) {
*out = *in
if in.Duration != nil {
in, out := &in.Duration, &out.Duration
*out = new(int32)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RolloutPause.
func (in *RolloutPause) DeepCopy() *RolloutPause {
if in == nil {
return nil
}
out := new(RolloutPause)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RolloutSpec) DeepCopyInto(out *RolloutSpec) {
*out = *in
out.WorkloadRef = in.WorkloadRef
in.Strategy.DeepCopyInto(&out.Strategy)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RolloutSpec.
func (in *RolloutSpec) DeepCopy() *RolloutSpec {
if in == nil {
return nil
}
out := new(RolloutSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RolloutStatus) DeepCopyInto(out *RolloutStatus) {
*out = *in
if in.CanaryStatus != nil {
in, out := &in.CanaryStatus, &out.CanaryStatus
*out = new(CanaryStatus)
(*in).DeepCopyInto(*out)
}
if in.BlueGreenStatus != nil {
in, out := &in.BlueGreenStatus, &out.BlueGreenStatus
*out = new(BlueGreenStatus)
(*in).DeepCopyInto(*out)
}
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]RolloutCondition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RolloutStatus.
func (in *RolloutStatus) DeepCopy() *RolloutStatus {
if in == nil {
return nil
}
out := new(RolloutStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RolloutStrategy) DeepCopyInto(out *RolloutStrategy) {
*out = *in
if in.Canary != nil {
in, out := &in.Canary, &out.Canary
*out = new(CanaryStrategy)
(*in).DeepCopyInto(*out)
}
if in.BlueGreen != nil {
in, out := &in.BlueGreen, &out.BlueGreen
*out = new(BlueGreenStrategy)
(*in).DeepCopyInto(*out)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RolloutStrategy.
func (in *RolloutStrategy) DeepCopy() *RolloutStrategy {
if in == nil {
return nil
}
out := new(RolloutStrategy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TrafficRoutingRef) DeepCopyInto(out *TrafficRoutingRef) {
*out = *in
if in.Ingress != nil {
in, out := &in.Ingress, &out.Ingress
*out = new(IngressTrafficRouting)
**out = **in
}
if in.Gateway != nil {
in, out := &in.Gateway, &out.Gateway
*out = new(GatewayTrafficRouting)
(*in).DeepCopyInto(*out)
}
if in.CustomNetworkRefs != nil {
in, out := &in.CustomNetworkRefs, &out.CustomNetworkRefs
*out = make([]ObjectRef, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficRoutingRef.
func (in *TrafficRoutingRef) DeepCopy() *TrafficRoutingRef {
if in == nil {
return nil
}
out := new(TrafficRoutingRef)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TrafficRoutingStrategy) DeepCopyInto(out *TrafficRoutingStrategy) {
*out = *in
if in.Traffic != nil {
in, out := &in.Traffic, &out.Traffic
*out = new(string)
**out = **in
}
if in.RequestHeaderModifier != nil {
in, out := &in.RequestHeaderModifier, &out.RequestHeaderModifier
*out = new(apisv1beta1.HTTPHeaderFilter)
(*in).DeepCopyInto(*out)
}
if in.Matches != nil {
in, out := &in.Matches, &out.Matches
*out = make([]HttpRouteMatch, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TrafficRoutingStrategy.
func (in *TrafficRoutingStrategy) DeepCopy() *TrafficRoutingStrategy {
if in == nil {
return nil
}
out := new(TrafficRoutingStrategy)
in.DeepCopyInto(out)
return out
}

View File

@ -1,11 +1,9 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.7.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.14.0
name: batchreleases.rollouts.kruise.io
spec:
group: rollouts.kruise.io
@ -37,14 +35,19 @@ spec:
openAPIV3Schema:
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'
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'
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
@ -56,20 +59,23 @@ spec:
description: ReleasePlan is the details on how to rollout the resources
properties:
batchPartition:
description: All pods in the batches up to the batchPartition
(included) will have the target resource specification while
the rest still is the stable revision. This is designed for
the operators to manually rollout. Default is nil, which means
no partition and will release all batches. BatchPartition start
from 0.
description: |-
All pods in the batches up to the batchPartition (included) will have
the target resource specification while the rest still is the stable revision.
This is designed for the operators to manually rollout.
Default is nil, which means no partition and will release all batches.
BatchPartition start from 0.
format: int32
type: integer
batches:
description: 'Batches is the details on each batch of the ReleasePlan.
Users can specify their batch plan in this field, such as: batches:
- canaryReplicas: 1 # batches 0 - canaryReplicas: 2 # batches
1 - canaryReplicas: 5 # batches 2 Not that these canaryReplicas
should be a non-decreasing sequence.'
description: |-
Batches is the details on each batch of the ReleasePlan.
Users can specify their batch plan in this field, such as:
batches:
- canaryReplicas: 1 # batches 0
- canaryReplicas: 2 # batches 1
- canaryReplicas: 5 # batches 2
Not that these canaryReplicas should be a non-decreasing sequence.
items:
description: ReleaseBatch is used to describe how each batch
release should be
@ -78,33 +84,44 @@ spec:
anyOf:
- type: integer
- type: string
description: 'CanaryReplicas is the number of upgraded pods
that should have in this batch. it can be an absolute
number (ex: 5) or a percentage of workload replicas. batches[i].canaryReplicas
should less than or equal to batches[j].canaryReplicas
if i < j.'
description: |-
CanaryReplicas is the number of upgraded pods that should have in this batch.
it can be an absolute number (ex: 5) or a percentage of workload replicas.
batches[i].canaryReplicas should less than or equal to batches[j].canaryReplicas if i < j.
x-kubernetes-int-or-string: true
required:
- canaryReplicas
type: object
type: array
enableExtraWorkloadForCanary:
description: |-
EnableExtraWorkloadForCanary indicates whether to create extra workload for canary
True corresponds to RollingStyle "Canary".
False corresponds to RollingStyle "Partiton".
Ignored in BlueGreen-style.
This field is about to deprecate, use RollingStyle instead.
If both of them are set, controller will only consider this
filed when RollingStyle is empty
type: boolean
failureThreshold:
anyOf:
- type: integer
- type: string
description: FailureThreshold indicates how many failed pods can
be tolerated in all upgraded pods. Only when FailureThreshold
are satisfied, Rollout can enter ready state. If FailureThreshold
is nil, Rollout will use the MaxUnavailable of workload as its
FailureThreshold. Defaults to nil.
description: |-
FailureThreshold indicates how many failed pods can be tolerated in all upgraded pods.
Only when FailureThreshold are satisfied, Rollout can enter ready state.
If FailureThreshold is nil, Rollout will use the MaxUnavailable of workload as its
FailureThreshold.
Defaults to nil.
x-kubernetes-int-or-string: true
finalizingPolicy:
description: FinalizingPolicy define the behavior of controller
when phase enter Finalizing Defaults to "Immediate"
description: |-
FinalizingPolicy define the behavior of controller when phase enter Finalizing
Defaults to "Immediate"
type: string
patchPodTemplateMetadata:
description: PatchPodTemplateMetadata indicates patch configuration(e.g.
labels, annotations) to the canary deployment podTemplateSpec.metadata
description: |-
PatchPodTemplateMetadata indicates patch configuration(e.g. labels, annotations) to the canary deployment podTemplateSpec.metadata
only support for canary deployment
properties:
annotations:
@ -118,17 +135,23 @@ spec:
description: labels
type: object
type: object
rollingStyle:
description: RollingStyle can be "Canary", "Partiton" or "BlueGreen"
type: string
rolloutID:
description: RolloutID indicates an id for each rollout progress
type: string
required:
- enableExtraWorkloadForCanary
type: object
targetReference:
description: TargetRef contains the GVK and name of the workload that
we need to upgrade to.
properties:
workloadRef:
description: WorkloadRef contains enough information to let you
identify a workload for Rollout Batch release of the bypass
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
@ -157,10 +180,10 @@ spec:
description: CanaryStatus describes the state of the canary rollout.
properties:
batchReadyTime:
description: BatchReadyTime is the ready timestamp of the current
batch or the last batch. This field is updated once a batch
ready, and the batches[x].pausedSeconds relies on this field
to calculate the real-time duration.
description: |-
BatchReadyTime is the ready timestamp of the current batch or the last batch.
This field is updated once a batch ready, and the batches[x].pausedSeconds
relies on this field to calculate the real-time duration.
format: date-time
type: string
batchState:
@ -190,9 +213,10 @@ spec:
- currentBatch
type: object
collisionCount:
description: Count of hash collisions for creating canary Deployment.
The controller uses this field as a collision avoidance mechanism
when it needs to create the name for the newest canary Deployment.
description: |-
Count of hash collisions for creating canary Deployment. The controller uses this
field as a collision avoidance mechanism when it needs to create the name for the
newest canary Deployment.
format: int32
type: integer
conditions:
@ -232,10 +256,10 @@ spec:
type: object
type: array
observedGeneration:
description: ObservedGeneration is the most recent generation observed
for this BatchRelease. It corresponds to this BatchRelease's generation,
which is updated on mutation by the API Server, and only if BatchRelease
Spec was changed, its generation will increase 1.
description: |-
ObservedGeneration is the most recent generation observed for this BatchRelease.
It corresponds to this BatchRelease's generation, which is updated on mutation
by the API Server, and only if BatchRelease Spec was changed, its generation will increase 1.
format: int64
type: integer
observedReleasePlanHash:
@ -243,21 +267,304 @@ spec:
spec.releasePlan.
type: string
observedRolloutID:
description: ObservedRolloutID is the most recent rollout-id observed
for this BatchRelease. If RolloutID was changed, we will restart
to roll out from batch 0, to ensure the batch-id and rollout-id
labels of Pods are correct.
description: |-
ObservedRolloutID is the most recent rollout-id observed for this BatchRelease.
If RolloutID was changed, we will restart to roll out from batch 0,
to ensure the batch-id and rollout-id labels of Pods are correct.
type: string
observedWorkloadReplicas:
description: ObservedWorkloadReplicas is observed replicas of target
referenced workload. This field is designed to deal with scaling
event during rollout, if this field changed, it means that the workload
is scaling during rollout.
description: |-
ObservedWorkloadReplicas is observed replicas of target referenced workload.
This field is designed to deal with scaling event during rollout, if this field changed,
it means that the workload is scaling during rollout.
format: int32
type: integer
phase:
description: Phase is the release plan phase, which indicates the
current state of release plan state machine in BatchRelease controller.
description: |-
Phase is the release plan phase, which indicates the current state of release
plan state machine in BatchRelease controller.
type: string
stableRevision:
description: StableRevision is the pod-template-hash of stable revision
pod template.
type: string
updateRevision:
description: UpdateRevision is the pod-template-hash of update revision
pod template.
type: string
type: object
type: object
served: true
storage: false
subresources:
status: {}
- additionalPrinterColumns:
- jsonPath: .spec.targetReference.workloadRef.kind
name: KIND
type: string
- jsonPath: .status.phase
name: PHASE
type: string
- jsonPath: .status.canaryStatus.currentBatch
name: BATCH
type: integer
- jsonPath: .status.canaryStatus.batchState
name: BATCH-STATE
type: string
- jsonPath: .metadata.creationTimestamp
name: AGE
type: date
name: v1beta1
schema:
openAPIV3Schema:
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: BatchReleaseSpec defines how to describe an update between
different compRevision
properties:
releasePlan:
description: ReleasePlan is the details on how to rollout the resources
properties:
batchPartition:
description: |-
All pods in the batches up to the batchPartition (included) will have
the target resource specification while the rest still is the stable revision.
This is designed for the operators to manually rollout.
Default is nil, which means no partition and will release all batches.
BatchPartition start from 0.
format: int32
type: integer
batches:
description: |-
Batches is the details on each batch of the ReleasePlan.
Users can specify their batch plan in this field, such as:
batches:
- canaryReplicas: 1 # batches 0
- canaryReplicas: 2 # batches 1
- canaryReplicas: 5 # batches 2
Not that these canaryReplicas should be a non-decreasing sequence.
items:
description: ReleaseBatch is used to describe how each batch
release should be
properties:
canaryReplicas:
anyOf:
- type: integer
- type: string
description: |-
CanaryReplicas is the number of upgraded pods that should have in this batch.
it can be an absolute number (ex: 5) or a percentage of workload replicas.
batches[i].canaryReplicas should less than or equal to batches[j].canaryReplicas if i < j.
x-kubernetes-int-or-string: true
required:
- canaryReplicas
type: object
type: array
enableExtraWorkloadForCanary:
description: |-
EnableExtraWorkloadForCanary indicates whether to create extra workload for canary
True corresponds to RollingStyle "Canary".
False corresponds to RollingStyle "Partiton".
Ignored in BlueGreen-style.
This field is about to deprecate, use RollingStyle instead.
If both of them are set, controller will only consider this
filed when RollingStyle is empty
type: boolean
failureThreshold:
anyOf:
- type: integer
- type: string
description: |-
FailureThreshold indicates how many failed pods can be tolerated in all upgraded pods.
Only when FailureThreshold are satisfied, Rollout can enter ready state.
If FailureThreshold is nil, Rollout will use the MaxUnavailable of workload as its
FailureThreshold.
Defaults to nil.
x-kubernetes-int-or-string: true
finalizingPolicy:
description: |-
FinalizingPolicy define the behavior of controller when phase enter Finalizing
Defaults to "Immediate"
type: string
patchPodTemplateMetadata:
description: |-
PatchPodTemplateMetadata indicates patch configuration(e.g. labels, annotations) to the canary deployment podTemplateSpec.metadata
only support for canary deployment
properties:
annotations:
additionalProperties:
type: string
description: annotations
type: object
labels:
additionalProperties:
type: string
description: labels
type: object
type: object
rollingStyle:
description: RollingStyle can be "Canary", "Partiton" or "BlueGreen"
type: string
rolloutID:
description: RolloutID indicates an id for each rollout progress
type: string
required:
- enableExtraWorkloadForCanary
type: object
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
required:
- releasePlan
type: object
status:
description: BatchReleaseStatus defines the observed state of a release
plan
properties:
canaryStatus:
description: CanaryStatus describes the state of the canary rollout.
properties:
batchReadyTime:
description: |-
BatchReadyTime is the ready timestamp of the current batch or the last batch.
This field is updated once a batch ready, and the batches[x].pausedSeconds
relies on this field to calculate the real-time duration.
format: date-time
type: string
batchState:
description: CurrentBatchState indicates the release state of
the current batch.
type: string
currentBatch:
description: The current batch the rollout is working on/blocked,
it starts from 0
format: int32
type: integer
noNeedUpdateReplicas:
description: the number of pods that no need to rollback in rollback
scene.
format: int32
type: integer
updatedReadyReplicas:
description: UpdatedReadyReplicas is the number upgraded Pods
that have a Ready Condition.
format: int32
type: integer
updatedReplicas:
description: UpdatedReplicas is the number of upgraded Pods.
format: int32
type: integer
required:
- currentBatch
type: object
collisionCount:
description: |-
Count of hash collisions for creating canary Deployment. The controller uses this
field as a collision avoidance mechanism when it needs to create the name for the
newest canary Deployment.
format: int32
type: integer
conditions:
description: Conditions represents the observed process state of each
phase during executing the release plan.
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 BatchRelease.
It corresponds to this BatchRelease's generation, which is updated on mutation
by the API Server, and only if BatchRelease Spec was changed, its generation will increase 1.
format: int64
type: integer
observedReleasePlanHash:
description: ObservedReleasePlanHash is a hash code of observed itself
spec.releasePlan.
type: string
observedRolloutID:
description: |-
ObservedRolloutID is the most recent rollout-id observed for this BatchRelease.
If RolloutID was changed, we will restart to roll out from batch 0,
to ensure the batch-id and rollout-id labels of Pods are correct.
type: string
observedWorkloadReplicas:
description: |-
ObservedWorkloadReplicas is observed replicas of target referenced workload.
This field is designed to deal with scaling event during rollout, if this field changed,
it means that the workload is scaling during rollout.
format: int32
type: integer
phase:
description: |-
Phase is the release plan phase, which indicates the current state of release
plan state machine in BatchRelease controller.
type: string
stableRevision:
description: StableRevision is the pod-template-hash of stable revision
@ -273,9 +580,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -1,11 +1,9 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.7.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.14.0
name: rollouthistories.rollouts.kruise.io
spec:
group: rollouts.kruise.io
@ -22,14 +20,19 @@ spec:
description: RolloutHistory is the Schema for the rollouthistories 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'
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'
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
@ -48,8 +51,9 @@ spec:
name, workload name, ingress name, etc.
type: string
rolloutID:
description: RolloutID indicates the new rollout if there is no
new RolloutID this time, ignore it and not execute RolloutHistory
description: |-
RolloutID indicates the new rollout
if there is no new RolloutID this time, ignore it and not execute RolloutHistory
type: string
required:
- name
@ -105,19 +109,22 @@ spec:
as cloneset, deployment, advanced statefulset
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'
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
data:
description: Data indecates the spec of object ref
x-kubernetes-preserve-unknown-fields: true
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'
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
name:
description: Name indicates the name of object ref, such as rollout
@ -168,9 +175,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,9 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.7.0
creationTimestamp: null
controller-gen.kubebuilder.io/version: v0.14.0
name: trafficroutings.rollouts.kruise.io
spec:
group: rollouts.kruise.io
@ -34,14 +32,19 @@ spec:
description: TrafficRouting is the Schema for the TrafficRoutings 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'
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'
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
@ -54,10 +57,27 @@ spec:
for supported service meshes to enable more fine-grained traffic
routing
properties:
customNetworkRefs:
description: CustomNetworkRefs hold a list of custom providers
to route traffic
items:
properties:
apiVersion:
type: string
kind:
type: string
name:
type: string
required:
- apiVersion
- kind
- name
type: object
type: array
gateway:
description: Gateway holds Gateway specific configuration to
route traffic Gateway configuration only supports >= v0.4.0
(v1alpha2).
description: |-
Gateway holds Gateway specific configuration to route traffic
Gateway configuration only supports >= v0.4.0 (v1alpha2).
properties:
httpRouteName:
description: HTTPRouteName refers to the name of an `HTTPRoute`
@ -65,6 +85,7 @@ spec:
type: string
type: object
gracePeriodSeconds:
default: 3
description: Optional duration in seconds the traffic provider(e.g.
nginx ingress controller) consumes the service, ingress configuration
changes gracefully.
@ -75,7 +96,8 @@ spec:
route traffic, e.g. Nginx, Alb.
properties:
classType:
description: ClassType refers to the type of `Ingress`.
description: |-
ClassType refers to the type of `Ingress`.
current support nginx, aliyun-alb. default is nginx.
type: string
name:
@ -98,52 +120,61 @@ spec:
description: trafficrouting strategy
properties:
matches:
description: Matches define conditions used for matching the incoming
HTTP requests to canary service. Each match is independent,
i.e. this rule will be matched if **any** one of the matches
is satisfied. If Gateway API, current only support one match.
And cannot support both weight and matches, if both are configured,
then matches takes precedence.
description: |-
Matches define conditions used for matching the incoming HTTP requests to canary service.
Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied.
If Gateway API, current only support one match.
And cannot support both weight and matches, if both are configured, then matches takes precedence.
items:
properties:
headers:
description: Headers specifies HTTP request header matchers.
Multiple match values are ANDed together, meaning, a request
must match all the specified headers to select the route.
description: |-
Headers specifies HTTP request header matchers. Multiple match values are
ANDed together, meaning, a request must match all the specified headers
to select the route.
items:
description: HTTPHeaderMatch describes how to select a
HTTP route by matching HTTP request headers.
description: |-
HTTPHeaderMatch describes how to select a HTTP route by matching HTTP request
headers.
properties:
name:
description: "Name is the name of the HTTP Header
to be matched. Name matching MUST be case insensitive.
(See https://tools.ietf.org/html/rfc7230#section-3.2).
\n If multiple entries specify equivalent header
names, only the first entry with an equivalent name
MUST be considered for a match. Subsequent entries
with an equivalent header name MUST be ignored.
Due to the case-insensitivity of header names, \"foo\"
and \"Foo\" are considered equivalent. \n When a
header is repeated in an HTTP request, it is implementation-specific
behavior as to how this is represented. Generally,
proxies should follow the guidance from the RFC:
https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2
regarding processing a repeated header, with special
handling for \"Set-Cookie\"."
description: |-
Name is the name of the HTTP Header to be matched. Name matching MUST be
case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2).
If multiple entries specify equivalent header names, only the first
entry with an equivalent name MUST be considered for a match. Subsequent
entries with an equivalent header name MUST be ignored. Due to the
case-insensitivity of header names, "foo" and "Foo" are considered
equivalent.
When a header is repeated in an HTTP request, it is
implementation-specific behavior as to how this is represented.
Generally, proxies should follow the guidance from the RFC:
https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding
processing a repeated header, with special handling for "Set-Cookie".
maxLength: 256
minLength: 1
pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$
type: string
type:
default: Exact
description: "Type specifies how to match against
the value of the header. \n Support: Core (Exact)
\n Support: Custom (RegularExpression) \n Since
RegularExpression HeaderMatchType has custom conformance,
implementations can support POSIX, PCRE or any other
dialects of regular expressions. Please read the
implementation's documentation to determine the
supported dialect."
description: |-
Type specifies how to match against the value of the header.
Support: Core (Exact)
Support: Implementation-specific (RegularExpression)
Since RegularExpression HeaderMatchType has implementation-specific
conformance, implementations can support POSIX, PCRE or any other dialects
of regular expressions. Please read the implementation's documentation to
determine the supported dialect.
enum:
- Exact
- RegularExpression
@ -163,33 +194,62 @@ spec:
type: object
type: array
requestHeaderModifier:
description: "Set overwrites the request with the given header
(name, value) before the action. \n Input: GET /foo HTTP/1.1
\ my-header: foo \n requestHeaderModifier: set: - name:
\"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1
\ my-header: bar"
description: |-
Set overwrites the request with the given header (name, value)
before the action.
Input:
GET /foo HTTP/1.1
my-header: foo
requestHeaderModifier:
set:
- name: "my-header"
value: "bar"
Output:
GET /foo HTTP/1.1
my-header: bar
properties:
add:
description: "Add adds the given header(s) (name, value) to
the request before the action. It appends to any existing
values associated with the header name. \n Input: GET
/foo HTTP/1.1 my-header: foo \n Config: add: - name:
\"my-header\" value: \"bar\" \n Output: GET /foo HTTP/1.1
\ my-header: foo my-header: bar"
description: |-
Add adds the given header(s) (name, value) to the request
before the action. It appends to any existing values associated
with the header name.
Input:
GET /foo HTTP/1.1
my-header: foo
Config:
add:
- name: "my-header"
value: "bar,baz"
Output:
GET /foo HTTP/1.1
my-header: foo,bar,baz
items:
description: HTTPHeader represents an HTTP Header name and
value as defined by RFC 7230.
properties:
name:
description: "Name is the name of the HTTP Header to
be matched. Name matching MUST be case insensitive.
(See https://tools.ietf.org/html/rfc7230#section-3.2).
\n If multiple entries specify equivalent header names,
the first entry with an equivalent name MUST be considered
for a match. Subsequent entries with an equivalent
header name MUST be ignored. Due to the case-insensitivity
of header names, \"foo\" and \"Foo\" are considered
equivalent."
description: |-
Name is the name of the HTTP Header to be matched. Name matching MUST be
case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2).
If multiple entries specify equivalent header names, the first entry with
an equivalent name MUST be considered for a match. Subsequent entries
with an equivalent header name MUST be ignored. Due to the
case-insensitivity of header names, "foo" and "Foo" are considered
equivalent.
maxLength: 256
minLength: 1
pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$
@ -210,38 +270,67 @@ spec:
- name
x-kubernetes-list-type: map
remove:
description: "Remove the given header(s) from the HTTP request
before the action. The value of Remove is a list of HTTP
header names. Note that the header names are case-insensitive
(see https://datatracker.ietf.org/doc/html/rfc2616#section-4.2).
\n Input: GET /foo HTTP/1.1 my-header1: foo my-header2:
bar my-header3: baz \n Config: remove: [\"my-header1\",
\"my-header3\"] \n Output: GET /foo HTTP/1.1 my-header2:
bar"
description: |-
Remove the given header(s) from the HTTP request before the action. The
value of Remove is a list of HTTP header names. Note that the header
names are case-insensitive (see
https://datatracker.ietf.org/doc/html/rfc2616#section-4.2).
Input:
GET /foo HTTP/1.1
my-header1: foo
my-header2: bar
my-header3: baz
Config:
remove: ["my-header1", "my-header3"]
Output:
GET /foo HTTP/1.1
my-header2: bar
items:
type: string
maxItems: 16
type: array
x-kubernetes-list-type: set
set:
description: "Set overwrites the request with the given header
(name, value) before the action. \n Input: GET /foo HTTP/1.1
\ my-header: foo \n Config: set: - name: \"my-header\"
\ value: \"bar\" \n Output: GET /foo HTTP/1.1 my-header:
bar"
description: |-
Set overwrites the request with the given header (name, value)
before the action.
Input:
GET /foo HTTP/1.1
my-header: foo
Config:
set:
- name: "my-header"
value: "bar"
Output:
GET /foo HTTP/1.1
my-header: bar
items:
description: HTTPHeader represents an HTTP Header name and
value as defined by RFC 7230.
properties:
name:
description: "Name is the name of the HTTP Header to
be matched. Name matching MUST be case insensitive.
(See https://tools.ietf.org/html/rfc7230#section-3.2).
\n If multiple entries specify equivalent header names,
the first entry with an equivalent name MUST be considered
for a match. Subsequent entries with an equivalent
header name MUST be ignored. Due to the case-insensitivity
of header names, \"foo\" and \"Foo\" are considered
equivalent."
description: |-
Name is the name of the HTTP Header to be matched. Name matching MUST be
case insensitive. (See https://tools.ietf.org/html/rfc7230#section-3.2).
If multiple entries specify equivalent header names, the first entry with
an equivalent name MUST be considered for a match. Subsequent entries
with an equivalent header name MUST be ignored. Due to the
case-insensitivity of header names, "foo" and "Foo" are considered
equivalent.
maxLength: 256
minLength: 1
pattern: ^[A-Za-z0-9!#$%&'*+\-.^_\x60|~]+$
@ -292,9 +381,3 @@ spec:
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []

View File

@ -11,8 +11,8 @@ resources:
patchesStrategicMerge:
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
# patches here are for enabling the conversion webhook for each CRD
#- patches/webhook_in_rollouts.yaml
#- patches/webhook_in_batchreleases.yaml
- patches/webhook_in_rollouts.yaml
- patches/webhook_in_batchreleases.yaml
#+kubebuilder:scaffold:crdkustomizewebhookpatch
# [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix.

View File

@ -13,4 +13,4 @@ spec:
name: webhook-service
path: /convert
conversionReviewVersions:
- v1
- v1beta1

View File

@ -13,4 +13,4 @@ spec:
name: webhook-service
path: /convert
conversionReviewVersions:
- v1
- v1beta1

View File

@ -1,9 +1,7 @@
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
creationTimestamp: null
name: manager-role
rules:
- apiGroups:
@ -162,6 +160,16 @@ rules:
- get
- patch
- update
- apiGroups:
- autoscaling
resources:
- horizontalpodautoscalers
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
@ -196,18 +204,6 @@ rules:
- get
- patch
- update
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
@ -248,6 +244,17 @@ rules:
- get
- patch
- update
- apiGroups:
- networking.istio.io
resources:
- destinationrules
- virtualservices
verbs:
- get
- list
- patch
- update
- watch
- apiGroups:
- networking.k8s.io
resources:
@ -365,3 +372,22 @@ rules:
- get
- patch
- update
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: manager-role
namespace: system
rules:
- apiGroups:
- ""
resources:
- secrets
verbs:
- create
- delete
- get
- list
- patch
- update
- watch

View File

@ -10,3 +10,17 @@ subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: manager-rolebinding
namespace: system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: manager-role
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system

View File

@ -1,9 +1,7 @@
---
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
creationTimestamp: null
name: mutating-webhook-configuration
webhooks:
- admissionReviewVersions:
@ -66,48 +64,6 @@ webhooks:
resources:
- deployments
sideEffects: None
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
service:
name: webhook-service
namespace: system
path: /mutate-apps-v1-statefulset
failurePolicy: Fail
name: mstatefulset.kb.io
rules:
- apiGroups:
- apps
apiVersions:
- v1
operations:
- UPDATE
resources:
- statefulsets
sideEffects: None
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
service:
name: webhook-service
namespace: system
path: /mutate-apps-kruise-io-statefulset
failurePolicy: Fail
name: madvancedstatefulset.kb.io
rules:
- apiGroups:
- apps.kruise.io
apiVersions:
- v1alpha1
- v1beta1
operations:
- CREATE
- UPDATE
resources:
- statefulsets
sideEffects: None
- admissionReviewVersions:
- v1
- v1beta1
@ -129,12 +85,10 @@ webhooks:
resources:
- '*'
sideEffects: None
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingWebhookConfiguration
metadata:
creationTimestamp: null
name: validating-webhook-configuration
webhooks:
- admissionReviewVersions:
@ -152,6 +106,7 @@ webhooks:
- rollouts.kruise.io
apiVersions:
- v1alpha1
- v1beta1
operations:
- CREATE
- UPDATE

View File

@ -18,16 +18,16 @@ webhooks:
matchExpressions:
- key: rollouts.kruise.io/workload-type
operator: Exists
- name: mstatefulset.kb.io
objectSelector:
matchExpressions:
- key: rollouts.kruise.io/workload-type
operator: Exists
- name: madvancedstatefulset.kb.io
objectSelector:
matchExpressions:
- key: rollouts.kruise.io/workload-type
operator: Exists
# - name: mstatefulset.kb.io
# objectSelector:
# matchExpressions:
# - key: rollouts.kruise.io/workload-type
# operator: Exists
# - name: madvancedstatefulset.kb.io
# objectSelector:
# matchExpressions:
# - key: rollouts.kruise.io/workload-type
# operator: Exists
- name: mdeployment.kb.io
objectSelector:
matchExpressions:

View File

@ -0,0 +1,224 @@
---
title: v1beta1-apis-proposal
authors:
- "@zmberg"
creation-date: 2023-11-07
---
## Motivation
The Kruise Rollout project has been stable for a year, recently we plan to upgrade the apis from v1alpha1 to v1beta1 and optimize some of the fields in response to past questions and community feedback,
this proposal will organize the v1beta1 apis and discuss it with the community.
## Proposal
To make it easier to understand, I'm going to introduce the v1beta1 field from 6 scenario.
### Canary Release
```
apiVersion: rollouts.kruise.io/v1beta1
kind: Rollout
metadata:
name: rollouts-demo
spec:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: workload-demo
strategy:
canary:
# If true, then it will create new deployment for canary, such as: workload-demo-canary.
# When user verifies that the canary version is OK, we will remove the canary deployment and release the deployment workload-demo in full.
# Current only support k8s native deployment
enableExtraWorkloadForCanary: true
steps:
- trafficWeight: 20%
desiredReplicas: 2
trafficRoutings:
- service: service-demo
ingress:
classType: nginx
name: ingress-demo
```
### A/B Testing Release
```
apiVersion: rollouts.kruise.io/v1beta1
kind: Rollout
metadata:
name: rollouts-demo
spec:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: workload-demo
strategy:
canary:
enableExtraWorkloadForCanary: true
steps:
- desiredReplicas: 2
trafficMatches:
- headers:
- name: user-agent
type: Exact
value: pc
trafficRoutings:
- service: service-demo
ingress:
classType: nginx
name: ingress-demo
```
### Only Batch Release
```
apiVersion: rollouts.kruise.io/v1beta1
kind: Rollout
metadata:
name: rollouts-demo
spec:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: workload-demo
strategy:
canary:
steps:
- desiredReplicas: 1
- desiredReplicas: 10%
# After desiredReplicas Pods are ready, sleep 60 and continue to release later batches.
# If you don't configure it, manual confirmation is required by default.
pause: {duration: 60}
- desiredReplicas: 30%
pause: {duration: 60}
- desiredReplicas: 60%
pause: {duration: 60}
- desiredReplicas: 100%
pause: {duration: 60}
```
### Batch Release + Traffic Weight
```
apiVersion: rollouts.kruise.io/v1beta1
kind: Rollout
metadata:
name: rollouts-demo
spec:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: workload-demo
strategy:
canary:
steps:
- trafficWeight: 5%
desiredReplicas: 2
- desiredReplicas: 30%
- desiredReplicas: 60%
- desiredReplicas: 100%
trafficRoutings:
- service: service-demo
ingress:
classType: nginx
name: ingress-demo
```
### Batch Release + Traffic A/B Testing
```
apiVersion: rollouts.kruise.io/v1beta1
kind: Rollout
metadata:
name: rollouts-demo
spec:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: workload-demo
strategy:
canary:
steps:
- trafficMatches:
- headers:
- name: user-agent
type: Exact
value: pc
desiredReplicas: 2
- desiredReplicas: 30%
- desiredReplicas: 60%
- desiredReplicas: 100%
trafficRoutings:
- service: service-demo
ingress:
classType: nginx
name: ingress-demo
```
### End-to-End progressive delivery for microservice application
```
apiVersion: rollouts.kruise.io/v1alpha1
kind: TrafficRouting
metadata:
name: mse-traffic
spec:
objectRef:
- service: spring-cloud-a
ingress:
classType: mse
name: spring-cloud-a
strategy:
matches:
- headers:
- type: Exact
name: User-Agent
value: xiaoming
# http request via ingress, and add header[x-mse-tag]=gray
# for mse or istio routing the gray traffic to gray application
requestHeaderModifier:
set:
- name: x-mse-tag
value: gray
---
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
name: rollout-a
spec:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: spring-cloud-a
strategy:
canary:
enableExtraWorkloadForCanary: true
# Type TrafficRouting's name
trafficRoutingRef: mse-traffic
steps:
- desiredReplicas: 1
# patch pod template metadata to canary workload
# current only support deployment, and when enableExtraWorkloadForCanary=true
patchPodTemplateMetadata:
labels:
alicloud.service.tag: gray
opensergo.io/canary-gray: gray
---
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:
name: rollout-a
spec:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: spring-cloud-a
strategy:
canary:
enableExtraWorkloadForCanary: true
# Type TrafficRouting's name
trafficRoutingRef: mse-traffic
steps:
- desiredReplicas: 1
# patch pod template metadata to canary workload
patchPodTemplateMetadata:
labels:
alicloud.service.tag: gray
opensergo.io/canary-gray: gray
```

114
go.mod
View File

@ -1,81 +1,81 @@
module github.com/openkruise/rollouts
go 1.18
go 1.20
require (
github.com/davecgh/go-spew v1.1.1
github.com/evanphx/json-patch v4.11.0+incompatible
github.com/evanphx/json-patch v5.6.0+incompatible
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.17.0
github.com/openkruise/kruise-api v1.3.0
github.com/onsi/gomega v1.27.10
github.com/openkruise/kruise-api v1.7.0
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.7.0
github.com/stretchr/testify v1.9.0
github.com/yuin/gopher-lua v0.0.0-20220504180219-658193537a64
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
golang.org/x/time v0.3.0
gopkg.in/yaml.v2 v2.4.0
k8s.io/api v0.22.6
k8s.io/apiextensions-apiserver v0.22.6
k8s.io/apimachinery v0.22.6
k8s.io/apiserver v0.22.6
k8s.io/client-go v0.22.6
k8s.io/component-base v0.22.6
k8s.io/klog/v2 v2.10.0
k8s.io/utils v0.0.0-20210820185131-d34e5cb4466e
k8s.io/api v0.28.9
k8s.io/apiextensions-apiserver v0.28.9
k8s.io/apimachinery v0.28.9
k8s.io/apiserver v0.28.9
k8s.io/client-go v0.28.9
k8s.io/component-base v0.28.9
k8s.io/klog/v2 v2.120.1
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
layeh.com/gopher-json v0.0.0-20201124131017-552bb3c4c3bf
sigs.k8s.io/controller-runtime v0.10.3
sigs.k8s.io/gateway-api v0.4.3
sigs.k8s.io/yaml v1.2.0
sigs.k8s.io/controller-runtime v0.16.6
sigs.k8s.io/gateway-api v0.8.1
sigs.k8s.io/yaml v1.4.0
)
require (
cloud.google.com/go v0.81.0 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest v0.11.18 // indirect
github.com/Azure/go-autorest/autorest/adal v0.9.13 // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
github.com/Azure/go-autorest/logger v0.2.1 // indirect
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-logr/logr v0.4.0 // indirect
github.com/go-logr/zapr v0.4.0 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch/v5 v5.6.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/zapr v1.2.4 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.22.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/gofuzz v1.1.0 // indirect
github.com/google/uuid v1.1.2 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/json-iterator/go v1.1.11 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nxadm/tail v1.4.8 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.11.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.26.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
go.uber.org/zap v1.19.0 // indirect
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 // indirect
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602 // indirect
golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2 // indirect
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d // indirect
golang.org/x/text v0.3.6 // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.26.0 // indirect
github.com/prometheus/client_golang v1.16.0 // indirect
github.com/prometheus/client_model v0.4.0 // indirect
github.com/prometheus/common v0.44.0 // indirect
github.com/prometheus/procfs v0.10.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.25.0 // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/oauth2 v0.17.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/term v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
gomodules.xyz/jsonpatch/v2 v2.4.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/kube-openapi v0.0.0-20230717233707-2695361300d9 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)

1042
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
/*
Copyright 2022 The Kruise Authors.
Copyright 2023 The Kruise Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

View File

@ -0,0 +1,242 @@
package main
import (
"fmt"
"io"
"os"
"path/filepath"
"strings"
lua "github.com/yuin/gopher-lua"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
utilpointer "k8s.io/utils/pointer"
"sigs.k8s.io/yaml"
"github.com/openkruise/rollouts/api/v1alpha1"
"github.com/openkruise/rollouts/api/v1beta1"
custom "github.com/openkruise/rollouts/pkg/trafficrouting/network/customNetworkProvider"
"github.com/openkruise/rollouts/pkg/util/luamanager"
)
type TestCase struct {
Rollout *v1beta1.Rollout `json:"rollout,omitempty"`
TrafficRouting *v1alpha1.TrafficRouting `json:"trafficRouting,omitempty"`
Original *unstructured.Unstructured `json:"original,omitempty"`
Expected []*unstructured.Unstructured `json:"expected,omitempty"`
}
// this function aims to convert testdata to lua object for debugging
// run `go run lua.go`, then this program will get all testdata and convert them into lua objects
// copy the generated objects to lua scripts and then you can start debugging your lua scripts
func main() {
err := convertTestCaseToLuaObject()
if err != nil {
fmt.Println(err)
}
}
func convertTestCaseToLuaObject() error {
err := filepath.Walk("./", func(path string, f os.FileInfo, err error) error {
if !strings.Contains(path, "trafficRouting.lua") {
return nil
}
if err != nil {
return fmt.Errorf("failed to walk path: %s", err.Error())
}
dir := filepath.Dir(path)
if _, err := os.Stat(filepath.Join(dir, "testdata")); err != nil {
fmt.Printf("testdata not found in %s\n", dir)
return nil
}
err = filepath.Walk(filepath.Join(dir, "testdata"), func(path string, info os.FileInfo, err error) error {
if !info.IsDir() && filepath.Ext(path) == ".yaml" || filepath.Ext(path) == ".yml" {
fmt.Printf("--- walking path: %s ---\n", path)
err = objectToTable(path)
if err != nil {
return fmt.Errorf("failed to convert object to table: %s", err)
}
}
return nil
})
if err != nil {
return fmt.Errorf("failed to walk path: %s", err.Error())
}
return nil
})
if err != nil {
return fmt.Errorf("failed to walk path: %s", err)
}
return nil
}
// convert a testcase object to lua table for debug
func objectToTable(path string) error {
dir, file := filepath.Split(path)
testCase, err := getLuaTestCase(path)
if err != nil {
return fmt.Errorf("failed to get lua testcase: %s", err)
}
uList := make(map[string]interface{})
rollout := testCase.Rollout
trafficRouting := testCase.TrafficRouting
if rollout != nil {
steps := rollout.Spec.Strategy.GetSteps()
for i, step := range steps {
var weight *int32
if step.TrafficRoutingStrategy.Traffic != nil {
is := intstr.FromString(*step.TrafficRoutingStrategy.Traffic)
weightInt, _ := intstr.GetScaledValueFromIntOrPercent(&is, 100, true)
weight = utilpointer.Int32(int32(weightInt))
} else {
weight = utilpointer.Int32(-1)
}
var canaryService string
stableService := rollout.Spec.Strategy.GetTrafficRouting()[0].Service
canaryService = fmt.Sprintf("%s-canary", stableService)
data := &custom.LuaData{
Data: custom.Data{
Labels: testCase.Original.GetLabels(),
Annotations: testCase.Original.GetAnnotations(),
Spec: testCase.Original.Object["spec"],
},
Matches: step.TrafficRoutingStrategy.Matches,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
CanaryService: canaryService,
StableService: stableService,
RequestHeaderModifier: step.TrafficRoutingStrategy.RequestHeaderModifier,
}
uList[fmt.Sprintf("step_%d", i)] = data
}
} else if trafficRouting != nil {
weight := trafficRouting.Spec.Strategy.Weight
if weight == nil {
weight = utilpointer.Int32(-1)
}
var canaryService string
stableService := trafficRouting.Spec.ObjectRef[0].Service
canaryService = stableService
matches := make([]v1beta1.HttpRouteMatch, 0)
for _, match := range trafficRouting.Spec.Strategy.Matches {
obj := v1beta1.HttpRouteMatch{}
obj.Headers = match.Headers
matches = append(matches, obj)
}
data := &custom.LuaData{
Data: custom.Data{
Labels: testCase.Original.GetLabels(),
Annotations: testCase.Original.GetAnnotations(),
Spec: testCase.Original.Object["spec"],
},
Matches: matches,
CanaryWeight: *weight,
StableWeight: 100 - *weight,
CanaryService: canaryService,
StableService: stableService,
RequestHeaderModifier: trafficRouting.Spec.Strategy.RequestHeaderModifier,
}
uList["steps_0"] = data
} else {
return fmt.Errorf("neither rollout nor trafficRouting defined in test case: %s", path)
}
objStr, err := executeLua(uList)
if err != nil {
return fmt.Errorf("failed to execute lua: %s", err.Error())
}
filePath := fmt.Sprintf("%s%s_obj.lua", dir, strings.Split(file, ".")[0])
fileStream, err := os.OpenFile(filePath, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0666)
if err != nil {
return fmt.Errorf("failed to open file: %s", err)
}
defer fileStream.Close()
header := "-- THIS IS GENERATED BY CONVERT_TEST_CASE_TO_LUA_OBJECT.GO FOR DEBUGGING --\n"
_, err = io.WriteString(fileStream, header+objStr)
if err != nil {
return fmt.Errorf("failed to WriteString %s", err)
}
return nil
}
func getLuaTestCase(path string) (*TestCase, error) {
yamlFile, err := os.ReadFile(path)
if err != nil {
return nil, err
}
luaTestCase := &TestCase{}
err = yaml.Unmarshal(yamlFile, luaTestCase)
if err != nil {
return nil, err
}
return luaTestCase, nil
}
func executeLua(steps map[string]interface{}) (string, error) {
luaManager := &luamanager.LuaManager{}
unObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&steps)
if err != nil {
return "", fmt.Errorf("failed to convert to unstructured: %s", err)
}
u := &unstructured.Unstructured{Object: unObj}
script := `
function serialize(obj, isKey)
local lua = ""
local t = type(obj)
if t == "number" then
lua = lua .. obj
elseif t == "boolean" then
lua = lua .. tostring(obj)
elseif t == "string" then
if isKey then
lua = lua .. string.format("%s", obj)
else
lua = lua .. string.format("%q", obj)
end
elseif t == "table" then
lua = lua .. "{"
for k, v in pairs(obj) do
if type(k) == "string" then
lua = lua .. serialize(k, true) .. "=" .. serialize(v, false) .. ","
else
lua = lua .. serialize(v, false) .. ","
end
end
local metatable = getmetatable(obj)
if metatable ~= nil and type(metatable.__index) == "table" then
for k, v in pairs(metatable.__index) do
if type(k) == "string" then
lua = lua .. serialize(k, true) .. "=" .. serialize(v, false) .. ","
else
lua = lua .. serialize(v, false) .. ","
end
end
end
lua = lua .. "}"
elseif t == "nil" then
return nil
else
error("can not serialize a " .. t .. " type.")
end
return lua
end
function table2string(tablevalue)
local stringtable = "steps=" .. serialize(tablevalue)
print(stringtable)
return stringtable
end
return table2string(obj)
`
l, err := luaManager.RunLuaScript(u, script)
if err != nil {
return "", fmt.Errorf("failed to run lua script: %s", err)
}
returnValue := l.Get(-1)
if returnValue.Type() == lua.LTString {
return returnValue.String(), nil
} else {
return "", fmt.Errorf("unexpected lua output type")
}
}

View File

@ -0,0 +1,49 @@
trafficRouting:
apiVersion: rollouts.kruise.io/v1alpha1
kind: TrafficRouting
metadata:
name: tr-demo
spec:
strategy:
matches:
- headers:
- type: Exact
name: version
value: canary
objectRef:
- service: svc-demo
customNetworkRefs:
- apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
name: ds-demo
original:
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: ds-demo
spec:
host: svc-demo
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
subsets:
- labels:
version: base
name: version-base
expected:
- apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: ds-demo
spec:
host: svc-demo
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
subsets:
- labels:
version: base
name: version-base
- labels:
istio.service.tag: gray
name: canary

View File

@ -0,0 +1,8 @@
local spec = obj.data.spec
local canary = {}
canary.labels = {}
canary.name = "canary"
local podLabelKey = "istio.service.tag"
canary.labels[podLabelKey] = "gray"
table.insert(spec.subsets, canary)
return obj.data

View File

@ -0,0 +1,126 @@
rollout:
apiVersion: rollouts.kruise.io/v1beta1
kind: Rollout
metadata:
name: rollouts-demo
spec:
workloadRef:
apiVersion: apps/v1
kind: Deployment
name: deploy-demo
strategy:
canary:
steps:
- matches:
- headers:
- type: Exact
name: user-agent
value: pc
- type: RegularExpression
name: name
value: ".*demo"
requestHeaderModifier:
set:
- name: "header-foo"
value: "bar"
- matches:
- headers:
- type: Exact
name: user-agent
value: pc
- headers:
- type: RegularExpression
name: name
value: ".*demo"
- traffic: "50%"
trafficRoutings:
- service: svc-demo
customNetworkRefs:
- apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
name: vs-demo
original:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-demo
spec:
hosts:
- "*"
gateways:
- nginx-gateway
http:
- route:
- destination:
host: svc-demo
expected:
- apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-demo
spec:
hosts:
- "*"
gateways:
- nginx-gateway
http:
- match:
- headers:
user-agent:
exact: pc
name:
regex: .*demo
headers:
request:
set:
header-foo: bar
route:
- destination:
host: svc-demo-canary
- route:
- destination:
host: svc-demo
- apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-demo
spec:
hosts:
- "*"
gateways:
- nginx-gateway
http:
- match:
- headers:
name:
regex: .*demo
route:
- destination:
host: svc-demo-canary
- match:
- headers:
user-agent:
exact: pc
route:
- destination:
host: svc-demo-canary
- route:
- destination:
host: svc-demo
- apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-demo
spec:
hosts:
- "*"
gateways:
- nginx-gateway
http:
- route:
- destination:
host: svc-demo
weight: 50
- destination:
host: svc-demo-canary
weight: 50

View File

@ -0,0 +1,69 @@
trafficRouting:
apiVersion: rollouts.kruise.io/v1alpha1
kind: TrafficRouting
metadata:
name: tr-demo
spec:
strategy:
matches:
- headers:
- type: Exact
name: user-agent
value: pc
- type: RegularExpression
name: name
value: ".*demo"
requestHeaderModifier:
set:
- name: "header-foo"
value: "bar"
objectRef:
- service: svc-demo
customNetworkRefs:
- apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
name: vs-demo
original:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-demo
spec:
hosts:
- "*"
gateways:
- nginx-gateway
http:
- route:
- destination:
host: svc-demo
subset: base
expected:
- apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-demo
spec:
hosts:
- "*"
gateways:
- nginx-gateway
http:
- match:
- headers:
user-agent:
exact: pc
name:
regex: .*demo
headers:
request:
set:
header-foo: bar
route:
- destination:
host: svc-demo
subset: canary
- route:
- destination:
host: svc-demo
subset: base

View File

@ -0,0 +1,80 @@
trafficRouting:
apiVersion: rollouts.kruise.io/v1alpha1
kind: TrafficRouting
metadata:
name: tr-demo
spec:
strategy:
matches:
- headers:
- type: Exact
name: user-agent
value: pc
- headers:
- type: RegularExpression
name: name
value: ".*demo"
requestHeaderModifier:
set:
- name: "header-foo"
value: "bar"
objectRef:
- service: svc-demo
customNetworkRefs:
- apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
name: vs-demo
original:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-demo
spec:
hosts:
- "*"
gateways:
- nginx-gateway
http:
- route:
- destination:
host: svc-demo
subset: base
expected:
- apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-demo
spec:
hosts:
- "*"
gateways:
- nginx-gateway
http:
- match:
- headers:
name:
regex: .*demo
headers:
request:
set:
header-foo: bar
route:
- destination:
host: svc-demo
subset: canary
- match:
- headers:
user-agent:
exact: pc
headers:
request:
set:
header-foo: bar
route:
- destination:
host: svc-demo
subset: canary
- route:
- destination:
host: svc-demo
subset: base

View File

@ -0,0 +1,50 @@
trafficRouting:
apiVersion: rollouts.kruise.io/v1alpha1
kind: TrafficRouting
metadata:
name: tr-demo
spec:
strategy:
weight: 50
objectRef:
- service: svc-demo
customNetworkRefs:
- apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
name: vs-demo
original:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: vs-demo
spec:
hosts:
- "*"
gateways:
- nginx-gateway
http:
- route:
- destination:
host: svc-demo
subset: base
expected:
- apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: nginx-vs
namespace: demo
spec:
hosts:
- "*"
gateways:
- nginx-gateway
http:
- route:
- destination:
host: svc-demo
subset: base
weight: 50
- destination:
host: svc-demo
subset: canary
weight: 50

View File

@ -0,0 +1,156 @@
spec = obj.data.spec
if obj.canaryWeight == -1 then
obj.canaryWeight = 100
obj.stableWeight = 0
end
function GetHost(destination)
local host = destination.destination.host
dot_position = string.find(host, ".", 1, true)
if (dot_position) then
host = string.sub(host, 1, dot_position - 1)
end
return host
end
-- find routes of VirtualService with stableService
function GetRulesToPatch(spec, stableService, protocol)
local matchedRoutes = {}
if (spec[protocol] ~= nil) then
for _, rule in ipairs(spec[protocol]) do
-- skip routes contain matches
if (rule.match == nil) then
for _, route in ipairs(rule.route) do
if GetHost(route) == stableService then
table.insert(matchedRoutes, rule)
end
end
end
end
end
return matchedRoutes
end
function CalculateWeight(route, stableWeight, n)
local weight
if (route.weight) then
weight = math.floor(route.weight * stableWeight / 100)
else
weight = math.floor(stableWeight / n)
end
return weight
end
-- generate routes with matches, insert a rule before other rules, only support http headers, cookies etc.
function GenerateRoutesWithMatches(spec, matches, stableService, canaryService, requestHeaderModifier)
for _, match in ipairs(matches) do
local route = {}
route["match"] = {}
local vsMatch = {}
for key, value in pairs(match) do
if key == "path" then
vsMatch["uri"] = {}
local rule = value
if rule["type"] == "RegularExpression" then
matchType = "regex"
elseif rule["type"] == "Exact" then
matchType = "exact"
elseif rule["type"] == "PathPrefix" then
matchType = "prefix"
end
vsMatch["uri"][matchType] = rule.value
else
vsMatch[key] = {}
for _, rule in ipairs(value) do
if rule["type"] == "RegularExpression" then
matchType = "regex"
elseif rule["type"] == "Exact" then
matchType = "exact"
elseif rule["type"] == "Prefix" then
matchType = "prefix"
end
if key == "headers" or key == "queryParams" then
vsMatch[key][rule["name"]] = {}
vsMatch[key][rule["name"]][matchType] = rule.value
else
vsMatch[key][matchType] = rule.value
end
end
end
end
table.insert(route["match"], vsMatch)
if requestHeaderModifier then
route["headers"] = {}
route["headers"]["request"] = {}
for action, headers in pairs(requestHeaderModifier) do
if action == "set" or action == "add" then
route["headers"]["request"][action] = {}
for _, header in ipairs(headers) do
route["headers"]["request"][action][header["name"]] = header["value"]
end
elseif action == "remove" then
route["headers"]["request"]["remove"] = {}
for _, rHeader in ipairs(headers) do
table.insert(route["headers"]["request"]["remove"], rHeader)
end
end
end
end
route.route = {
{
destination = {}
}
}
-- stableService == canaryService indicates DestinationRule exists and subset is set to be canary by default
if stableService == canaryService then
route.route[1].destination.host = stableService
route.route[1].destination.subset = "canary"
else
route.route[1].destination.host = canaryService
end
table.insert(spec.http, 1, route)
end
end
-- generate routes without matches, change every rule whose host is stableService
function GenerateRoutes(spec, stableService, canaryService, stableWeight, canaryWeight, protocol)
local matchedRules = GetRulesToPatch(spec, stableService, protocol)
for _, rule in ipairs(matchedRules) do
local canary
if stableService ~= canaryService then
canary = {
destination = {
host = canaryService,
},
weight = canaryWeight,
}
else
canary = {
destination = {
host = stableService,
subset = "canary",
},
weight = canaryWeight,
}
end
-- incase there are multiple versions traffic already, do a for-loop
for _, route in ipairs(rule.route) do
-- update stable service weight
route.weight = CalculateWeight(route, stableWeight, #rule.route)
end
table.insert(rule.route, canary)
end
end
if (obj.matches and next(obj.matches) ~= nil)
then
GenerateRoutesWithMatches(spec, obj.matches, obj.stableService, obj.canaryService, obj.requestHeaderModifier)
else
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "http")
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tcp")
GenerateRoutes(spec, obj.stableService, obj.canaryService, obj.stableWeight, obj.canaryWeight, "tls")
end
return obj.data

View File

@ -10,6 +10,10 @@ annotations["nginx.ingress.kubernetes.io/canary-by-cookie"] = nil
annotations["nginx.ingress.kubernetes.io/canary-by-header"] = nil
annotations["nginx.ingress.kubernetes.io/canary-by-header-pattern"] = nil
annotations["nginx.ingress.kubernetes.io/canary-by-header-value"] = nil
-- MSE extended annotations
annotations["mse.ingress.kubernetes.io/canary-by-query"] = nil
annotations["mse.ingress.kubernetes.io/canary-by-query-pattern"] = nil
annotations["mse.ingress.kubernetes.io/canary-by-query-value"] = nil
annotations["nginx.ingress.kubernetes.io/canary-weight"] = nil
if ( obj.weight ~= "-1" )
then
@ -33,18 +37,30 @@ then
return annotations
end
for _,match in ipairs(obj.matches) do
header = match.headers[1]
if ( header.name == "canary-by-cookie" )
then
annotations["nginx.ingress.kubernetes.io/canary-by-cookie"] = header.value
else
annotations["nginx.ingress.kubernetes.io/canary-by-header"] = header.name
if ( header.type == "RegularExpression" )
if match.headers and next(match.headers) ~= nil then
header = match.headers[1]
if ( header.name == "canary-by-cookie" )
then
annotations["nginx.ingress.kubernetes.io/canary-by-header-pattern"] = header.value
annotations["nginx.ingress.kubernetes.io/canary-by-cookie"] = header.value
else
annotations["nginx.ingress.kubernetes.io/canary-by-header-value"] = header.value
annotations["nginx.ingress.kubernetes.io/canary-by-header"] = header.name
if ( header.type == "RegularExpression" )
then
annotations["nginx.ingress.kubernetes.io/canary-by-header-pattern"] = header.value
else
annotations["nginx.ingress.kubernetes.io/canary-by-header-value"] = header.value
end
end
end
if match.queryParams and next(match.queryParams) ~= nil then
queryParam = match.queryParams[1]
annotations["nginx.ingress.kubernetes.io/canary-by-query"] = queryParam.name
if ( queryParam.type == "RegularExpression" )
then
annotations["nginx.ingress.kubernetes.io/canary-by-query-pattern"] = queryParam.value
else
annotations["nginx.ingress.kubernetes.io/canary-by-query-value"] = queryParam.value
end
end
end
return annotations
return annotations

View File

@ -26,19 +26,21 @@ end
-- headers & cookie apis
-- traverse matches
for _,match in ipairs(obj.matches) do
local header = match.headers[1]
-- cookie
if ( header.name == "canary-by-cookie" )
then
annotations["nginx.ingress.kubernetes.io/canary-by-cookie"] = header.value
else
annotations["nginx.ingress.kubernetes.io/canary-by-header"] = header.name
-- if regular expression
if ( header.type == "RegularExpression" )
if match.headers and next(match.headers) ~= nil then
local header = match.headers[1]
-- cookie
if ( header.name == "canary-by-cookie" )
then
annotations["nginx.ingress.kubernetes.io/canary-by-header-pattern"] = header.value
annotations["nginx.ingress.kubernetes.io/canary-by-cookie"] = header.value
else
annotations["nginx.ingress.kubernetes.io/canary-by-header-value"] = header.value
annotations["nginx.ingress.kubernetes.io/canary-by-header"] = header.name
-- if regular expression
if ( header.type == "RegularExpression" )
then
annotations["nginx.ingress.kubernetes.io/canary-by-header-pattern"] = header.value
else
annotations["nginx.ingress.kubernetes.io/canary-by-header-value"] = header.value
end
end
end
end

43
main.go
View File

@ -20,17 +20,10 @@ import (
"flag"
"os"
webhookutil "github.com/openkruise/rollouts/pkg/webhook/util"
kruisev1aplphal1 "github.com/openkruise/kruise-api/apps/v1alpha1"
kruisev1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
rolloutsv1alpha1 "github.com/openkruise/rollouts/api/v1alpha1"
br "github.com/openkruise/rollouts/pkg/controller/batchrelease"
"github.com/openkruise/rollouts/pkg/controller/deployment"
"github.com/openkruise/rollouts/pkg/controller/rollout"
"github.com/openkruise/rollouts/pkg/controller/rollouthistory"
"github.com/openkruise/rollouts/pkg/controller/trafficrouting"
utilclient "github.com/openkruise/rollouts/pkg/util/client"
utilfeature "github.com/openkruise/rollouts/pkg/util/feature"
"github.com/openkruise/rollouts/pkg/webhook"
"github.com/spf13/pflag"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -40,7 +33,19 @@ import (
"k8s.io/klog/v2/klogr"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
ctrlwebhook "sigs.k8s.io/controller-runtime/pkg/webhook"
gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1"
rolloutapi "github.com/openkruise/rollouts/api"
br "github.com/openkruise/rollouts/pkg/controller/batchrelease"
"github.com/openkruise/rollouts/pkg/controller/deployment"
"github.com/openkruise/rollouts/pkg/controller/rollout"
"github.com/openkruise/rollouts/pkg/controller/rollouthistory"
"github.com/openkruise/rollouts/pkg/controller/trafficrouting"
utilclient "github.com/openkruise/rollouts/pkg/util/client"
utilfeature "github.com/openkruise/rollouts/pkg/util/feature"
"github.com/openkruise/rollouts/pkg/webhook"
// Import all Kubernetes client auth plugins (e.g. Azure, GCP, OIDC, etc.)
// to ensure that exec-entrypoint and run can make use of them.
@ -57,8 +62,8 @@ func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
utilruntime.Must(kruisev1aplphal1.AddToScheme(scheme))
utilruntime.Must(kruisev1beta1.AddToScheme(scheme))
utilruntime.Must(rolloutsv1alpha1.AddToScheme(scheme))
utilruntime.Must(gatewayv1alpha2.AddToScheme(scheme))
utilruntime.Must(rolloutapi.AddToScheme(scheme))
utilruntime.Must(gatewayv1beta1.AddToScheme(scheme))
utilruntime.Must(admissionregistrationv1.AddToScheme(scheme))
//+kubebuilder:scaffold:scheme
}
@ -89,13 +94,19 @@ func main() {
}
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme,
MetricsBindAddress: metricsAddr,
Port: 9443,
Scheme: scheme,
Metrics: metricsserver.Options{
BindAddress: metricsAddr,
},
WebhookServer: ctrlwebhook.NewServer(ctrlwebhook.Options{
Host: "0.0.0.0",
Port: webhookutil.GetPort(),
CertDir: webhookutil.GetCertDir(),
}),
HealthProbeBindAddress: probeAddr,
LeaderElection: enableLeaderElection,
LeaderElectionID: "71ddec2c.kruise.io",
NewClient: utilclient.NewClient,
NewCache: utilclient.NewCache,
})
if err != nil {
setupLog.Error(err, "unable to start manager")

View File

@ -0,0 +1,19 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package versioned

View File

@ -0,0 +1,20 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated clientset.
package versioned

View File

@ -0,0 +1,19 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake

View File

@ -0,0 +1,20 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated fake clientset.
package fake

View File

@ -0,0 +1,19 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake

View File

@ -0,0 +1,20 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package contains the scheme of the automatically generated clientset.
package scheme

View File

@ -0,0 +1,19 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package scheme

View File

@ -0,0 +1,20 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
// This package has the automatically generated typed clients.
package v1beta1

View File

@ -0,0 +1,20 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
// Package fake has the automatically generated clients.
package fake

View File

@ -0,0 +1,19 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package fake

View File

@ -0,0 +1,19 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1beta1

View File

@ -0,0 +1,19 @@
/*
Copyright 2024 The Kruise 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.
*/
// Code generated by client-gen. DO NOT EDIT.
package v1beta1

View File

@ -24,8 +24,8 @@ import (
"sync"
"time"
"github.com/openkruise/rollouts/api/v1alpha1"
"github.com/openkruise/rollouts/pkg/util"
"sigs.k8s.io/controller-runtime/pkg/cache"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
@ -43,6 +43,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
"github.com/openkruise/rollouts/api/v1beta1"
"github.com/openkruise/rollouts/pkg/util"
)
var (
@ -80,6 +83,7 @@ func newReconciler(mgr manager.Manager) reconcile.Reconciler {
Client: cli,
Scheme: mgr.GetScheme(),
recorder: recorder,
cache: mgr.GetCache(),
executor: NewReleasePlanExecutor(cli, recorder),
}
}
@ -94,10 +98,10 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
}
// Watch for changes to BatchRelease
err = c.Watch(&source.Kind{Type: &v1alpha1.BatchRelease{}}, &handler.EnqueueRequestForObject{}, predicate.Funcs{
err = c.Watch(source.Kind(mgr.GetCache(), &v1beta1.BatchRelease{}), &handler.EnqueueRequestForObject{}, predicate.Funcs{
UpdateFunc: func(e event.UpdateEvent) bool {
oldObject := e.ObjectOld.(*v1alpha1.BatchRelease)
newObject := e.ObjectNew.(*v1alpha1.BatchRelease)
oldObject := e.ObjectOld.(*v1beta1.BatchRelease)
newObject := e.ObjectNew.(*v1beta1.BatchRelease)
if oldObject.Generation != newObject.Generation || newObject.DeletionTimestamp != nil {
klog.V(3).Infof("Observed updated Spec for BatchRelease: %s/%s", newObject.Namespace, newObject.Name)
return true
@ -113,14 +117,14 @@ func add(mgr manager.Manager, r reconcile.Reconciler) error {
return err
}
err = c.Watch(&source.Kind{Type: &corev1.Pod{}}, &podEventHandler{Reader: mgr.GetCache()})
err = c.Watch(source.Kind(mgr.GetCache(), &corev1.Pod{}), &podEventHandler{Reader: mgr.GetCache()})
if err != nil {
return err
}
runtimeController = c
workloadHandler = &workloadEventHandler{Reader: mgr.GetCache()}
return util.AddWorkloadWatcher(c, workloadHandler)
return util.AddWorkloadWatcher(mgr.GetCache(), c, workloadHandler)
}
var _ reconcile.Reconciler = &BatchReleaseReconciler{}
@ -128,6 +132,7 @@ var _ reconcile.Reconciler = &BatchReleaseReconciler{}
// BatchReleaseReconciler reconciles a BatchRelease object
type BatchReleaseReconciler struct {
client.Client
cache cache.Cache
Scheme *runtime.Scheme
recorder record.EventRecorder
executor *Executor
@ -148,11 +153,12 @@ type BatchReleaseReconciler struct {
// +kubebuilder:rbac:groups=apps.kruise.io,resources=statefulsets/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=apps.kruise.io,resources=daemonsets,verbs=get;list;watch;update;patch
// +kubebuilder:rbac:groups=apps.kruise.io,resources=daemonsets/status,verbs=get;update;patch
// +kubebuilder:rbac:groups=autoscaling,resources=horizontalpodautoscalers,verbs=get;list;watch;update;patch
// Reconcile reads that state of the cluster for a Rollout object and makes changes based on the state read
// and what is in the Rollout.Spec
func (r *BatchReleaseReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
release := new(v1alpha1.BatchRelease)
release := new(v1beta1.BatchRelease)
err := r.Get(context.TODO(), req.NamespacedName, release)
if err != nil {
if errors.IsNotFound(err) {
@ -167,11 +173,11 @@ func (r *BatchReleaseReconciler) Reconcile(ctx context.Context, req ctrl.Request
klog.Infof("Begin to reconcile BatchRelease(%v/%v), release-phase: %v", release.Namespace, release.Name, release.Status.Phase)
// If workload watcher does not exist, then add the watcher dynamically
workloadRef := release.Spec.TargetRef.WorkloadRef
workloadGVK := util.GetGVKFrom(workloadRef)
workloadRef := release.Spec.WorkloadRef
workloadGVK := util.GetGVKFrom(&workloadRef)
_, exists := watchedWorkload.Load(workloadGVK.String())
if workloadRef != nil && !exists {
succeeded, err := util.AddWatcherDynamically(runtimeController, workloadHandler, workloadGVK)
if !exists {
succeeded, err := util.AddWatcherDynamically(r.cache, runtimeController, workloadHandler, workloadGVK)
if err != nil {
return ctrl.Result{}, err
} else if succeeded {
@ -216,7 +222,7 @@ func (r *BatchReleaseReconciler) Reconcile(ctx context.Context, req ctrl.Request
}
// updateStatus update BatchRelease status to newStatus
func (r *BatchReleaseReconciler) updateStatus(release *v1alpha1.BatchRelease, newStatus *v1alpha1.BatchReleaseStatus) error {
func (r *BatchReleaseReconciler) updateStatus(release *v1beta1.BatchRelease, newStatus *v1beta1.BatchReleaseStatus) error {
var err error
defer func() {
if err != nil {
@ -234,7 +240,7 @@ func (r *BatchReleaseReconciler) updateStatus(release *v1alpha1.BatchRelease, ne
objectKey := client.ObjectKeyFromObject(release)
if !reflect.DeepEqual(release.Status, *newStatus) {
err = retry.RetryOnConflict(retry.DefaultBackoff, func() error {
clone := &v1alpha1.BatchRelease{}
clone := &v1beta1.BatchRelease{}
getErr := r.Get(context.TODO(), objectKey, clone)
if getErr != nil {
return getErr
@ -247,7 +253,7 @@ func (r *BatchReleaseReconciler) updateStatus(release *v1alpha1.BatchRelease, ne
}
// handleFinalizer will remove finalizer in finalized phase and add finalizer in the other phases.
func (r *BatchReleaseReconciler) handleFinalizer(release *v1alpha1.BatchRelease) (bool, error) {
func (r *BatchReleaseReconciler) handleFinalizer(release *v1beta1.BatchRelease) (bool, error) {
var err error
defer func() {
if err != nil {
@ -257,7 +263,7 @@ func (r *BatchReleaseReconciler) handleFinalizer(release *v1alpha1.BatchRelease)
// remove the release finalizer if it needs
if !release.DeletionTimestamp.IsZero() &&
release.Status.Phase == v1alpha1.RolloutPhaseCompleted &&
release.Status.Phase == v1beta1.RolloutPhaseCompleted &&
controllerutil.ContainsFinalizer(release, ReleaseFinalizer) {
err = util.UpdateFinalizer(r.Client, release, util.RemoveFinalizerOpType, ReleaseFinalizer)
if client.IgnoreNotFound(err) != nil {

View File

@ -27,8 +27,6 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
kruiseappsv1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
"github.com/openkruise/rollouts/api/v1alpha1"
"github.com/openkruise/rollouts/pkg/util"
apps "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -43,15 +41,19 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
rolloutapi "github.com/openkruise/rollouts/api"
"github.com/openkruise/rollouts/api/v1beta1"
"github.com/openkruise/rollouts/pkg/util"
)
const TIME_LAYOUT = "2006-01-02 15:04:05"
var (
scheme *runtime.Scheme
releaseDeploy = &v1alpha1.BatchRelease{
releaseDeploy = &v1beta1.BatchRelease{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha1.GroupVersion.String(),
APIVersion: v1beta1.GroupVersion.String(),
Kind: "BatchRelease",
},
ObjectMeta: metav1.ObjectMeta{
@ -59,17 +61,16 @@ var (
Namespace: "application",
UID: types.UID("87076677"),
},
Spec: v1alpha1.BatchReleaseSpec{
TargetRef: v1alpha1.ObjectRef{
WorkloadRef: &v1alpha1.WorkloadRef{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "sample",
},
Spec: v1beta1.BatchReleaseSpec{
WorkloadRef: v1beta1.ObjectRef{
APIVersion: "apps/v1",
Kind: "Deployment",
Name: "sample",
},
ReleasePlan: v1alpha1.ReleasePlan{
ReleasePlan: v1beta1.ReleasePlan{
RollingStyle: v1beta1.CanaryRollingStyle,
BatchPartition: pointer.Int32(0),
Batches: []v1alpha1.ReleaseBatch{
Batches: []v1beta1.ReleaseBatch{
{
CanaryReplicas: intstr.FromString("10%"),
},
@ -100,7 +101,7 @@ var (
},
},
Spec: apps.DeploymentSpec{
Replicas: pointer.Int32Ptr(100),
Replicas: pointer.Int32(100),
Strategy: apps.DeploymentStrategy{
Type: apps.RollingUpdateDeploymentStrategyType,
RollingUpdate: &apps.RollingUpdateDeployment{
@ -129,9 +130,9 @@ var (
)
var (
releaseClone = &v1alpha1.BatchRelease{
releaseClone = &v1beta1.BatchRelease{
TypeMeta: metav1.TypeMeta{
APIVersion: v1alpha1.GroupVersion.String(),
APIVersion: v1beta1.GroupVersion.String(),
Kind: "BatchRelease",
},
ObjectMeta: metav1.ObjectMeta{
@ -139,17 +140,16 @@ var (
Namespace: "application",
UID: types.UID("87076677"),
},
Spec: v1alpha1.BatchReleaseSpec{
TargetRef: v1alpha1.ObjectRef{
WorkloadRef: &v1alpha1.WorkloadRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "sample",
},
Spec: v1beta1.BatchReleaseSpec{
WorkloadRef: v1beta1.ObjectRef{
APIVersion: "apps.kruise.io/v1alpha1",
Kind: "CloneSet",
Name: "sample",
},
ReleasePlan: v1alpha1.ReleasePlan{
BatchPartition: pointer.Int32Ptr(0),
Batches: []v1alpha1.ReleaseBatch{
ReleasePlan: v1beta1.ReleasePlan{
BatchPartition: pointer.Int32(0),
RollingStyle: v1beta1.PartitionRollingStyle,
Batches: []v1beta1.ReleaseBatch{
{
CanaryReplicas: intstr.FromString("10%"),
},
@ -179,7 +179,7 @@ var (
},
},
Spec: kruiseappsv1alpha1.CloneSetSpec{
Replicas: pointer.Int32Ptr(100),
Replicas: pointer.Int32(100),
UpdateStrategy: kruiseappsv1alpha1.CloneSetUpdateStrategy{
Partition: &intstr.IntOrString{Type: intstr.Int, IntVal: int32(1)},
MaxSurge: &intstr.IntOrString{Type: intstr.Int, IntVal: int32(2)},
@ -209,7 +209,7 @@ var (
func init() {
scheme = runtime.NewScheme()
apimachineryruntime.Must(apps.AddToScheme(scheme))
apimachineryruntime.Must(v1alpha1.AddToScheme(scheme))
apimachineryruntime.Must(rolloutapi.AddToScheme(scheme))
apimachineryruntime.Must(kruiseappsv1alpha1.AddToScheme(scheme))
controlInfo, _ := json.Marshal(metav1.NewControllerRef(releaseDeploy, releaseDeploy.GroupVersionKind()))
@ -232,13 +232,13 @@ func TestReconcile_CloneSet(t *testing.T) {
GetRelease func() client.Object
GetCloneSet func() []client.Object
ExpectedBatch int32
ExpectedPhase v1alpha1.RolloutPhase
ExpectedState v1alpha1.BatchReleaseBatchStateType
ExpectedPhase v1beta1.RolloutPhase
ExpectedState v1beta1.BatchReleaseBatchStateType
}{
{
Name: "Preparing, Input-Phase=Preparing, Output-Phase=Progressing",
GetRelease: func() client.Object {
release := setPhase(releaseClone, v1alpha1.RolloutPhasePreparing)
release := setPhase(releaseClone, v1beta1.RolloutPhasePreparing)
stableTemplate := stableClone.Spec.Template.DeepCopy()
canaryTemplate := stableClone.Spec.Template.DeepCopy()
stableTemplate.Spec.Containers = containers("v1")
@ -254,12 +254,12 @@ func TestReconcile_CloneSet(t *testing.T) {
canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
},
{
Name: "Progressing, stage=0, Input-State=Upgrade, Output-State=Verify",
GetRelease: func() client.Object {
release := setState(releaseClone, v1alpha1.UpgradingBatchState)
release := setState(releaseClone, v1beta1.UpgradingBatchState)
stableTemplate := stableClone.Spec.Template.DeepCopy()
canaryTemplate := stableClone.Spec.Template.DeepCopy()
stableTemplate.Spec.Containers = containers("v1")
@ -275,13 +275,13 @@ func TestReconcile_CloneSet(t *testing.T) {
canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.VerifyingBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.VerifyingBatchState,
},
{
Name: "Progressing, stage=0, Input-State=Upgrade, Output-State=Verify",
GetRelease: func() client.Object {
release := setState(releaseClone, v1alpha1.UpgradingBatchState)
release := setState(releaseClone, v1beta1.UpgradingBatchState)
stableTemplate := stableClone.Spec.Template.DeepCopy()
canaryTemplate := stableClone.Spec.Template.DeepCopy()
stableTemplate.Spec.Containers = containers("v1")
@ -297,13 +297,13 @@ func TestReconcile_CloneSet(t *testing.T) {
canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.VerifyingBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.VerifyingBatchState,
},
{
Name: "Progressing, stage=0, Input-State=Verify, Output-State=BatchReady",
GetRelease: func() client.Object {
release := setState(releaseClone, v1alpha1.VerifyingBatchState)
release := setState(releaseClone, v1beta1.VerifyingBatchState)
stableTemplate := stableClone.Spec.Template.DeepCopy()
canaryTemplate := stableClone.Spec.Template.DeepCopy()
stableTemplate.Spec.Containers = containers("v1")
@ -321,13 +321,13 @@ func TestReconcile_CloneSet(t *testing.T) {
canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.ReadyBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.ReadyBatchState,
},
{
Name: "Progressing, stage=0->1, Input-State=BatchReady, Output-State=Upgrade",
GetRelease: func() client.Object {
release := setState(releaseClone, v1alpha1.ReadyBatchState)
release := setState(releaseClone, v1beta1.ReadyBatchState)
release.Status.CanaryStatus.BatchReadyTime = getOldTime()
stableTemplate := stableClone.Spec.Template.DeepCopy()
canaryTemplate := stableClone.Spec.Template.DeepCopy()
@ -347,14 +347,14 @@ func TestReconcile_CloneSet(t *testing.T) {
canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.UpgradingBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.UpgradingBatchState,
ExpectedBatch: 1,
},
{
Name: "Progressing, stage=0->1, Input-State=BatchReady, Output-State=BatchReady",
GetRelease: func() client.Object {
release := setState(releaseClone, v1alpha1.ReadyBatchState)
release := setState(releaseClone, v1beta1.ReadyBatchState)
now := metav1.Now()
release.Status.CanaryStatus.BatchReadyTime = &now
stableTemplate := stableClone.Spec.Template.DeepCopy()
@ -374,13 +374,13 @@ func TestReconcile_CloneSet(t *testing.T) {
canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.ReadyBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.ReadyBatchState,
},
{
Name: "Special Case: Scaling, Input-State=BatchReady, Output-State=Upgrade",
GetRelease: func() client.Object {
release := setState(releaseClone, v1alpha1.ReadyBatchState)
release := setState(releaseClone, v1beta1.ReadyBatchState)
now := metav1.Now()
release.Status.CanaryStatus.BatchReadyTime = &now
stableTemplate := stableClone.Spec.Template.DeepCopy()
@ -395,19 +395,19 @@ func TestReconcile_CloneSet(t *testing.T) {
},
GetCloneSet: func() []client.Object {
stable := getStableWithReady(stableClone, "v2").(*kruiseappsv1alpha1.CloneSet)
stable.Spec.Replicas = pointer.Int32Ptr(200)
stable.Spec.Replicas = pointer.Int32(200)
canary := getCanaryWithStage(stable, "v2", 0, true)
return []client.Object{
canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.UpgradingBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.UpgradingBatchState,
},
{
Name: `Special Case: RollBack, Input-Phase=Progressing, Output-Phase=Progressing`,
GetRelease: func() client.Object {
release := setState(releaseClone, v1alpha1.ReadyBatchState)
release := setState(releaseClone, v1beta1.ReadyBatchState)
now := metav1.Now()
release.Status.CanaryStatus.BatchReadyTime = &now
stableTemplate := stableClone.Spec.Template.DeepCopy()
@ -431,13 +431,13 @@ func TestReconcile_CloneSet(t *testing.T) {
canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.ReadyBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.ReadyBatchState,
},
{
Name: `Special Case: Deletion, Input-Phase=Progressing, Output-Phase=Finalizing`,
GetRelease: func() client.Object {
release := setState(releaseClone, v1alpha1.ReadyBatchState)
release := setState(releaseClone, v1beta1.ReadyBatchState)
now := metav1.Now()
release.Status.CanaryStatus.BatchReadyTime = &now
stableTemplate := stableClone.Spec.Template.DeepCopy()
@ -459,13 +459,13 @@ func TestReconcile_CloneSet(t *testing.T) {
canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseFinalizing,
ExpectedState: v1alpha1.ReadyBatchState,
ExpectedPhase: v1beta1.RolloutPhaseFinalizing,
ExpectedState: v1beta1.ReadyBatchState,
},
{
Name: `Special Case: Continuous Release, Input-Phase=Progressing, Output-Phase=Progressing`,
GetRelease: func() client.Object {
release := setState(releaseClone, v1alpha1.ReadyBatchState)
release := setState(releaseClone, v1beta1.ReadyBatchState)
now := metav1.Now()
release.Status.CanaryStatus.BatchReadyTime = &now
stableTemplate := stableClone.Spec.Template.DeepCopy()
@ -476,7 +476,7 @@ func TestReconcile_CloneSet(t *testing.T) {
release.Status.UpdateRevision = util.ComputeHash(canaryTemplate, nil)
release.Status.CanaryStatus.UpdatedReplicas = 10
release.Status.CanaryStatus.UpdatedReadyReplicas = 10
release.Spec.ReleasePlan.BatchPartition = pointer.Int32Ptr(1)
release.Spec.ReleasePlan.BatchPartition = pointer.Int32(1)
release.Status.ObservedReleasePlanHash = util.HashReleasePlanBatches(&release.Spec.ReleasePlan)
return release
},
@ -493,13 +493,13 @@ func TestReconcile_CloneSet(t *testing.T) {
canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.ReadyBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.ReadyBatchState,
},
{
Name: `Special Case: BatchPartition=nil, Input-Phase=Progressing, Output-Phase=Finalizing`,
GetRelease: func() client.Object {
release := setState(releaseClone, v1alpha1.ReadyBatchState)
release := setState(releaseClone, v1beta1.ReadyBatchState)
now := metav1.Now()
release.Status.CanaryStatus.BatchReadyTime = &now
stableTemplate := stableClone.Spec.Template.DeepCopy()
@ -521,8 +521,8 @@ func TestReconcile_CloneSet(t *testing.T) {
canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseFinalizing,
ExpectedState: v1alpha1.ReadyBatchState,
ExpectedPhase: v1beta1.RolloutPhaseFinalizing,
ExpectedState: v1beta1.ReadyBatchState,
},
}
@ -531,7 +531,11 @@ func TestReconcile_CloneSet(t *testing.T) {
release := cs.GetRelease()
clonesets := cs.GetCloneSet()
rec := record.NewFakeRecorder(100)
cli := fake.NewClientBuilder().WithScheme(scheme).WithObjects(release).WithObjects(clonesets...).Build()
cli := fake.NewClientBuilder().WithScheme(scheme).
WithObjects(release).
WithObjects(clonesets...).
WithStatusSubresource(&v1beta1.BatchRelease{}).
Build()
reconciler := &BatchReleaseReconciler{
Client: cli,
recorder: rec,
@ -545,7 +549,7 @@ func TestReconcile_CloneSet(t *testing.T) {
Expect(err).NotTo(HaveOccurred())
Expect(result.RequeueAfter).Should(BeNumerically(">=", int64(0)))
newRelease := v1alpha1.BatchRelease{}
newRelease := v1beta1.BatchRelease{}
err = cli.Get(context.TODO(), key, &newRelease)
Expect(err).NotTo(HaveOccurred())
Expect(newRelease.Status.Phase).Should(Equal(cs.ExpectedPhase))
@ -563,14 +567,14 @@ func TestReconcile_Deployment(t *testing.T) {
GetRelease func() client.Object
GetDeployments func() []client.Object
ExpectedBatch int32
ExpectedPhase v1alpha1.RolloutPhase
ExpectedState v1alpha1.BatchReleaseBatchStateType
ExpectedPhase v1beta1.RolloutPhase
ExpectedState v1beta1.BatchReleaseBatchStateType
}{
// Following cases of Linear Transaction on State Machine
{
Name: "IfNeedProgress=true, Input-Phase=Healthy, Output-Phase=Progressing",
GetRelease: func() client.Object {
return setPhase(releaseDeploy, v1alpha1.RolloutPhaseHealthy)
return setPhase(releaseDeploy, v1beta1.RolloutPhaseHealthy)
},
GetDeployments: func() []client.Object {
stable := getStableWithReady(stableDeploy, "v2").(*apps.Deployment)
@ -579,12 +583,12 @@ func TestReconcile_Deployment(t *testing.T) {
stable, canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
},
{
Name: "Preparing, Input-Phase=Preparing, Output-Phase=Progressing",
GetRelease: func() client.Object {
return setPhase(releaseDeploy, v1alpha1.RolloutPhasePreparing)
return setPhase(releaseDeploy, v1beta1.RolloutPhasePreparing)
},
GetDeployments: func() []client.Object {
stable := getStableWithReady(stableDeploy, "v2")
@ -593,12 +597,12 @@ func TestReconcile_Deployment(t *testing.T) {
stable, canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
},
{
Name: "Progressing, stage=0, Input-State=Upgrade, Output-State=Verify",
GetRelease: func() client.Object {
return setState(releaseDeploy, v1alpha1.UpgradingBatchState)
return setState(releaseDeploy, v1beta1.UpgradingBatchState)
},
GetDeployments: func() []client.Object {
stable := getStableWithReady(stableDeploy, "v2")
@ -607,8 +611,8 @@ func TestReconcile_Deployment(t *testing.T) {
stable, canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.VerifyingBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.VerifyingBatchState,
},
{
Name: "Progressing, stage=0, Input-State=Verify, Output-State=Upgrade",
@ -616,7 +620,7 @@ func TestReconcile_Deployment(t *testing.T) {
release := releaseDeploy.DeepCopy()
release.Status.CanaryStatus.UpdatedReplicas = 5
release.Status.CanaryStatus.UpdatedReadyReplicas = 5
return setState(release, v1alpha1.VerifyingBatchState)
return setState(release, v1beta1.VerifyingBatchState)
},
GetDeployments: func() []client.Object {
stable := getStableWithReady(stableDeploy, "v2")
@ -625,8 +629,8 @@ func TestReconcile_Deployment(t *testing.T) {
stable, canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.UpgradingBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.UpgradingBatchState,
},
{
Name: "Progressing, stage=0, Input-State=Verify, Output-State=BatchReady",
@ -634,7 +638,7 @@ func TestReconcile_Deployment(t *testing.T) {
release := releaseDeploy.DeepCopy()
release.Status.CanaryStatus.UpdatedReplicas = 10
release.Status.CanaryStatus.UpdatedReadyReplicas = 10
return setState(release, v1alpha1.VerifyingBatchState)
return setState(release, v1beta1.VerifyingBatchState)
},
GetDeployments: func() []client.Object {
stable := getStableWithReady(stableDeploy, "v2")
@ -643,8 +647,8 @@ func TestReconcile_Deployment(t *testing.T) {
stable, canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.ReadyBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.ReadyBatchState,
},
{
Name: "Progressing, stage=0->1, Input-State=BatchReady, Output-State=Upgrade",
@ -652,8 +656,8 @@ func TestReconcile_Deployment(t *testing.T) {
release := releaseDeploy.DeepCopy()
release.Status.CanaryStatus.UpdatedReplicas = 10
release.Status.CanaryStatus.UpdatedReadyReplicas = 10
release.Spec.ReleasePlan.BatchPartition = pointer.Int32Ptr(1)
return setState(release, v1alpha1.ReadyBatchState)
release.Spec.ReleasePlan.BatchPartition = pointer.Int32(1)
return setState(release, v1beta1.ReadyBatchState)
},
GetDeployments: func() []client.Object {
stable := getStableWithReady(stableDeploy, "v2")
@ -662,8 +666,8 @@ func TestReconcile_Deployment(t *testing.T) {
stable, canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.UpgradingBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.UpgradingBatchState,
ExpectedBatch: 1,
},
{
@ -672,7 +676,7 @@ func TestReconcile_Deployment(t *testing.T) {
release := releaseDeploy.DeepCopy()
release.Status.CanaryStatus.UpdatedReplicas = 10
release.Status.CanaryStatus.UpdatedReadyReplicas = 10
release = setState(release, v1alpha1.ReadyBatchState)
release = setState(release, v1beta1.ReadyBatchState)
return release
},
GetDeployments: func() []client.Object {
@ -682,32 +686,32 @@ func TestReconcile_Deployment(t *testing.T) {
stable, canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.ReadyBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.ReadyBatchState,
},
{
Name: "Special Case: Scaling, Input-State=BatchReady, Output-State=Upgrade",
GetRelease: func() client.Object {
release := setState(releaseDeploy, v1alpha1.ReadyBatchState)
release := setState(releaseDeploy, v1beta1.ReadyBatchState)
now := metav1.Now()
release.Status.CanaryStatus.BatchReadyTime = &now
return release
},
GetDeployments: func() []client.Object {
stable := getStableWithReady(stableDeploy, "v2").(*apps.Deployment)
stable.Spec.Replicas = pointer.Int32Ptr(200)
stable.Spec.Replicas = pointer.Int32(200)
canary := getCanaryWithStage(stable, "v2", 0, true)
return []client.Object{
stable, canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.UpgradingBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.UpgradingBatchState,
},
{
Name: `Special Case: RollBack, Input-Phase=Progressing, Output-Phase=Progressing`,
GetRelease: func() client.Object {
release := setState(releaseDeploy, v1alpha1.ReadyBatchState)
release := setState(releaseDeploy, v1beta1.ReadyBatchState)
now := metav1.Now()
release.Status.CanaryStatus.BatchReadyTime = &now
stableTemplate := stableDeploy.Spec.Template.DeepCopy()
@ -725,13 +729,13 @@ func TestReconcile_Deployment(t *testing.T) {
stable, canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1alpha1.ReadyBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
ExpectedState: v1beta1.ReadyBatchState,
},
{
Name: `Special Case: Deletion, Input-Phase=Progressing, Output-Phase=Finalizing`,
GetRelease: func() client.Object {
release := setState(releaseDeploy, v1alpha1.ReadyBatchState)
release := setState(releaseDeploy, v1beta1.ReadyBatchState)
now := metav1.Now()
release.Status.CanaryStatus.BatchReadyTime = &now
stableTemplate := stableDeploy.Spec.Template.DeepCopy()
@ -751,13 +755,13 @@ func TestReconcile_Deployment(t *testing.T) {
stable, canary,
}
},
ExpectedPhase: v1alpha1.RolloutPhaseFinalizing,
ExpectedState: v1alpha1.ReadyBatchState,
ExpectedPhase: v1beta1.RolloutPhaseFinalizing,
ExpectedState: v1beta1.ReadyBatchState,
},
{
Name: `Special Case: Continuous Release, Input-Phase=Progressing, Output-Phase=Progressing`,
GetRelease: func() client.Object {
release := setState(releaseDeploy, v1alpha1.ReadyBatchState)
release := setState(releaseDeploy, v1beta1.ReadyBatchState)
now := metav1.Now()
release.Status.CanaryStatus.BatchReadyTime = &now
stableTemplate := stableDeploy.Spec.Template.DeepCopy()
@ -775,8 +779,8 @@ func TestReconcile_Deployment(t *testing.T) {
stable, canary,
}
},
ExpectedState: v1alpha1.ReadyBatchState,
ExpectedPhase: v1alpha1.RolloutPhaseProgressing,
ExpectedState: v1beta1.ReadyBatchState,
ExpectedPhase: v1beta1.RolloutPhaseProgressing,
},
}
@ -795,6 +799,8 @@ func TestReconcile_Deployment(t *testing.T) {
cliBuilder = cliBuilder.WithObjects(makeCanaryReplicaSets(deployments[1:]...)...)
}
cliBuilder.WithStatusSubresource(&v1beta1.BatchRelease{})
cli := cliBuilder.Build()
reconciler := &BatchReleaseReconciler{
Client: cli,
@ -808,7 +814,7 @@ func TestReconcile_Deployment(t *testing.T) {
result, _ := reconciler.Reconcile(context.TODO(), request)
Expect(result.RequeueAfter).Should(BeNumerically(">=", int64(0)))
newRelease := v1alpha1.BatchRelease{}
newRelease := v1beta1.BatchRelease{}
err := cli.Get(context.TODO(), key, &newRelease)
Expect(err).NotTo(HaveOccurred())
Expect(newRelease.Status.Phase).Should(Equal(cs.ExpectedPhase))
@ -827,7 +833,7 @@ func containers(version string) []corev1.Container {
}
}
func setPhase(release *v1alpha1.BatchRelease, phase v1alpha1.RolloutPhase) *v1alpha1.BatchRelease {
func setPhase(release *v1beta1.BatchRelease, phase v1beta1.RolloutPhase) *v1beta1.BatchRelease {
r := release.DeepCopy()
r.Status.Phase = phase
r.Status.ObservedWorkloadReplicas = 100
@ -835,9 +841,9 @@ func setPhase(release *v1alpha1.BatchRelease, phase v1alpha1.RolloutPhase) *v1al
return r
}
func setState(release *v1alpha1.BatchRelease, state v1alpha1.BatchReleaseBatchStateType) *v1alpha1.BatchRelease {
func setState(release *v1beta1.BatchRelease, state v1beta1.BatchReleaseBatchStateType) *v1beta1.BatchRelease {
r := release.DeepCopy()
r.Status.Phase = v1alpha1.RolloutPhaseProgressing
r.Status.Phase = v1beta1.RolloutPhaseProgressing
r.Status.CanaryStatus.CurrentBatchState = state
r.Status.ObservedWorkloadReplicas = 100
r.Status.ObservedReleasePlanHash = util.HashReleasePlanBatches(&release.Spec.ReleasePlan)
@ -892,7 +898,7 @@ func getCanaryWithStage(workload client.Object, version string, stage int, ready
d.ResourceVersion = strconv.Itoa(rand.Intn(100000000000))
d.Labels[util.CanaryDeploymentLabel] = "87076677"
d.Finalizers = []string{util.CanaryDeploymentFinalizer}
d.Spec.Replicas = pointer.Int32Ptr(int32(stageReplicas))
d.Spec.Replicas = pointer.Int32(int32(stageReplicas))
d.Spec.Template.Spec.Containers = containers(version)
d.Status.Replicas = int32(stageReplicas)
d.Status.ReadyReplicas = int32(stageReplicas)

View File

@ -23,10 +23,6 @@ import (
kruiseappsv1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
kruiseappsv1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
"github.com/openkruise/rollouts/api/v1alpha1"
"github.com/openkruise/rollouts/pkg/util"
utilclient "github.com/openkruise/rollouts/pkg/util/client"
expectations "github.com/openkruise/rollouts/pkg/util/expectation"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -39,6 +35,11 @@ import (
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"github.com/openkruise/rollouts/api/v1beta1"
"github.com/openkruise/rollouts/pkg/util"
utilclient "github.com/openkruise/rollouts/pkg/util/client"
expectations "github.com/openkruise/rollouts/pkg/util/expectation"
)
type EventAction string
@ -55,7 +56,7 @@ type podEventHandler struct {
client.Reader
}
func (p podEventHandler) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
func (p podEventHandler) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
pod, ok := evt.Object.(*corev1.Pod)
if !ok {
return
@ -63,13 +64,13 @@ func (p podEventHandler) Create(evt event.CreateEvent, q workqueue.RateLimitingI
p.enqueue(pod, q)
}
func (p podEventHandler) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
func (p podEventHandler) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
}
func (p podEventHandler) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
func (p podEventHandler) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
}
func (p podEventHandler) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
func (p podEventHandler) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
oldPod, oldOK := evt.ObjectOld.(*corev1.Pod)
newPod, newOK := evt.ObjectNew.(*corev1.Pod)
if !oldOK || !newOK {
@ -121,12 +122,12 @@ type workloadEventHandler struct {
client.Reader
}
func (w workloadEventHandler) Create(evt event.CreateEvent, q workqueue.RateLimitingInterface) {
func (w workloadEventHandler) Create(ctx context.Context, evt event.CreateEvent, q workqueue.RateLimitingInterface) {
expectationObserved(evt.Object)
w.handleWorkload(q, evt.Object, CreateEventAction)
}
func (w workloadEventHandler) Update(evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
func (w workloadEventHandler) Update(ctx context.Context, evt event.UpdateEvent, q workqueue.RateLimitingInterface) {
var gvk schema.GroupVersionKind
switch obj := evt.ObjectNew.(type) {
case *kruiseappsv1alpha1.CloneSet:
@ -145,8 +146,8 @@ func (w workloadEventHandler) Update(evt event.UpdateEvent, q workqueue.RateLimi
return
}
oldObject := evt.ObjectNew
newObject := evt.ObjectOld
newObject := evt.ObjectNew
oldObject := evt.ObjectOld
expectationObserved(newObject)
if newObject.GetResourceVersion() == oldObject.GetResourceVersion() {
return
@ -172,11 +173,11 @@ func (w workloadEventHandler) Update(evt event.UpdateEvent, q workqueue.RateLimi
}
}
func (w workloadEventHandler) Delete(evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
func (w workloadEventHandler) Delete(ctx context.Context, evt event.DeleteEvent, q workqueue.RateLimitingInterface) {
w.handleWorkload(q, evt.Object, DeleteEventAction)
}
func (w workloadEventHandler) Generic(evt event.GenericEvent, q workqueue.RateLimitingInterface) {
func (w workloadEventHandler) Generic(ctx context.Context, evt event.GenericEvent, q workqueue.RateLimitingInterface) {
}
func (w *workloadEventHandler) handleWorkload(q workqueue.RateLimitingInterface, obj client.Object, action EventAction) {
@ -224,14 +225,14 @@ func getBatchRelease(c client.Reader, workloadNamespaceName types.NamespacedName
klog.Errorf("Failed to unmarshal controller info annotations for %v(%v)", gvk, workloadNamespaceName)
}
if br.APIVersion == v1alpha1.GroupVersion.String() && br.Kind == "BatchRelease" {
if br.APIVersion == v1beta1.GroupVersion.String() && br.Kind == "BatchRelease" {
klog.V(3).Infof("%s (%v) is managed by BatchRelease (%s), append queue and will reconcile BatchRelease", gvk.Kind, workloadNamespaceName, br.Name)
nsn = types.NamespacedName{Namespace: workloadNamespaceName.Namespace, Name: br.Name}
return
}
}
brList := &v1alpha1.BatchReleaseList{}
brList := &v1beta1.BatchReleaseList{}
namespace := workloadNamespaceName.Namespace
if err = c.List(context.TODO(), brList, client.InNamespace(namespace), utilclient.DisableDeepCopy); err != nil {
klog.Errorf("List BatchRelease failed: %s", err.Error())
@ -240,14 +241,14 @@ func getBatchRelease(c client.Reader, workloadNamespaceName types.NamespacedName
for i := range brList.Items {
br := &brList.Items[i]
targetRef := br.Spec.TargetRef
targetGV, err := schema.ParseGroupVersion(targetRef.WorkloadRef.APIVersion)
targetRef := br.Spec.WorkloadRef
targetGV, err := schema.ParseGroupVersion(targetRef.APIVersion)
if err != nil {
klog.Errorf("Failed to parse targetRef's group version: %s for BatchRelease(%v)", targetRef.WorkloadRef.APIVersion, client.ObjectKeyFromObject(br))
klog.Errorf("Failed to parse targetRef's group version: %s for BatchRelease(%v)", targetRef.APIVersion, client.ObjectKeyFromObject(br))
continue
}
if targetRef.WorkloadRef.Kind == gvk.Kind && targetGV.Group == gvk.Group && targetRef.WorkloadRef.Name == workloadNamespaceName.Name {
if targetRef.Kind == gvk.Kind && targetGV.Group == gvk.Group && targetRef.Name == workloadNamespaceName.Name {
nsn = client.ObjectKeyFromObject(br)
}
}
@ -269,7 +270,7 @@ func getControllerKey(object client.Object) *string {
if owner == nil {
return nil
}
if owner.APIVersion == v1alpha1.GroupVersion.String() {
if owner.Kind == "BatchRelease" {
key := types.NamespacedName{Namespace: object.GetNamespace(), Name: owner.Name}.String()
return &key
}

View File

@ -17,14 +17,13 @@ limitations under the License.
package batchrelease
import (
"context"
"encoding/json"
"fmt"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/openkruise/rollouts/api/v1alpha1"
"github.com/openkruise/rollouts/pkg/util"
apps "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -34,6 +33,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"sigs.k8s.io/controller-runtime/pkg/event"
"github.com/openkruise/rollouts/api/v1beta1"
"github.com/openkruise/rollouts/pkg/util"
)
func TestWorkloadEventHandler_Update(t *testing.T) {
@ -91,14 +93,14 @@ func TestWorkloadEventHandler_Update(t *testing.T) {
oldObject := getStableWithReady(stableDeploy, "v2").(*apps.Deployment)
oldObject.SetGeneration(2)
oldObject.Status.ObservedGeneration = 2
oldObject.Spec.Replicas = pointer.Int32Ptr(1000)
oldObject.Spec.Replicas = pointer.Int32(1000)
return oldObject
},
GetNewWorkload: func() client.Object {
newObject := getStableWithReady(stableDeploy, "v2").(*apps.Deployment)
newObject.SetGeneration(2)
newObject.Status.ObservedGeneration = 2
newObject.Spec.Replicas = pointer.Int32Ptr(1000)
newObject.Spec.Replicas = pointer.Int32(1000)
newObject.Status.Replicas = 1000
return newObject
},
@ -137,7 +139,7 @@ func TestWorkloadEventHandler_Update(t *testing.T) {
ObjectOld: oldObject,
ObjectNew: newObject,
}
handler.Update(updateEvt, updateQ)
handler.Update(context.TODO(), updateEvt, updateQ)
Expect(updateQ.Len()).Should(Equal(cs.ExpectedQueueLen))
})
}
@ -172,7 +174,7 @@ func TestWorkloadEventHandler_Create(t *testing.T) {
GetNewWorkload: func() client.Object {
object := getStableWithReady(stableDeploy, "v2").(*apps.Deployment)
controlInfo, _ := json.Marshal(&metav1.OwnerReference{
APIVersion: v1alpha1.GroupVersion.String(),
APIVersion: v1beta1.GroupVersion.String(),
Kind: "Rollout",
Name: "whatever",
})
@ -193,7 +195,7 @@ func TestWorkloadEventHandler_Create(t *testing.T) {
createEvt := event.CreateEvent{
Object: newObject,
}
handler.Create(createEvt, createQ)
handler.Create(context.TODO(), createEvt, createQ)
Expect(createQ.Len()).Should(Equal(cs.ExpectedQueueLen))
})
}
@ -228,7 +230,7 @@ func TestWorkloadEventHandler_Delete(t *testing.T) {
GetNewWorkload: func() client.Object {
object := getStableWithReady(stableDeploy, "v2").(*apps.Deployment)
controlInfo, _ := json.Marshal(&metav1.OwnerReference{
APIVersion: v1alpha1.GroupVersion.String(),
APIVersion: v1beta1.GroupVersion.String(),
Kind: "Rollout",
Name: "whatever",
})
@ -249,7 +251,7 @@ func TestWorkloadEventHandler_Delete(t *testing.T) {
deleteEvt := event.DeleteEvent{
Object: newObject,
}
handler.Delete(deleteEvt, deleteQ)
handler.Delete(context.TODO(), deleteEvt, deleteQ)
Expect(deleteQ.Len()).Should(Equal(cs.ExpectedQueueLen))
})
}
@ -399,7 +401,7 @@ func TestPodEventHandler_Update(t *testing.T) {
ObjectOld: oldObject,
ObjectNew: newObject,
}
handler.Update(updateEvt, updateQ)
handler.Update(context.TODO(), updateEvt, updateQ)
Expect(updateQ.Len()).Should(Equal(cs.ExpectedQueueLen))
})
}
@ -466,7 +468,7 @@ func TestPodEventHandler_Create(t *testing.T) {
createEvt := event.CreateEvent{
Object: newObject,
}
handler.Create(createEvt, createQ)
handler.Create(context.TODO(), createEvt, createQ)
Expect(createQ.Len()).Should(Equal(cs.ExpectedQueueLen))
})
}

View File

@ -19,20 +19,9 @@ package batchrelease
import (
"fmt"
"reflect"
"strings"
"time"
appsv1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
"github.com/openkruise/rollouts/api/v1alpha1"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control/canarystyle"
canarydeployment "github.com/openkruise/rollouts/pkg/controller/batchrelease/control/canarystyle/deployment"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control/partitionstyle"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control/partitionstyle/cloneset"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control/partitionstyle/daemonset"
partitiondeployment "github.com/openkruise/rollouts/pkg/controller/batchrelease/control/partitionstyle/deployment"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control/partitionstyle/statefulset"
"github.com/openkruise/rollouts/pkg/util"
apps "k8s.io/api/apps/v1"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -42,6 +31,21 @@ import (
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"github.com/openkruise/rollouts/api/v1beta1"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control/bluegreenstyle"
bgcloneset "github.com/openkruise/rollouts/pkg/controller/batchrelease/control/bluegreenstyle/cloneset"
bgdeplopyment "github.com/openkruise/rollouts/pkg/controller/batchrelease/control/bluegreenstyle/deployment"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control/canarystyle"
canarydeployment "github.com/openkruise/rollouts/pkg/controller/batchrelease/control/canarystyle/deployment"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control/partitionstyle"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control/partitionstyle/cloneset"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control/partitionstyle/daemonset"
partitiondeployment "github.com/openkruise/rollouts/pkg/controller/batchrelease/control/partitionstyle/deployment"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control/partitionstyle/statefulset"
"github.com/openkruise/rollouts/pkg/util"
"github.com/openkruise/rollouts/pkg/util/errors"
)
const (
@ -63,7 +67,7 @@ func NewReleasePlanExecutor(cli client.Client, recorder record.EventRecorder) *E
}
// Do execute the release plan
func (r *Executor) Do(release *v1alpha1.BatchRelease) (reconcile.Result, *v1alpha1.BatchReleaseStatus, error) {
func (r *Executor) Do(release *v1beta1.BatchRelease) (reconcile.Result, *v1beta1.BatchReleaseStatus, error) {
klog.InfoS("Starting one round of reconciling release plan",
"BatchRelease", client.ObjectKeyFromObject(release),
"phase", release.Status.Phase,
@ -84,7 +88,7 @@ func (r *Executor) Do(release *v1alpha1.BatchRelease) (reconcile.Result, *v1alph
return r.executeBatchReleasePlan(release, newStatus, workloadController)
}
func (r *Executor) executeBatchReleasePlan(release *v1alpha1.BatchRelease, newStatus *v1alpha1.BatchReleaseStatus, workloadController control.Interface) (reconcile.Result, *v1alpha1.BatchReleaseStatus, error) {
func (r *Executor) executeBatchReleasePlan(release *v1beta1.BatchRelease, newStatus *v1beta1.BatchReleaseStatus, workloadController control.Interface) (reconcile.Result, *v1beta1.BatchReleaseStatus, error) {
var err error
result := reconcile.Result{}
@ -93,42 +97,42 @@ func (r *Executor) executeBatchReleasePlan(release *v1alpha1.BatchRelease, newSt
switch newStatus.Phase {
default:
// for compatibility. if it is an unknown phase, should start from beginning.
newStatus.Phase = v1alpha1.RolloutPhasePreparing
newStatus.Phase = v1beta1.RolloutPhasePreparing
fallthrough
case v1alpha1.RolloutPhasePreparing:
case v1beta1.RolloutPhasePreparing:
// prepare and initialize something before progressing in this state.
err = workloadController.Initialize()
switch {
case err == nil:
newStatus.Phase = v1alpha1.RolloutPhaseProgressing
newStatus.Phase = v1beta1.RolloutPhaseProgressing
result = reconcile.Result{RequeueAfter: DefaultDuration}
default:
klog.Warningf("Failed to initialize %v, err %v", klog.KObj(release), err)
}
case v1alpha1.RolloutPhaseProgressing:
case v1beta1.RolloutPhaseProgressing:
// progress the release plan in this state.
result, err = r.progressBatches(release, newStatus, workloadController)
case v1alpha1.RolloutPhaseFinalizing:
case v1beta1.RolloutPhaseFinalizing:
err = workloadController.Finalize()
switch {
case err == nil:
newStatus.Phase = v1alpha1.RolloutPhaseCompleted
newStatus.Phase = v1beta1.RolloutPhaseCompleted
default:
klog.Warningf("Failed to finalize %v, err %v", klog.KObj(release), err)
}
case v1alpha1.RolloutPhaseCompleted:
// this state indicates that the plan is executed/cancelled successfully, should do nothing in these states.
case v1beta1.RolloutPhaseCompleted:
// this state indicates that the plan is executed/canceled successfully, should do nothing in these states.
}
return result, newStatus, err
}
// reconcile logic when we are in the middle of release, we have to go through finalizing state before succeed or fail
func (r *Executor) progressBatches(release *v1alpha1.BatchRelease, newStatus *v1alpha1.BatchReleaseStatus, workloadController control.Interface) (reconcile.Result, error) {
func (r *Executor) progressBatches(release *v1beta1.BatchRelease, newStatus *v1beta1.BatchReleaseStatus, workloadController control.Interface) (reconcile.Result, error) {
var err error
result := reconcile.Result{}
@ -137,43 +141,47 @@ func (r *Executor) progressBatches(release *v1alpha1.BatchRelease, newStatus *v1
switch newStatus.CanaryStatus.CurrentBatchState {
default:
// for compatibility. if it is an unknown state, should start from beginning.
newStatus.CanaryStatus.CurrentBatchState = v1alpha1.UpgradingBatchState
newStatus.CanaryStatus.CurrentBatchState = v1beta1.UpgradingBatchState
fallthrough
case v1alpha1.UpgradingBatchState:
case v1beta1.UpgradingBatchState:
// modify workload replicas/partition based on release plan in this state.
err = workloadController.UpgradeBatch()
switch {
case err == nil:
result = reconcile.Result{RequeueAfter: DefaultDuration}
newStatus.CanaryStatus.CurrentBatchState = v1alpha1.VerifyingBatchState
removeProgressingCondition(newStatus)
newStatus.CanaryStatus.CurrentBatchState = v1beta1.VerifyingBatchState
case errors.IsBadRequest(err):
progressingStateTransition(newStatus, v1.ConditionTrue, v1beta1.ProgressingReasonInRolling, err.Error())
fallthrough
default:
klog.Warningf("Failed to upgrade %v, err %v", klog.KObj(release), err)
}
case v1alpha1.VerifyingBatchState:
case v1beta1.VerifyingBatchState:
// replicas/partition has been modified, should wait pod ready in this state.
err = workloadController.CheckBatchReady()
err = workloadController.EnsureBatchPodsReadyAndLabeled()
switch {
case err != nil:
// should go to upgrade state to do again to avoid dead wait.
newStatus.CanaryStatus.CurrentBatchState = v1alpha1.UpgradingBatchState
newStatus.CanaryStatus.CurrentBatchState = v1beta1.UpgradingBatchState
klog.Warningf("%v current batch is not ready, err %v", klog.KObj(release), err)
default:
now := metav1.Now()
newStatus.CanaryStatus.BatchReadyTime = &now
result = reconcile.Result{RequeueAfter: DefaultDuration}
newStatus.CanaryStatus.CurrentBatchState = v1alpha1.ReadyBatchState
newStatus.CanaryStatus.CurrentBatchState = v1beta1.ReadyBatchState
}
case v1alpha1.ReadyBatchState:
case v1beta1.ReadyBatchState:
// replicas/partition may be modified even though ready, should recheck in this state.
err = workloadController.CheckBatchReady()
err = workloadController.EnsureBatchPodsReadyAndLabeled()
switch {
case err != nil:
// if the batch ready condition changed due to some reasons, just recalculate the current batch.
newStatus.CanaryStatus.BatchReadyTime = nil
newStatus.CanaryStatus.CurrentBatchState = v1alpha1.UpgradingBatchState
newStatus.CanaryStatus.CurrentBatchState = v1beta1.UpgradingBatchState
klog.Warningf("%v current batch is not ready, err %v", klog.KObj(release), err)
case !isPartitioned(release):
r.moveToNextBatch(release, newStatus)
@ -185,12 +193,8 @@ func (r *Executor) progressBatches(release *v1alpha1.BatchRelease, newStatus *v1
}
// GetWorkloadController pick the right workload controller to work on the workload
func (r *Executor) getReleaseController(release *v1alpha1.BatchRelease, newStatus *v1alpha1.BatchReleaseStatus) (control.Interface, error) {
targetRef := release.Spec.TargetRef.WorkloadRef
if targetRef == nil {
return nil, nil
}
func (r *Executor) getReleaseController(release *v1beta1.BatchRelease, newStatus *v1beta1.BatchReleaseStatus) (control.Interface, error) {
targetRef := release.Spec.WorkloadRef
gvk := schema.FromAPIVersionAndKind(targetRef.APIVersion, targetRef.Kind)
if !util.IsSupportedWorkload(gvk) {
message := fmt.Sprintf("the workload type '%v' is not supported", gvk)
@ -202,28 +206,43 @@ func (r *Executor) getReleaseController(release *v1alpha1.BatchRelease, newStatu
Namespace: release.Namespace,
Name: targetRef.Name,
}
rollingStyle := release.Spec.ReleasePlan.RollingStyle
if len(rollingStyle) == 0 && release.Spec.ReleasePlan.EnableExtraWorkloadForCanary {
rollingStyle = v1beta1.CanaryRollingStyle
}
klog.Infof("BatchRelease(%v) using %s-style release controller for this batch release", klog.KObj(release), rollingStyle)
switch rollingStyle {
case v1beta1.BlueGreenRollingStyle:
if targetRef.APIVersion == appsv1alpha1.GroupVersion.String() && targetRef.Kind == reflect.TypeOf(appsv1alpha1.CloneSet{}).Name() {
klog.InfoS("Using CloneSet bluegreen-style release controller for this batch release", "workload name", targetKey.Name, "namespace", targetKey.Namespace)
return bluegreenstyle.NewControlPlane(bgcloneset.NewController, r.client, r.recorder, release, newStatus, targetKey, gvk), nil
}
if targetRef.APIVersion == apps.SchemeGroupVersion.String() && targetRef.Kind == reflect.TypeOf(apps.Deployment{}).Name() {
klog.InfoS("Using Deployment bluegreen-style release controller for this batch release", "workload name", targetKey.Name, "namespace", targetKey.Namespace)
return bluegreenstyle.NewControlPlane(bgdeplopyment.NewController, r.client, r.recorder, release, newStatus, targetKey, gvk), nil
}
switch targetRef.APIVersion {
case appsv1alpha1.GroupVersion.String():
if targetRef.Kind == reflect.TypeOf(appsv1alpha1.CloneSet{}).Name() {
case v1beta1.CanaryRollingStyle:
if targetRef.APIVersion == apps.SchemeGroupVersion.String() && targetRef.Kind == reflect.TypeOf(apps.Deployment{}).Name() {
klog.InfoS("Using Deployment canary-style release controller for this batch release", "workload name", targetKey.Name, "namespace", targetKey.Namespace)
return canarystyle.NewControlPlane(canarydeployment.NewController, r.client, r.recorder, release, newStatus, targetKey), nil
}
fallthrough
case v1beta1.PartitionRollingStyle, "":
if targetRef.APIVersion == appsv1alpha1.GroupVersion.String() && targetRef.Kind == reflect.TypeOf(appsv1alpha1.CloneSet{}).Name() {
klog.InfoS("Using CloneSet partition-style release controller for this batch release", "workload name", targetKey.Name, "namespace", targetKey.Namespace)
return partitionstyle.NewControlPlane(cloneset.NewController, r.client, r.recorder, release, newStatus, targetKey, gvk), nil
}
if targetRef.Kind == reflect.TypeOf(appsv1alpha1.DaemonSet{}).Name() {
if targetRef.APIVersion == appsv1alpha1.GroupVersion.String() && targetRef.Kind == reflect.TypeOf(appsv1alpha1.DaemonSet{}).Name() {
klog.InfoS("Using DaemonSet partition-style release controller for this batch release", "workload name", targetKey.Name, "namespace", targetKey.Namespace)
return partitionstyle.NewControlPlane(daemonset.NewController, r.client, r.recorder, release, newStatus, targetKey, gvk), nil
}
case apps.SchemeGroupVersion.String():
if targetRef.Kind == reflect.TypeOf(apps.Deployment{}).Name() {
if strings.EqualFold(release.Annotations[v1alpha1.RolloutStyleAnnotation], string(v1alpha1.PartitionRollingStyle)) {
klog.InfoS("Using Deployment partition-style release controller for this batch release", "workload name", targetKey.Name, "namespace", targetKey.Namespace)
return partitionstyle.NewControlPlane(partitiondeployment.NewController, r.client, r.recorder, release, newStatus, targetKey, gvk), nil
} else {
klog.InfoS("Using Deployment canary-style release controller for this batch release", "workload name", targetKey.Name, "namespace", targetKey.Namespace)
return canarystyle.NewControlPlane(canarydeployment.NewController, r.client, r.recorder, release, newStatus, targetKey), nil
}
if targetRef.APIVersion == apps.SchemeGroupVersion.String() && targetRef.Kind == reflect.TypeOf(apps.Deployment{}).Name() {
klog.InfoS("Using Deployment partition-style release controller for this batch release", "workload name", targetKey.Name, "namespace", targetKey.Namespace)
return partitionstyle.NewControlPlane(partitiondeployment.NewController, r.client, r.recorder, release, newStatus, targetKey, gvk), nil
}
klog.Info("Partition, but use StatefulSet-Like partition-style release controller for this batch release")
}
// try to use StatefulSet-like rollout controller by default
@ -231,7 +250,7 @@ func (r *Executor) getReleaseController(release *v1alpha1.BatchRelease, newStatu
return partitionstyle.NewControlPlane(statefulset.NewController, r.client, r.recorder, release, newStatus, targetKey, gvk), nil
}
func (r *Executor) moveToNextBatch(release *v1alpha1.BatchRelease, status *v1alpha1.BatchReleaseStatus) {
func (r *Executor) moveToNextBatch(release *v1beta1.BatchRelease, status *v1beta1.BatchReleaseStatus) {
currentBatch := int(status.CanaryStatus.CurrentBatch)
if currentBatch >= len(release.Spec.ReleasePlan.Batches)-1 {
klog.V(3).Infof("BatchRelease(%v) finished all batch, release current batch: %v", klog.KObj(release), status.CanaryStatus.CurrentBatch)
@ -239,11 +258,31 @@ func (r *Executor) moveToNextBatch(release *v1alpha1.BatchRelease, status *v1alp
if release.Spec.ReleasePlan.BatchPartition == nil || *release.Spec.ReleasePlan.BatchPartition > status.CanaryStatus.CurrentBatch {
status.CanaryStatus.CurrentBatch++
}
status.CanaryStatus.CurrentBatchState = v1alpha1.UpgradingBatchState
status.CanaryStatus.CurrentBatchState = v1beta1.UpgradingBatchState
klog.V(3).Infof("BatchRelease(%v) finished one batch, release current batch: %v", klog.KObj(release), status.CanaryStatus.CurrentBatch)
}
func isPartitioned(release *v1alpha1.BatchRelease) bool {
func isPartitioned(release *v1beta1.BatchRelease) bool {
return release.Spec.ReleasePlan.BatchPartition != nil &&
*release.Spec.ReleasePlan.BatchPartition <= release.Status.CanaryStatus.CurrentBatch
}
func progressingStateTransition(status *v1beta1.BatchReleaseStatus, condStatus v1.ConditionStatus, reason, message string) {
cond := util.GetBatchReleaseCondition(*status, v1beta1.RolloutConditionProgressing)
if cond == nil {
cond = util.NewRolloutCondition(v1beta1.RolloutConditionProgressing, condStatus, reason, message)
} else {
cond.Status = condStatus
cond.Reason = reason
if message != "" {
cond.Message = message
}
}
util.SetBatchReleaseCondition(status, *cond)
status.Message = cond.Message
}
func removeProgressingCondition(status *v1beta1.BatchReleaseStatus) {
util.RemoveBatchReleaseCondition(status, v1beta1.RolloutConditionProgressing)
status.Message = ""
}

View File

@ -19,17 +19,19 @@ package batchrelease
import (
"reflect"
"github.com/openkruise/rollouts/api/v1alpha1"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control"
"github.com/openkruise/rollouts/pkg/util"
"k8s.io/apimachinery/pkg/api/errors"
"k8s.io/klog/v2"
"k8s.io/utils/integer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"github.com/openkruise/rollouts/api/v1alpha1"
"github.com/openkruise/rollouts/api/v1beta1"
"github.com/openkruise/rollouts/pkg/controller/batchrelease/control"
"github.com/openkruise/rollouts/pkg/util"
)
func (r *Executor) syncStatusBeforeExecuting(release *v1alpha1.BatchRelease, newStatus *v1alpha1.BatchReleaseStatus, controller control.Interface) (bool, reconcile.Result, error) {
func (r *Executor) syncStatusBeforeExecuting(release *v1beta1.BatchRelease, newStatus *v1beta1.BatchReleaseStatus, controller control.Interface) (bool, reconcile.Result, error) {
var err error
var message string
var needRetry bool
@ -45,7 +47,7 @@ func (r *Executor) syncStatusBeforeExecuting(release *v1alpha1.BatchRelease, new
*************************************************************************/
//The following special cases are about the **batch release plan**, include:
// (1). Plan has been terminated
// (2). Plan is deleted or cancelled
// (2). Plan is deleted or canceled
// (3). Plan is changed during rollout
// (4). Plan status is unexpected/unhealthy
case isPlanCompleted(release):
@ -54,7 +56,7 @@ func (r *Executor) syncStatusBeforeExecuting(release *v1alpha1.BatchRelease, new
case isPlanFinalizing(release):
// handle the case that the plan is deleted or is terminating
message = "release plan is deleted or cancelled, then finalize"
message = "release plan is deleted or canceled, then finalize"
signalFinalizing(newStatus)
case isPlanChanged(release):
@ -145,7 +147,7 @@ func (r *Executor) syncStatusBeforeExecuting(release *v1alpha1.BatchRelease, new
return needStopThisRound, result, err
}
func refreshStatus(release *v1alpha1.BatchRelease, newStatus *v1alpha1.BatchReleaseStatus, workloadInfo *util.WorkloadInfo) {
func refreshStatus(release *v1beta1.BatchRelease, newStatus *v1beta1.BatchReleaseStatus, workloadInfo *util.WorkloadInfo) {
// refresh workload info for status
if workloadInfo != nil {
newStatus.CanaryStatus.UpdatedReplicas = workloadInfo.Status.UpdatedReplicas
@ -154,78 +156,79 @@ func refreshStatus(release *v1alpha1.BatchRelease, newStatus *v1alpha1.BatchRele
if len(newStatus.ObservedReleasePlanHash) == 0 {
newStatus.ObservedReleasePlanHash = util.HashReleasePlanBatches(&release.Spec.ReleasePlan)
}
newStatus.ObservedRolloutID = release.Spec.ReleasePlan.RolloutID
}
func isPlanFinalizing(release *v1alpha1.BatchRelease) bool {
if release.DeletionTimestamp != nil || release.Status.Phase == v1alpha1.RolloutPhaseFinalizing {
func isPlanFinalizing(release *v1beta1.BatchRelease) bool {
if release.DeletionTimestamp != nil || release.Status.Phase == v1beta1.RolloutPhaseFinalizing {
return true
}
return release.Spec.ReleasePlan.BatchPartition == nil
}
func isPlanCompleted(release *v1alpha1.BatchRelease) bool {
return release.Status.Phase == v1alpha1.RolloutPhaseCompleted
func isPlanCompleted(release *v1beta1.BatchRelease) bool {
return release.Status.Phase == v1beta1.RolloutPhaseCompleted
}
func isPlanChanged(release *v1alpha1.BatchRelease) bool {
return release.Status.ObservedReleasePlanHash != util.HashReleasePlanBatches(&release.Spec.ReleasePlan) && release.Status.Phase == v1alpha1.RolloutPhaseProgressing
func isPlanChanged(release *v1beta1.BatchRelease) bool {
return release.Status.ObservedReleasePlanHash != util.HashReleasePlanBatches(&release.Spec.ReleasePlan) && release.Status.Phase == v1beta1.RolloutPhaseProgressing
}
func isPlanUnhealthy(release *v1alpha1.BatchRelease) bool {
return int(release.Status.CanaryStatus.CurrentBatch) >= len(release.Spec.ReleasePlan.Batches) && release.Status.Phase == v1alpha1.RolloutPhaseProgressing
func isPlanUnhealthy(release *v1beta1.BatchRelease) bool {
return int(release.Status.CanaryStatus.CurrentBatch) >= len(release.Spec.ReleasePlan.Batches) && release.Status.Phase == v1beta1.RolloutPhaseProgressing
}
func isGetWorkloadInfoError(err error) bool {
return err != nil && !errors.IsNotFound(err)
}
func isWorkloadGone(event control.WorkloadEventType, release *v1alpha1.BatchRelease) bool {
return event == control.WorkloadHasGone && release.Status.Phase != v1alpha1.RolloutPhaseInitial && release.Status.Phase != ""
func isWorkloadGone(event control.WorkloadEventType, release *v1beta1.BatchRelease) bool {
return event == control.WorkloadHasGone && release.Status.Phase != v1beta1.RolloutPhaseInitial && release.Status.Phase != ""
}
func isWorkloadScaling(event control.WorkloadEventType, release *v1alpha1.BatchRelease) bool {
return event == control.WorkloadReplicasChanged && release.Status.Phase == v1alpha1.RolloutPhaseProgressing
func isWorkloadScaling(event control.WorkloadEventType, release *v1beta1.BatchRelease) bool {
return event == control.WorkloadReplicasChanged && release.Status.Phase == v1beta1.RolloutPhaseProgressing
}
func isWorkloadRevisionChanged(event control.WorkloadEventType, release *v1alpha1.BatchRelease) bool {
return event == control.WorkloadPodTemplateChanged && release.Status.Phase == v1alpha1.RolloutPhaseProgressing
func isWorkloadRevisionChanged(event control.WorkloadEventType, release *v1beta1.BatchRelease) bool {
return event == control.WorkloadPodTemplateChanged && release.Status.Phase == v1beta1.RolloutPhaseProgressing
}
func isWorkloadRollbackInBatch(event control.WorkloadEventType, release *v1alpha1.BatchRelease) bool {
func isWorkloadRollbackInBatch(event control.WorkloadEventType, release *v1beta1.BatchRelease) bool {
return (event == control.WorkloadRollbackInBatch || release.Annotations[v1alpha1.RollbackInBatchAnnotation] != "") &&
release.Status.CanaryStatus.NoNeedUpdateReplicas == nil && release.Status.Phase == v1alpha1.RolloutPhaseProgressing
release.Status.CanaryStatus.NoNeedUpdateReplicas == nil && release.Status.Phase == v1beta1.RolloutPhaseProgressing
}
func isWorkloadUnstable(event control.WorkloadEventType, _ *v1alpha1.BatchRelease) bool {
func isWorkloadUnstable(event control.WorkloadEventType, _ *v1beta1.BatchRelease) bool {
return event == control.WorkloadStillReconciling
}
func isRollbackInBatchSatisfied(workloadInfo *util.WorkloadInfo, release *v1alpha1.BatchRelease) bool {
func isRollbackInBatchSatisfied(workloadInfo *util.WorkloadInfo, release *v1beta1.BatchRelease) bool {
return workloadInfo.Status.StableRevision == workloadInfo.Status.UpdateRevision && release.Annotations[v1alpha1.RollbackInBatchAnnotation] != ""
}
func signalRePrepareRollback(newStatus *v1alpha1.BatchReleaseStatus) {
newStatus.Phase = v1alpha1.RolloutPhasePreparing
func signalRePrepareRollback(newStatus *v1beta1.BatchReleaseStatus) {
newStatus.Phase = v1beta1.RolloutPhasePreparing
newStatus.CanaryStatus.BatchReadyTime = nil
newStatus.CanaryStatus.CurrentBatchState = v1alpha1.UpgradingBatchState
newStatus.CanaryStatus.CurrentBatchState = v1beta1.UpgradingBatchState
}
func signalRestartBatch(status *v1alpha1.BatchReleaseStatus) {
func signalRestartBatch(status *v1beta1.BatchReleaseStatus) {
status.CanaryStatus.BatchReadyTime = nil
status.CanaryStatus.CurrentBatchState = v1alpha1.UpgradingBatchState
status.CanaryStatus.CurrentBatchState = v1beta1.UpgradingBatchState
}
func signalRestartAll(status *v1alpha1.BatchReleaseStatus) {
emptyStatus := v1alpha1.BatchReleaseStatus{}
func signalRestartAll(status *v1beta1.BatchReleaseStatus) {
emptyStatus := v1beta1.BatchReleaseStatus{}
resetStatus(&emptyStatus)
*status = emptyStatus
}
func signalFinalizing(status *v1alpha1.BatchReleaseStatus) {
status.Phase = v1alpha1.RolloutPhaseFinalizing
func signalFinalizing(status *v1beta1.BatchReleaseStatus) {
status.Phase = v1beta1.RolloutPhaseFinalizing
}
func signalRecalculate(release *v1alpha1.BatchRelease, newStatus *v1alpha1.BatchReleaseStatus) {
func signalRecalculate(release *v1beta1.BatchRelease, newStatus *v1beta1.BatchReleaseStatus) {
// When BatchRelease plan was changed, rollout controller will update this batchRelease cr,
// and rollout controller will set BatchPartition as its expected current batch index.
currentBatch := int32(0)
@ -242,11 +245,11 @@ func signalRecalculate(release *v1alpha1.BatchRelease, newStatus *v1alpha1.Batch
newStatus.CanaryStatus.BatchReadyTime = nil
newStatus.CanaryStatus.CurrentBatch = currentBatch
newStatus.ObservedRolloutID = release.Spec.ReleasePlan.RolloutID
newStatus.CanaryStatus.CurrentBatchState = v1alpha1.UpgradingBatchState
newStatus.CanaryStatus.CurrentBatchState = v1beta1.UpgradingBatchState
newStatus.ObservedReleasePlanHash = util.HashReleasePlanBatches(&release.Spec.ReleasePlan)
}
func getInitializedStatus(status *v1alpha1.BatchReleaseStatus) *v1alpha1.BatchReleaseStatus {
func getInitializedStatus(status *v1beta1.BatchReleaseStatus) *v1beta1.BatchReleaseStatus {
newStatus := status.DeepCopy()
if len(status.Phase) == 0 {
resetStatus(newStatus)
@ -254,11 +257,11 @@ func getInitializedStatus(status *v1alpha1.BatchReleaseStatus) *v1alpha1.BatchRe
return newStatus
}
func resetStatus(status *v1alpha1.BatchReleaseStatus) {
status.Phase = v1alpha1.RolloutPhasePreparing
func resetStatus(status *v1beta1.BatchReleaseStatus) {
status.Phase = v1beta1.RolloutPhasePreparing
status.StableRevision = ""
status.UpdateRevision = ""
status.ObservedReleasePlanHash = ""
status.ObservedWorkloadReplicas = -1
status.CanaryStatus = v1alpha1.BatchReleaseCanaryStatus{}
status.CanaryStatus = v1beta1.BatchReleaseCanaryStatus{}
}

View File

@ -20,10 +20,11 @@ import (
"encoding/json"
"fmt"
"github.com/openkruise/rollouts/api/v1alpha1"
"github.com/openkruise/rollouts/pkg/util"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"github.com/openkruise/rollouts/api/v1beta1"
"github.com/openkruise/rollouts/pkg/util"
)
type BatchContext struct {
@ -61,6 +62,9 @@ type BatchContext struct {
Pods []*corev1.Pod `json:"-"`
// filter or sort pods before patch label
FilterFunc FilterFuncType `json:"-"`
// the next two fields are only used for bluegreen style
CurrentSurge intstr.IntOrString `json:"currentSurge,omitempty"`
DesiredSurge intstr.IntOrString `json:"desiredSurge,omitempty"`
}
type FilterFuncType func(pods []*corev1.Pod, ctx *BatchContext) []*corev1.Pod
@ -73,20 +77,20 @@ func (bc *BatchContext) Log() string {
// IsBatchReady return nil if the batch is ready
func (bc *BatchContext) IsBatchReady() error {
if bc.UpdatedReplicas < bc.DesiredUpdatedReplicas {
return fmt.Errorf("current batch not ready: updated replicas not satified")
return fmt.Errorf("current batch not ready: updated replicas not satisfied, UpdatedReplicas %d < DesiredUpdatedReplicas %d", bc.UpdatedReplicas, bc.DesiredUpdatedReplicas)
}
unavailableToleration := allowedUnavailable(bc.FailureThreshold, bc.UpdatedReplicas)
if unavailableToleration+bc.UpdatedReadyReplicas < bc.DesiredUpdatedReplicas {
return fmt.Errorf("current batch not ready: updated ready replicas not satified")
return fmt.Errorf("current batch not ready: updated ready replicas not satisfied, allowedUnavailable + UpdatedReadyReplicas %d < DesiredUpdatedReplicas %d", unavailableToleration+bc.UpdatedReadyReplicas, bc.DesiredUpdatedReplicas)
}
if bc.DesiredUpdatedReplicas > 0 && bc.UpdatedReadyReplicas == 0 {
return fmt.Errorf("current batch not ready: no updated ready replicas")
return fmt.Errorf("current batch not ready: no updated ready replicas, DesiredUpdatedReplicas %d > 0 and UpdatedReadyReplicas %d = 0", bc.DesiredUpdatedReplicas, bc.UpdatedReadyReplicas)
}
if !batchLabelSatisfied(bc.Pods, bc.RolloutID, bc.PlannedUpdatedReplicas) {
return fmt.Errorf("current batch not ready: pods with batch label not satified")
return fmt.Errorf("current batch not ready: pods with batch label not satisfied, RolloutID %s, PlannedUpdatedReplicas %d", bc.RolloutID, bc.PlannedUpdatedReplicas)
}
return nil
}
@ -100,7 +104,7 @@ func batchLabelSatisfied(pods []*corev1.Pod, rolloutID string, targetCount int32
if !pod.DeletionTimestamp.IsZero() {
return false
}
return pod.Labels[v1alpha1.RolloutIDLabel] == rolloutID
return pod.Labels[v1beta1.RolloutIDLabel] == rolloutID
})
return patchedCount >= int(targetCount)
}

View File

@ -22,12 +22,13 @@ import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/openkruise/rollouts/api/v1alpha1"
"github.com/openkruise/rollouts/pkg/util"
apps "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
"github.com/openkruise/rollouts/api/v1beta1"
"github.com/openkruise/rollouts/pkg/util"
)
func TestIsBatchReady(t *testing.T) {
@ -36,14 +37,14 @@ func TestIsBatchReady(t *testing.T) {
p := func(f intstr.IntOrString) *intstr.IntOrString {
return &f
}
r := func(f *intstr.IntOrString, id, revision string) *v1alpha1.BatchRelease {
return &v1alpha1.BatchRelease{
Spec: v1alpha1.BatchReleaseSpec{ReleasePlan: v1alpha1.ReleasePlan{RolloutID: id, FailureThreshold: f}},
Status: v1alpha1.BatchReleaseStatus{UpdateRevision: revision},
r := func(f *intstr.IntOrString, id, revision string) *v1beta1.BatchRelease {
return &v1beta1.BatchRelease{
Spec: v1beta1.BatchReleaseSpec{ReleasePlan: v1beta1.ReleasePlan{RolloutID: id, FailureThreshold: f}},
Status: v1beta1.BatchReleaseStatus{UpdateRevision: revision},
}
}
cases := map[string]struct {
release *v1alpha1.BatchRelease
release *v1beta1.BatchRelease
pods []*corev1.Pod
maxUnavailable *intstr.IntOrString
labelDesired int32
@ -151,11 +152,11 @@ func TestIsBatchReady(t *testing.T) {
func generatePods(updatedReplicas, noNeedRollbackReplicas int) []*corev1.Pod {
podsNoNeed := generatePodsWith(map[string]string{
util.NoNeedUpdatePodLabel: "0x1",
v1alpha1.RolloutIDLabel: "1",
v1beta1.RolloutIDLabel: "1",
apps.ControllerRevisionHashLabelKey: "version-1",
}, noNeedRollbackReplicas, 0)
return append(generatePodsWith(map[string]string{
v1alpha1.RolloutIDLabel: "1",
v1beta1.RolloutIDLabel: "1",
apps.ControllerRevisionHashLabelKey: "version-1",
}, updatedReplicas-noNeedRollbackReplicas, noNeedRollbackReplicas), podsNoNeed...)
}

View File

@ -0,0 +1,42 @@
/*
Copyright 2022 The Kruise 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 control
import "k8s.io/apimachinery/pkg/util/intstr"
// OriginalDeploymentStrategy stores part of the fileds of a workload,
// so that it can be restored when finalizing.
// It is only used for BlueGreen Release
// Similar to DeploymentStrategy, it is an annotation used in workload
// However, unlike DeploymentStrategy, it is only used to store and restore the user's strategy
type OriginalDeploymentStrategy struct {
// +optional
MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty" protobuf:"bytes,1,opt,name=maxUnavailable"`
// +optional
MaxSurge *intstr.IntOrString `json:"maxSurge,omitempty" protobuf:"bytes,2,opt,name=maxSurge"`
// Minimum number of seconds for which a newly created pod should be ready
// without any of its container crashing, for it to be considered available.
// Defaults to 0 (pod will be considered available as soon as it is ready)
// +optional
MinReadySeconds int32 `json:"minReadySeconds,omitempty" protobuf:"varint,5,opt,name=minReadySeconds"`
// The maximum time in seconds for a deployment to make progress before it
// is considered to be failed. The deployment controller will continue to
// process failed deployments and a condition with a ProgressDeadlineExceeded
// reason will be surfaced in the deployment status. Note that progress will
// not be estimated during the time a deployment is paused. Defaults to 600s.
ProgressDeadlineSeconds *int32 `json:"progressDeadlineSeconds,omitempty" protobuf:"varint,9,opt,name=progressDeadlineSeconds"`
}

Some files were not shown because too many files have changed in this diff Show More