Compare commits

...

28 Commits

Author SHA1 Message Date
Parship Chowdhury 7c240e5828
Add support for sonatype nancy vulnerability scanning (#153)
* added sonatype nancy vulnerability scanning

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

* fix 1

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

* fix 2

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

* vulnerability check fixed

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

---------

Signed-off-by: Parship Chowdhury <i.am.parship@gmail.com>
2025-07-22 21:26:30 +08:00
Gautam Manchandani da2b3fbac8
added unit test for util package (#138)
Signed-off-by: GautamBytes <manchandanigautam@gmail.com>
2025-07-21 13:00:51 +08:00
Gautam Manchandani ebb124d8cd
updated actions and enhanced build process (#137)
Signed-off-by: GautamBytes <manchandanigautam@gmail.com>
2025-07-08 09:51:29 +08:00
Gautam Manchandani 68d571ec42
add Go module & build cache to speed up CI (#135)
Signed-off-by: GautamBytes <manchandanigautam@gmail.com>
Co-authored-by: Jeremy <hantmac@outlook.com>
2025-07-06 22:41:44 +08:00
Gautam Manchandani d973c2aa1d
verify go.mod & go.sum consistency in CI (#136)
Signed-off-by: GautamBytes <manchandanigautam@gmail.com>
2025-07-06 18:22:15 +08:00
Gautam Manchandani 94742398cd
support UnitedDeployment in kubectl-kruise rollout restart (#128)
Signed-off-by: GautamBytes <manchandanigautam@gmail.com>
2025-06-23 17:01:26 +08:00
Zhen Zhang 0fc1342e14
fix namespace setting (#127)
Signed-off-by: 守辰 <shouchen.zz@alibaba-inc.com>
2025-06-16 21:37:47 +08:00
Zhen Zhang c9efb12a8a
fix build problem by replace go dependency (#125)
Signed-off-by: shouchen.zz <shouchen.zz@gmail.com>
Co-authored-by: shouchen.zz <shouchen.zz@gmail.com>
2025-06-06 23:03:31 +08:00
dependabot[bot] 60858fed19
Bump golang.org/x/net in the go_modules group across 1 directory (#123)
Bumps the go_modules group with 1 update in the / directory: [golang.org/x/net](https://github.com/golang/net).


Updates `golang.org/x/net` from 0.33.0 to 0.38.0
- [Commits](https://github.com/golang/net/compare/v0.33.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.38.0
  dependency-type: indirect
  dependency-group: go_modules
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-05-15 16:00:11 +08:00
Vaibhav K f3a7f4bd33
add kubectl kruise get all command (#119)
* feat/cmd: add support for kruise get all command

Signed-off-by: Vaibhav <vaibhaavv8@gmail.com>

* add viewer for crr, cronjob, Resource Distribution, United Deployments, Broadcast

Signed-off-by: Vaibhav <vaibhaavv8@gmail.com>

* add viewer for sidecar, podprobe, imagepull, podBudget

Signed-off-by: Vaibhav <vaibhaavv8@gmail.com>

* fix golangci-lint

Signed-off-by: Vaibhav <vaibhaavv8@gmail.com>

---------

Signed-off-by: Vaibhav <vaibhaavv8@gmail.com>
2025-05-15 15:57:49 +08:00
Zhen Zhang b8db027748
update kruise-api to 1.8.0 (#124)
Signed-off-by: 守辰 <shouchen.zz@alibaba-inc.com>
2025-04-21 14:21:27 +08:00
Harkirat Singh 82ce71b931
feat: add support for blue-green in describe rollout (#122)
Signed-off-by: Harkirat Singh <multaniharry714@gmail.com>
2025-03-20 19:25:06 +08:00
Ai Ranthem 791f2b6075
Feature: rollout undo command supports fast rollback (#117)
* add rollout rollback command
* generate doc
* update ci
---------

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2025-03-12 19:30:07 +08:00
dependabot[bot] a4fc9a3051
Bump golang.org/x/net from 0.24.0 to 0.33.0 (#116)
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.24.0 to 0.33.0.
- [Commits](https://github.com/golang/net/compare/v0.24.0...v0.33.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 16:29:09 +08:00
Ai Ranthem 355ed0a11a
can approve blue-green release (#115)
Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2025-02-07 13:01:23 +08:00
Kiraat f422c7d1cd
feat: show pods related to current step of the Rollout in describe cmd (#111)
* feat: show pods related to current step of the Rollout in describe cmd

Signed-off-by: maanugh <manusin46@gmail.com>
2025-01-30 08:32:58 +08:00
myname4423 2d0a16f996
fix a rollout version bug (#113)
Signed-off-by: yunbo <yunbo10124scut@gmail.com>
Co-authored-by: yunbo <yunbo10124scut@gmail.com>
2024-12-09 14:55:15 +08:00
Kiraat 9d68939d6c
feat: add support for v1alpha1 resources (#112)
* feat: add support for v1alpha1 resources

Signed-off-by: maanugh <manusin46@gmail.com>
2024-11-26 09:54:59 +08:00
Kiraat 631fde0936
feat: add support for describe command (#96)
* feat: add support for rollout describe command

Signed-off-by: maanugh <manusin46@gmail.com>
2024-11-13 09:40:47 +08:00
hantmac cafa34158f fix 2024-11-11 09:38:37 +08:00
hantmac 6193994cfe fix 2024-11-11 09:38:37 +08:00
hantmac 7935dd511e fix 2024-11-11 09:38:37 +08:00
hantmac 33d8021ea2 fix: ci download sha256 file
Signed-off-by: hantmac <hantmac@outlook.com>
2024-11-11 09:38:37 +08:00
Jeremy 93a0cefcfd
fix: shasum file in release ci (#109) 2024-11-06 15:29:22 +08:00
Jeremy 7b60eae6d4
fix: add release tag in assert name (#108) 2024-11-06 15:13:22 +08:00
Ai Ranthem ea79dee83f
update dependencies (#106)
* update dependencies

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

* update workflow go version

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

---------

Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
Co-authored-by: Jeremy <hantmac@outlook.com>
2024-11-05 09:01:41 +08:00
dependabot[bot] 039650b77e
Bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 (#107)
Bumps [github.com/golang-jwt/jwt/v4](https://github.com/golang-jwt/jwt) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/golang-jwt/jwt/releases)
- [Changelog](https://github.com/golang-jwt/jwt/blob/main/VERSION_HISTORY.md)
- [Commits](https://github.com/golang-jwt/jwt/compare/v4.5.0...v4.5.1)

---
updated-dependencies:
- dependency-name: github.com/golang-jwt/jwt/v4
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-05 08:39:18 +08:00
Ai Ranthem a1f4d247e2
support both rollout api v1beta1 and v1alpha1 (#105)
Signed-off-by: AiRanthem <zhongtianyun.zty@alibaba-inc.com>
2024-10-29 17:16:32 +08:00
88 changed files with 2947 additions and 1173 deletions

View File

@ -12,48 +12,112 @@ on:
env:
# Common versions
GO_VERSION: '1.18'
GOLANGCI_VERSION: 'v1.51'
GO_VERSION: '1.23'
GOLANGCI_VERSION: 'v1.55.2'
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@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Verify go.mod is tidy
run: |
go mod tidy
if [ -n "$(git status --porcelain go.mod go.sum)" ]; then
echo "go.mod or go.sum is not tidy"
git diff go.mod go.sum
exit 1
fi
- 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') }}
restore-keys: ${{ runner.os }}-go-
- name: Lint golang code
uses: golangci/golangci-lint-action@v3.5.0
uses: golangci/golangci-lint-action@2226d7cb06a077cd73e56eedd38eecad18e5d837 # v6.5.0
with:
version: ${{ env.GOLANGCI_VERSION }}
args: --verbose
build-and-test:
name: ci-build
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@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Cache Go modules and build cache
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: |
~/go/pkg/mod
~/.cache/go-build
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-
- name: Verify go.mod is tidy
run: |
go mod tidy
if [ -n "$(git status --porcelain go.mod go.sum)" ]; then
echo "go.mod or go.sum is not tidy"
git diff go.mod go.sum
exit 1
fi
- name: Build
run: |
make build
- name: Test
run: |
make test
security-scan:
name: Security Vulnerability Scan
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
submodules: true
- name: Setup Go
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Cache Go Dependencies
uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-
- name: Generate go.list file for Nancy
run: go list -json -deps ./... > go.list
- name: Run Nancy vulnerability scan
uses: sonatype-nexus-community/nancy-github-action@main
with:
nancyCommand: sleuth
goListFile: go.list
- name: Install and run govulncheck
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...

View File

@ -6,111 +6,145 @@ on:
- created
env:
# Common versions
GO_VERSION: '1.18'
GO_VERSION: '1.22'
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
build_and_upload:
runs-on: ubuntu-20.04
runs-on: ubuntu-24.04
strategy:
matrix:
TARGETS: [ linux/amd64, darwin/amd64, windows/amd64, linux/arm64, darwin/arm64 ]
include:
- os: linux
arch: amd64
- os: linux
arch: arm64
- os: darwin
arch: amd64
- os: darwin
arch: arm64
- os: windows
arch: amd64
env:
GO_BUILD_ENV: GO111MODULE=on CGO_ENABLED=0
DIST_DIRS: find * -type d -exec
steps:
- uses: actions/checkout@v4
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
fetch-depth: 0 # Needed for version.sh to work properly
- name: Setup Go
uses: actions/setup-go@v4
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
with:
go-version: ${{ env.GO_VERSION }}
- name: Get release
id: get_release
uses: bruceadams/get-release@v1.2.2
- name: Get matrix
id: get_matrix
run: |
TARGETS=${{matrix.TARGETS}}
echo ::set-output name=OS::${TARGETS%/*}
echo ::set-output name=ARCH::${TARGETS#*/}
cache: true # Enable built-in Go caching
- name: Get ldflags
id: get_ldflags
run: |
LDFLAGS=$(./version.sh)
echo "LDFLAGS=${LDFLAGS}" >> $GITHUB_ENV
- name: Build
echo "LDFLAGS=${LDFLAGS}" >> $GITHUB_OUTPUT
- name: Build kubectl-kruise
run: |
${{ env.GO_BUILD_ENV }} GOOS=${{ steps.get_matrix.outputs.OS }} GOARCH=${{ steps.get_matrix.outputs.ARCH }} \
go build -ldflags "${{ env.LDFLAGS }}" \
-o _bin/kubectl-kruise/${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}/kubectl-kruise -v \
${{ env.GO_BUILD_ENV }} GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} \
go build -ldflags "${{ steps.get_ldflags.outputs.LDFLAGS }}" \
-o _bin/kubectl-kruise/${{ matrix.os }}-${{ matrix.arch }}/kubectl-kruise${{ matrix.os == 'windows' && '.exe' || '' }} \
./cmd/plugin/main.go
- name: Compress
run: |
cd _bin/kubectl-kruise && \
${{ env.DIST_DIRS }} cp ../../LICENSE {} \; && \
${{ env.DIST_DIRS }} cp ../../README.md {} \; && \
${{ env.DIST_DIRS }} tar -zcf kubectl-kruise-{}.tar.gz {} \; && \
cd .. && \
sha256sum kubectl-kruise/kubectl-kruise-* >> sha256-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.txt \
- name: Upload Kubectl-kruise tar.gz
uses: actions/upload-release-asset@v1.0.2
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: ./_bin/kubectl-kruise/kubectl-kruise-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz
asset_name: kubectl-kruise-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz
asset_content_type: binary/octet-stream
- name: Build resourcedistribution-generator
run: |
${{ env.GO_BUILD_ENV }} GOOS=${{ steps.get_matrix.outputs.OS }} GOARCH=${{ steps.get_matrix.outputs.ARCH }} \
go build -ldflags "${{ env.LDFLAGS }}" \
-o _bin/resourcedistribution-generator/${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}/resourcedistributiongenerator -v \
${{ env.GO_BUILD_ENV }} GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} \
go build -ldflags "${{ steps.get_ldflags.outputs.LDFLAGS }}" \
-o _bin/resourcedistribution-generator/${{ matrix.os }}-${{ matrix.arch }}/resourcedistributiongenerator${{ matrix.os == 'windows' && '.exe' || '' }} \
./cmd/resourcedistributiongenerator/main.go
- name: Compress resourcedistribution-generator
- name: Package artifacts
run: |
cd _bin/resourcedistribution-generator && \
${{ env.DIST_DIRS }} tar -zcf resourcedistribution-generator-{}.tar.gz {} \; && \
cd .. && \
sha256sum resourcedistribution-generator/resourcedistribution-generator-* >> sha256-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.txt \
- name: Upload resourcedistribution-generator tar.gz
uses: actions/upload-release-asset@v1.0.2
# Package kubectl-kruise
cd _bin/kubectl-kruise/${{ matrix.os }}-${{ matrix.arch }}
cp ../../../LICENSE .
cp ../../../README.md .
if [ "${{ matrix.os }}" = "windows" ]; then
zip -r kubectl-kruise-${{ matrix.os }}-${{ matrix.arch }}.zip .
else
tar -czf kubectl-kruise-${{ matrix.os }}-${{ matrix.arch }}.tar.gz .
fi
cd ../../..
# Package resourcedistribution-generator
cd _bin/resourcedistribution-generator/${{ matrix.os }}-${{ matrix.arch }}
if [ "${{ matrix.os }}" = "windows" ]; then
zip -r resourcedistribution-generator-${{ matrix.os }}-${{ matrix.arch }}.zip .
else
tar -czf resourcedistribution-generator-${{ matrix.os }}-${{ matrix.arch }}.tar.gz .
fi
cd ../../..
- name: Generate checksums
run: |
cd _bin
find . -name "*.tar.gz" -o -name "*.zip" | xargs sha256sum > sha256-${{ matrix.os }}-${{ matrix.arch }}.txt
- name: Upload checksums artifact
uses: actions/upload-artifact@v4.4.3
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: ./_bin/resourcedistribution-generator/resourcedistribution-generator-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz
asset_name: resourcedistribution-generator-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.tar.gz
asset_content_type: binary/octet-stream
- name: Post sha256
uses: actions/upload-artifact@v4
with:
name: sha256sums
path: ./_bin/sha256-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}.txt
name: sha256sums-${{ matrix.os }}-${{ matrix.arch }}
path: _bin/sha256-${{ matrix.os }}-${{ matrix.arch }}.txt
retention-days: 1
upload-sha256sums-plugin:
- name: Upload build artifacts
uses: actions/upload-artifact@v4.4.3
with:
name: binaries-${{ matrix.os }}-${{ matrix.arch }}
path: |
_bin/kubectl-kruise/${{ matrix.os }}-${{ matrix.arch }}/*.tar.gz
_bin/kubectl-kruise/${{ matrix.os }}-${{ matrix.arch }}/*.zip
_bin/resourcedistribution-generator/${{ matrix.os }}-${{ matrix.arch }}/*.tar.gz
_bin/resourcedistribution-generator/${{ matrix.os }}-${{ matrix.arch }}/*.zip
retention-days: 1
upload-release-assets:
needs: build_and_upload
runs-on: ubuntu-latest
name: upload-sha256sums
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Get release
id: get_release
uses: bruceadams/get-release@v1.2.2
- name: Download sha256sums
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Download all artifacts
uses: actions/download-artifact@v4.1.7
with:
name: sha256sums
- shell: bash
pattern: "*"
merge-multiple: true
path: artifacts
- name: Prepare release assets
run: |
for file in *.txt
do
cat ${file} >> sha256sums.txt
mkdir -p release-assets
# Move binary archives to release assets
find artifacts -name "*.tar.gz" -o -name "*.zip" | while read file; do
filename=$(basename "$file")
# Add version tag to filename
name_part="${filename%.*}"
ext="${filename##*.}"
if [[ "$filename" == *.tar.gz ]]; then
ext="tar.gz"
name_part="${filename%.tar.gz}"
fi
cp "$file" "release-assets/${name_part}-${GITHUB_REF_NAME}.${ext}"
done
- name: Upload Checksums
uses: actions/upload-release-asset@v1.0.2
# Combine all checksums
cat artifacts/sha256-*.txt > release-assets/sha256sums-${GITHUB_REF_NAME}.txt
- name: Upload release assets
uses: softprops/action-gh-release@v2.0.8
with:
upload_url: ${{ steps.get_release.outputs.upload_url }}
asset_path: sha256sums.txt
asset_name: sha256sums.txt
asset_content_type: text/plain
files: release-assets/*
fail_on_unmatched_files: true
- name: Update kubectl plugin version in krew-index
uses: rajatjindal/krew-release-bot@v0.0.43
uses: rajatjindal/krew-release-bot@v0.0.46

3
.nancy-ignore Normal file
View File

@ -0,0 +1,3 @@
# Temporary exclusion - proxy/tokenizer vulnerabilities don't affect our usage
CVE-2025-22870
CVE-2025-22872

View File

@ -103,6 +103,9 @@ $ kubectl kruise rollout approve rollout/rollout-demo -n ns-demo`
# undo a kruise rollout resource
$ kubectl kruise rollout undo rollout/rollout-demo
# Fast rollback during blue-green release (will go back to a previous step with no traffic and most replicas)
$ kubectl kruise rollout undo rollout/rollout-demo --fast
```
### set
@ -195,6 +198,60 @@ kubectl kruise migrate CloneSet --from Deployment --src-name deployment-demo --d
#### kubectl kruise autoscale SUBCOMMAND [options]
* [ ] kubectl kruise autoscale
## Security
This project includes automated vulnerability scanning to ensure the security of dependencies.
### Vulnerability Scanning
We use two complementary tools to scan for vulnerabilities in our Go dependencies:
1. **Nancy by Sonatype** - Comprehensive dependency scanning against the Sonatype OSS Index
2. **govulncheck** - Official Go vulnerability scanner with call graph analysis to reduce false positives
### CI/CD Security Integration
Security scans are automatically run:
- On every push to `master` and `release*` branches
- On every pull request
- Daily at 2 AM UTC via scheduled workflow
### Handling Vulnerabilities
If vulnerabilities are found:
1. **Review the vulnerability report** - Check if the vulnerability affects your usage
2. **Update dependencies** - Upgrade to a non-vulnerable version if available
3. **Apply workarounds** - If no update is available, consider alternative approaches
4. **Temporary exclusions** - For false positives or accepted risks, add the CVE ID to `.nancy-ignore`
#### Excluding Vulnerabilities
To exclude specific vulnerabilities from Nancy scans, add the CVE ID or OSS Index ID to the `.nancy-ignore` file:
```
# Example: Exclude a specific CVE
CVE-2021-12345
# Example: Exclude by OSS Index ID
9eb9a5bc-8310-4104-bf85-3a820d28ba79
```
### Running Security Scans Locally
To run vulnerability scans locally:
```bash
# Install tools
go install github.com/sonatype-nexus-community/nancy@latest
go install golang.org/x/vuln/cmd/govulncheck@latest
# Run Nancy scan
go list -json -deps ./... > go.list
nancy sleuth --loud
# Run govulncheck
govulncheck ./...
```
### Contributing
We encourage you to help out by reporting issues, improving documentation, fixing bugs, or adding new features.

View File

@ -24,6 +24,7 @@ kubectl-kruise [flags]
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
-h, --help help for kubectl-kruise
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
@ -44,9 +45,11 @@ kubectl-kruise [flags]
### SEE ALSO
* [kubectl-kruise create](kubectl-kruise_create.md) - Create a resource from a file or from stdin.
* [kubectl-kruise describe](kubectl-kruise_describe.md) - Show details of a specific resource or group of resources
* [kubectl-kruise expose](kubectl-kruise_expose.md) - Take a workload(e.g. deployment, cloneset), service or pod and expose it as a new Kubernetes Service
* [kubectl-kruise migrate](kubectl-kruise_migrate.md) - Migrate from K8s original workloads to Kruise workloads
* [kubectl-kruise rollout](kubectl-kruise_rollout.md) - Manage the rollout of a resource
* [kubectl-kruise scaledown](kubectl-kruise_scaledown.md) - Scaledown a cloneset with selective Pods
* [kubectl-kruise set](kubectl-kruise_set.md) - Set specific features on objects
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -42,7 +42,7 @@ kubectl-kruise create -f FILENAME
-l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
--show-managed-fields If true, keep the managedFields when printing objects in JSON or YAML format.
--template string Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
--validate string Must be one of: strict (or true), warn, ignore (or false).
--validate string[="strict"] Must be one of: strict (or true), warn, ignore (or false).
"true" or "strict" will use a schema to validate the input and fail the request if invalid. It will perform server side validation if ServerSideFieldValidation is enabled on the api-server, but will fall back to less reliable client-side validation if not.
"warn" will warn about unknown or duplicate fields without blocking the request if server-side field validation is enabled on the API server, and behave as "ignore" otherwise.
"false" or "ignore" will not perform any schema validation, silently dropping any unknown or duplicate fields. (default "strict")
@ -61,6 +61,7 @@ kubectl-kruise create -f FILENAME
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -84,3 +85,4 @@ kubectl-kruise create -f FILENAME
* [kubectl-kruise create broadcastJob](kubectl-kruise_create_broadcastJob.md) - Create a broadcastJob with the specified name.
* [kubectl-kruise create job](kubectl-kruise_create_job.md) - Create a job with the specified name.
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -45,7 +45,7 @@ kubectl-kruise create ContainerRecreateRequest NAME --pod=podName [--containers=
--show-managed-fields If true, keep the managedFields when printing objects in JSON or YAML format.
--template string Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
-u, --unreadyGracePeriodSeconds int UnreadyGracePeriodSeconds is the optional duration in seconds to mark Pod as not ready over this duration before executing preStop hook and stopping the container
--validate string Must be one of: strict (or true), warn, ignore (or false).
--validate string[="strict"] Must be one of: strict (or true), warn, ignore (or false).
"true" or "strict" will use a schema to validate the input and fail the request if invalid. It will perform server side validation if ServerSideFieldValidation is enabled on the api-server, but will fall back to less reliable client-side validation if not.
"warn" will warn about unknown or duplicate fields without blocking the request if server-side field validation is enabled on the API server, and behave as "ignore" otherwise.
"false" or "ignore" will not perform any schema validation, silently dropping any unknown or duplicate fields. (default "strict")
@ -63,6 +63,7 @@ kubectl-kruise create ContainerRecreateRequest NAME --pod=podName [--containers=
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -83,3 +84,4 @@ kubectl-kruise create ContainerRecreateRequest NAME --pod=podName [--containers=
* [kubectl-kruise create](kubectl-kruise_create.md) - Create a resource from a file or from stdin.
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -36,7 +36,7 @@ kubectl-kruise create broadcastJob NAME --image=image [--from=cronjob/name] -- [
--save-config If true, the configuration of current object will be saved in its annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.
--show-managed-fields If true, keep the managedFields when printing objects in JSON or YAML format.
--template string Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
--validate string Must be one of: strict (or true), warn, ignore (or false).
--validate string[="strict"] Must be one of: strict (or true), warn, ignore (or false).
"true" or "strict" will use a schema to validate the input and fail the request if invalid. It will perform server side validation if ServerSideFieldValidation is enabled on the api-server, but will fall back to less reliable client-side validation if not.
"warn" will warn about unknown or duplicate fields without blocking the request if server-side field validation is enabled on the API server, and behave as "ignore" otherwise.
"false" or "ignore" will not perform any schema validation, silently dropping any unknown or duplicate fields. (default "strict")
@ -54,6 +54,7 @@ kubectl-kruise create broadcastJob NAME --image=image [--from=cronjob/name] -- [
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -74,3 +75,4 @@ kubectl-kruise create broadcastJob NAME --image=image [--from=cronjob/name] -- [
* [kubectl-kruise create](kubectl-kruise_create.md) - Create a resource from a file or from stdin.
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -36,7 +36,7 @@ kubectl-kruise create job NAME --image=image [--from=cronjob/name] -- [COMMAND]
--save-config If true, the configuration of current object will be saved in its annotation. Otherwise, the annotation will be unchanged. This flag is useful when you want to perform kubectl apply on this object in the future.
--show-managed-fields If true, keep the managedFields when printing objects in JSON or YAML format.
--template string Template string or path to template file to use when -o=go-template, -o=go-template-file. The template format is golang templates [http://golang.org/pkg/text/template/#pkg-overview].
--validate string Must be one of: strict (or true), warn, ignore (or false).
--validate string[="strict"] Must be one of: strict (or true), warn, ignore (or false).
"true" or "strict" will use a schema to validate the input and fail the request if invalid. It will perform server side validation if ServerSideFieldValidation is enabled on the api-server, but will fall back to less reliable client-side validation if not.
"warn" will warn about unknown or duplicate fields without blocking the request if server-side field validation is enabled on the API server, and behave as "ignore" otherwise.
"false" or "ignore" will not perform any schema validation, silently dropping any unknown or duplicate fields. (default "strict")
@ -54,6 +54,7 @@ kubectl-kruise create job NAME --image=image [--from=cronjob/name] -- [COMMAND]
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -74,3 +75,4 @@ kubectl-kruise create job NAME --image=image [--from=cronjob/name] -- [COMMAND]
* [kubectl-kruise create](kubectl-kruise_create.md) - Create a resource from a file or from stdin.
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -0,0 +1,60 @@
## kubectl-kruise describe
Show details of a specific resource or group of resources
### Synopsis
Show details of a rollout.
```
kubectl-kruise describe SUBCOMMAND
```
### Examples
```
# Describe the rollout named rollout-demo
kubectl-kruise describe rollout rollout-demo
```
### Options
```
-h, --help help for describe
```
### Options inherited from parent commands
```
--as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace.
--as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
--as-uid string UID to impersonate for the operation.
--cache-dir string Default cache directory (default "$HOME/.kube/cache")
--certificate-authority string Path to a cert file for the certificate authority
--client-certificate string Path to a client certificate file for TLS
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
-n, --namespace string If present, the namespace scope for this CLI request
--password string Password for basic authentication to the API server
--profile string Name of profile to capture. One of (none|cpu|heap|goroutine|threadcreate|block|mutex) (default "none")
--profile-output string Name of the file to write the profile to (default "profile.pprof")
--request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
-s, --server string The address and port of the Kubernetes API server
--tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used
--token string Bearer token for authentication to the API server
--user string The name of the kubeconfig user to use
--username string Username for basic authentication to the API server
--warnings-as-errors Treat warnings received from the server as errors and exit with a non-zero exit code
```
### SEE ALSO
* [kubectl-kruise](kubectl-kruise.md) - kubectl-kruise controls the OpenKruise CRs
* [kubectl-kruise describe rollout](kubectl-kruise_describe_rollout.md) - Get details about a rollout
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -0,0 +1,66 @@
## kubectl-kruise describe rollout
Get details about a rollout
### Synopsis
Get details about and visual representation of a rollout.
```
kubectl-kruise describe rollout SUBCOMMAND
```
### Examples
```
# Describe the rollout named rollout-demo within namespace default
kubectl-kruise describe rollout rollout-demo/default
# Watch for changes to the rollout named rollout-demo
kubectl-kruise describe rollout rollout-demo/default -w
```
### Options
```
--all Show all pods in the rollout
-h, --help help for rollout
--no-color If true, print output without color
--timeout int Timeout after specified seconds
-w, --watch Watch for changes to the rollout
```
### Options inherited from parent commands
```
--as string Username to impersonate for the operation. User could be a regular user or a service account in a namespace.
--as-group stringArray Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
--as-uid string UID to impersonate for the operation.
--cache-dir string Default cache directory (default "$HOME/.kube/cache")
--certificate-authority string Path to a cert file for the certificate authority
--client-certificate string Path to a client certificate file for TLS
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
-n, --namespace string If present, the namespace scope for this CLI request
--password string Password for basic authentication to the API server
--profile string Name of profile to capture. One of (none|cpu|heap|goroutine|threadcreate|block|mutex) (default "none")
--profile-output string Name of the file to write the profile to (default "profile.pprof")
--request-timeout string The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests. (default "0")
-s, --server string The address and port of the Kubernetes API server
--tls-server-name string Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used
--token string Bearer token for authentication to the API server
--user string The name of the kubeconfig user to use
--username string Username for basic authentication to the API server
--warnings-as-errors Treat warnings received from the server as errors and exit with a non-zero exit code
```
### SEE ALSO
* [kubectl-kruise describe](kubectl-kruise_describe.md) - Show details of a specific resource or group of resources
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -85,6 +85,7 @@ kubectl-kruise expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UD
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -105,3 +106,4 @@ kubectl-kruise expose (-f FILENAME | TYPE NAME) [--port=port] [--protocol=TCP|UD
* [kubectl-kruise](kubectl-kruise.md) - kubectl-kruise controls the OpenKruise CRs
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -51,6 +51,7 @@ kubectl-kruise migrate [DST_KIND] --from [SRC_KIND] [flags]
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -71,3 +72,4 @@ kubectl-kruise migrate [DST_KIND] --from [SRC_KIND] [flags]
* [kubectl-kruise](kubectl-kruise.md) - kubectl-kruise controls the OpenKruise CRs
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -8,13 +8,13 @@ Manage the rollout of a resource.
Valid resource types include:
* deployments
* daemonsets
* statefulsets
* clonesets
* statefulsets.apps.kruise.io
* daemonsets.apps.kruise.io
* rollouts.rollouts.kruise.io
* deployments
* daemonsets
* statefulsets
* clonesets
* statefulsets.apps.kruise.io
* daemonsets.apps.kruise.io
* rollouts.rollouts.kruise.io
```
kubectl-kruise rollout SUBCOMMAND
@ -48,6 +48,7 @@ kubectl-kruise rollout SUBCOMMAND
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -75,3 +76,4 @@ kubectl-kruise rollout SUBCOMMAND
* [kubectl-kruise rollout status](kubectl-kruise_rollout_status.md) - Show the status of the rollout
* [kubectl-kruise rollout undo](kubectl-kruise_rollout_undo.md) - Undo a previous rollout
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -17,7 +17,7 @@ kubectl-kruise rollout approve RESOURCE
```
# approve a kruise rollout resource named "rollout-demo" in "ns-demo" namespace
kubectl-kruise rollout approve rollout-demo -n ns-demo
kubectl-kruise rollout approve rollout/rollout-demo -n ns-demo
```
### Options
@ -45,6 +45,7 @@ kubectl-kruise rollout approve RESOURCE
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -65,3 +66,4 @@ kubectl-kruise rollout approve RESOURCE
* [kubectl-kruise rollout](kubectl-kruise_rollout.md) - Manage the rollout of a resource
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -49,6 +49,7 @@ kubectl-kruise rollout history (TYPE NAME | TYPE/NAME) [flags]
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -69,3 +70,4 @@ kubectl-kruise rollout history (TYPE NAME | TYPE/NAME) [flags]
* [kubectl-kruise rollout](kubectl-kruise_rollout.md) - Manage the rollout of a resource
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -47,6 +47,7 @@ kubectl-kruise rollout pause RESOURCE
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -67,3 +68,4 @@ kubectl-kruise rollout pause RESOURCE
* [kubectl-kruise rollout](kubectl-kruise_rollout.md) - Manage the rollout of a resource
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -6,7 +6,8 @@ Restart a resource
Restart a resource.
Resource will be rollout restarted.
Resource will be rollout restarted. Supported kinds include:
CloneSet, DaemonSet, Deployment, StatefulSet, and UnitedDeployment.
```
kubectl-kruise rollout restart RESOURCE
@ -21,6 +22,9 @@ kubectl-kruise rollout restart RESOURCE
# Restart a daemonset
kubectl-kruise rollout restart daemonset/abc
# Restart a UnitedDeployment
kubectl-kruise rollout restart uniteddeployment/my-app
```
### Options
@ -48,6 +52,7 @@ kubectl-kruise rollout restart RESOURCE
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -68,3 +73,4 @@ kubectl-kruise rollout restart RESOURCE
* [kubectl-kruise rollout](kubectl-kruise_rollout.md) - Manage the rollout of a resource
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -47,6 +47,7 @@ kubectl-kruise rollout resume RESOURCE
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -67,3 +68,4 @@ kubectl-kruise rollout resume RESOURCE
* [kubectl-kruise rollout](kubectl-kruise_rollout.md) - Manage the rollout of a resource
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -50,6 +50,7 @@ kubectl-kruise rollout status (TYPE NAME | TYPE/NAME) [flags]
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -70,3 +71,4 @@ kubectl-kruise rollout status (TYPE NAME | TYPE/NAME) [flags]
* [kubectl-kruise rollout](kubectl-kruise_rollout.md) - Manage the rollout of a resource
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -27,6 +27,9 @@ kubectl-kruise rollout undo (TYPE NAME | TYPE/NAME) [flags]
# Rollback to workload via rollout api object
kubectl-kruise rollout undo rollout/abc
# Fast rollback during blue-green release (will go back to a previous step with no traffic and most replicas)
kubectl-kruise rollout undo rollout/abc --fast
```
### Options
@ -34,6 +37,7 @@ kubectl-kruise rollout undo (TYPE NAME | TYPE/NAME) [flags]
```
--allow-missing-template-keys If true, ignore any errors in templates when a field or map key is missing in the template. Only applies to golang and jsonpath output formats. (default true)
--dry-run string[="unchanged"] Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource. (default "none")
--fast fast rollback for blue-green release
-f, --filename strings Filename, directory, or URL to files identifying the resource to get from a server.
-h, --help help for undo
-k, --kustomize string Process the kustomization directory. This flag can't be used together with -f or -R.
@ -56,6 +60,7 @@ kubectl-kruise rollout undo (TYPE NAME | TYPE/NAME) [flags]
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -76,3 +81,4 @@ kubectl-kruise rollout undo (TYPE NAME | TYPE/NAME) [flags]
* [kubectl-kruise rollout](kubectl-kruise_rollout.md) - Manage the rollout of a resource
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -38,6 +38,7 @@ kubectl-kruise scaledown [CLONESET] --pods [POD1,POD2] -n [NAMESPACE]
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -58,3 +59,4 @@ kubectl-kruise scaledown [CLONESET] --pods [POD1,POD2] -n [NAMESPACE]
* [kubectl-kruise](kubectl-kruise.md) - kubectl-kruise controls the OpenKruise CRs
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -30,6 +30,7 @@ kubectl-kruise set SUBCOMMAND
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -56,3 +57,4 @@ kubectl-kruise set SUBCOMMAND
* [kubectl-kruise set serviceaccount](kubectl-kruise_set_serviceaccount.md) - Update ServiceAccount of a resource
* [kubectl-kruise set subject](kubectl-kruise_set_subject.md) - Update User, Group or ServiceAccount in a RoleBinding/ClusterRoleBinding
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -12,7 +12,7 @@ Update environment variables on a pod template.
Possible resources include (case insensitive):
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
```
kubectl-kruise set env RESOURCE/NAME KEY_1=VAL_1 ... KEY_N=VAL_N
@ -93,6 +93,7 @@ kubectl-kruise set env RESOURCE/NAME KEY_1=VAL_1 ... KEY_N=VAL_N
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -113,3 +114,4 @@ kubectl-kruise set env RESOURCE/NAME KEY_1=VAL_1 ... KEY_N=VAL_N
* [kubectl-kruise set](kubectl-kruise_set.md) - Set specific features on objects
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -8,7 +8,7 @@ Update existing container image(s) of resources.
Possible resources include (case insensitive):
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
```
kubectl-kruise set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N
@ -59,6 +59,7 @@ kubectl-kruise set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IM
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -79,3 +80,4 @@ kubectl-kruise set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IM
* [kubectl-kruise set](kubectl-kruise_set.md) - Set specific features on objects
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -10,7 +10,7 @@ Specify compute resource requirements (cpu, memory) for any resource that define
Possible resources include (case insensitive):
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
```
kubectl-kruise set resources (-f FILENAME | TYPE NAME) ([--limits=LIMITS & --requests=REQUESTS]
@ -64,6 +64,7 @@ kubectl-kruise set resources (-f FILENAME | TYPE NAME) ([--limits=LIMITS & --re
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -84,3 +85,4 @@ kubectl-kruise set resources (-f FILENAME | TYPE NAME) ([--limits=LIMITS & --re
* [kubectl-kruise set](kubectl-kruise_set.md) - Set specific features on objects
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -6,7 +6,7 @@ Set the selector on a resource
Set the selector on a resource. Note that the new selector will overwrite the old selector if the resource had one prior to the invocation of 'set selector'.
A selector must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to 63 characters. If --resource-version is specified, then updates will use this resource version, otherwise the existing resource-version will be used. Note: currently selectors can only be set on Service objects.
A selector must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to 63 characters. If --resource-version is specified, then updates will use this resource version, otherwise the existing resource-version will be used. Note: currently selectors can only be set on Service objects.
```
kubectl-kruise set selector (-f FILENAME | TYPE NAME) EXPRESSIONS [--resource-version=version]
@ -48,6 +48,7 @@ kubectl-kruise set selector (-f FILENAME | TYPE NAME) EXPRESSIONS [--resource-ve
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -68,3 +69,4 @@ kubectl-kruise set selector (-f FILENAME | TYPE NAME) EXPRESSIONS [--resource-ve
* [kubectl-kruise set](kubectl-kruise_set.md) - Set specific features on objects
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -52,6 +52,7 @@ kubectl-kruise set serviceaccount (-f FILENAME | TYPE NAME) SERVICE_ACCOUNT
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -72,3 +73,4 @@ kubectl-kruise set serviceaccount (-f FILENAME | TYPE NAME) SERVICE_ACCOUNT
* [kubectl-kruise set](kubectl-kruise_set.md) - Set specific features on objects
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -55,6 +55,7 @@ kubectl-kruise set subject (-f FILENAME | TYPE NAME) [--user=username] [--group=
--client-key string Path to a client key file for TLS
--cluster string The name of the kubeconfig cluster to use
--context string The name of the kubeconfig context to use
--disable-compression If true, opt-out of response compression for all requests to the server
--insecure-skip-tls-verify If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
--match-server-version Require server version to match client version
@ -74,3 +75,4 @@ kubectl-kruise set subject (-f FILENAME | TYPE NAME) [--user=username] [--group=
* [kubectl-kruise set](kubectl-kruise_set.md) - Set specific features on objects
###### Auto generated by spf13/cobra on 12-Mar-2025

View File

@ -28,6 +28,10 @@ options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: help
shorthand: h
default_value: "false"
@ -75,6 +79,7 @@ options:
Treat warnings received from the server as errors and exit with a non-zero exit code
see_also:
- kubectl-kruise create - Create a resource from a file or from stdin.
- kubectl-kruise describe - Show details of a specific resource or group of resources
- kubectl-kruise expose - Take a workload(e.g. deployment, cloneset), service or pod and expose it as a new Kubernetes Service
- kubectl-kruise migrate - Migrate from K8s original workloads to Kruise workloads
- kubectl-kruise rollout - Manage the rollout of a resource

View File

@ -98,6 +98,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -79,6 +79,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -68,6 +68,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -68,6 +68,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -0,0 +1,83 @@
name: kubectl-kruise describe
synopsis: Show details of a specific resource or group of resources
description: Show details of a rollout.
usage: kubectl-kruise describe SUBCOMMAND
options:
- name: help
shorthand: h
default_value: "false"
usage: help for describe
inherited_options:
- name: as
usage: |
Username to impersonate for the operation. User could be a regular user or a service account in a namespace.
- name: as-group
default_value: '[]'
usage: |
Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
- name: as-uid
usage: UID to impersonate for the operation.
- name: cache-dir
default_value: $HOME/.kube/cache
usage: Default cache directory
- name: certificate-authority
usage: Path to a cert file for the certificate authority
- name: client-certificate
usage: Path to a client certificate file for TLS
- name: client-key
usage: Path to a client key file for TLS
- name: cluster
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |
If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
- name: kubeconfig
usage: Path to the kubeconfig file to use for CLI requests.
- name: match-server-version
default_value: "false"
usage: Require server version to match client version
- name: namespace
shorthand: "n"
usage: If present, the namespace scope for this CLI request
- name: password
usage: Password for basic authentication to the API server
- name: profile
default_value: none
usage: |
Name of profile to capture. One of (none|cpu|heap|goroutine|threadcreate|block|mutex)
- name: profile-output
default_value: profile.pprof
usage: Name of the file to write the profile to
- name: request-timeout
default_value: "0"
usage: |
The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests.
- name: server
shorthand: s
usage: The address and port of the Kubernetes API server
- name: tls-server-name
usage: |
Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used
- name: token
usage: Bearer token for authentication to the API server
- name: user
usage: The name of the kubeconfig user to use
- name: username
usage: Username for basic authentication to the API server
- name: warnings-as-errors
default_value: "false"
usage: |
Treat warnings received from the server as errors and exit with a non-zero exit code
example: |4-
# Describe the rollout named rollout-demo
kubectl-kruise describe rollout rollout-demo
see_also:
- kubectl-kruise - kubectl-kruise controls the OpenKruise CRs
- kubectl-kruise describe rollout - Get details about a rollout

View File

@ -0,0 +1,93 @@
name: kubectl-kruise describe rollout
synopsis: Get details about a rollout
description: Get details about and visual representation of a rollout.
usage: kubectl-kruise describe rollout SUBCOMMAND
options:
- name: all
default_value: "false"
usage: Show all pods in the rollout
- name: help
shorthand: h
default_value: "false"
usage: help for rollout
- name: no-color
default_value: "false"
usage: If true, print output without color
- name: timeout
default_value: "0"
usage: Timeout after specified seconds
- name: watch
shorthand: w
default_value: "false"
usage: Watch for changes to the rollout
inherited_options:
- name: as
usage: |
Username to impersonate for the operation. User could be a regular user or a service account in a namespace.
- name: as-group
default_value: '[]'
usage: |
Group to impersonate for the operation, this flag can be repeated to specify multiple groups.
- name: as-uid
usage: UID to impersonate for the operation.
- name: cache-dir
default_value: $HOME/.kube/cache
usage: Default cache directory
- name: certificate-authority
usage: Path to a cert file for the certificate authority
- name: client-certificate
usage: Path to a client certificate file for TLS
- name: client-key
usage: Path to a client key file for TLS
- name: cluster
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |
If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
- name: kubeconfig
usage: Path to the kubeconfig file to use for CLI requests.
- name: match-server-version
default_value: "false"
usage: Require server version to match client version
- name: namespace
shorthand: "n"
usage: If present, the namespace scope for this CLI request
- name: password
usage: Password for basic authentication to the API server
- name: profile
default_value: none
usage: |
Name of profile to capture. One of (none|cpu|heap|goroutine|threadcreate|block|mutex)
- name: profile-output
default_value: profile.pprof
usage: Name of the file to write the profile to
- name: request-timeout
default_value: "0"
usage: |
The length of time to wait before giving up on a single server request. Non-zero values should contain a corresponding time unit (e.g. 1s, 2m, 3h). A value of zero means don't timeout requests.
- name: server
shorthand: s
usage: The address and port of the Kubernetes API server
- name: tls-server-name
usage: |
Server name to use for server certificate validation. If it is not provided, the hostname used to contact the server is used
- name: token
usage: Bearer token for authentication to the API server
- name: user
usage: The name of the kubeconfig user to use
- name: username
usage: Username for basic authentication to the API server
- name: warnings-as-errors
default_value: "false"
usage: |
Treat warnings received from the server as errors and exit with a non-zero exit code
example: " # Describe the rollout named rollout-demo within namespace default\n kubectl-kruise describe rollout rollout-demo/default\n \n # Watch for changes to the rollout named rollout-demo\n kubectl-kruise describe rollout rollout-demo/default -w"
see_also:
- kubectl-kruise describe - Show details of a specific resource or group of resources

View File

@ -123,6 +123,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -52,6 +52,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -1,6 +1,6 @@
name: kubectl-kruise rollout
synopsis: Manage the rollout of a resource
description: "Manage the rollout of a resource.\n \n Valid resource types include:\n\n * deployments\n * daemonsets\n * statefulsets\n * clonesets\n * statefulsets.apps.kruise.io\n * daemonsets.apps.kruise.io\n * rollouts.rollouts.kruise.io"
description: "Manage the rollout of a resource.\n \n Valid resource types include:\n\n * deployments\n * daemonsets\n * statefulsets\n * clonesets\n * statefulsets.apps.kruise.io\n * daemonsets.apps.kruise.io\n * rollouts.rollouts.kruise.io"
usage: kubectl-kruise rollout SUBCOMMAND
options:
- name: help
@ -30,6 +30,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -62,6 +62,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |
@ -103,6 +107,6 @@ inherited_options:
default_value: "false"
usage: |
Treat warnings received from the server as errors and exit with a non-zero exit code
example: " # approve a kruise rollout resource named \"rollout-demo\" in \"ns-demo\" namespace\n \n kubectl-kruise rollout approve rollout-demo -n ns-demo"
example: " # approve a kruise rollout resource named \"rollout-demo\" in \"ns-demo\" namespace\n \n kubectl-kruise rollout approve rollout/rollout-demo -n ns-demo"
see_also:
- kubectl-kruise rollout - Manage the rollout of a resource

View File

@ -63,6 +63,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -62,6 +62,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -3,7 +3,7 @@ synopsis: Restart a resource
description: |-
Restart a resource.
Resource will be rollout restarted.
Resource will be rollout restarted.
usage: kubectl-kruise rollout restart RESOURCE
options:
- name: allow-missing-template-keys
@ -62,6 +62,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -62,6 +62,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -63,6 +63,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -11,6 +11,9 @@ options:
default_value: none
usage: |
Must be "none", "server", or "client". If client strategy, only print the object that would be sent, without sending it. If server strategy, submit server-side request without persisting the resource.
- name: fast
default_value: "false"
usage: fast rollback for blue-green release
- name: filename
shorthand: f
default_value: '[]'
@ -66,6 +69,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |
@ -107,6 +114,6 @@ inherited_options:
default_value: "false"
usage: |
Treat warnings received from the server as errors and exit with a non-zero exit code
example: " # Rollback to the previous cloneset\n kubectl-kruise rollout undo cloneset/abc\n \n # Rollback to the previous Advanced StatefulSet\n kubectl-kruise rollout undo asts/abc\n \n # Rollback to daemonset revision 3\n kubectl-kruise rollout undo daemonset/abc --to-revision=3\n \n # Rollback to the previous deployment with dry-run\n kubectl-kruise rollout undo --dry-run=server deployment/abc\n \n # Rollback to workload via rollout api object\n kubectl-kruise rollout undo rollout/abc"
example: " # Rollback to the previous cloneset\n kubectl-kruise rollout undo cloneset/abc\n \n # Rollback to the previous Advanced StatefulSet\n kubectl-kruise rollout undo asts/abc\n \n # Rollback to daemonset revision 3\n kubectl-kruise rollout undo daemonset/abc --to-revision=3\n \n # Rollback to the previous deployment with dry-run\n kubectl-kruise rollout undo --dry-run=server deployment/abc\n \n # Rollback to workload via rollout api object\n kubectl-kruise rollout undo rollout/abc\n \n # Fast rollback during blue-green release (will go back to a previous step with no traffic and most replicas)\n kubectl-kruise rollout undo rollout/abc --fast"
see_also:
- kubectl-kruise rollout - Manage the rollout of a resource

View File

@ -32,6 +32,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -33,6 +33,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -9,7 +9,7 @@ description: |-
Possible resources include (case insensitive):
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
usage: kubectl-kruise set env RESOURCE/NAME KEY_1=VAL_1 ... KEY_N=VAL_N
options:
- name: all
@ -114,6 +114,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -5,7 +5,7 @@ description: |-
Possible resources include (case insensitive):
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
usage: kubectl-kruise set image (-f FILENAME | TYPE NAME) CONTAINER_NAME_1=CONTAINER_IMAGE_1 ... CONTAINER_NAME_N=CONTAINER_IMAGE_N
options:
- name: all
@ -84,6 +84,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -8,7 +8,7 @@ description: |-
Possible resources include (case insensitive):
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
pod (po), deployment (deploy), statefulset (sts), daemonset (ds), replicaset (rs), cloneset (clone), statefulset.apps.kruise.io (asts), daemonset.apps.kruise.io (ads)
usage: kubectl-kruise set resources (-f FILENAME | TYPE NAME) ([--limits=LIMITS & --requests=REQUESTS]
options:
- name: all
@ -98,6 +98,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -3,7 +3,7 @@ synopsis: Set the selector on a resource
description: |-
Set the selector on a resource. Note that the new selector will overwrite the old selector if the resource had one prior to the invocation of 'set selector'.
A selector must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to 63 characters. If --resource-version is specified, then updates will use this resource version, otherwise the existing resource-version will be used. Note: currently selectors can only be set on Service objects.
A selector must begin with a letter or number, and may contain letters, numbers, hyphens, dots, and underscores, up to 63 characters. If --resource-version is specified, then updates will use this resource version, otherwise the existing resource-version will be used. Note: currently selectors can only be set on Service objects.
usage: kubectl-kruise set selector (-f FILENAME | TYPE NAME) EXPRESSIONS [--resource-version=version]
options:
- name: all
@ -76,6 +76,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -80,6 +80,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

View File

@ -86,6 +86,10 @@ inherited_options:
usage: The name of the kubeconfig cluster to use
- name: context
usage: The name of the kubeconfig context to use
- name: disable-compression
default_value: "false"
usage: |
If true, opt-out of response compression for all requests to the server
- name: insecure-skip-tls-verify
default_value: "false"
usage: |

BIN
go.list Normal file

Binary file not shown.

124
go.mod
View File

@ -1,61 +1,57 @@
module github.com/openkruise/kruise-tools
go 1.18
go 1.23.0
toolchain go1.23.4
require (
github.com/go-errors/errors v1.0.1
github.com/go-errors/errors v1.4.2
github.com/lithammer/dedent v1.1.0
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6
github.com/openkruise/kruise-api v1.5.0
github.com/openkruise/kruise-rollout-api v0.5.0
github.com/moby/term v0.0.0-20221205130635-1aeaba878587
github.com/openkruise/kruise-api v1.8.0
github.com/openkruise/kruise-rollout-api v0.6.0
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.8.2
k8s.io/api v0.24.16
k8s.io/apimachinery v0.24.16
k8s.io/cli-runtime v0.24.0
k8s.io/client-go v0.24.1
k8s.io/component-base v0.24.0
k8s.io/klog/v2 v2.80.1
k8s.io/kubectl v0.24.0
k8s.io/utils v0.0.0-20221107191617-1a15be271d1d
sigs.k8s.io/controller-runtime v0.12.1
sigs.k8s.io/kustomize/api v0.11.4
sigs.k8s.io/kustomize/kyaml v0.13.6
github.com/stretchr/testify v1.9.0
k8s.io/api v0.30.11
k8s.io/apimachinery v0.30.11
k8s.io/cli-runtime v0.30.11
k8s.io/client-go v0.30.11
k8s.io/component-base v0.30.11
k8s.io/klog/v2 v2.120.1
k8s.io/kubectl v0.30.11
k8s.io/utils v0.0.0-20230726121419-3b25d923346b
sigs.k8s.io/controller-runtime v0.18.6
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3
)
require (
cloud.google.com/go v0.81.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // 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.23 // 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/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a // indirect
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
github.com/chai2010/gettext-go v1.0.2 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful v2.16.0+incompatible // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/emicklei/go-restful/v3 v3.11.0 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/evanphx/json-patch/v5 v5.9.0 // indirect
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
github.com/fatih/camelcase v1.0.0 // indirect
github.com/fvbommel/sortorder v1.0.1 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
github.com/go-openapi/jsonreference v0.20.0 // indirect
github.com/go-openapi/swag v0.19.14 // indirect
github.com/fvbommel/sortorder v1.1.0 // indirect
github.com/go-logr/logr v1.4.2 // 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-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.1.0 // 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/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
@ -63,37 +59,45 @@ require (
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/russross/blackfriday v1.5.2 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.1 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
golang.org/x/exp v0.0.0-20220722155223-a9213eeb770e // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/oauth2 v0.17.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/term v0.30.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/time v0.3.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/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42 // indirect
sigs.k8s.io/gateway-api v0.5.1 // indirect
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
sigs.k8s.io/kustomize/kustomize/v4 v4.5.4 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect
sigs.k8s.io/yaml v1.3.0 // indirect
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
sigs.k8s.io/gateway-api v0.7.1 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/kustomize/v5 v5.0.4-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
replace (
golang.org/x/net => golang.org/x/net v0.33.0
golang.org/x/sync => golang.org/x/sync v0.10.0
golang.org/x/sys => golang.org/x/sys v0.19.0
golang.org/x/term => golang.org/x/term v0.19.0
golang.org/x/text => golang.org/x/text v0.21.0
)

986
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,9 @@ package api
import (
kruiseappsv1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
kruiseappsv1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
kruiserolloutsv1apha1 "github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
kruisepolicyv1alpha1 "github.com/openkruise/kruise-api/policy/v1alpha1"
kruiserolloutsv1alpha1 "github.com/openkruise/kruise-rollout-api/rollouts/v1alpha1"
kruiserolloutsv1beta1 "github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
apps "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
@ -39,7 +41,9 @@ func init() {
_ = clientgoscheme.AddToScheme(Scheme)
_ = kruiseappsv1alpha1.AddToScheme(Scheme)
_ = kruiseappsv1beta1.AddToScheme(Scheme)
_ = kruiserolloutsv1apha1.AddToScheme(Scheme)
_ = kruiserolloutsv1alpha1.AddToScheme(Scheme)
_ = kruiserolloutsv1beta1.AddToScheme(Scheme)
_ = kruisepolicyv1alpha1.AddToScheme(Scheme)
}
func GetScheme() *runtime.Scheme {

View File

@ -24,8 +24,10 @@ import (
"github.com/spf13/cobra"
"github.com/openkruise/kruise-tools/pkg/cmd/create"
"github.com/openkruise/kruise-tools/pkg/cmd/describe"
cmdexec "github.com/openkruise/kruise-tools/pkg/cmd/exec"
"github.com/openkruise/kruise-tools/pkg/cmd/expose"
"github.com/openkruise/kruise-tools/pkg/cmd/get"
"github.com/openkruise/kruise-tools/pkg/cmd/migrate"
krollout "github.com/openkruise/kruise-tools/pkg/cmd/rollout"
"github.com/openkruise/kruise-tools/pkg/cmd/scaledown"
@ -443,6 +445,8 @@ func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
cmds.AddCommand(alpha)
cmds.AddCommand(NewCmdGenerateDocs(f, ioStreams))
cmds.AddCommand(NewAutoCompleteCommand())
cmds.AddCommand(get.NewCmdGet(f, ioStreams))
cmds.AddCommand(describe.NewCmdDescibe(f, ioStreams))
cmds.AddCommand(cmdconfig.NewCmdConfig(clientcmd.NewDefaultPathOptions(), ioStreams))
cmds.AddCommand(plugin.NewCmdPlugin(ioStreams))
cmds.AddCommand(version.NewCmdVersion(f, ioStreams))

View File

@ -53,10 +53,8 @@ type CreateOptions struct {
RecordFlags *genericclioptions.RecordFlags
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.QueryParamVerifier
FieldValidationVerifier *resource.QueryParamVerifier
ValidationDirective string
ValidationDirective string
fieldManager string
@ -193,12 +191,6 @@ func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error {
return err
}
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
o.FieldValidationVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamFieldValidation)
o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd)
if err != nil {
@ -231,7 +223,7 @@ func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error {
if o.EditBeforeCreate {
return RunEditOnCreate(f, o.PrintFlags, o.RecordFlags, o.IOStreams, cmd, &o.FilenameOptions, o.fieldManager)
}
schema, err := f.Validator(o.ValidationDirective, o.FieldValidationVerifier)
schema, err := f.Validator(o.ValidationDirective)
if err != nil {
return err
@ -270,11 +262,6 @@ func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error {
}
if o.DryRunStrategy != cmdutil.DryRunClient {
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
return cmdutil.AddSourceToErr("creating", info.Source, err)
}
}
obj, err := resource.
NewHelper(info.Client, info.Mapping).
DryRun(o.DryRunStrategy == cmdutil.DryRunServer).
@ -344,7 +331,6 @@ type CreateSubcommandOptions struct {
// StructuredGenerator is the resource generator for the object being created
StructuredGenerator generate.StructuredGenerator
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.QueryParamVerifier
CreateAnnotation bool
FieldManager string
@ -380,11 +366,6 @@ func (o *CreateSubcommandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
@ -448,9 +429,6 @@ func (o *CreateSubcommandOptions) Run() error {
createOptions.FieldManager = o.FieldManager
}
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(mapping.GroupVersionKind); err != nil {
return err
}
createOptions.DryRun = []string{metav1.DryRunAll}
}
actualObject, err := o.DynamicClient.Resource(mapping.Resource).Namespace(o.Namespace).Create(context.TODO(), asUnstructured, createOptions)

View File

@ -69,7 +69,6 @@ type CreateBroadcastJobOptions struct {
EnforceNamespace bool
kruisev1alpha1Client kruiseclientsets.Interface
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.QueryParamVerifier
Builder *resource.Builder
FieldManager string
CreateAnnotation bool
@ -144,11 +143,6 @@ func (o *CreateBroadcastJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Comma
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
@ -214,9 +208,6 @@ func (o *CreateBroadcastJobOptions) Run() error {
createOptions.FieldManager = o.FieldManager
}
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(job.GroupVersionKind()); err != nil {
return err
}
createOptions.DryRun = []string{metav1.DryRunAll}
}
var err error

View File

@ -86,7 +86,6 @@ type CreateCRROptions struct {
ClientSet kubernetes.Interface
EnforceNamespace bool
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.QueryParamVerifier
Builder *resource.Builder
FieldManager string
CreateAnnotation bool
@ -175,11 +174,6 @@ func (o *CreateCRROptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
@ -224,9 +218,6 @@ func (o *CreateCRROptions) Run() error {
createOptions.FieldManager = o.FieldManager
}
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(crr.GroupVersionKind()); err != nil {
return err
}
createOptions.DryRun = []string{metav1.DryRunAll}
}
var err error

View File

@ -70,7 +70,6 @@ type CreateJobOptions struct {
EnforceNamespace bool
Client batchv1client.BatchV1Interface
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.QueryParamVerifier
Builder *resource.Builder
FieldManager string
CreateAnnotation bool
@ -145,11 +144,6 @@ func (o *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
printer, err := o.PrintFlags.ToPrinter()
if err != nil {
@ -219,9 +213,6 @@ func (o *CreateJobOptions) Run() error {
createOptions.FieldManager = o.FieldManager
}
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(job.GroupVersionKind()); err != nil {
return err
}
createOptions.DryRun = []string{metav1.DryRunAll}
}
var err error

View File

@ -0,0 +1,50 @@
package describe
/*
Copyright 2021 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.
*/
import (
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
)
var (
describeLong = templates.LongDesc(i18n.T(`
Show details of a rollout.`))
describeExample = templates.Examples(`
# Describe the rollout named rollout-demo
kubectl-kruise describe rollout rollout-demo`)
)
// NewCmdRollout returns a Command instance for 'rollout' sub command
func NewCmdDescibe(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
cmd := &cobra.Command{
Use: "describe SUBCOMMAND",
DisableFlagsInUseLine: true,
Short: i18n.T("Show details of a specific resource or group of resources"),
Long: describeLong,
Example: describeExample,
Run: cmdutil.DefaultSubCommandRun(streams.Out),
}
// subcommands
cmd.AddCommand(NewCmdDescribeRollout(f, streams))
return cmd
}

View File

@ -0,0 +1,806 @@
/*
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.
*/
package describe
import (
"context"
"fmt"
"reflect"
"sort"
"strconv"
"strings"
"text/tabwriter"
"time"
kruiseappsv1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
kruiseappsv1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
rolloutsapi "github.com/openkruise/kruise-rollout-api/client/clientset/versioned"
rolloutv1alpha1types "github.com/openkruise/kruise-rollout-api/client/clientset/versioned/typed/rollouts/v1alpha1"
rolloutsv1beta1types "github.com/openkruise/kruise-rollout-api/client/clientset/versioned/typed/rollouts/v1beta1"
rolloutsapiv1alpha1 "github.com/openkruise/kruise-rollout-api/rollouts/v1alpha1"
rolloutsapiv1beta1 "github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
internalapi "github.com/openkruise/kruise-tools/pkg/api"
internalpolymorphichelpers "github.com/openkruise/kruise-tools/pkg/internal/polymorphichelpers"
"github.com/spf13/cobra"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/duration"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/client-go/kubernetes/scheme"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
)
const (
tableFormat = "%-19s%v\n"
)
var (
rolloutLong = templates.LongDesc(i18n.T(`
Get details about and visual representation of a rollout.`))
rolloutExample = templates.Examples(`
# Describe the rollout named rollout-demo within namespace default
kubectl-kruise describe rollout rollout-demo -n default
# Watch for changes to the rollout named rollout-demo
kubectl-kruise describe rollout rollout-demo -n default -w`)
)
type DescribeRolloutOptions struct {
genericclioptions.IOStreams
Builder func() *resource.Builder
Namespace string
EnforceNamespace bool
Resources []string
RolloutViewerFn func(runtime.Object) (interface{}, error)
Watch bool
NoColor bool
All bool
TimeoutSeconds int
RolloutsV1beta1Client rolloutsv1beta1types.RolloutInterface
RolloutsV1alpha1Client rolloutv1alpha1types.RolloutInterface
}
type WorkloadInfo struct {
Name string
Kind string
Images []string
Replicas struct {
Desired int32
Current int32
Updated int32
Ready int32
Available int32
}
Pod []struct {
Name string
BatchID string
Status string
Ready string
Age string
Restarts string
Revision string
}
CurrentRevision string
UpdateRevision string
}
type RolloutInfo struct {
Name string
Namespace string
Phase string
Message string
ObservedGeneration int64
Generation int64
CurrentStepIndex int32
CurrentStepState string
CanaryStrategy rolloutsapiv1beta1.CanaryStrategy
BlueGreenStrategy rolloutsapiv1beta1.BlueGreenStrategy
TrafficRoutingRef string
WorkloadRef RolloutWorkloadRef
StrategyType string
}
func NewCmdDescribeRollout(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := &DescribeRolloutOptions{IOStreams: streams}
cmd := &cobra.Command{
Use: "rollout SUBCOMMAND",
DisableFlagsInUseLine: true,
Short: i18n.T("Get details about a rollout"),
Long: rolloutLong,
Example: rolloutExample,
Aliases: []string{"rollouts", "ro"},
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, args))
cmdutil.CheckErr(o.Run())
},
}
cmd.Flags().BoolVarP(&o.Watch, "watch", "w", false, "Watch for changes to the rollout")
cmd.Flags().BoolVar(&o.NoColor, "no-color", false, "If true, print output without color")
cmd.Flags().IntVar(&o.TimeoutSeconds, "timeout", 0, "Timeout after specified seconds")
cmd.Flags().BoolVar(&o.All, "all", false, "Show all pods in the rollout")
return cmd
}
func (o *DescribeRolloutOptions) Complete(f cmdutil.Factory, args []string) error {
var err error
if len(args) == 0 {
return fmt.Errorf("required rollout name not specified")
}
o.Resources = args
o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
}
o.Resources = []string{args[0]}
o.RolloutViewerFn = internalpolymorphichelpers.RolloutViewerFn
o.Builder = f.NewBuilder
config, err := f.ToRESTConfig()
if err != nil {
return err
}
rolloutsClientset, err := rolloutsapi.NewForConfig(config)
if err != nil {
return err
}
o.RolloutsV1beta1Client = rolloutsClientset.RolloutsV1beta1().Rollouts(o.Namespace)
o.RolloutsV1alpha1Client = rolloutsClientset.RolloutsV1alpha1().Rollouts(o.Namespace)
return nil
}
func (o *DescribeRolloutOptions) Run() error {
rolloutName := o.Resources[0]
r := o.Builder().
WithScheme(internalapi.GetScheme(), scheme.Scheme.PrioritizedVersionsAllGroups()...).
NamespaceParam(o.Namespace).DefaultNamespace().
ResourceNames("rollouts.rollouts.kruise.io", rolloutName).
ContinueOnError().
Latest().
Flatten().
Do()
if err := r.Err(); err != nil {
return err
}
if !o.Watch {
return r.Visit(o.describeRollout)
}
return o.watchRollout(r)
}
func (o *DescribeRolloutOptions) describeRollout(info *resource.Info, err error) error {
if err != nil {
return err
}
rollout, err := o.RolloutViewerFn(info.Object)
if err != nil {
return err
}
o.printRolloutInfo(rollout)
return nil
}
func (o *DescribeRolloutOptions) watchRollout(r *resource.Result) error {
infos, err := r.Infos()
if err != nil {
return err
}
if len(infos) != 1 {
return fmt.Errorf("watch is only supported on a single rollout")
}
info := infos[0]
var watcher watch.Interface
switch info.Object.(type) {
case *rolloutsapiv1beta1.Rollout:
watcher, err = o.RolloutsV1beta1Client.Watch(context.TODO(), metav1.ListOptions{
FieldSelector: "metadata.name=" + info.Name,
})
case *rolloutsapiv1alpha1.Rollout:
watcher, err = o.RolloutsV1alpha1Client.Watch(context.TODO(), metav1.ListOptions{
FieldSelector: "metadata.name=" + info.Name,
})
default:
return fmt.Errorf("unsupported rollout type %T", info.Object)
}
if err != nil {
return err
}
defer watcher.Stop()
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
if o.TimeoutSeconds > 0 {
ctx, cancel = context.WithTimeout(ctx, time.Duration(o.TimeoutSeconds)*time.Second)
defer cancel()
}
return o.watchRolloutUpdates(ctx, watcher)
}
func (o *DescribeRolloutOptions) watchRolloutUpdates(ctx context.Context, watcher watch.Interface) error {
for {
select {
case event, ok := <-watcher.ResultChan():
if !ok {
return nil
}
if event.Type == watch.Added || event.Type == watch.Modified {
var rollout interface{}
switch obj := event.Object.(type) {
case *rolloutsapiv1beta1.Rollout:
rollout = obj
case *rolloutsapiv1alpha1.Rollout:
rollout = obj
default:
continue
}
o.clearScreen()
o.printRolloutInfo(rollout)
}
case <-ctx.Done():
return ctx.Err()
}
}
}
func (o *DescribeRolloutOptions) clearScreen() {
fmt.Fprint(o.Out, "\033[2J\033[H")
}
type RolloutWorkloadRef struct {
Kind string
Name string
StableRevision string
CanaryRevision string
UpdatedRevision string
PodTemplateHash string
CurrentStepIndex int32
}
func (o *DescribeRolloutOptions) GetResources(rollout RolloutWorkloadRef) (*WorkloadInfo, error) {
resources := []string{rollout.Kind + "/" + rollout.Name}
r := o.Builder().
WithScheme(internalapi.GetScheme(), scheme.Scheme.PrioritizedVersionsAllGroups()...).
NamespaceParam(o.Namespace).DefaultNamespace().
ResourceTypeOrNameArgs(true, resources...).
ContinueOnError().
Latest().
Flatten().
Do()
if err := r.Err(); err != nil {
return nil, err
}
obj, err := r.Object()
if err != nil {
return nil, err
}
workloadInfo := &WorkloadInfo{}
objValue := reflect.ValueOf(obj).Elem()
workloadInfo.Name = objValue.FieldByName("Name").String()
workloadInfo.Kind = objValue.Type().Name()
podTemplateSpec := objValue.FieldByName("Spec").FieldByName("Template").FieldByName("Spec")
containers := podTemplateSpec.FieldByName("Containers")
for i := 0; i < containers.Len(); i++ {
container := containers.Index(i)
workloadInfo.Images = append(workloadInfo.Images, container.FieldByName("Image").String())
}
// Deployment,StatefulSet,CloneSet,Advanced StatefulSet,Advanced DaemonSet
switch o := obj.(type) {
case *appsv1.Deployment:
workloadInfo.Replicas.Desired = *o.Spec.Replicas
workloadInfo.Replicas.Current = o.Status.Replicas
workloadInfo.Replicas.Updated = o.Status.UpdatedReplicas
workloadInfo.Replicas.Ready = o.Status.ReadyReplicas
workloadInfo.Replicas.Available = o.Status.AvailableReplicas
case *appsv1.StatefulSet:
workloadInfo.Replicas.Desired = *o.Spec.Replicas
workloadInfo.Replicas.Current = o.Status.Replicas
workloadInfo.Replicas.Updated = o.Status.UpdatedReplicas
workloadInfo.Replicas.Ready = o.Status.ReadyReplicas
workloadInfo.Replicas.Available = o.Status.AvailableReplicas
case *kruiseappsv1alpha1.DaemonSet:
workloadInfo.Replicas.Desired = o.Spec.BurstReplicas.IntVal
workloadInfo.Replicas.Current = o.Status.CurrentNumberScheduled
workloadInfo.Replicas.Updated = o.Status.UpdatedNumberScheduled
workloadInfo.Replicas.Ready = o.Status.NumberReady
workloadInfo.Replicas.Available = o.Status.NumberAvailable
case *kruiseappsv1beta1.StatefulSet:
workloadInfo.Replicas.Desired = *o.Spec.Replicas
workloadInfo.Replicas.Current = o.Status.Replicas
workloadInfo.Replicas.Updated = o.Status.UpdatedReplicas
workloadInfo.Replicas.Ready = o.Status.ReadyReplicas
workloadInfo.Replicas.Available = o.Status.AvailableReplicas
case *kruiseappsv1alpha1.CloneSet:
workloadInfo.Replicas.Desired = *o.Spec.Replicas
workloadInfo.Replicas.Current = o.Status.Replicas
workloadInfo.Replicas.Updated = o.Status.UpdatedReplicas
workloadInfo.Replicas.Ready = o.Status.ReadyReplicas
workloadInfo.Replicas.Available = o.Status.AvailableReplicas
default:
return nil, fmt.Errorf("unsupported workload kind %T", obj)
}
workloadInfo.CurrentRevision = rollout.StableRevision
workloadInfo.UpdateRevision = rollout.CanaryRevision
if rollout.UpdatedRevision != "" {
workloadInfo.UpdateRevision = rollout.UpdatedRevision
}
var labelSelectorParam string
switch obj.(type) {
case *appsv1.Deployment:
labelSelectorParam = "pod-template-hash"
default:
labelSelectorParam = "controller-revision-hash"
}
selectorParam := rollout.PodTemplateHash
if selectorParam == "" {
selectorParam = rollout.StableRevision
}
labelSelectors := []string{
fmt.Sprintf("%s=%s", labelSelectorParam, selectorParam),
}
if !o.All && rollout.CurrentStepIndex != 0 {
labelSelectors = append(labelSelectors,
fmt.Sprintf("rollouts.kruise.io/rollout-batch-id=%v",
rollout.CurrentStepIndex))
}
// Fetch pods
r2 := o.Builder().
WithScheme(internalapi.GetScheme(), scheme.Scheme.PrioritizedVersionsAllGroups()...).
NamespaceParam(o.Namespace).DefaultNamespace().
ResourceTypes("pods").
LabelSelectorParam(strings.Join(labelSelectors, ",")).
Latest().
Flatten().
Do()
if err := r2.Err(); err != nil {
return nil, err
}
err = r2.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
}
pod, ok := info.Object.(*corev1.Pod)
if !ok {
return fmt.Errorf("expected *corev1.Pod, got %T", info.Object)
}
podInfo := struct {
Name string
BatchID string
Status string
Ready string
Age string
Restarts string
Revision string
}{
Name: pod.Name,
BatchID: pod.Labels["rollouts.kruise.io/rollout-batch-id"],
Status: string(pod.Status.Phase),
Age: duration.HumanDuration(time.Since(pod.CreationTimestamp.Time)),
Restarts: "0",
}
if pod.DeletionTimestamp != nil {
podInfo.Status = "Terminating"
}
if len(pod.Status.ContainerStatuses) > 0 {
restartCount := 0
for _, containerStatus := range pod.Status.ContainerStatuses {
restartCount += int(containerStatus.RestartCount)
}
podInfo.Restarts = strconv.Itoa(restartCount)
}
// Calculate ready status
readyContainers := 0
for _, containerStatus := range pod.Status.ContainerStatuses {
if containerStatus.Ready {
readyContainers++
}
}
podInfo.Ready = fmt.Sprintf("%d/%d", readyContainers, len(pod.Spec.Containers))
// Calculate revision
if pod.Labels["pod-template-hash"] != "" {
podInfo.Revision = pod.Labels["pod-template-hash"]
} else if pod.Labels["controller-revision-hash"] != "" {
podInfo.Revision = pod.Labels["controller-revision-hash"]
}
workloadInfo.Pod = append(workloadInfo.Pod, podInfo)
return nil
})
if err != nil {
return nil, err
}
// Sort pods by batch ID and ready count
sort.Slice(workloadInfo.Pod, func(i, j int) bool {
if workloadInfo.Pod[i].BatchID != workloadInfo.Pod[j].BatchID {
return workloadInfo.Pod[i].BatchID < workloadInfo.Pod[j].BatchID
}
iReady := strings.Split(workloadInfo.Pod[i].Ready, "/")
jReady := strings.Split(workloadInfo.Pod[j].Ready, "/")
iReadyCount, _ := strconv.Atoi(iReady[0])
jReadyCount, _ := strconv.Atoi(jReady[0])
return iReadyCount > jReadyCount
})
return workloadInfo, nil
}
func (o *DescribeRolloutOptions) colorizeIcon(phase string) string {
if o.NoColor || phase == "" {
return ""
}
switch phase {
case string(rolloutsapiv1beta1.RolloutPhaseHealthy), string(corev1.PodRunning):
return "\033[32m✔\033[0m"
case string(rolloutsapiv1beta1.RolloutPhaseProgressing), string(corev1.PodPending):
return "\033[33m⚠\033[0m"
case string(rolloutsapiv1beta1.RolloutPhaseDisabled), string(corev1.PodUnknown), string(rolloutsapiv1beta1.RolloutPhaseTerminating), string(rolloutsapiv1beta1.RolloutPhaseDisabling), string(corev1.PodFailed):
return "\033[31m✘\033[0m"
case string(rolloutsapiv1beta1.RolloutPhaseInitial):
return "\033[33m⚠\033[0m"
default:
return ""
}
}
func (o *DescribeRolloutOptions) printTrafficRouting(trafficRouting []rolloutsapiv1beta1.TrafficRoutingRef) {
if len(trafficRouting) == 0 {
return
}
fmt.Fprint(o.Out, "Traffic Routings:\n")
for _, trafficRouting := range trafficRouting {
fmt.Fprintf(o.Out, tableFormat, " - Service: ", trafficRouting.Service)
if trafficRouting.Ingress != nil {
fmt.Fprintln(o.Out, ` Ingress: `)
fmt.Fprintf(o.Out, tableFormat, " classType: ", trafficRouting.Ingress.ClassType)
fmt.Fprintf(o.Out, tableFormat, " name: ", trafficRouting.Ingress.Name)
}
if trafficRouting.Gateway != nil {
fmt.Fprintln(o.Out, ` Gateway: `)
fmt.Fprintf(o.Out, tableFormat, " HttpRouteName: ", trafficRouting.Gateway.HTTPRouteName)
}
if trafficRouting.CustomNetworkRefs != nil {
fmt.Fprintln(o.Out, ` CustomNetworkRefs: `)
for _, customNetworkRef := range trafficRouting.CustomNetworkRefs {
fmt.Fprintf(o.Out, tableFormat, " name: ", customNetworkRef.Name)
fmt.Fprintf(o.Out, tableFormat, " kind: ", customNetworkRef.Kind)
fmt.Fprintf(o.Out, tableFormat, " apiVersion: ", customNetworkRef.APIVersion)
}
}
}
}
func convertCustomNetworkRefs(refs []rolloutsapiv1alpha1.CustomNetworkRef) []rolloutsapiv1beta1.ObjectRef {
var result []rolloutsapiv1beta1.ObjectRef
for _, ref := range refs {
result = append(result, rolloutsapiv1beta1.ObjectRef{
Name: ref.Name,
Kind: ref.Kind,
APIVersion: ref.APIVersion,
})
}
return result
}
func extractRolloutInfo(obj interface{}) *RolloutInfo {
info := &RolloutInfo{}
switch r := obj.(type) {
case *rolloutsapiv1beta1.Rollout:
info.Name = r.Name
info.Namespace = r.Namespace
info.Phase = string(r.Status.Phase)
info.Message = r.Status.Message
info.ObservedGeneration = r.Status.ObservedGeneration
info.Generation = r.GetObjectMeta().GetGeneration()
if r.Spec.Strategy.BlueGreen != nil {
info.CurrentStepIndex = r.Status.BlueGreenStatus.CurrentStepIndex
info.CurrentStepState = string(r.Status.BlueGreenStatus.CurrentStepState)
info.WorkloadRef = RolloutWorkloadRef{
Kind: r.Spec.WorkloadRef.Kind,
Name: r.Spec.WorkloadRef.Name,
StableRevision: r.Status.BlueGreenStatus.StableRevision,
UpdatedRevision: r.Status.BlueGreenStatus.UpdatedRevision,
PodTemplateHash: r.Status.BlueGreenStatus.PodTemplateHash,
CurrentStepIndex: r.Status.BlueGreenStatus.CurrentStepIndex,
}
} else {
info.CurrentStepIndex = r.Status.CanaryStatus.CurrentStepIndex
info.CurrentStepState = string(r.Status.CanaryStatus.CurrentStepState)
info.WorkloadRef = RolloutWorkloadRef{
Kind: r.Spec.WorkloadRef.Kind,
Name: r.Spec.WorkloadRef.Name,
StableRevision: r.Status.CanaryStatus.StableRevision,
CanaryRevision: r.Status.CanaryStatus.CanaryRevision,
PodTemplateHash: r.Status.CanaryStatus.PodTemplateHash,
CurrentStepIndex: r.Status.CanaryStatus.CurrentStepIndex,
}
}
if r.Spec.Strategy.Canary != nil {
info.CanaryStrategy = *r.Spec.Strategy.Canary
info.StrategyType = "Canary"
info.TrafficRoutingRef = r.Spec.Strategy.Canary.TrafficRoutingRef
} else if r.Spec.Strategy.BlueGreen != nil {
info.BlueGreenStrategy = *r.Spec.Strategy.BlueGreen
info.StrategyType = "BlueGreen"
}
case *rolloutsapiv1alpha1.Rollout:
info.Name = r.Name
info.Namespace = r.Namespace
info.Phase = string(r.Status.Phase)
info.Message = r.Status.Message
info.ObservedGeneration = r.Status.ObservedGeneration
info.Generation = r.GetObjectMeta().GetGeneration()
info.CurrentStepIndex = r.Status.CanaryStatus.CurrentStepIndex
info.CurrentStepState = string(r.Status.CanaryStatus.CurrentStepState)
info.WorkloadRef = RolloutWorkloadRef{
Kind: r.Spec.ObjectRef.WorkloadRef.Kind,
Name: r.Spec.ObjectRef.WorkloadRef.Name,
StableRevision: r.Status.CanaryStatus.StableRevision,
CanaryRevision: r.Status.CanaryStatus.CanaryRevision,
PodTemplateHash: r.Status.CanaryStatus.PodTemplateHash,
CurrentStepIndex: r.Status.CanaryStatus.CurrentStepIndex,
}
if r.Spec.Strategy.Canary != nil {
info.StrategyType = "Canary"
info.TrafficRoutingRef = r.ObjectMeta.Annotations["rollouts.kruise.io/trafficrouting"]
}
// BlueGreen strategy is not supported in v1alpha1 API
}
if obj.(*rolloutsapiv1beta1.Rollout).Spec.Strategy.Canary != nil {
info.CanaryStrategy = *obj.(*rolloutsapiv1beta1.Rollout).Spec.Strategy.Canary
} else if obj.(*rolloutsapiv1beta1.Rollout).Spec.Strategy.BlueGreen != nil {
info.BlueGreenStrategy = *obj.(*rolloutsapiv1beta1.Rollout).Spec.Strategy.BlueGreen
}
return info
}
func (o *DescribeRolloutOptions) fetchAndPrintTrafficRoutingRef(ref string) {
r := o.Builder().
WithScheme(internalapi.GetScheme(), scheme.Scheme.PrioritizedVersionsAllGroups()...).
NamespaceParam(o.Namespace).DefaultNamespace().
ResourceNames("trafficroutings.rollouts.kruise.io", ref).
ContinueOnError().
Latest().
Flatten().
Do()
if err := r.Err(); err != nil {
fmt.Fprintf(o.Out, "Error getting TrafficRoutingRef: %v\n", err)
return
}
err := r.Visit(func(info *resource.Info, err error) error {
if err != nil {
return err
}
trafficRouting, ok := info.Object.(*rolloutsapiv1alpha1.TrafficRouting)
if !ok {
return fmt.Errorf("expected *rolloutsapiv1alpha1.TrafficRouting")
}
var trafficRoutingRef []rolloutsapiv1beta1.TrafficRoutingRef
for _, ref := range trafficRouting.Spec.ObjectRef {
trafficRoutingRef = append(trafficRoutingRef, rolloutsapiv1beta1.TrafficRoutingRef{
Service: ref.Service,
Ingress: (*rolloutsapiv1beta1.IngressTrafficRouting)(ref.Ingress),
Gateway: (*rolloutsapiv1beta1.GatewayTrafficRouting)(ref.Gateway),
CustomNetworkRefs: convertCustomNetworkRefs(ref.CustomNetworkRefs),
})
}
o.printTrafficRouting(trafficRoutingRef)
return nil
})
if err != nil {
return
}
}
func (o *DescribeRolloutOptions) printRolloutInfo(rollout interface{}) {
info := extractRolloutInfo(rollout)
// Print basic info
fmt.Fprintf(o.Out, tableFormat, "Name:", info.Name)
fmt.Fprintf(o.Out, tableFormat, "Namespace:", info.Namespace)
if info.ObservedGeneration == info.Generation {
fmt.Fprintf(o.Out, tableFormat, "Status:", o.colorizeIcon(info.Phase)+" "+info.Phase)
if info.Message != "" {
fmt.Fprintf(o.Out, tableFormat, "Message:", info.Message)
}
}
// Print strategy
fmt.Fprintf(o.Out, tableFormat, "Strategy:", info.StrategyType)
if info.StrategyType == "Canary" {
fmt.Fprintf(o.Out, tableFormat, " Step:", strconv.Itoa(int(info.CurrentStepIndex))+"/"+strconv.Itoa(len(info.CanaryStrategy.Steps)))
fmt.Fprint(o.Out, " Steps:\n")
o.printSteps(info)
o.printTrafficRouting(info.CanaryStrategy.TrafficRoutings)
} else if info.StrategyType == "BlueGreen" {
fmt.Fprintf(o.Out, tableFormat, " Step:", strconv.Itoa(int(info.CurrentStepIndex))+"/"+strconv.Itoa(len(info.BlueGreenStrategy.Steps)))
fmt.Fprint(o.Out, " Steps:\n")
o.printSteps(info)
o.printTrafficRouting(info.BlueGreenStrategy.TrafficRoutings)
}
if info.TrafficRoutingRef != "" {
o.fetchAndPrintTrafficRoutingRef(info.TrafficRoutingRef)
}
// Print workload info
workloadInfo, err := o.GetResources(info.WorkloadRef)
if err != nil {
fmt.Fprintf(o.Out, "Error getting resources: %v\n", err)
return
}
// Print images
for i, image := range workloadInfo.Images {
if i == 0 {
fmt.Fprintf(o.Out, tableFormat, "Images:", image)
} else {
fmt.Fprintf(o.Out, tableFormat, "", image)
}
}
// Print revisions
fmt.Fprintf(o.Out, tableFormat, "Current Revision:", workloadInfo.CurrentRevision)
fmt.Fprintf(o.Out, tableFormat, "Update Revision:", workloadInfo.UpdateRevision)
// Print replicas
if info.ObservedGeneration == info.Generation {
o.printReplicas(workloadInfo)
}
// Print pods
if len(workloadInfo.Pod) > 0 {
o.printPods(workloadInfo)
}
}
func (o *DescribeRolloutOptions) printSteps(info *RolloutInfo) {
currentStepIndex := int(info.CurrentStepIndex)
Steps := info.CanaryStrategy.Steps
if info.StrategyType == "BlueGreen" {
Steps = info.BlueGreenStrategy.Steps
}
for i, step := range Steps {
isCurrentStep := (i + 1) == currentStepIndex
if isCurrentStep {
fmt.Fprint(o.Out, "\033[32m")
}
if step.Replicas != nil {
fmt.Fprintf(o.Out, tableFormat, " - Replicas: ", step.Replicas)
}
if step.Traffic != nil {
fmt.Fprintf(o.Out, tableFormat, " Traffic: ", *step.Traffic)
}
if len(step.Matches) > 0 {
fmt.Fprintln(o.Out, " Matches: ")
for _, match := range step.Matches {
fmt.Fprintln(o.Out, " - Headers: ")
for _, header := range match.Headers {
fmt.Fprintf(o.Out, tableFormat, " - Name:", header.Name)
fmt.Fprintf(o.Out, tableFormat, " Value:", header.Value)
fmt.Fprintf(o.Out, tableFormat, " Type:", *header.Type)
}
}
}
if isCurrentStep {
fmt.Fprintf(o.Out, tableFormat, " State:", info.CurrentStepState)
fmt.Fprint(o.Out, "\033[0m")
}
}
}
func (o *DescribeRolloutOptions) printReplicas(info *WorkloadInfo) {
fmt.Fprint(o.Out, "Replicas:\n")
fmt.Fprintf(o.Out, tableFormat, " Desired:", info.Replicas.Desired)
fmt.Fprintf(o.Out, tableFormat, " Updated:", info.Replicas.Updated)
fmt.Fprintf(o.Out, tableFormat, " Current:", info.Replicas.Current)
fmt.Fprintf(o.Out, tableFormat, " Ready:", info.Replicas.Ready)
fmt.Fprintf(o.Out, tableFormat, " Available:", info.Replicas.Available)
}
func (o *DescribeRolloutOptions) printPods(info *WorkloadInfo) {
w := tabwriter.NewWriter(o.Out, 0, 0, 2, ' ', 0)
fmt.Fprintln(w, "NAME\tREADY\tBATCH ID\tREVISION\tAGE\tRESTARTS\tSTATUS")
for _, pod := range info.Pod {
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s %s\n",
pod.Name,
pod.Ready,
pod.BatchID,
pod.Revision,
pod.Age,
pod.Restarts,
o.colorizeIcon(pod.Status),
pod.Status,
)
}
w.Flush()
}

View File

@ -92,7 +92,6 @@ type ExposeServiceOptions struct {
PrintObj printers.ResourcePrinterFunc
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.QueryParamVerifier
EnforceNamespace bool
fieldManager string
@ -178,11 +177,6 @@ func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) e
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
printer, err := o.PrintFlags.ToPrinter()
@ -356,11 +350,6 @@ func (o *ExposeServiceOptions) RunExpose(cmd *cobra.Command, args []string) erro
if err != nil {
return err
}
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(objMapping.GroupVersionKind); err != nil {
return err
}
}
// Serialize the object with the annotation applied.
client, err := o.ClientForMapping(objMapping)
if err != nil {

421
pkg/cmd/get/get.go Normal file
View File

@ -0,0 +1,421 @@
/*
Copyright 2025 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 get
import (
"fmt"
"time"
kruiseappsv1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
kruiseappsv1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
kruisepolicyv1alpha1 "github.com/openkruise/kruise-api/policy/v1alpha1"
rolloutv1alpha1 "github.com/openkruise/kruise-rollout-api/rollouts/v1alpha1"
rolloutv1beta1 "github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
internalpolymorphichelpers "github.com/openkruise/kruise-tools/pkg/internal/polymorphichelpers"
"github.com/spf13/cobra"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/resource"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
)
var (
getLong = templates.Examples(i18n.T(`
Display one or many resources related to kruise.`))
getExample = templates.Examples(i18n.T(`
# List all resources in the default namespace
kubectl-kruise get all
# List all resources in the specific namespace
kubectl-kruise get all -n namespace
# Watch all resources in the default namespace
kubectl-kruise get all -w`))
)
type GetOptions struct {
genericclioptions.IOStreams
Builder func() *resource.Builder
Resources []string
Namespace string
EnforceNamespace bool
GetViewerFn internalpolymorphichelpers.GetViewerFunc
}
func NewCmdGet(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := &GetOptions{IOStreams: streams}
cmd := &cobra.Command{
Use: "get all",
DisableFlagsInUseLine: true,
Short: i18n.T("Display one or many resources"),
Long: getLong,
Example: getExample,
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, args))
cmdutil.CheckErr(o.Run())
},
}
cmd.Flags().StringVarP(&o.Namespace, "namespace", "n", o.Namespace, "If present, the namespace scope for this CLI request")
return cmd
}
func (o *GetOptions) Complete(f cmdutil.Factory, args []string) error {
var err error
if len(args) == 0 {
return fmt.Errorf("required resource not specified")
}
o.Resources = args
o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
if err != nil {
return err
}
o.GetViewerFn = internalpolymorphichelpers.GetViewerFn
o.Builder = f.NewBuilder
return nil
}
func (o *GetOptions) Run() error {
if len(o.Resources) == 0 {
return fmt.Errorf("you must specify the type of resource to get")
}
if o.Resources[0] == "all" {
resourceTypes := []string{
"clonesets.apps.kruise.io",
"statefulsets.apps.kruise.io",
"daemonsets.apps.kruise.io",
"rollouts.rollouts.kruise.io",
"broadcastjobs.apps.kruise.io",
"containerrecreaterequests.apps.kruise.io",
"advancedcronjobs.apps.kruise.io",
"resourcedistributions.apps.kruise.io",
"uniteddeployments.apps.kruise.io",
"sidecarsets.apps.kruise.io",
"podprobemarkers.apps.kruise.io",
"imagepulljobs.apps.kruise.io",
"podunavailablebudgets.policy.kruise.io",
}
for _, resourceType := range resourceTypes {
b := o.Builder().
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
NamespaceParam(o.Namespace).DefaultNamespace().
ResourceTypeOrNameArgs(true, resourceType).
ContinueOnError().
Latest().
Flatten()
if resourceType == "sidecarsets.apps.kruise.io" {
b = b.AllNamespaces(true)
}
infos, err := b.Do().Infos()
if err != nil {
return err
}
if len(infos) > 0 {
// Print resource type header and table header only if there are resources
fmt.Fprintf(o.Out, "\n%s:\n", resourceType)
switch resourceType {
case "clonesets.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-14s\t%-18s\t%-8s\t%-8s\t%-s\n",
"NAME", "DESIRED", "UPDATED", "UPDATED_READY", "UPDATED_AVAILABLE", "READY", "TOTAL", "AGE")
case "statefulsets.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "DESIRED", "CURRENT", "UPDATED", "READY", "AGE")
case "daemonsets.apps.kruise.io":
fmt.Fprintf(o.Out, "%-8s\t%-8s\t%-8s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "DESIRED", "CURRENT", "READY", "UP-TO-DATE", "AVAILABLE", "NODE SELECTOR", "AGE")
case "rollouts.rollouts.kruise.io":
fmt.Fprintf(o.Out, "%-20s\t%-8s\t%-12s\t%-12s\t%-40s\t%-s\n",
"NAME", "STATUS", "CANARY_STEP", "CANARY_STATE", "MESSAGE", "AGE")
case "broadcastjobs.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "DESIRED", "ACTIVE", "SUCCEEDED", "FAILED", "AGE")
case "containerrecreaterequests.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "PHASE", "COMPLETED", "FAILED", "AGE")
case "advancedcronjobs.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "SCHEDULE", "SUSPEND", "ACTIVE", "LAST SCHEDULE", "AGE")
case "resourcedistributions.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "TARGETS", "SUCCEEDED", "FAILED", "AGE")
case "uniteddeployments.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "DESIRED", "UPDATED", "READY", "AVAILABLE", "AGE")
case "sidecarsets.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "MATCHED", "UPDATED", "READY", "INJECTED", "AGE")
case "podprobemarkers.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-s\n",
"NAME", "TARGETS", "PROBES", "AGE")
case "imagepulljobs.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "PHASE", "COMPLETED", "FAILED", "TOTAL", "AGE")
case "podunavailablebudgets.policy.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "MAXUNAVAILABLE", "UNAVAILABLE", "DISRUPTIONS", "TARGETS", "AGE")
}
for _, info := range infos {
if err := o.printResourceInfo(info.Object, resourceType); err != nil {
return err
}
}
}
}
return nil
}
// Handle single resource type
b := o.Builder().
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
NamespaceParam(o.Namespace).DefaultNamespace().
ResourceTypeOrNameArgs(true, o.Resources...).
ContinueOnError().
Latest().
Flatten()
infos, err := b.Do().Infos()
if err != nil {
return err
}
if len(infos) > 0 {
switch o.Resources[0] {
case "clonesets.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-14s\t%-18s\t%-8s\t%-8s\t%-s\n",
"NAME", "DESIRED", "UPDATED", "UPDATED_READY", "UPDATED_AVAILABLE", "READY", "TOTAL", "AGE")
case "statefulsets.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "DESIRED", "CURRENT", "UPDATED", "READY", "AGE")
case "daemonsets.apps.kruise.io":
fmt.Fprintf(o.Out, "%-8s\t%-8s\t%-8s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "DESIRED", "CURRENT", "READY", "UP-TO-DATE", "AVAILABLE", "NODE SELECTOR", "AGE")
case "rollouts.rollouts.kruise.io":
fmt.Fprintf(o.Out, "%-20s\t%-8s\t%-12s\t%-12s\t%-40s\t%-s\n",
"NAME", "STATUS", "CANARY_STEP", "CANARY_STATE", "MESSAGE", "AGE")
case "broadcastjobs.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "DESIRED", "ACTIVE", "SUCCEEDED", "FAILED", "AGE")
case "containerrecreaterequests.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "PHASE", "COMPLETED", "FAILED", "AGE")
case "advancedcronjobs.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "SCHEDULE", "SUSPEND", "ACTIVE", "LAST SCHEDULE", "AGE")
case "resourcedistributions.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "TARGETS", "SUCCEEDED", "FAILED", "AGE")
case "uniteddeployments.apps.kruise.io":
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-8s\t%-s\n",
"NAME", "DESIRED", "UPDATED", "READY", "AVAILABLE", "AGE")
}
for _, info := range infos {
if err := o.printResourceInfo(info.Object, o.Resources[0]); err != nil {
return err
}
}
}
return nil
}
func (o *GetOptions) printResourceInfo(obj runtime.Object, resourceType string) error {
metaObj, ok := obj.(v1.Object)
if !ok {
return fmt.Errorf("object does not implement v1.Object interface")
}
name := metaObj.GetName()
age := time.Since(metaObj.GetCreationTimestamp().Time).Round(time.Second)
// Print based on resource type
switch resourceType {
case "clonesets.apps.kruise.io":
cloneset, ok := obj.(*kruiseappsv1alpha1.CloneSet)
if !ok {
return fmt.Errorf("object is not a CloneSet")
}
desired := cloneset.Spec.Replicas
updated := cloneset.Status.UpdatedReplicas
updatedReady := cloneset.Status.UpdatedReadyReplicas
updatedAvailable := cloneset.Status.UpdatedAvailableReplicas
ready := cloneset.Status.ReadyReplicas
total := cloneset.Status.Replicas
fmt.Fprintf(o.Out, "%-12s\t%-8d\t%-8d\t%-14d\t%-18d\t%-8d\t%-8d\t%-s\n",
name, *desired, updated, updatedReady, updatedAvailable, ready, total, age)
case "statefulsets.apps.kruise.io":
statefulset, ok := obj.(*kruiseappsv1beta1.StatefulSet)
if !ok {
return fmt.Errorf("object is not a StatefulSet")
}
desired := statefulset.Spec.Replicas
current := statefulset.Status.CurrentReplicas
updated := statefulset.Status.UpdatedReplicas
ready := statefulset.Status.ReadyReplicas
fmt.Fprintf(o.Out, "%-12s\t%-8d\t%-8d\t%-8d\t%-8d\t%-s\n",
name, *desired, current, updated, ready, age)
case "daemonsets.apps.kruise.io":
daemonset, ok := obj.(*kruiseappsv1alpha1.DaemonSet)
if !ok {
return fmt.Errorf("object is not a DaemonSet")
}
desired := daemonset.Status.DesiredNumberScheduled
current := daemonset.Status.CurrentNumberScheduled
ready := daemonset.Status.NumberReady
updated := daemonset.Status.UpdatedNumberScheduled
available := daemonset.Status.NumberAvailable
nodeSelector := daemonset.Spec.Template.Spec.NodeSelector
fmt.Fprintf(o.Out, "%-8s\t%-8d\t%-8d\t%-8d\t%-8d\t%-8d\t%-8s\t%-s\n",
name, desired, current, ready, updated, available, fmt.Sprintf("%v", nodeSelector), age)
case "rollouts.rollouts.kruise.io":
rollout, ok := obj.(*rolloutv1beta1.Rollout)
if !ok {
rolloutV1alpha1, ok := obj.(*rolloutv1alpha1.Rollout)
if !ok {
return fmt.Errorf("object is not a Rollout")
}
status := rolloutV1alpha1.Status.Phase
canaryStep := int32(0)
canaryState := string(rolloutv1alpha1.CanaryStepStateCompleted)
message := rolloutV1alpha1.Status.Message
if rolloutV1alpha1.Status.CanaryStatus != nil {
canaryStep = rolloutV1alpha1.Status.CanaryStatus.CurrentStepIndex
canaryState = string(rolloutV1alpha1.Status.CanaryStatus.CurrentStepState)
}
fmt.Fprintf(o.Out, "%-20s\t%-8s\t%-12d\t%-12s\t%-40s\t%-s\n",
name, status, canaryStep, canaryState, message, age)
return nil
}
status := rollout.Status.Phase
canaryStep := int32(0)
canaryState := string(rolloutv1beta1.CanaryStepStateCompleted)
message := rollout.Status.Message
if rollout.Status.CanaryStatus != nil {
canaryStep = rollout.Status.CanaryStatus.CurrentStepIndex
canaryState = string(rollout.Status.CanaryStatus.CurrentStepState)
}
fmt.Fprintf(o.Out, "%-20s\t%-8s\t%-12d\t%-12s\t%-40s\t%-s\n",
name, status, canaryStep, canaryState, message, age)
case "broadcastjobs.apps.kruise.io":
broadcastjob, ok := obj.(*kruiseappsv1alpha1.BroadcastJob)
if !ok {
return fmt.Errorf("object is not a BroadcastJob")
}
desired := broadcastjob.Spec.Parallelism
active := broadcastjob.Status.Active
successful := broadcastjob.Status.Succeeded
failed := broadcastjob.Status.Failed
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8d\t%-8d\t%-8d\t%-s\n",
name, desired.String(), active, successful, failed, age)
case "containerrecreaterequests.apps.kruise.io":
containerrecreaterequest, ok := obj.(*kruiseappsv1alpha1.ContainerRecreateRequest)
if !ok {
return fmt.Errorf("object is not a ContainerRecreateRequest")
}
phase := containerrecreaterequest.Status.Phase
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-s\n",
name, phase, "-", "-", age)
case "advancedcronjobs.apps.kruise.io":
advancedcronjob, ok := obj.(*kruiseappsv1alpha1.AdvancedCronJob)
if !ok {
return fmt.Errorf("object is not a AdvancedCronJob")
}
schedule := advancedcronjob.Spec.Schedule
suspend := advancedcronjob.Spec.Paused
active := len(advancedcronjob.Status.Active)
lastSchedule := advancedcronjob.Status.LastScheduleTime
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8v\t%-8d\t%-8s\t%-s\n",
name, schedule, suspend, active, lastSchedule, age)
case "resourcedistributions.apps.kruise.io":
_, ok := obj.(*kruiseappsv1alpha1.ResourceDistribution)
if !ok {
return fmt.Errorf("object is not a ResourceDistribution")
}
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8s\t%-8s\t%-s\n",
name, "-", "-", "-", age)
case "uniteddeployments.apps.kruise.io":
uniteddeployment, ok := obj.(*kruiseappsv1alpha1.UnitedDeployment)
if !ok {
return fmt.Errorf("object is not a UnitedDeployment")
}
desired := uniteddeployment.Spec.Replicas
updated := uniteddeployment.Status.UpdatedReplicas
ready := uniteddeployment.Status.ReadyReplicas
total := uniteddeployment.Status.Replicas
fmt.Fprintf(o.Out, "%-12s\t%-8d\t%-8d\t%-8d\t%-8d\t%-s\n",
name, *desired, updated, ready, total, age)
case "sidecarsets.apps.kruise.io":
sidecarset, ok := obj.(*kruiseappsv1alpha1.SidecarSet)
if !ok {
return fmt.Errorf("object is not a SidecarSet")
}
matched := sidecarset.Status.MatchedPods
updated := sidecarset.Status.UpdatedPods
ready := sidecarset.Status.ReadyPods
fmt.Fprintf(o.Out, "%-12s\t%-8d\t%-8d\t%-8d\t%-8s\t%-s\n",
name, matched, updated, ready, "-", age)
case "podprobemarkers.apps.kruise.io":
podprobemarker, ok := obj.(*kruiseappsv1alpha1.PodProbeMarker)
if !ok {
return fmt.Errorf("object is not a PodProbeMarker")
}
targets := len(podprobemarker.Spec.Selector.MatchLabels)
probes := len(podprobemarker.Spec.Probes)
fmt.Fprintf(o.Out, "%-12s\t%-8d\t%-8d\t%-s\n",
name, targets, probes, age)
case "imagepulljobs.apps.kruise.io":
imagepulljob, ok := obj.(*kruiseappsv1alpha1.ImagePullJob)
if !ok {
return fmt.Errorf("object is not a ImagePullJob")
}
completed := imagepulljob.Status.Succeeded
failed := imagepulljob.Status.Failed
total := imagepulljob.Status.Desired
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8d\t%-8d\t%-8d\t%-s\n",
name, "-", completed, failed, total, age)
case "podunavailablebudgets.policy.kruise.io":
pub, ok := obj.(*kruisepolicyv1alpha1.PodUnavailableBudget)
if !ok {
return fmt.Errorf("object is not a PodUnavailableBudget")
}
maxUnavailable := pub.Spec.MaxUnavailable
unavailable := pub.Status.UnavailablePods
disruptions := pub.Status.DisruptedPods
targets := len(pub.Spec.Selector.MatchLabels)
fmt.Fprintf(o.Out, "%-12s\t%-8s\t%-8d\t%-8d\t%-8d\t%-s\n",
name, maxUnavailable.String(), len(unavailable), len(disruptions), targets, age)
}
return nil
}

View File

@ -128,7 +128,7 @@ func (o *ApproveOptions) Validate() error {
}
// RunApprove performs the execution of 'rollout approve' sub command
func (o ApproveOptions) RunApprove() error {
func (o *ApproveOptions) RunApprove() error {
r := o.Builder().
WithScheme(internalapi.GetScheme(), scheme.Scheme.PrioritizedVersionsAllGroups()...).
NamespaceParam(o.Namespace).DefaultNamespace().

View File

@ -65,7 +65,10 @@ var (
kubectl-kruise rollout restart cloneset/abc
# Restart a daemonset
kubectl-kruise rollout restart daemonset/abc`)
kubectl-kruise rollout restart daemonset/abc
# Restart a UnitedDeployment
kubectl-kruise rollout restart uniteddeployment/my-app`)
)
// NewRolloutRestartOptions returns an initialized RestartOptions instance
@ -80,7 +83,7 @@ func NewRolloutRestartOptions(streams genericclioptions.IOStreams) *RestartOptio
func NewCmdRolloutRestart(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
o := NewRolloutRestartOptions(streams)
validArgs := []string{"deployment", "daemonset", "statefulset", "cloneset"}
validArgs := []string{"deployment", "daemonset", "statefulset", "cloneset", "uniteddeployment"}
cmd := &cobra.Command{
Use: "restart RESOURCE",

View File

@ -20,15 +20,19 @@ package rollout
import (
"fmt"
rolloutsapi "github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
rolloutsapiv1alpha1 "github.com/openkruise/kruise-rollout-api/rollouts/v1alpha1"
rolloutsapiv1beta1 "github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
internalapi "github.com/openkruise/kruise-tools/pkg/api"
"github.com/openkruise/kruise-tools/pkg/cmd/util"
internalpolymorphichelpers "github.com/openkruise/kruise-tools/pkg/internal/polymorphichelpers"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/errors"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/cli-runtime/pkg/printers"
"k8s.io/cli-runtime/pkg/resource"
"k8s.io/kubectl/pkg/cmd/set"
cmdutil "k8s.io/kubectl/pkg/cmd/util"
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util/i18n"
@ -44,12 +48,13 @@ type UndoOptions struct {
Builder func() *resource.Builder
ToRevision int64
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.QueryParamVerifier
Resources []string
Namespace string
EnforceNamespace bool
RESTClientGetter genericclioptions.RESTClientGetter
Fast bool // fast rollback for blue-green
resource.FilenameOptions
genericclioptions.IOStreams
}
@ -72,7 +77,10 @@ var (
kubectl-kruise rollout undo --dry-run=server deployment/abc
# Rollback to workload via rollout api object
kubectl-kruise rollout undo rollout/abc`)
kubectl-kruise rollout undo rollout/abc
# Fast rollback during blue-green release (will go back to a previous step with no traffic and most replicas)
kubectl-kruise rollout undo rollout/abc --fast`)
)
// NewRolloutUndoOptions returns an initialized UndoOptions instance
@ -99,12 +107,17 @@ func NewCmdRolloutUndo(f cmdutil.Factory, streams genericclioptions.IOStreams) *
Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(o.Complete(f, cmd, args))
cmdutil.CheckErr(o.Validate())
cmdutil.CheckErr(o.RunUndo())
if o.Fast {
cmdutil.CheckErr(o.FastUndo())
} else {
cmdutil.CheckErr(o.RunUndo())
}
},
ValidArgs: validArgs,
}
cmd.Flags().Int64Var(&o.ToRevision, "to-revision", o.ToRevision, "The revision to rollback to. Default to 0 (last revision).")
cmd.Flags().BoolVar(&o.Fast, "fast", false, "fast rollback for blue-green release")
usage := "identifying the resource to get from a server."
cmdutil.AddFilenameOptionFlags(cmd, &o.FilenameOptions, usage)
cmdutil.AddDryRunFlag(cmd)
@ -120,11 +133,6 @@ func (o *UndoOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []str
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
if o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace(); err != nil {
return err
@ -149,6 +157,76 @@ func (o *UndoOptions) Validate() error {
return nil
}
func (o *UndoOptions) FastUndo() error {
r := o.Builder().
WithScheme(internalapi.GetScheme(), scheme.Scheme.PrioritizedVersionsAllGroups()...).
NamespaceParam(o.Namespace).DefaultNamespace().
FilenameParam(o.EnforceNamespace, &o.FilenameOptions).
ResourceTypeOrNameArgs(true, o.Resources...).
ContinueOnError().
Latest().
Flatten().
Do()
if err := r.Err(); err != nil {
return err
}
allErrs := []error{}
infos, err := r.Infos()
if err != nil {
// restore previous command behavior where
// an error caused by retrieving infos due to
// at least a single broken object did not result
// in an immediate return, but rather an overall
// aggregation of errors.
allErrs = append(allErrs, err)
}
for _, patch := range set.CalculatePatches(infos, scheme.DefaultJSONEncoder(), internalpolymorphichelpers.DefaultFastRollbackFunc) {
info := patch.Info
if patch.Err != nil {
resourceString := info.Mapping.Resource.Resource
if len(info.Mapping.Resource.Group) > 0 {
resourceString = resourceString + "." + info.Mapping.Resource.Group
}
allErrs = append(allErrs, fmt.Errorf("error: %s %q %v", resourceString, info.Name, patch.Err))
continue
}
if string(patch.Patch) == "{}" || len(patch.Patch) == 0 {
printer, err := o.ToPrinter("already rolled back")
if err != nil {
allErrs = append(allErrs, err)
continue
}
if err = printer.PrintObj(info.Object, o.Out); err != nil {
allErrs = append(allErrs, err)
}
continue
}
obj, err := util.PatchSubResource(info.Client, info.Mapping.Resource.Resource, "status", info.Namespace, info.Name, info.Namespaced(), types.MergePatchType, patch.Patch, nil)
if err != nil {
allErrs = append(allErrs, fmt.Errorf("failed to patch: %v", err))
continue
}
info.Refresh(obj, true)
printer, err := o.ToPrinter("rolled back" +
"")
if err != nil {
allErrs = append(allErrs, err)
continue
}
if err = printer.PrintObj(info.Object, o.Out); err != nil {
allErrs = append(allErrs, err)
}
}
return errors.NewAggregate(allErrs)
}
// RunUndo performs the execution of 'rollout undo' sub command
func (o *UndoOptions) RunUndo() error {
r := o.Builder().
@ -173,11 +251,6 @@ func (o *UndoOptions) RunUndo() error {
return err
}
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
return err
}
}
result, err := rollbacker.Rollback(info.Object, nil, o.ToRevision, o.DryRunStrategy)
if err != nil {
return err
@ -208,11 +281,10 @@ func (o *UndoOptions) RunUndo() error {
if obj == nil {
return fmt.Errorf("Rollout object not found")
}
ro, ok := obj.(*rolloutsapi.Rollout)
if !ok {
return fmt.Errorf("unsupported version of Rollout")
workloadRef, err := getWorkloadRefFromRollout(obj)
if err != nil {
return err
}
workloadRef := ro.Spec.WorkloadRef
gv, err := schema.ParseGroupVersion(workloadRef.APIVersion)
if err != nil {
return err
@ -257,3 +329,19 @@ func (o *UndoOptions) RunUndo() error {
aggErrs = append(aggErrs, err)
return errors.NewAggregate(aggErrs)
}
func getWorkloadRefFromRollout(obj interface{}) (workloadRef *rolloutsapiv1beta1.ObjectRef, err error) {
switch rollout := obj.(type) {
case *rolloutsapiv1alpha1.Rollout:
workloadRef = &rolloutsapiv1beta1.ObjectRef{
Kind: rollout.Spec.ObjectRef.WorkloadRef.Kind,
APIVersion: rollout.Spec.ObjectRef.WorkloadRef.APIVersion,
Name: rollout.Spec.ObjectRef.WorkloadRef.Name,
}
case *rolloutsapiv1beta1.Rollout:
workloadRef = &rollout.Spec.WorkloadRef
default:
return nil, fmt.Errorf("unsupported version of Rollout")
}
return workloadRef, nil
}

View File

@ -123,7 +123,6 @@ type EnvOptions struct {
resources []string
output string
dryRunStrategy cmdutil.DryRunStrategy
dryRunVerifier *resource.QueryParamVerifier
builder func() *resource.Builder
updatePodSpecForObject polymorphichelpers.UpdatePodSpecForObjectFunc
namespace string
@ -226,11 +225,6 @@ func (o *EnvOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.dryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.dryRunStrategy)
printer, err := o.PrintFlags.ToPrinter()
@ -781,13 +775,6 @@ func (o *EnvOptions) RunEnv() error {
continue
}
if o.dryRunStrategy == cmdutil.DryRunServer {
if err := o.dryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
allErrs = append(allErrs, err)
continue
}
}
actual, err := resource.
NewHelper(info.Client, info.Mapping).
DryRun(o.dryRunStrategy == cmdutil.DryRunServer).

View File

@ -47,7 +47,6 @@ type SetImageOptions struct {
Infos []*resource.Info
Selector string
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.QueryParamVerifier
All bool
Output string
Local bool
@ -147,11 +146,6 @@ func (o *SetImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
o.Output = cmdutil.GetFlagString(cmd, "output")
o.ResolveImage = resolveImageFunc
@ -283,12 +277,6 @@ func (o *SetImageOptions) Run() error {
continue
}
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
return err
}
}
// patch the change
actual, err := resource.
NewHelper(info.Client, info.Mapping).

View File

@ -93,7 +93,6 @@ type SetResourcesOptions struct {
UpdatePodSpecForObject polymorphichelpers.UpdatePodSpecForObjectFunc
Resources []string
DryRunVerifier *resource.QueryParamVerifier
genericclioptions.IOStreams
}
@ -167,11 +166,6 @@ func (o *SetResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, ar
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
printer, err := o.PrintFlags.ToPrinter()
@ -431,13 +425,6 @@ func (o *SetResourcesOptions) Run() error {
continue
}
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
allErrs = append(allErrs, fmt.Errorf("failed to patch resources update to pod template %v", err))
continue
}
}
actual, err := resource.
NewHelper(info.Client, info.Mapping).
DryRun(o.DryRunStrategy == cmdutil.DryRunServer).

View File

@ -45,7 +45,6 @@ type SetSelectorOptions struct {
PrintFlags *genericclioptions.PrintFlags
RecordFlags *genericclioptions.RecordFlags
dryRunStrategy cmdutil.DryRunStrategy
dryRunVerifier *resource.QueryParamVerifier
// set by args
resources []string
@ -134,11 +133,6 @@ func (o *SetSelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.dryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
o.resources, o.selector, err = getResourcesAndSelector(args)
if err != nil {
@ -211,11 +205,6 @@ func (o *SetSelectorOptions) RunSelector() error {
if !o.WriteToServer {
return o.PrintObj(info.Object, o.Out)
}
if o.dryRunStrategy == cmdutil.DryRunServer {
if err := o.dryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
return err
}
}
actual, err := resource.
NewHelper(info.Client, info.Mapping).

View File

@ -63,7 +63,6 @@ type SetServiceAccountOptions struct {
fileNameOptions resource.FilenameOptions
dryRunStrategy cmdutil.DryRunStrategy
dryRunVerifier *resource.QueryParamVerifier
shortOutput bool
all bool
output string
@ -136,11 +135,6 @@ func (o *SetServiceAccountOptions) Complete(f cmdutil.Factory, cmd *cobra.Comman
if o.local && o.dryRunStrategy == cmdutil.DryRunServer {
return fmt.Errorf("cannot specify --local and --dry-run=server - did you mean --dry-run=client?")
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.dryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
o.output = cmdutil.GetFlagString(cmd, "output")
o.updatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn
@ -212,12 +206,6 @@ func (o *SetServiceAccountOptions) Run() error {
}
continue
}
if o.dryRunStrategy == cmdutil.DryRunServer {
if err := o.dryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
patchErrs = append(patchErrs, err)
continue
}
}
actual, err := resource.
NewHelper(info.Client, info.Mapping).
DryRun(o.dryRunStrategy == cmdutil.DryRunServer).

View File

@ -66,7 +66,6 @@ type SubjectOptions struct {
Output string
All bool
DryRunStrategy cmdutil.DryRunStrategy
DryRunVerifier *resource.QueryParamVerifier
Local bool
Users []string
@ -126,11 +125,6 @@ func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []
if err != nil {
return err
}
dynamicClient, err := f.DynamicClient()
if err != nil {
return err
}
o.DryRunVerifier = resource.NewQueryParamVerifier(dynamicClient, f.OpenAPIGetter(), resource.QueryParamDryRun)
cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
printer, err := o.PrintFlags.ToPrinter()
@ -268,12 +262,6 @@ func (o *SubjectOptions) Run(fn updateSubjects) error {
continue
}
if o.DryRunStrategy == cmdutil.DryRunServer {
if err := o.DryRunVerifier.HasSupport(info.Mapping.GroupVersionKind); err != nil {
allErrs = append(allErrs, err)
continue
}
}
actual, err := resource.
NewHelper(info.Client, info.Mapping).
DryRun(o.DryRunStrategy == cmdutil.DryRunServer).

View File

@ -38,7 +38,11 @@ type control struct {
func NewControl(cfg *rest.Config) (creation.Control, error) {
scheme := api.GetScheme()
mapper, err := apiutil.NewDynamicRESTMapper(cfg)
c, err := rest.HTTPClientFor(cfg)
if err != nil {
return nil, err
}
mapper, err := apiutil.NewDynamicRESTMapper(cfg, c)
if err != nil {
return nil, err
}

View File

@ -0,0 +1,8 @@
package polymorphichelpers
import (
rolloutschema "github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
)
type RolloutViewer func(obj runtime.Unstructured) (*rolloutschema.Rollout, error)

View File

@ -0,0 +1,55 @@
/*
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.
*/
package polymorphichelpers
import (
"fmt"
kruiseappsv1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
kruiseappsv1beta1 "github.com/openkruise/kruise-api/apps/v1beta1"
kruisepolicyv1alpha1 "github.com/openkruise/kruise-api/policy/v1alpha1"
rolloutv1alpha1 "github.com/openkruise/kruise-rollout-api/rollouts/v1alpha1"
rolloutv1beta1 "github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/cli-runtime/pkg/printers"
)
// getViewer returns a printer for Kruise resources
func getViewer(obj runtime.Object) (interface{}, error) {
switch obj.(type) {
case *kruiseappsv1alpha1.CloneSet,
*kruiseappsv1beta1.StatefulSet,
*kruiseappsv1alpha1.DaemonSet,
*rolloutv1beta1.Rollout,
*rolloutv1alpha1.Rollout,
*kruiseappsv1alpha1.BroadcastJob,
*kruiseappsv1alpha1.ContainerRecreateRequest,
*kruiseappsv1alpha1.AdvancedCronJob,
*kruiseappsv1alpha1.ResourceDistribution,
*kruiseappsv1alpha1.UnitedDeployment,
*kruiseappsv1alpha1.SidecarSet,
*kruiseappsv1alpha1.PodProbeMarker,
*kruiseappsv1alpha1.ImagePullJob,
*kruisepolicyv1alpha1.PodUnavailableBudget:
return printers.NewTablePrinter(printers.PrintOptions{
WithKind: true,
WithNamespace: true,
}), nil
default:
return nil, fmt.Errorf("no viewer has been implemented for %T", obj)
}
}

View File

@ -25,6 +25,7 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/cli-runtime/pkg/genericclioptions"
"k8s.io/client-go/rest"
"k8s.io/kubectl/pkg/cmd/set"
)
// LogsForObjectFunc is a function type that can tell you how to get logs for a runtime.object
@ -51,6 +52,10 @@ type StatusViewerFunc func(mapping *meta.RESTMapping) (StatusViewer, error)
// StatusViewerFn gives a way to easily override the function for unit testing if needed
var StatusViewerFn StatusViewerFunc = statusViewer
type RolloutViewerFunc func(obj runtime.Object) (interface{}, error)
var RolloutViewerFn RolloutViewerFunc = rolloutViewer
// UpdatePodSpecForObjectFunc will call the provided function on the pod spec this object supports,
// return false if no pod spec is supported, or return an error.
type UpdatePodSpecForObjectFunc func(obj runtime.Object, fn func(*v1.PodSpec) error) (bool, error)
@ -58,6 +63,10 @@ type UpdatePodSpecForObjectFunc func(obj runtime.Object, fn func(*v1.PodSpec) er
// UpdatePodSpecForObjectFn gives a way to easily override the function for unit testing if needed
var UpdatePodSpecForObjectFn UpdatePodSpecForObjectFunc = updatePodSpecForObject
type GetViewerFunc func(obj runtime.Object) (interface{}, error)
var GetViewerFn GetViewerFunc = getViewer
// MapBasedSelectorForObjectFunc will call the provided function on mapping the baesd selector for object,
// return "" if object is not supported, or return an error.
type MapBasedSelectorForObjectFunc func(object runtime.Object) (string, error)
@ -120,3 +129,6 @@ type ObjectRestarterFunc func(runtime.Object) ([]byte, error)
// ObjectRestarterFn gives a way to easily override the function for unit testing if needed.
// Returns the patched object in bytes and any error that occurred during the encoding.
var ObjectRestarterFn ObjectRestarterFunc = defaultObjectRestarter
// DefaultFastRollbackFunc is a function type that rollbacks a rollout process.
var DefaultFastRollbackFunc set.PatchFn = defaultRolloutRollbackGetter(-1)

View File

@ -20,7 +20,8 @@ import (
"errors"
"fmt"
rolloutsapi "github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
rolloutsapiv1alpha1 "github.com/openkruise/kruise-rollout-api/rollouts/v1alpha1"
rolloutsapiv1beta1 "github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/kubectl/pkg/scheme"
)
@ -28,12 +29,28 @@ import (
// defaultObjectApprover currently only support Kruise Rollout.
func defaultObjectApprover(obj runtime.Object) ([]byte, error) {
switch obj := obj.(type) {
case *rolloutsapi.Rollout:
if obj.Status.CanaryStatus == nil || obj.Status.CanaryStatus.CurrentStepState != rolloutsapi.CanaryStepStatePaused {
case *rolloutsapiv1alpha1.Rollout:
if obj.Status.CanaryStatus == nil || obj.Status.CanaryStatus.CurrentStepState != rolloutsapiv1alpha1.CanaryStepStatePaused {
return nil, errors.New("does not allow to approve, because current canary state is not 'StepPaused'")
}
obj.Status.CanaryStatus.CurrentStepState = rolloutsapi.CanaryStepStateReady
return runtime.Encode(scheme.Codecs.LegacyCodec(rolloutsapi.GroupVersion), obj)
obj.Status.CanaryStatus.CurrentStepState = rolloutsapiv1alpha1.CanaryStepStateReady
return runtime.Encode(scheme.Codecs.LegacyCodec(rolloutsapiv1alpha1.GroupVersion), obj)
case *rolloutsapiv1beta1.Rollout:
switch {
case obj.Status.CanaryStatus != nil:
if obj.Status.CanaryStatus.CurrentStepState != rolloutsapiv1beta1.CanaryStepStatePaused {
return nil, fmt.Errorf("does not allow to approve, because current canary state is not '%s'", rolloutsapiv1beta1.CanaryStepStatePaused)
}
obj.Status.CanaryStatus.CurrentStepState = rolloutsapiv1beta1.CanaryStepStateReady
case obj.Status.BlueGreenStatus != nil:
if obj.Status.BlueGreenStatus.CurrentStepState != rolloutsapiv1beta1.CanaryStepStatePaused {
return nil, fmt.Errorf("does not allow to approve, because current blue-green state is not '%s'", rolloutsapiv1beta1.CanaryStepStatePaused)
}
obj.Status.BlueGreenStatus.CurrentStepState = rolloutsapiv1beta1.CanaryStepStateReady
default:
return nil, fmt.Errorf("no need to approve: not in canary or blue-green progress")
}
return runtime.Encode(scheme.Codecs.LegacyCodec(rolloutsapiv1beta1.GroupVersion), obj)
default:
return nil, fmt.Errorf("approving is not supported")

View File

@ -0,0 +1,38 @@
/*
Copyright 2018 The Kubernetes 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 polymorphichelpers
import (
"fmt"
"k8s.io/apimachinery/pkg/runtime"
rolloutv1alpha1 "github.com/openkruise/kruise-rollout-api/rollouts/v1alpha1"
rolloutv1beta1 "github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
)
// statusViewer returns a StatusViewer for printing rollout status.
func rolloutViewer(obj runtime.Object) (interface{}, error) {
if rollout, ok := obj.(*rolloutv1beta1.Rollout); ok {
return rollout, nil
}
if rollout, ok := obj.(*rolloutv1alpha1.Rollout); ok {
return rollout, nil
}
return nil, fmt.Errorf("unknown rollout type: %T", obj)
}

View File

@ -0,0 +1,79 @@
package polymorphichelpers
import (
"fmt"
"github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/klog/v2"
"k8s.io/kubectl/pkg/scheme"
)
func defaultRolloutRollbackGetter(targetStep int32) func(runtime.Object) ([]byte, error) {
return func(obj runtime.Object) ([]byte, error) {
switch rollout := obj.(type) {
case *v1beta1.Rollout:
steps := rollout.Spec.Strategy.GetSteps()
curStep := rollout.Status.CurrentStepIndex
if len(steps) < int(curStep) {
return nil, fmt.Errorf("has %d steps, but current step is too large %d", len(steps), curStep)
}
if curStep <= 1 {
return nil, fmt.Errorf("already at the first step")
}
if targetStep == -1 {
s, err := findPreviousStepWithNoTrafficAndMostReplicas(steps, rollout.Status.CurrentStepIndex)
if err != nil {
return nil, err
}
targetStep = s
}
if targetStep >= rollout.Status.CurrentStepIndex {
return nil, fmt.Errorf("specified step %d is not a previous step (current step is %d)", targetStep, rollout.Status.CurrentStepIndex)
}
style := rollout.Spec.Strategy.GetRollingStyle()
switch style {
case v1beta1.BlueGreenRollingStyle:
rollout.Status.BlueGreenStatus.NextStepIndex = targetStep
default:
// canary and partition
rollout.Status.CanaryStatus.NextStepIndex = targetStep
}
return runtime.Encode(scheme.Codecs.LegacyCodec(v1beta1.GroupVersion), rollout)
default:
return nil, fmt.Errorf("rollback is not supported on given object")
}
}
}
func findPreviousStepWithNoTrafficAndMostReplicas(steps []v1beta1.CanaryStep, curStep int32) (int32, error) {
maxReplicas := 0
var targetStep int32 = -1
for i := curStep - 2; i >= 0; i-- {
step := steps[i]
if hasTraffic(step) {
klog.V(5).InfoS("has traffic", "step", i+1)
continue
}
replicas, _ := intstr.GetScaledValueFromIntOrPercent(step.Replicas, 100, true)
klog.V(5).InfoS("replicas percent", "percent", replicas, "step", i+1, "obj", step)
if replicas > maxReplicas {
maxReplicas = replicas
targetStep = i + 1
}
}
if targetStep == -1 {
return 0, fmt.Errorf("no previous step with no traffic found")
}
return targetStep, nil
}
func hasTraffic(step v1beta1.CanaryStep) bool {
if step.Traffic == nil {
return false
}
is := intstr.FromString(*step.Traffic)
trafficPercent, _ := intstr.GetScaledValueFromIntOrPercent(&is, 100, true)
return trafficPercent != 0
}

View File

@ -0,0 +1,162 @@
package polymorphichelpers
import (
"encoding/json"
"testing"
"github.com/openkruise/kruise-rollout-api/rollouts/v1alpha1"
"github.com/openkruise/kruise-rollout-api/rollouts/v1beta1"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/kubectl/pkg/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"
)
func init() {
_ = v1beta1.AddToScheme(scheme.Scheme)
}
func TestRolloutRollbackGetter(t *testing.T) {
getRollout := func(currentIdx int32, steps []v1beta1.CanaryStep) []client.Object {
canary := &v1beta1.Rollout{
Status: v1beta1.RolloutStatus{
CurrentStepIndex: currentIdx,
},
}
canary.Spec.Strategy.Canary = &v1beta1.CanaryStrategy{
Steps: steps,
EnableExtraWorkloadForCanary: true,
}
canary.Status.CanaryStatus = &v1beta1.CanaryStatus{}
blueGreen := canary.DeepCopy()
blueGreen.Spec.Strategy.BlueGreen = &v1beta1.BlueGreenStrategy{
Steps: steps,
}
blueGreen.Status.BlueGreenStatus = &v1beta1.BlueGreenStatus{}
return []client.Object{canary, blueGreen}
}
newStep := func(replicas string, traffic string) v1beta1.CanaryStep {
r := intstr.FromString(replicas)
var trafficPtr *string
if traffic != "" {
trafficPtr = &traffic
}
return v1beta1.CanaryStep{
Replicas: &r,
TrafficRoutingStrategy: v1beta1.TrafficRoutingStrategy{
Traffic: trafficPtr,
},
}
}
tests := []struct {
name string
rollout []client.Object
targetStep int32
expectedStep int32
expectedErr string
}{
{
name: "valid rollback to previous step",
rollout: getRollout(3, []v1beta1.CanaryStep{
newStep("10%", ""),
newStep("20%", ""),
newStep("30%", ""),
}),
targetStep: 2,
expectedStep: 2,
},
{
name: "invalid rollback to same or future step",
rollout: getRollout(3, []v1beta1.CanaryStep{
newStep("10%", ""),
newStep("20%", ""),
newStep("30%", ""),
}),
targetStep: 3,
expectedErr: "specified step 3 is not a previous step (current step is 3)",
},
{
name: "rollback to previous step with no traffic and most replicas",
rollout: getRollout(4, []v1beta1.CanaryStep{
newStep("10%", ""),
newStep("20%", ""),
newStep("30%", "50%"),
newStep("40%", "50%"),
}),
targetStep: -1,
expectedStep: 2,
},
{
name: "no previous step with no traffic found",
rollout: getRollout(5, []v1beta1.CanaryStep{
newStep("10%", "10%"),
newStep("20%", "10%"),
newStep("30%", "10%"),
newStep("40%", "10%"),
newStep("50%", "10%"),
}),
targetStep: -1,
expectedErr: "no previous step with no traffic found",
},
{
name: "already at the first step",
rollout: getRollout(1, []v1beta1.CanaryStep{
newStep("10%", ""),
}),
targetStep: 2,
expectedErr: "already at the first step",
},
{
name: "current step index out of range",
rollout: getRollout(3, []v1beta1.CanaryStep{
newStep("10%", ""),
newStep("20%", ""),
}),
targetStep: 2,
expectedErr: "has 2 steps, but current step is too large 3",
},
{
name: "not supported object",
rollout: []client.Object{&v1alpha1.Rollout{}},
expectedErr: "rollback is not supported on given object",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
rollback := defaultRolloutRollbackGetter(tt.targetStep)
for _, rollout := range tt.rollout {
data, err := rollback(rollout)
if tt.expectedErr != "" {
if err == nil || err.Error() != tt.expectedErr {
t.Errorf("expected error %v, got %v", tt.expectedErr, err)
}
return
}
if err != nil {
t.Errorf("unexpected error: %v", err)
return
}
var updatedRollout v1beta1.Rollout
if err := json.Unmarshal(data, &updatedRollout); err != nil {
t.Errorf("failed to unmarshal updated rollout: %v", err)
return
}
var nextStepIndex int32
if updatedRollout.Spec.Strategy.GetRollingStyle() == v1beta1.BlueGreenRollingStyle {
nextStepIndex = updatedRollout.Status.BlueGreenStatus.NextStepIndex
} else {
nextStepIndex = updatedRollout.Status.CanaryStatus.NextStepIndex
}
if nextStepIndex != tt.expectedStep {
t.Errorf("expected next step index %d, got %d", tt.expectedStep, nextStepIndex)
}
}
})
}
}

View File

@ -22,10 +22,7 @@ import (
"sync"
"time"
appsv1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
"github.com/openkruise/kruise-tools/pkg/api"
"github.com/openkruise/kruise-tools/pkg/migration"
"github.com/openkruise/kruise-tools/pkg/utils"
"k8s.io/client-go/discovery"
apps "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -35,10 +32,15 @@ import (
"k8s.io/apimachinery/pkg/util/uuid"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/rest"
"k8s.io/client-go/restmapper"
"k8s.io/client-go/util/workqueue"
"sigs.k8s.io/controller-runtime/pkg/cache"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
appsv1alpha1 "github.com/openkruise/kruise-api/apps/v1alpha1"
"github.com/openkruise/kruise-tools/pkg/api"
"github.com/openkruise/kruise-tools/pkg/migration"
"github.com/openkruise/kruise-tools/pkg/utils"
)
var (
@ -77,10 +79,20 @@ var _ migration.Control = &control{}
func NewControl(cfg *rest.Config, stopChan <-chan struct{}) (migration.Control, error) {
scheme := api.GetScheme()
mapper, err := apiutil.NewDiscoveryRESTMapper(cfg)
c, err := rest.HTTPClientFor(cfg)
if err != nil {
return nil, err
}
// Get a mapper
dc, err := discovery.NewDiscoveryClientForConfigAndClient(cfg, c)
if err != nil {
return nil, err
}
gr, err := restmapper.GetAPIGroupResources(dc)
if err != nil {
return nil, err
}
mapper := restmapper.NewDiscoveryRESTMapper(gr)
ctrl := &control{
stopChan: stopChan,

View File

@ -30,7 +30,7 @@ type cloneSetHandler struct {
var _ toolscache.ResourceEventHandler = &cloneSetHandler{}
func (ch *cloneSetHandler) OnAdd(obj interface{}) {
func (ch *cloneSetHandler) OnAdd(obj interface{}, isInInitialList bool) {
d, ok := obj.(*appsv1alpha1.CloneSet)
if !ok {
return
@ -94,7 +94,7 @@ type deploymentHandler struct {
var _ toolscache.ResourceEventHandler = &deploymentHandler{}
func (dh *deploymentHandler) OnAdd(obj interface{}) {
func (dh *deploymentHandler) OnAdd(obj interface{}, isInInitialList bool) {
d, ok := obj.(*apps.Deployment)
if !ok {
return

73
pkg/utils/math_test.go Normal file
View File

@ -0,0 +1,73 @@
/*
Copyright 2025 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 utils
import "testing"
func TestInt32Min(t *testing.T) {
testCases := []struct {
name string
a int32
items []int32
expected int32
}{
{
name: "No extra items",
a: 10,
items: []int32{},
expected: 10,
},
{
name: "All positive numbers",
a: 10,
items: []int32{5, 20, 12},
expected: 5,
},
{
name: "With negative numbers",
a: -5,
items: []int32{10, -2, -10},
expected: -10,
},
{
name: "With zero",
a: 1,
items: []int32{5, 0, 2},
expected: 0,
},
{
name: "All numbers are the same",
a: 7,
items: []int32{7, 7, 7},
expected: 7,
},
{
name: "Initial value 'a' is the minimum",
a: 3,
items: []int32{10, 5, 8},
expected: 3,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if got := Int32Min(tc.a, tc.items...); got != tc.expected {
t.Errorf("Int32Min() = %v, want %v", got, tc.expected)
}
})
}
}

132
pkg/utils/misc_test.go Normal file
View File

@ -0,0 +1,132 @@
/*
Copyright 2025 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 utils
import (
"testing"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Helper function for string pointers
func strPtr(s string) *string { return &s }
func TestIsKruiseRolloutsAnnotation(t *testing.T) {
testCases := []struct {
name string
input *string
expected bool
}{
{name: "Nil string", input: nil, expected: false},
{name: "Kruise prefix", input: strPtr("rollouts.kruise.io/annotation"), expected: true},
{name: "Non-matching string", input: strPtr("other.domain/key"), expected: false},
{name: "Exact prefix", input: strPtr("rollouts.kruise.io/"), expected: true},
{name: "Empty string", input: strPtr(""), expected: false},
{name: "Substring match", input: strPtr("pre/rollouts.kruise.io/suffix"), expected: true},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if got := IsKruiseRolloutsAnnotation(tc.input); got != tc.expected {
t.Errorf("expected %v, got %v", tc.expected, got)
}
})
}
}
func TestInCanaryProgress(t *testing.T) {
testCases := []struct {
name string
deployment *appsv1.Deployment
expected bool
}{
{
name: "Not paused",
deployment: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{Paused: false},
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{InRolloutProgressingAnnotation: "true"}},
},
expected: false,
},
{
name: "Missing progressing annotation",
deployment: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{Paused: true},
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}},
},
expected: false,
},
{
name: "Has strategy annotation",
deployment: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{Paused: true},
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
InRolloutProgressingAnnotation: "true",
DeploymentStrategyAnnotation: "partition",
},
},
},
expected: false,
},
{
name: "Valid canary state",
deployment: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{Paused: true},
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{InRolloutProgressingAnnotation: "true"},
},
},
expected: true,
},
{
name: "Nil annotations",
deployment: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{Paused: true},
ObjectMeta: metav1.ObjectMeta{},
},
expected: false,
},
{
name: "Explicit empty annotations",
deployment: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{Paused: true},
ObjectMeta: metav1.ObjectMeta{Annotations: map[string]string{}},
},
expected: false,
},
{
name: "Only strategy annotation present",
deployment: &appsv1.Deployment{
Spec: appsv1.DeploymentSpec{Paused: true},
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{DeploymentStrategyAnnotation: "partition"},
},
},
expected: false,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if got := InCanaryProgress(tc.deployment); got != tc.expected {
t.Errorf("expected %v, got %v", tc.expected, got)
}
})
}
}