Compare commits
6 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
7c240e5828 | |
|
|
da2b3fbac8 | |
|
|
ebb124d8cd | |
|
|
68d571ec42 | |
|
|
d973c2aa1d | |
|
|
94742398cd |
|
|
@ -12,7 +12,7 @@ on:
|
|||
|
||||
env:
|
||||
# Common versions
|
||||
GO_VERSION: '1.22'
|
||||
GO_VERSION: '1.23'
|
||||
GOLANGCI_VERSION: 'v1.55.2'
|
||||
|
||||
jobs:
|
||||
|
|
@ -27,6 +27,14 @@ jobs:
|
|||
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@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0
|
||||
with:
|
||||
|
|
@ -47,13 +55,69 @@ jobs:
|
|||
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 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 ./...
|
||||
|
|
@ -6,7 +6,6 @@ on:
|
|||
- created
|
||||
|
||||
env:
|
||||
# Common versions
|
||||
GO_VERSION: '1.22'
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
|
@ -15,101 +14,137 @@ jobs:
|
|||
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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- 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@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 }}-${{ steps.get_release.outputs.tag_name }}.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 }}-${{ steps.get_release.outputs.tag_name }}.tar.gz
|
||||
asset_content_type: binary/octet-stream
|
||||
- name: Post sha256
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sha256sums-${{ steps.get_matrix.outputs.OS }}-${{ steps.get_matrix.outputs.ARCH }}
|
||||
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:
|
||||
|
||||
- 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 artifacts
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Download all artifacts
|
||||
uses: actions/download-artifact@v4.1.7
|
||||
with:
|
||||
pattern: sha256sums-*
|
||||
pattern: "*"
|
||||
merge-multiple: true
|
||||
path: sha256sums
|
||||
- shell: bash
|
||||
path: artifacts
|
||||
|
||||
- name: Prepare release assets
|
||||
run: |
|
||||
cat sha256sums/*.txt > sha256sums.txt
|
||||
- name: Upload Checksums
|
||||
uses: actions/upload-release-asset@v1.0.2
|
||||
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
|
||||
|
||||
# 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-${{ steps.get_release.outputs.tag_name }}.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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
# Temporary exclusion - proxy/tokenizer vulnerabilities don't affect our usage
|
||||
CVE-2025-22870
|
||||
CVE-2025-22872
|
||||
54
README.md
54
README.md
|
|
@ -198,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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
4
go.mod
4
go.mod
|
|
@ -1,8 +1,8 @@
|
|||
module github.com/openkruise/kruise-tools
|
||||
|
||||
go 1.22.0
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.22.4
|
||||
toolchain go1.23.4
|
||||
|
||||
require (
|
||||
github.com/go-errors/errors v1.4.2
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue