mirror of
https://github.com/kubevela/kubevela.git
synced 2026-02-27 16:23:52 +00:00
Compare commits
47 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2fe0b9fdc | ||
|
|
217a71e598 | ||
|
|
bbbdd0d299 | ||
|
|
f89622eec7 | ||
|
|
8401ff4d85 | ||
|
|
17b7edca9e | ||
|
|
773149aa53 | ||
|
|
a8b652e59d | ||
|
|
36f217e258 | ||
|
|
c298c0eb06 | ||
|
|
8aabc9f789 | ||
|
|
af1ce628d1 | ||
|
|
707ae396ce | ||
|
|
c0e906629e | ||
|
|
90e601a51e | ||
|
|
2139c813ad | ||
|
|
d6ad578070 | ||
|
|
2758afb1b2 | ||
|
|
70e6c9a49f | ||
|
|
2d46bb300f | ||
|
|
6fbeb6887f | ||
|
|
e533898192 | ||
|
|
72d5c2f0a5 | ||
|
|
e8428e704c | ||
|
|
56bc3b02e9 | ||
|
|
af1fb9a0fd | ||
|
|
8b7950cf61 | ||
|
|
a5de74ec1e | ||
|
|
3aa94842fb | ||
|
|
1a934e1618 | ||
|
|
721c75e44a | ||
|
|
d598d0a6fd | ||
|
|
4a9ecd9ce7 | ||
|
|
a27261bd14 | ||
|
|
0b6092cf2b | ||
|
|
aebccf90d0 | ||
|
|
3f5b5e6593 | ||
|
|
b5a9925042 | ||
|
|
c79f03fe92 | ||
|
|
fedcca1c7b | ||
|
|
b601d28afd | ||
|
|
7d72fa904c | ||
|
|
4d6fa58c0f | ||
|
|
26123cf671 | ||
|
|
ad9cda63c9 | ||
|
|
011e1f1445 | ||
|
|
974d3e88bf |
35
.github/actions/deploy-current-branch/README.md
vendored
Normal file
35
.github/actions/deploy-current-branch/README.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
# Deploy Current Branch Action
|
||||
|
||||
This GitHub composite action builds a Docker image from the current branch commit and deploys it to a KubeVela cluster for development testing.
|
||||
|
||||
## What it does
|
||||
|
||||
- Generates a unique image tag from the latest commit hash
|
||||
- Builds and loads the Docker image into a KinD cluster
|
||||
- Applies KubeVela CRDs for upgrade safety
|
||||
- Upgrades the KubeVela Helm release to use the local development image
|
||||
- Verifies deployment status and the running image version
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- name: Deploy Current Branch
|
||||
uses: ./path/to/this/action
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Docker, Helm, kubectl, and KinD must be available in your runner environment
|
||||
- Kubernetes cluster access
|
||||
- `charts/vela-core/crds` directory with CRDs
|
||||
- Valid Helm chart at `charts/vela-core`
|
||||
|
||||
## Steps performed
|
||||
|
||||
1. **Generate commit hash for image tag**
|
||||
2. **Build & load Docker image into KinD**
|
||||
3. **Pre-apply chart CRDs**
|
||||
4. **Upgrade KubeVela using local image**
|
||||
5. **Verify deployment and image version**
|
||||
|
||||
---
|
||||
89
.github/actions/deploy-current-branch/action.yaml
vendored
Normal file
89
.github/actions/deploy-current-branch/action.yaml
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
name: 'Deploy Current Branch'
|
||||
description: 'Builds Docker image from current branch commit and deploys it to KubeVela cluster for development testing'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# ========================================================================
|
||||
# Git Commit Hash Generation
|
||||
# Generate unique image tag from current branch's latest commit
|
||||
# ========================================================================
|
||||
- name: Get commit hash
|
||||
id: commit_hash
|
||||
shell: bash
|
||||
run: |
|
||||
COMMIT_HASH="git-$(git rev-parse --short HEAD)"
|
||||
echo "Using commit hash: $COMMIT_HASH"
|
||||
echo "COMMIT_HASH=$COMMIT_HASH" >> $GITHUB_ENV
|
||||
|
||||
# ========================================================================
|
||||
# Docker Image Build and Cluster Loading
|
||||
# Build development image from current code and load into KinD cluster
|
||||
# ========================================================================
|
||||
- name: Build and load Docker image
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Building development image: vela-core-test:${{ env.COMMIT_HASH }}"
|
||||
|
||||
mkdir -p $HOME/tmp/
|
||||
|
||||
docker build --no-cache \
|
||||
-t vela-core-test:${{ env.COMMIT_HASH }} \
|
||||
-f Dockerfile .
|
||||
|
||||
echo "Loading image into KinD cluster..."
|
||||
TMPDIR=$HOME/tmp/ kind load docker-image vela-core-test:${{ env.COMMIT_HASH }}
|
||||
|
||||
# ========================================================================
|
||||
# Custom Resource Definitions Application
|
||||
# Pre-apply CRDs to ensure upgrade compatibility and prevent conflicts
|
||||
# ========================================================================
|
||||
- name: Pre-apply CRDs from target chart (upgrade-safe)
|
||||
shell: bash
|
||||
run: |
|
||||
CRD_DIR="charts/vela-core/crds"
|
||||
|
||||
echo "Applying CRDs idempotently..."
|
||||
kubectl apply -f "${CRD_DIR}"
|
||||
|
||||
# ========================================================================
|
||||
# KubeVela Helm Chart Upgrade
|
||||
# Upgrade existing installation to use locally built development image
|
||||
# ========================================================================
|
||||
- name: Upgrade KubeVela to development image
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Upgrading KubeVela to development version..."
|
||||
helm upgrade kubevela ./charts/vela-core \
|
||||
--namespace vela-system \
|
||||
--set image.repository=vela-core-test \
|
||||
--set image.tag=${{ env.COMMIT_HASH }} \
|
||||
--set image.pullPolicy=IfNotPresent \
|
||||
--timeout 5m \
|
||||
--wait \
|
||||
--debug
|
||||
|
||||
# ========================================================================
|
||||
# Deployment Status Verification
|
||||
# Verify successful upgrade and confirm correct image deployment
|
||||
# ========================================================================
|
||||
- name: Verify deployment status
|
||||
shell: bash
|
||||
run: |
|
||||
echo "=== DEPLOYMENT VERIFICATION ==="
|
||||
echo "Verifying upgrade to local development image..."
|
||||
|
||||
echo "--- Pod Status ---"
|
||||
kubectl get pods -n vela-system
|
||||
|
||||
echo "--- Deployment Rollout ---"
|
||||
kubectl rollout status deployment/kubevela-vela-core \
|
||||
-n vela-system \
|
||||
--timeout=300s
|
||||
|
||||
echo "--- Deployed Image Version ---"
|
||||
kubectl get deployment kubevela-vela-core \
|
||||
-n vela-system \
|
||||
-o yaml | grep "image:" | head -1
|
||||
|
||||
echo "Deployment verification completed successfully!"
|
||||
32
.github/actions/deploy-latest-release/README.md
vendored
Normal file
32
.github/actions/deploy-latest-release/README.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
# Install Latest KubeVela Release Action
|
||||
|
||||
This GitHub composite action installs the latest stable KubeVela release from the official Helm repository and verifies its deployment status.
|
||||
|
||||
## What it does
|
||||
|
||||
- Discovers the latest stable KubeVela release tag from GitHub
|
||||
- Adds and updates the official KubeVela Helm chart repository
|
||||
- Installs KubeVela into the `vela-system` namespace (using Helm)
|
||||
- Verifies pod status and deployment rollout for successful installation
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- name: Install Latest KubeVela Release
|
||||
uses: ./path/to/this/action
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Helm, kubectl, jq, and curl must be available in your runner environment
|
||||
- Kubernetes cluster access
|
||||
|
||||
## Steps performed
|
||||
|
||||
1. **Release Tag Discovery:** Fetches latest stable tag (without `v` prefix)
|
||||
2. **Helm Repo Setup:** Adds/updates KubeVela Helm chart repo
|
||||
3. **Install KubeVela:** Installs latest release in the `vela-system` namespace
|
||||
4. **Status Verification:** Checks pod status and rollout for readiness
|
||||
|
||||
---
|
||||
|
||||
68
.github/actions/deploy-latest-release/action.yaml
vendored
Normal file
68
.github/actions/deploy-latest-release/action.yaml
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
name: 'Install Latest KubeVela Release'
|
||||
description: 'Installs the latest stable KubeVela release from official Helm repository with status verification'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# ========================================================================
|
||||
# Latest Release Tag Discovery
|
||||
# Fetch current stable release version from GitHub API
|
||||
# ========================================================================
|
||||
- name: Get latest KubeVela release tag (no v prefix)
|
||||
id: get_latest_tag
|
||||
shell: bash
|
||||
run: |
|
||||
TAG=$(curl -s https://api.github.com/repos/kubevela/kubevela/releases/latest | \
|
||||
jq -r ".tag_name" | \
|
||||
awk '{sub(/^v/, ""); print}')
|
||||
echo "LATEST_TAG=$TAG" >> $GITHUB_ENV
|
||||
echo "Discovered latest release: $TAG"
|
||||
|
||||
# ========================================================================
|
||||
# Helm Repository Configuration
|
||||
# Add and update official KubeVela chart repository
|
||||
# ========================================================================
|
||||
- name: Add KubeVela Helm repo
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Adding KubeVela Helm repository..."
|
||||
helm repo add kubevela https://kubevela.github.io/charts
|
||||
helm repo update
|
||||
echo "Helm repository configuration completed"
|
||||
|
||||
# ========================================================================
|
||||
# KubeVela Stable Release Installation
|
||||
# Deploy latest stable version to vela-system namespace
|
||||
# ========================================================================
|
||||
- name: Install KubeVela ${{ env.LATEST_TAG }}
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Installing KubeVela version: ${{ env.LATEST_TAG }}"
|
||||
helm install \
|
||||
--create-namespace \
|
||||
-n vela-system \
|
||||
kubevela kubevela/vela-core \
|
||||
--version ${{ env.LATEST_TAG }} \
|
||||
--timeout 10m \
|
||||
--wait
|
||||
echo "KubeVela installation completed"
|
||||
|
||||
# ========================================================================
|
||||
# Installation Status Verification
|
||||
# Verify successful deployment and readiness of KubeVela components
|
||||
# ========================================================================
|
||||
- name: Post-install status
|
||||
shell: bash
|
||||
run: |
|
||||
echo "=== INSTALLATION VERIFICATION ==="
|
||||
echo "Verifying KubeVela deployment status..."
|
||||
|
||||
echo "--- Pod Status ---"
|
||||
kubectl get pods -n vela-system
|
||||
|
||||
echo "--- Deployment Rollout ---"
|
||||
kubectl rollout status deployment/kubevela-vela-core \
|
||||
-n vela-system \
|
||||
--timeout=300s
|
||||
|
||||
echo "KubeVela installation verification completed successfully!"
|
||||
51
.github/actions/e2e-test/README.md
vendored
Normal file
51
.github/actions/e2e-test/README.md
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
# Kubevela K8s Upgrade E2E Test Action
|
||||
|
||||
A comprehensive GitHub composite action for running KubeVela Kubernetes upgrade end-to-end (E2E) tests with complete environment setup, multiple test suites, and failure diagnostics.
|
||||
|
||||
|
||||
> **Note**: This action requires the `GO_VERSION` environment variable to be set in your workflow.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```yaml
|
||||
name: E2E Tests
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
e2e-tests:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GO_VERSION: '1.23.8'
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run KubeVela E2E Tests
|
||||
uses: ./.github/actions/upgrade-e2e-test
|
||||
```
|
||||
|
||||
## Test Flow Diagram
|
||||
|
||||
```
|
||||
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
|
||||
│ Environment │ │ E2E Environment │ │ Test Execution │
|
||||
│ Setup │───▶│ Preparation │───▶│ (3 Suites) │
|
||||
│ │ │ │ │ │
|
||||
│ • Install tools │ │ • Cleanup │ │ • API tests │
|
||||
│ • Setup Go │ │ • Core setup │ │ • Addon tests │
|
||||
│ • Dependencies │ │ • Helm tests │ │ • General tests │
|
||||
│ • Build project │ │ │ │ │
|
||||
└─────────────────┘ └──────────────────┘ └─────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ Diagnostics │
|
||||
│ (On Failure) │
|
||||
│ │
|
||||
│ • Cluster logs │
|
||||
│ • System events │
|
||||
│ • Test artifacts│
|
||||
└─────────────────┘
|
||||
```
|
||||
96
.github/actions/e2e-test/action.yaml
vendored
Normal file
96
.github/actions/e2e-test/action.yaml
vendored
Normal file
@@ -0,0 +1,96 @@
|
||||
name: 'Kubevela K8s Upgrade e2e Test'
|
||||
description: 'Runs Kubevela K8s upgrade e2e tests, uploads coverage, and collects diagnostics on failure.'
|
||||
|
||||
inputs:
|
||||
codecov-token:
|
||||
description: 'Codecov token for uploading coverage reports'
|
||||
required: false
|
||||
default: ''
|
||||
codecov-enable:
|
||||
description: 'Enable codecov coverage upload'
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# ========================================================================
|
||||
# Environment Setup
|
||||
# ========================================================================
|
||||
- name: Configure environment setup
|
||||
uses: ./.github/actions/env-setup
|
||||
|
||||
- name: Build project
|
||||
shell: bash
|
||||
run: make
|
||||
|
||||
# ========================================================================
|
||||
# E2E Test Environment Preparation
|
||||
# ========================================================================
|
||||
- name: Prepare e2e environment
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Preparing e2e test environment..."
|
||||
make e2e-cleanup
|
||||
make e2e-setup-core
|
||||
|
||||
echo "Running Helm tests..."
|
||||
helm test -n vela-system kubevela --timeout 5m
|
||||
|
||||
# ========================================================================
|
||||
# E2E Test Execution
|
||||
# ========================================================================
|
||||
- name: Run API e2e tests
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Running API e2e tests..."
|
||||
make e2e-api-test
|
||||
|
||||
- name: Run addon e2e tests
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Running addon e2e tests..."
|
||||
make e2e-addon-test
|
||||
|
||||
- name: Run general e2e tests
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Running general e2e tests..."
|
||||
make e2e-test
|
||||
|
||||
- name: Upload coverage report
|
||||
if: ${{ inputs.codecov-enable == 'true' }}
|
||||
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24
|
||||
with:
|
||||
token: ${{ inputs.codecov-token }}
|
||||
files: ./coverage.txt
|
||||
flags: core-unittests
|
||||
name: codecov-umbrella
|
||||
fail_ci_if_error: false
|
||||
|
||||
# ========================================================================
|
||||
# Failure Diagnostics
|
||||
# ========================================================================
|
||||
- name: Collect failure diagnostics
|
||||
if: failure()
|
||||
shell: bash
|
||||
run: |
|
||||
echo "=== FAILURE DIAGNOSTICS ==="
|
||||
echo "Collecting diagnostic information for debugging..."
|
||||
|
||||
echo "--- Cluster Status ---"
|
||||
kubectl get nodes -o wide || true
|
||||
kubectl get pods -A || true
|
||||
|
||||
echo "--- KubeVela System Logs ---"
|
||||
kubectl logs -n vela-system -l app.kubernetes.io/name=vela-core --tail=100 || true
|
||||
|
||||
echo "--- Recent Events ---"
|
||||
kubectl get events -A --sort-by='.lastTimestamp' --field-selector type!=Normal || true
|
||||
|
||||
echo "--- Helm Release Status ---"
|
||||
helm list -A || true
|
||||
helm status kubevela -n vela-system || true
|
||||
|
||||
echo "--- Test Artifacts ---"
|
||||
find . -name "*.log" -type f -exec echo "=== {} ===" \; -exec cat {} \; || true
|
||||
67
.github/actions/env-setup/README.md
vendored
Normal file
67
.github/actions/env-setup/README.md
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
# Kubevela Test Environment Setup Action
|
||||
|
||||
A GitHub Actions composite action that sets up a complete testing environment for Kubevela projects with Go, Kubernetes tools, and the Ginkgo testing framework.
|
||||
|
||||
## Features
|
||||
|
||||
- 🛠️ **System Dependencies**: Installs essential build tools (make, gcc, jq, curl, etc.)
|
||||
- ☸️ **Kubernetes Tools**: Sets up kubectl and Helm for cluster operations
|
||||
- 🐹 **Go Environment**: Configurable Go version with module caching
|
||||
- 📦 **Dependency Management**: Downloads and verifies Go module dependencies
|
||||
- 🧪 **Testing Framework**: Installs Ginkgo v2 for BDD-style testing
|
||||
|
||||
## Usage
|
||||
|
||||
```yaml
|
||||
- name: Setup Kubevela Test Environment
|
||||
uses: ./path/to/this/action
|
||||
with:
|
||||
go-version: '1.23.8' # Optional: Go version (default: 1.23.8)
|
||||
```
|
||||
|
||||
### Example Workflow
|
||||
|
||||
```yaml
|
||||
name: Kubevela Tests
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Test Environment
|
||||
uses: ./path/to/this/action
|
||||
with:
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Run Tests
|
||||
run: |
|
||||
ginkgo -r ./tests/e2e/
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Description | Required | Default | Usage |
|
||||
|-------|-------------|----------|---------|-------|
|
||||
| `go-version` | Go version to install and use | No | `1.23.8` | Specify Go version for your project |
|
||||
|
||||
## What This Action Installs
|
||||
|
||||
### System Tools
|
||||
- **make**: Build automation tool
|
||||
- **gcc**: GNU Compiler Collection
|
||||
- **jq**: JSON processor for shell scripts
|
||||
- **ca-certificates**: SSL/TLS certificates
|
||||
- **curl**: HTTP client for downloads
|
||||
- **gnupg**: GNU Privacy Guard for security
|
||||
|
||||
### Kubernetes Ecosystem
|
||||
- **kubectl**: Kubernetes command-line tool (latest stable)
|
||||
- **helm**: Kubernetes package manager (latest stable)
|
||||
|
||||
### Go Development
|
||||
- **Go Runtime**: Specified version with module caching enabled
|
||||
- **Go Modules**: Downloaded and verified dependencies
|
||||
- **Ginkgo v2.14.0**: BDD testing framework for Go
|
||||
72
.github/actions/env-setup/action.yaml
vendored
Normal file
72
.github/actions/env-setup/action.yaml
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
name: 'Kubevela Test Environment Setup'
|
||||
description: 'Sets up complete testing environment for Kubevela with Go, Kubernetes tools, and Ginkgo framework for E2E testing.'
|
||||
|
||||
inputs:
|
||||
go-version:
|
||||
description: 'Go version to use for testing'
|
||||
required: false
|
||||
default: '1.23.8'
|
||||
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
# ========================================================================
|
||||
# Environment Setup
|
||||
# ========================================================================
|
||||
- name: Install system dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
# Update package manager and install essential tools
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y \
|
||||
make \
|
||||
gcc \
|
||||
jq \
|
||||
ca-certificates \
|
||||
curl \
|
||||
gnupg
|
||||
|
||||
- name: Install kubectl and helm
|
||||
shell: bash
|
||||
run: |
|
||||
# Detect architecture
|
||||
ARCH=$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')
|
||||
|
||||
# Install kubectl
|
||||
echo "Installing kubectl for architecture: $ARCH"
|
||||
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/${ARCH}/kubectl"
|
||||
chmod +x kubectl
|
||||
sudo mv kubectl /usr/local/bin/
|
||||
|
||||
# Install helm using the official script (more reliable)
|
||||
echo "Installing Helm using official script..."
|
||||
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
|
||||
chmod 700 get_helm.sh
|
||||
./get_helm.sh
|
||||
rm get_helm.sh
|
||||
|
||||
# Verify installations
|
||||
echo "Verifying installations..."
|
||||
kubectl version --client
|
||||
helm version
|
||||
|
||||
|
||||
- name: Setup Go environment
|
||||
uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32
|
||||
with:
|
||||
go-version: ${{ inputs.go-version }}
|
||||
cache: true
|
||||
|
||||
- name: Download Go dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
# Download and cache Go module dependencies
|
||||
go mod download
|
||||
go mod verify
|
||||
|
||||
- name: Install Ginkgo testing framework
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Installing Ginkgo testing framework..."
|
||||
go install github.com/onsi/ginkgo/v2/ginkgo@v2.14.0
|
||||
35
.github/actions/multicluster-test/README.md
vendored
Normal file
35
.github/actions/multicluster-test/README.md
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
# Kubevela K8s Upgrade Multicluster E2E Test Action
|
||||
|
||||
A comprehensive GitHub Actions composite action for running Kubevela Kubernetes upgrade multicluster end-to-end tests with automated coverage reporting and failure diagnostics.
|
||||
|
||||
## Usage
|
||||
|
||||
|
||||
```yaml
|
||||
name: Kubevela Multicluster E2E Tests
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
multicluster-e2e:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run Multicluster E2E Tests
|
||||
uses: ./.github/actions/multicluster-test
|
||||
with:
|
||||
codecov-enable: 'true'
|
||||
codecov-token: ${{ secrets.CODECOV_TOKEN }}
|
||||
```
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Description | Required | Default | Type |
|
||||
|-------|-------------|----------|---------|------|
|
||||
| `codecov-token` | Codecov token for uploading coverage reports | No | `''` | string |
|
||||
| `codecov-enable` | Enable codecov coverage upload | No | `'false'` | string |
|
||||
76
.github/actions/multicluster-test/action.yaml
vendored
Normal file
76
.github/actions/multicluster-test/action.yaml
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
name: 'Kubevela K8s Upgrade Multicluster E2E Test'
|
||||
description: 'Runs Kubevela Kubernetes upgrade multicluster end-to-end tests, uploads coverage, and collects diagnostics on failure.'
|
||||
author: 'viskumar_gwre'
|
||||
|
||||
inputs:
|
||||
codecov-token:
|
||||
description: 'Codecov token for uploading coverage reports'
|
||||
required: false
|
||||
default: ''
|
||||
codecov-enable:
|
||||
description: 'Enable codecov coverage upload'
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
# ========================================================================
|
||||
# Environment Setup
|
||||
# ========================================================================
|
||||
- name: Configure environment setup
|
||||
uses: ./.github/actions/env-setup
|
||||
|
||||
# ========================================================================
|
||||
# E2E Test Execution
|
||||
# ========================================================================
|
||||
- name: Prepare e2e test environment
|
||||
shell: bash
|
||||
run: |
|
||||
# Build CLI tools and prepare test environment
|
||||
echo "Building KubeVela CLI..."
|
||||
make vela-cli
|
||||
|
||||
echo "Cleaning up previous test artifacts..."
|
||||
make e2e-cleanup
|
||||
|
||||
echo "Setting up core authentication for e2e tests..."
|
||||
make e2e-setup-core-auth
|
||||
|
||||
- name: Execute multicluster upgrade e2e tests
|
||||
shell: bash
|
||||
run: |
|
||||
# Add built CLI to PATH and run multicluster tests
|
||||
export PATH=$(pwd)/bin:$PATH
|
||||
|
||||
echo "Running e2e multicluster upgrade tests..."
|
||||
make e2e-multicluster-test
|
||||
|
||||
- name: Upload coverage report
|
||||
if: ${{ inputs.codecov-enable == 'true' }}
|
||||
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24
|
||||
with:
|
||||
token: ${{ inputs.codecov-token }}
|
||||
files: /tmp/e2e-profile.out,/tmp/e2e_multicluster_test.out
|
||||
flags: e2e-multicluster-test
|
||||
name: codecov-umbrella
|
||||
|
||||
# ========================================================================
|
||||
# Failure Diagnostics
|
||||
# ========================================================================
|
||||
- name: Collect failure diagnostics
|
||||
if: failure()
|
||||
shell: bash
|
||||
run: |
|
||||
echo "=== FAILURE DIAGNOSTICS ==="
|
||||
echo "Collecting diagnostic information for debugging..."
|
||||
|
||||
echo "--- Cluster Status ---"
|
||||
kubectl get nodes -o wide || true
|
||||
kubectl get pods -A || true
|
||||
|
||||
echo "--- KubeVela System Logs ---"
|
||||
kubectl logs -n vela-system -l app.kubernetes.io/name=vela-core --tail=100 || true
|
||||
|
||||
echo "--- Recent Events ---"
|
||||
kubectl get events -A --sort-by='.lastTimestamp' --field-selector type!=Normal || true
|
||||
78
.github/actions/setup-kind-cluster/README.md
vendored
Normal file
78
.github/actions/setup-kind-cluster/README.md
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
# Setup Kind Cluster Action
|
||||
|
||||
A GitHub Action that sets up a Kubernetes testing environment using Kind (Kubernetes in Docker) for E2E testing.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `k8s-version` | Kubernetes version for the kind cluster | No | `v1.31.9` |
|
||||
|
||||
## Quick Start
|
||||
|
||||
```yaml
|
||||
name: E2E Tests
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.21'
|
||||
|
||||
- name: Setup Kind Cluster
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
with:
|
||||
k8s-version: 'v1.31.9'
|
||||
|
||||
- name: Run tests
|
||||
run: |
|
||||
kubectl cluster-info
|
||||
make test-e2e
|
||||
```
|
||||
|
||||
## What it does
|
||||
|
||||
1. **Installs Kind CLI** - Downloads Kind v0.29.0 using Go
|
||||
2. **Cleans up** - Removes any existing Kind clusters
|
||||
3. **Creates cluster** - Spins up Kubernetes v1.31.9 cluster
|
||||
4. **Sets up environment** - Configures KUBECONFIG for kubectl access
|
||||
5. **Loads images** - Builds and loads Docker images using `make image-load`
|
||||
|
||||
## File Structure
|
||||
|
||||
Save as `.github/actions/setup-kind-cluster/action.yaml`:
|
||||
|
||||
```yaml
|
||||
name: 'SetUp kind cluster'
|
||||
description: 'Sets up complete testing environment for Kubevela with Go, Kubernetes tools, and Ginkgo framework for E2E testing.'
|
||||
|
||||
inputs:
|
||||
k8s-version:
|
||||
description: 'Kubernetes version for the kind cluster'
|
||||
required: false
|
||||
default: 'v1.31.9'
|
||||
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
# ========================================================================
|
||||
# Kind cluster Setup
|
||||
# ========================================================================
|
||||
- name: Setup KinD
|
||||
run: |
|
||||
go install sigs.k8s.io/kind@v0.29.0
|
||||
kind delete cluster || true
|
||||
kind create cluster --image=kindest/node:${{ inputs.k8s-version }}
|
||||
shell: bash
|
||||
|
||||
- name: Load image
|
||||
run: |
|
||||
mkdir -p $HOME/tmp/
|
||||
TMPDIR=$HOME/tmp/ make image-load
|
||||
shell: bash
|
||||
```
|
||||
36
.github/actions/setup-kind-cluster/action.yaml
vendored
Normal file
36
.github/actions/setup-kind-cluster/action.yaml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: 'SetUp kind cluster'
|
||||
description: 'Sets up a KinD (Kubernetes in Docker) cluster with configurable Kubernetes version and optional cluster naming for testing and development workflows.'
|
||||
inputs:
|
||||
k8s-version:
|
||||
description: 'Kubernetes version for the kind cluster'
|
||||
required: false
|
||||
default: 'v1.31.9'
|
||||
name:
|
||||
description: 'Name of the kind cluster'
|
||||
required: false
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
# ========================================================================
|
||||
# Kind cluster Setup
|
||||
# ========================================================================
|
||||
- name: Setup KinD
|
||||
run: |
|
||||
go install sigs.k8s.io/kind@v0.29.0
|
||||
if [ -n "${{ inputs.name }}" ]; then
|
||||
kind delete cluster --name="${{ inputs.name }}" || true
|
||||
kind create cluster --name="${{ inputs.name }}" --image=kindest/node:${{ inputs.k8s-version }}
|
||||
kind export kubeconfig --internal --name="${{ inputs.name }}" --kubeconfig /tmp/${{ inputs.name }}.kubeconfig
|
||||
else
|
||||
kind delete cluster || true
|
||||
kind create cluster --image=kindest/node:${{ inputs.k8s-version }}
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Load image
|
||||
run: |
|
||||
if [ -z "${{ inputs.name }}" ]; then
|
||||
mkdir -p $HOME/tmp/
|
||||
TMPDIR=$HOME/tmp/ make image-load
|
||||
fi
|
||||
shell: bash
|
||||
34
.github/actions/unit-test/README.md
vendored
Normal file
34
.github/actions/unit-test/README.md
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# Kubevela K8s Upgrade Unit Test Action
|
||||
|
||||
A comprehensive GitHub composite action for running KubeVela Kubernetes upgrade unit tests with coverage reporting and failure diagnostics.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Input | Description | Required | Default |
|
||||
|-------|-------------|----------|---------|
|
||||
| `codecov-token` | Codecov token for uploading coverage reports | ❌ | `''` |
|
||||
| `codecov-enable` | Enable Codecov coverage upload (`'true'` or `'false'`) | ❌ | `'false'` |
|
||||
| `go-version` | Go version to use for testing | ❌ | `'1.23.8'` |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```yaml
|
||||
name: Unit Tests with Coverage
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Run KubeVela Unit Tests
|
||||
uses: viskumar_gwre/kubevela-k8s-upgrade-unit-test-action@v1
|
||||
with:
|
||||
codecov-enable: 'true'
|
||||
codecov-token: ${{ secrets.CODECOV_TOKEN }}
|
||||
go-version: '1.23.8'
|
||||
```
|
||||
67
.github/actions/unit-test/action.yaml
vendored
Normal file
67
.github/actions/unit-test/action.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
name: 'Kubevela K8s Upgrade Unit Test'
|
||||
description: 'Runs Kubevela K8s upgrade unit tests, uploads coverage, and collects diagnostics on failure.'
|
||||
|
||||
inputs:
|
||||
codecov-token:
|
||||
description: 'Codecov token for uploading coverage reports'
|
||||
required: false
|
||||
default: ''
|
||||
codecov-enable:
|
||||
description: 'Enable codecov coverage upload'
|
||||
required: false
|
||||
default: 'false'
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# ========================================================================
|
||||
# Environment Setup
|
||||
# ========================================================================
|
||||
- name: Configure environment setup
|
||||
uses: ./.github/actions/env-setup
|
||||
|
||||
# ========================================================================
|
||||
# Unit Test Execution
|
||||
# ========================================================================
|
||||
- name: Run unit tests
|
||||
shell: bash
|
||||
run: |
|
||||
echo "Running unit tests..."
|
||||
make test
|
||||
|
||||
- name: Upload coverage report
|
||||
if: ${{ inputs.codecov-enable == 'true' }}
|
||||
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24
|
||||
with:
|
||||
token: ${{ inputs.codecov-token }}
|
||||
files: ./coverage.txt
|
||||
flags: core-unittests
|
||||
name: codecov-umbrella
|
||||
fail_ci_if_error: false
|
||||
|
||||
# ========================================================================
|
||||
# Failure Diagnostics
|
||||
# ========================================================================
|
||||
- name: Collect failure diagnostics
|
||||
if: failure()
|
||||
shell: bash
|
||||
run: |
|
||||
echo "=== FAILURE DIAGNOSTICS ==="
|
||||
echo "Collecting diagnostic information for debugging..."
|
||||
|
||||
echo "--- Go Environment ---"
|
||||
go version || true
|
||||
go env || true
|
||||
|
||||
echo "--- Cluster Status ---"
|
||||
kubectl get nodes -o wide || true
|
||||
kubectl get pods -A || true
|
||||
|
||||
echo "--- KubeVela System Logs ---"
|
||||
kubectl logs -n vela-system -l app.kubernetes.io/name=vela-core --tail=100 || true
|
||||
|
||||
echo "--- Recent Events ---"
|
||||
kubectl get events -A --sort-by='.lastTimestamp' --field-selector type!=Normal || true
|
||||
|
||||
echo "--- Test Artifacts ---"
|
||||
find . -name "*.log" -o -name "*test*.xml" -o -name "coverage.*" | head -20 || true
|
||||
4
.github/workflows/back-port.yml
vendored
4
.github/workflows/back-port.yml
vendored
@@ -17,12 +17,12 @@ jobs:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Open Backport PR
|
||||
uses: zeebe-io/backport-action@08bafb375e6e9a9a2b53a744b987e5d81a133191
|
||||
uses: zeebe-io/backport-action@0193454f0c5947491d348f33a275c119f30eb736
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
github_workspace: ${{ github.workspace }}
|
||||
|
||||
4
.github/workflows/chart.yml
vendored
4
.github/workflows/chart.yml
vendored
@@ -17,7 +17,7 @@ jobs:
|
||||
HELM_CHART_NAME: vela-core
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
- name: Get git revision
|
||||
id: vars
|
||||
shell: bash
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
with:
|
||||
version: v3.4.0
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
|
||||
with:
|
||||
node-version: '14'
|
||||
- name: Generate helm doc
|
||||
|
||||
6
.github/workflows/codeql-analysis.yml
vendored
6
.github/workflows/codeql-analysis.yml
vendored
@@ -26,12 +26,12 @@ jobs:
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
||||
uses: github/codeql-action/init@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
||||
uses: github/codeql-action/autobuild@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
||||
uses: github/codeql-action/analyze@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
|
||||
10
.github/workflows/definition-lint.yml
vendored
10
.github/workflows/definition-lint.yml
vendored
@@ -23,19 +23,19 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup KinD
|
||||
run: |
|
||||
go install sigs.k8s.io/kind@v0.19.0
|
||||
kind create cluster
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
with:
|
||||
name: linter
|
||||
|
||||
- name: Definition Doc generate check
|
||||
run: |
|
||||
|
||||
74
.github/workflows/e2e-multicluster-test.yml
vendored
74
.github/workflows/e2e-multicluster-test.yml
vendored
@@ -44,70 +44,40 @@ jobs:
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
strategy:
|
||||
matrix:
|
||||
k8s-version: ["v1.29"]
|
||||
k8s-version: ["v1.31.9"]
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.k8s-version }}
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install make gcc jq ca-certificates curl gnupg -y
|
||||
sudo snap install kubectl --classic
|
||||
sudo snap install helm --classic
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
- name: Setup worker cluster kinD
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
name: worker
|
||||
k8s-version: ${{ matrix.k8s-version }}
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
|
||||
- name: Setup KinD
|
||||
run: |
|
||||
go install sigs.k8s.io/kind@v0.24.0
|
||||
kind delete cluster --name worker || true
|
||||
kind create cluster --name worker --image=kindest/node:v1.29.8
|
||||
kind export kubeconfig --internal --name worker --kubeconfig /tmp/worker.kubeconfig
|
||||
kind delete cluster || true
|
||||
kind create cluster --image=kindest/node:v1.29.8
|
||||
|
||||
- name: Load image
|
||||
run: |
|
||||
mkdir -p $HOME/tmp/
|
||||
TMPDIR=$HOME/tmp/ make image-load
|
||||
|
||||
- name: Cleanup for e2e tests
|
||||
run: |
|
||||
make vela-cli
|
||||
make e2e-cleanup
|
||||
make e2e-setup-core-auth
|
||||
|
||||
- name: Run e2e multicluster tests
|
||||
run: |
|
||||
export PATH=$(pwd)/bin:$PATH
|
||||
make e2e-multicluster-test
|
||||
|
||||
- name: Stop kubevela, get profile
|
||||
run: |
|
||||
make end-e2e-core-shards
|
||||
|
||||
- name: Upload coverage report
|
||||
uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d
|
||||
- name: Setup master cluster kinD
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: /tmp/e2e-profile.out,/tmp/e2e_multicluster_test.out
|
||||
flags: e2e-multicluster-test
|
||||
name: codecov-umbrella
|
||||
k8s-version: ${{ matrix.k8s-version }}
|
||||
|
||||
- name: Run upgrade multicluster tests
|
||||
uses: ./.github/actions/multicluster-test
|
||||
with:
|
||||
codecov-enable: true
|
||||
codecov-token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
- name: Clean e2e profile
|
||||
run: rm /tmp/e2e-profile.out
|
||||
run: |
|
||||
if [ -f /tmp/e2e-profile.out ]; then
|
||||
rm /tmp/e2e-profile.out
|
||||
echo "E2E profile cleaned"
|
||||
else
|
||||
echo "E2E profile not found, skipping cleanup"
|
||||
fi
|
||||
|
||||
- name: Cleanup image
|
||||
if: ${{ always() }}
|
||||
|
||||
76
.github/workflows/e2e-test.yml
vendored
76
.github/workflows/e2e-test.yml
vendored
@@ -44,77 +44,35 @@ jobs:
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
strategy:
|
||||
matrix:
|
||||
k8s-version: ["v1.29"]
|
||||
k8s-version: ["v1.31"]
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.k8s-version }}
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
|
||||
- name: Install tools
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install make gcc jq ca-certificates curl gnupg -y
|
||||
sudo snap install kubectl --classic
|
||||
sudo snap install helm --classic
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
|
||||
- name: Setup KinD
|
||||
run: |
|
||||
go install sigs.k8s.io/kind@v0.24.0
|
||||
kind delete cluster || true
|
||||
kind create cluster --image=kindest/node:v1.29.8
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
|
||||
- name: Get Ginkgo
|
||||
run: |
|
||||
go install github.com/onsi/ginkgo/v2/ginkgo@v2.14.0
|
||||
|
||||
- name: Load image
|
||||
run: |
|
||||
mkdir -p $HOME/tmp/
|
||||
TMPDIR=$HOME/tmp/ make image-load
|
||||
|
||||
- name: Run Make
|
||||
run: make
|
||||
|
||||
- name: Prepare for e2e tests
|
||||
run: |
|
||||
make e2e-cleanup
|
||||
make e2e-setup-core
|
||||
helm test -n vela-system kubevela --timeout 5m
|
||||
|
||||
- name: Run api e2e tests
|
||||
run: make e2e-api-test
|
||||
|
||||
- name: Run addons e2e tests
|
||||
run: make e2e-addon-test
|
||||
|
||||
- name: Run e2e tests
|
||||
run: make e2e-test
|
||||
|
||||
- name: Stop kubevela, get profile
|
||||
run: make end-e2e
|
||||
|
||||
- name: Upload coverage report
|
||||
uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d
|
||||
# ========================================================================
|
||||
# E2E Test Execution
|
||||
# ========================================================================
|
||||
- name: Run upgrade e2e tests
|
||||
uses: ./.github/actions/e2e-test
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: /tmp/e2e-profile.out
|
||||
flags: e2etests
|
||||
name: codecov-umbrella
|
||||
codecov-enable: true
|
||||
codecov-token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
- name: Clean e2e profile
|
||||
run: rm /tmp/e2e-profile.out
|
||||
run: |
|
||||
if [ -f /tmp/e2e-profile.out ]; then
|
||||
rm /tmp/e2e-profile.out
|
||||
echo "E2E profile cleaned"
|
||||
else
|
||||
echo "E2E profile not found, skipping cleanup"
|
||||
fi
|
||||
|
||||
- name: Cleanup image
|
||||
if: ${{ always() }}
|
||||
|
||||
56
.github/workflows/go.yml
vendored
56
.github/workflows/go.yml
vendored
@@ -43,12 +43,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -68,12 +68,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
@@ -93,32 +93,20 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Setup Env
|
||||
uses: ./.github/actions/env-setup
|
||||
|
||||
- name: Setup node
|
||||
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
|
||||
with:
|
||||
node-version: "14"
|
||||
|
||||
- name: Cache Go Dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: .work/pkg
|
||||
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-pkg-
|
||||
|
||||
- name: Setup KinD
|
||||
run: |
|
||||
go install sigs.k8s.io/kind@v0.19.0
|
||||
kind delete cluster --name kind || true
|
||||
kind create cluster --name kind --image=kindest/node:v1.26.4 --kubeconfig ~/.kube/config
|
||||
- name: Setup kinD
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
|
||||
- name: Run cross-build
|
||||
run: make cross-build
|
||||
@@ -138,12 +126,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
@@ -169,15 +157,15 @@ jobs:
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
|
||||
- name: Build Test for vela core
|
||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile
|
||||
@@ -189,15 +177,15 @@ jobs:
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
submodules: true
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0
|
||||
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
- name: Build Test for CLI
|
||||
uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # v6.15.0
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
|
||||
- name: Build Test for CLI
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.cli
|
||||
2
.github/workflows/issue-commands.yml
vendored
2
.github/workflows/issue-commands.yml
vendored
@@ -80,7 +80,7 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Open Backport PR
|
||||
uses: zeebe-io/backport-action@08bafb375e6e9a9a2b53a744b987e5d81a133191
|
||||
uses: zeebe-io/backport-action@0193454f0c5947491d348f33a275c119f30eb736
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
github_workspace: ${{ github.workspace }}
|
||||
|
||||
4
.github/workflows/registry.yml
vendored
4
.github/workflows/registry.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
uses: imjasonh/setup-crane@00c9e93efa4e1138c9a7a5c594acd6c75a2fbf0c # v0.1
|
||||
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # main
|
||||
uses: sigstore/cosign-installer@d58896d6a1865668819e1d91763c7751a165e159 # main
|
||||
with:
|
||||
cosign-release: 'v2.5.0'
|
||||
|
||||
@@ -241,6 +241,6 @@ jobs:
|
||||
with:
|
||||
image: ${{ matrix.image }}
|
||||
digest: ${{ matrix.digest }}
|
||||
registry-username: oamdev
|
||||
secrets:
|
||||
registry-username: ${{ secrets.DOCKER_USERNAME }}
|
||||
registry-password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
35
.github/workflows/release.yml
vendored
35
.github/workflows/release.yml
vendored
@@ -3,7 +3,7 @@ name: Release
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
- "v*"
|
||||
workflow_dispatch: {}
|
||||
|
||||
permissions:
|
||||
@@ -26,6 +26,32 @@ jobs:
|
||||
outputs:
|
||||
hashes: ${{ steps.hash.outputs.hashes }}
|
||||
steps:
|
||||
- name: Check disk (before)
|
||||
run: |
|
||||
df -h
|
||||
sudo du -sh /usr/local/lib/android /usr/share/dotnet /opt/ghc || true
|
||||
|
||||
- name: Free Disk Space (Ubuntu)
|
||||
uses: insightsengineering/disk-space-reclaimer@v1
|
||||
with:
|
||||
# this might remove tools that are actually needed,
|
||||
# if set to "true" but frees about 6 GB
|
||||
tools-cache: false
|
||||
# all of these default to true, but feel free to set to
|
||||
# "false" if necessary for your workflow
|
||||
android: true
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: true
|
||||
swap-storage: true
|
||||
docker-images: true
|
||||
|
||||
# Extra prune in case your job builds/pulls images
|
||||
- name: Deep Docker prune
|
||||
run: |
|
||||
docker system prune -af || true
|
||||
docker builder prune -af || true
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
with:
|
||||
@@ -43,7 +69,7 @@ jobs:
|
||||
- name: Install Cosign
|
||||
uses: sigstore/cosign-installer@main
|
||||
with:
|
||||
cosign-release: 'v2.5.0'
|
||||
cosign-release: "v2.5.0"
|
||||
|
||||
- name: Install syft
|
||||
uses: anchore/sbom-action/download-syft@f325610c9f50a54015d37c8d16cb3b0e2c8f4de0 # v0.18.0
|
||||
@@ -65,6 +91,9 @@ jobs:
|
||||
HASHES=$(find dist -type f -exec sha256sum {} \; | base64 -w0)
|
||||
echo "hashes=$HASHES" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check disk (after)
|
||||
run: df -h
|
||||
|
||||
upload-plugin-homebrew:
|
||||
name: upload-sha256sums
|
||||
needs: goreleaser
|
||||
@@ -103,5 +132,5 @@ jobs:
|
||||
actions: read
|
||||
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 # has to be sem var
|
||||
with:
|
||||
base64-subjects: '${{ needs.goreleaser.outputs.hashes }}'
|
||||
base64-subjects: "${{ needs.goreleaser.outputs.hashes }}"
|
||||
upload-assets: true
|
||||
|
||||
2
.github/workflows/scorecards.yml
vendored
2
.github/workflows/scorecards.yml
vendored
@@ -55,6 +55,6 @@ jobs:
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
||||
uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
||||
19
.github/workflows/sdk-test.yml
vendored
19
.github/workflows/sdk-test.yml
vendored
@@ -16,22 +16,15 @@ on:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# Common versions
|
||||
GO_VERSION: '1.23.8'
|
||||
GOLANGCI_VERSION: 'v1.60.1'
|
||||
|
||||
jobs:
|
||||
sdk-tests:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
- name: Setup Env
|
||||
uses: ./.github/actions/env-setup
|
||||
|
||||
- name: Install Go tools
|
||||
run: |
|
||||
@@ -39,9 +32,9 @@ jobs:
|
||||
make golangci
|
||||
|
||||
- name: Setup KinD
|
||||
run: |
|
||||
go install sigs.k8s.io/kind@v0.19.0
|
||||
kind create cluster
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
with:
|
||||
name: sdk-test
|
||||
|
||||
- name: Build CLI
|
||||
run: make vela-cli
|
||||
|
||||
11
.github/workflows/sync-api.yml
vendored
11
.github/workflows/sync-api.yml
vendored
@@ -10,21 +10,16 @@ on:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.23.8'
|
||||
|
||||
jobs:
|
||||
sync-core-api:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
|
||||
- name: Setup Env
|
||||
uses: ./.github/actions/env-setup
|
||||
|
||||
- name: Get the version
|
||||
id: get_version
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
|
||||
20
.github/workflows/sync-sdk.yaml
vendored
20
.github/workflows/sync-sdk.yaml
vendored
@@ -14,28 +14,16 @@ on:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.23.8'
|
||||
|
||||
jobs:
|
||||
sync_sdk:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
|
||||
- name: Get the version
|
||||
id: get_version
|
||||
run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
- name: Env setup
|
||||
uses: ./.github/actions/env-setup
|
||||
|
||||
- name: Install Go tools
|
||||
run: |
|
||||
@@ -44,6 +32,10 @@ jobs:
|
||||
- name: Build CLI
|
||||
run: make vela-cli
|
||||
|
||||
- name: Get the version
|
||||
id: get_version
|
||||
run: echo "VERSION=${GITHUB_REF}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Sync SDK to kubevela/kubevela-go-sdk
|
||||
run: bash ./hack/sdk/sync.sh
|
||||
env:
|
||||
|
||||
2
.github/workflows/trivy-scan.yml
vendored
2
.github/workflows/trivy-scan.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
output: 'trivy-results.sarif'
|
||||
|
||||
- name: Upload Trivy scan results to GitHub Security tab
|
||||
uses: github/codeql-action/upload-sarif@28deaeda66b76a05916b6923827895f2b14ab387 # v3.28.16
|
||||
uses: github/codeql-action/upload-sarif@51f77329afa6477de8c49fc9c7046c15b9a4e79d # v3.29.5
|
||||
if: always()
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
48
.github/workflows/unit-test.yml
vendored
48
.github/workflows/unit-test.yml
vendored
@@ -14,10 +14,6 @@ on:
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
# Common versions
|
||||
GO_VERSION: "1.23.8"
|
||||
|
||||
jobs:
|
||||
detect-noop:
|
||||
permissions:
|
||||
@@ -41,41 +37,19 @@ jobs:
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
|
||||
steps:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
with:
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
- name: Cache Go Dependencies
|
||||
uses: actions/cache@v4
|
||||
- name: Setup Env
|
||||
uses: ./.github/actions/env-setup
|
||||
|
||||
- name: Setup KinD with Kubernetes
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
|
||||
- name: Run unit tests
|
||||
uses: ./.github/actions/unit-test
|
||||
with:
|
||||
path: .work/pkg
|
||||
key: ${{ runner.os }}-pkg-${{ hashFiles('**/go.sum') }}
|
||||
restore-keys: ${{ runner.os }}-pkg-
|
||||
|
||||
- name: Install ginkgo
|
||||
run: |
|
||||
sudo sed -i 's/azure\.//' /etc/apt/sources.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y golang-ginkgo-dev
|
||||
|
||||
- name: Setup KinD
|
||||
run: |
|
||||
go install sigs.k8s.io/kind@v0.19.0
|
||||
kind create cluster
|
||||
|
||||
- name: Run Make test
|
||||
run: make test
|
||||
|
||||
- name: Upload coverage report
|
||||
uses: codecov/codecov-action@eaaf4bedf32dbdc6b720b63067d99c4d77d6047d
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
file: ./coverage.txt
|
||||
flags: core-unittests
|
||||
name: codecov-umbrella
|
||||
codecov-enable: true
|
||||
codecov-token: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
98
.github/workflows/upgrade-e2e-multicluster-test.yml
vendored
Normal file
98
.github/workflows/upgrade-e2e-multicluster-test.yml
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
# =============================================================================
|
||||
# E2E Upgrade Multicluster Test Workflow
|
||||
# =============================================================================
|
||||
# This workflow performs end-to-end testing for KubeVela multicluster upgrades.
|
||||
# It tests the upgrade path from the latest released version to the current
|
||||
# development branch across multiple Kubernetes versions.
|
||||
#
|
||||
# Test Flow:
|
||||
# 1. Install latest KubeVela release
|
||||
# 2. Build and upgrade to current development version
|
||||
# 3. Run multicluster e2e tests to verify functionality
|
||||
# =============================================================================
|
||||
|
||||
name: E2E Upgrade Multicluster Test
|
||||
|
||||
# =============================================================================
|
||||
# Trigger Configuration
|
||||
# =============================================================================
|
||||
on:
|
||||
# Trigger on pull requests targeting main branches
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- release-*
|
||||
|
||||
# Allow manual workflow execution
|
||||
workflow_dispatch: {}
|
||||
|
||||
# =============================================================================
|
||||
# Security Configuration
|
||||
# =============================================================================
|
||||
permissions:
|
||||
contents: read # Read-only access to repository contents
|
||||
|
||||
# =============================================================================
|
||||
# Global Environment Variables
|
||||
# =============================================================================
|
||||
env:
|
||||
GO_VERSION: '1.23.8' # Go version for building and testing
|
||||
|
||||
# =============================================================================
|
||||
# Job Definitions
|
||||
# =============================================================================
|
||||
jobs:
|
||||
upgrade-multicluster-tests:
|
||||
name: Upgrade Multicluster Tests
|
||||
runs-on: ubuntu-22.04
|
||||
if: startsWith(github.head_ref, 'chore/upgrade-k8s-')
|
||||
timeout-minutes: 60 # Prevent hanging jobs
|
||||
|
||||
# ==========================================================================
|
||||
# Matrix Strategy - Test against multiple Kubernetes versions
|
||||
# ==========================================================================
|
||||
strategy:
|
||||
fail-fast: false # Continue testing other versions if one fails
|
||||
matrix:
|
||||
k8s-version: ['v1.31.9']
|
||||
|
||||
# ==========================================================================
|
||||
# Concurrency Control - Prevent overlapping runs
|
||||
# ==========================================================================
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.k8s-version }}
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
# ========================================================================
|
||||
# Environment Setup
|
||||
# ========================================================================
|
||||
|
||||
- name: Check out repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
|
||||
# ========================================================================
|
||||
# Kubernetes Cluster Setup
|
||||
# ========================================================================
|
||||
|
||||
- name: Setup worker cluster kinD
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
with:
|
||||
name: worker
|
||||
|
||||
- name: Setup KinD master clusters for multicluster testing
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
with:
|
||||
k8s-version: ${{ matrix.k8s-version }}
|
||||
|
||||
- name: Deploy latest release
|
||||
uses: ./.github/actions/deploy-latest-release
|
||||
|
||||
- name: Upgrade from current branch
|
||||
uses: ./.github/actions/deploy-current-branch
|
||||
|
||||
- name: Run upgarde multicluster tests
|
||||
uses: ./.github/actions/multicluster-test
|
||||
with:
|
||||
codecov-enable: false
|
||||
codecov-token: ''
|
||||
102
.github/workflows/upgrade-e2e-test.yml
vendored
Normal file
102
.github/workflows/upgrade-e2e-test.yml
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
# =============================================================================
|
||||
# Upgrade E2E Test Workflow
|
||||
# =============================================================================
|
||||
# This workflow performs comprehensive end-to-end testing for KubeVela upgrades.
|
||||
# It validates the upgrade path from the latest stable release to the current
|
||||
# development version by running multiple test suites including API, addon,
|
||||
# and general e2e tests.
|
||||
#
|
||||
# Test Flow:
|
||||
# 1. Install latest KubeVela release
|
||||
# 2. Build and upgrade to current development version
|
||||
# 3. Run comprehensive e2e test suites (API, addon, general)
|
||||
# 4. Validate upgrade functionality and compatibility
|
||||
# =============================================================================
|
||||
|
||||
name: Upgrade E2E Test
|
||||
|
||||
# =============================================================================
|
||||
# Trigger Configuration
|
||||
# =============================================================================
|
||||
on:
|
||||
# Trigger on pull requests targeting main branches
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- release-*
|
||||
|
||||
# Allow manual workflow execution
|
||||
workflow_dispatch: {}
|
||||
|
||||
# =============================================================================
|
||||
# Environment Variables
|
||||
# =============================================================================
|
||||
env:
|
||||
GO_VERSION: '1.23.8'
|
||||
|
||||
# =============================================================================
|
||||
# Security Configuration
|
||||
# =============================================================================
|
||||
permissions:
|
||||
contents: read # Read-only access to repository contents
|
||||
|
||||
# =============================================================================
|
||||
# Job Definitions
|
||||
# =============================================================================
|
||||
jobs:
|
||||
upgrade-tests:
|
||||
name: Upgrade E2E Tests
|
||||
runs-on: ubuntu-22.04
|
||||
if: startsWith(github.head_ref, 'chore/upgrade-k8s-')
|
||||
timeout-minutes: 90 # Extended timeout for comprehensive e2e testing
|
||||
|
||||
# ==========================================================================
|
||||
# Matrix Strategy - Test against multiple Kubernetes versions
|
||||
# ==========================================================================
|
||||
strategy:
|
||||
fail-fast: false # Continue testing other versions if one fails
|
||||
matrix:
|
||||
k8s-version: ['v1.31.9']
|
||||
|
||||
# ==========================================================================
|
||||
# Concurrency Control - Prevent overlapping runs
|
||||
# ==========================================================================
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.k8s-version }}
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
# ========================================================================
|
||||
# Repository Setup
|
||||
# ========================================================================
|
||||
- name: Check out code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
|
||||
# ========================================================================
|
||||
# Kubernetes Cluster Setup
|
||||
# ========================================================================
|
||||
- name: Setup KinD with Kubernetes ${{ matrix.k8s-version }}
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
with:
|
||||
k8s-version: ${{ matrix.k8s-version }}
|
||||
|
||||
- name: Build vela CLI
|
||||
run: make vela-cli
|
||||
|
||||
- name: Build kubectl-vela plugin
|
||||
run: make kubectl-vela
|
||||
|
||||
- name: Install kustomize
|
||||
run: make kustomize
|
||||
|
||||
- name: Deploy latest release
|
||||
uses: ./.github/actions/deploy-latest-release
|
||||
|
||||
- name: Upgrade from current branch
|
||||
uses: ./.github/actions/deploy-current-branch
|
||||
|
||||
# ========================================================================
|
||||
# E2E Test Execution
|
||||
# ========================================================================
|
||||
- name: Run upgrade e2e tests
|
||||
uses: ./.github/actions/e2e-test
|
||||
83
.github/workflows/upgrade-unit-test.yml
vendored
Normal file
83
.github/workflows/upgrade-unit-test.yml
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
# =============================================================================
|
||||
# Upgrade Unit Test Workflow
|
||||
# =============================================================================
|
||||
# This workflow performs unit testing for KubeVela upgrades by:
|
||||
# 1. Installing the latest stable KubeVela release
|
||||
# 2. Building and upgrading to the current development version
|
||||
# 3. Running unit tests to validate the upgrade functionality
|
||||
# =============================================================================
|
||||
|
||||
name: Upgrade Unit Test
|
||||
|
||||
# =============================================================================
|
||||
# Trigger Configuration
|
||||
# =============================================================================
|
||||
on:
|
||||
# Trigger on pull requests targeting main and release branches
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- release-*
|
||||
|
||||
# Allow manual workflow execution
|
||||
workflow_dispatch: {}
|
||||
|
||||
# =============================================================================
|
||||
# Security Configuration
|
||||
# =============================================================================
|
||||
permissions:
|
||||
contents: read # Read-only access to repository contents
|
||||
|
||||
# =============================================================================
|
||||
# Job Definitions
|
||||
# =============================================================================
|
||||
jobs:
|
||||
upgrade-tests:
|
||||
name: Upgrade Unit Tests
|
||||
runs-on: ubuntu-22.04
|
||||
if: startsWith(github.head_ref, 'chore/upgrade-k8s-')
|
||||
timeout-minutes: 45 # Prevent hanging jobs
|
||||
|
||||
# ==========================================================================
|
||||
# Matrix Strategy - Test against multiple Kubernetes versions
|
||||
# ==========================================================================
|
||||
strategy:
|
||||
fail-fast: false # Continue testing other versions if one fails
|
||||
matrix:
|
||||
k8s-version: ['v1.31.9']
|
||||
|
||||
# ==========================================================================
|
||||
# Concurrency Control - Prevent overlapping runs
|
||||
# ==========================================================================
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}-${{ matrix.k8s-version }}
|
||||
cancel-in-progress: true
|
||||
|
||||
steps:
|
||||
# ========================================================================
|
||||
# Environment Setup
|
||||
# ========================================================================
|
||||
|
||||
- name: Check out code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
|
||||
# ========================================================================
|
||||
# Kubernetes Cluster Setup
|
||||
# ========================================================================
|
||||
|
||||
- name: Setup KinD with Kubernetes ${{ matrix.k8s-version }}
|
||||
uses: ./.github/actions/setup-kind-cluster
|
||||
with:
|
||||
k8s-version: ${{ matrix.k8s-version }}
|
||||
|
||||
- name: Deploy latest release
|
||||
uses: ./.github/actions/deploy-latest-release
|
||||
|
||||
- name: Upgrade from current branch
|
||||
uses: ./.github/actions/deploy-current-branch
|
||||
|
||||
- name: Run unit tests
|
||||
uses: ./.github/actions/unit-test
|
||||
with:
|
||||
codecov-enable: false
|
||||
codecov-token: ''
|
||||
165
.github/workflows/webhook-upgrade-validation.yml
vendored
Normal file
165
.github/workflows/webhook-upgrade-validation.yml
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
name: Webhook Upgrade Validation
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- release-*
|
||||
tags:
|
||||
- v*
|
||||
workflow_dispatch: {}
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- release-*
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.23.8'
|
||||
|
||||
jobs:
|
||||
webhook-upgrade-check:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
|
||||
|
||||
- name: Setup Env
|
||||
uses: ./.github/actions/env-setup
|
||||
|
||||
- name: Setup KinD
|
||||
run: |
|
||||
go install sigs.k8s.io/kind@v0.29.0
|
||||
kind delete cluster || true
|
||||
kind create cluster --image=kindest/node:v1.31.9
|
||||
|
||||
- name: Install KubeVela CLI
|
||||
run: curl -fsSL https://kubevela.io/script/install.sh | bash
|
||||
|
||||
- name: Install KubeVela baseline
|
||||
run: |
|
||||
vela install --set featureGates.enableCueValidation=true
|
||||
kubectl wait --namespace vela-system --for=condition=Available deployment/kubevela-vela-core --timeout=300s
|
||||
|
||||
- name: Prepare failing chart changes
|
||||
run: |
|
||||
cat <<'CHART' > charts/vela-core/templates/defwithtemplate/resource.yaml
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/resource.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Add resource requests and limits on K8s pod for your workload which follows the pod spec in path 'spec.template.'
|
||||
name: resource
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
- cronjobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |2
|
||||
let resourceContent = {
|
||||
resources: {
|
||||
if parameter.cpu != _|_ if parameter.memory != _|_ if parameter.requests == _|_ if parameter.limits == _|_ {
|
||||
// +patchStrategy=retainKeys
|
||||
requests: {
|
||||
cpu: parameter.cpu
|
||||
memory: parameter.memory
|
||||
}
|
||||
// +patchStrategy=retainKeys
|
||||
limits: {
|
||||
cpu: parameter.cpu
|
||||
memory: parameter.memory
|
||||
}
|
||||
}
|
||||
if parameter.requests != _|_ {
|
||||
// +patchStrategy=retainKeys
|
||||
requests: {
|
||||
cpu: parameter.requests.cpu
|
||||
memory: parameter.requests.memory
|
||||
}
|
||||
}
|
||||
if parameter.limits != _|_ {
|
||||
// +patchStrategy=retainKeys
|
||||
limits: {
|
||||
cpu: parameter.limits.cpu
|
||||
memory: parameter.limits.memory
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if context.output.spec != _|_ if context.output.spec.template != _|_ {
|
||||
patch: spec: template: spec: {
|
||||
// +patchKey=name
|
||||
containers: [resourceContent]
|
||||
}
|
||||
}
|
||||
if context.output.spec != _|_ if context.output.spec.jobTemplate != _|_ {
|
||||
patch: spec: jobTemplate: spec: template: spec: {
|
||||
// +patchKey=name
|
||||
containers: [resourceContent]
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the amount of cpu for requests and limits
|
||||
cpu?: *1 | number | string
|
||||
// +usage=Specify the amount of memory for requests and limits
|
||||
memory?: *"2048Mi" | =~"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$"
|
||||
// +usage=Specify the resources in requests
|
||||
requests?: {
|
||||
// +usage=Specify the amount of cpu for requests
|
||||
cpu: *1 | number | string
|
||||
// +usage=Specify the amount of memory for requests
|
||||
memory: *"2048Mi" | =~"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$"
|
||||
}
|
||||
// +usage=Specify the resources in limits
|
||||
limits?: {
|
||||
// +usage=Specify the amount of cpu for limits
|
||||
cpu: *1 | number | string
|
||||
// +usage=Specify the amount of memory for limits
|
||||
memory: *"2048Mi" | =~"^([1-9][0-9]{0,63})(E|P|T|G|M|K|Ei|Pi|Ti|Gi|Mi|Ki)$"
|
||||
}
|
||||
}
|
||||
|
||||
- name: Load image
|
||||
run: |
|
||||
mkdir -p $HOME/tmp/
|
||||
TMPDIR=$HOME/tmp/ make image-load
|
||||
|
||||
- name: Run Helm upgrade (expected to fail)
|
||||
run: |
|
||||
set +e
|
||||
helm upgrade \
|
||||
--set image.repository=vela-core-test \
|
||||
--set image.tag=$(git rev-parse --short HEAD) \
|
||||
--set featureGates.enableCueValidation=true \
|
||||
--wait kubevela ./charts/vela-core --debug -n vela-system
|
||||
status=$?
|
||||
echo "Helm upgrade exit code: ${status}"
|
||||
if [ $status -eq 0 ]; then
|
||||
echo "Expected helm upgrade to fail" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "Helm upgrade failed as expected"
|
||||
|
||||
- name: Dump webhook configurations
|
||||
if: ${{ always() }}
|
||||
run: |
|
||||
kubectl get mutatingwebhookconfiguration kubevela-vela-core-admission -o yaml
|
||||
kubectl get validatingwebhookconfiguration kubevela-vela-core-admission -o yaml
|
||||
|
||||
- name: Verify webhook validation remains active
|
||||
run: ginkgo -v --focus-file requiredparam_validation_test.go ./test/e2e-test
|
||||
|
||||
- name: Cleanup kind cluster
|
||||
if: ${{ always() }}
|
||||
run: kind delete cluster --name kind
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -35,6 +35,14 @@ vendor/
|
||||
.vscode
|
||||
.history
|
||||
|
||||
# Debug binaries generated by VS Code/Delve
|
||||
__debug_bin*
|
||||
*/__debug_bin*
|
||||
|
||||
# Webhook certificates generated at runtime
|
||||
k8s-webhook-server/
|
||||
options.go.bak
|
||||
|
||||
pkg/test/vela
|
||||
config/crd/bases
|
||||
_tmp/
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# CONTRIBUTING Guide
|
||||
|
||||
Please refer to https://kubevela.io/docs/contributor/overview for details.
|
||||
Please refer to https://kubevela.io/docs/contributor/overview for details.
|
||||
2
Makefile
2
Makefile
@@ -61,7 +61,7 @@ staticcheck: staticchecktool
|
||||
## lint: Run the golangci-lint
|
||||
lint: golangci
|
||||
@$(INFO) lint
|
||||
@$(GOLANGCILINT) run --fix --verbose --exclude-dirs 'scaffold'
|
||||
@GOLANGCILINT=$(GOLANGCILINT) ./hack/utils/golangci-lint-wrapper.sh
|
||||
|
||||
## reviewable: Run the reviewable
|
||||
reviewable: manifests fmt vet lint staticcheck helm-doc-gen sdk_fmt
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
[](https://artifacthub.io/packages/search?repo=kubevela)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/4602)
|
||||

|
||||
[](https://api.securityscorecards.dev/projects/github.com/kubevela/kubevela)
|
||||
[](https://scorecard.dev/viewer/?uri=github.com/kubevela/kubevela)
|
||||
[](https://opensource.alibaba.com/contribution_leaderboard/details?projectValue=kubevela)
|
||||
|
||||
## Introduction
|
||||
@@ -115,4 +115,4 @@ Security is a first priority thing for us at KubeVela. If you come across a rela
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
KubeVela adopts [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
|
||||
KubeVela adopts [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md).
|
||||
@@ -135,6 +135,9 @@ type Status struct {
|
||||
// HealthPolicy defines the health check policy for the abstraction
|
||||
// +optional
|
||||
HealthPolicy string `json:"healthPolicy,omitempty"`
|
||||
// Details stores a string representation of a CUE status map to be evaluated at runtime for display
|
||||
// +optional
|
||||
Details string `json:"details,omitempty"`
|
||||
}
|
||||
|
||||
// ApplicationPhase is a label for the condition of an application at the current time
|
||||
@@ -172,6 +175,7 @@ type ApplicationComponentStatus struct {
|
||||
// WorkloadDefinition is the definition of a WorkloadDefinition, such as deployments/apps.v1
|
||||
WorkloadDefinition WorkloadGVK `json:"workloadDefinition,omitempty"`
|
||||
Healthy bool `json:"healthy"`
|
||||
Details map[string]string `json:"details,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Traits []ApplicationTraitStatus `json:"traits,omitempty"`
|
||||
Scopes []corev1.ObjectReference `json:"scopes,omitempty"`
|
||||
@@ -185,9 +189,10 @@ func (in ApplicationComponentStatus) Equal(r ApplicationComponentStatus) bool {
|
||||
|
||||
// ApplicationTraitStatus records the trait health status
|
||||
type ApplicationTraitStatus struct {
|
||||
Type string `json:"type"`
|
||||
Healthy bool `json:"healthy"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Healthy bool `json:"healthy"`
|
||||
Details map[string]string `json:"details,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// Revision has name and revision number
|
||||
|
||||
@@ -130,10 +130,19 @@ func (in *ApplicationComponent) DeepCopy() *ApplicationComponent {
|
||||
func (in *ApplicationComponentStatus) DeepCopyInto(out *ApplicationComponentStatus) {
|
||||
*out = *in
|
||||
out.WorkloadDefinition = in.WorkloadDefinition
|
||||
if in.Details != nil {
|
||||
in, out := &in.Details, &out.Details
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
if in.Traits != nil {
|
||||
in, out := &in.Traits, &out.Traits
|
||||
*out = make([]ApplicationTraitStatus, len(*in))
|
||||
copy(*out, *in)
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.Scopes != nil {
|
||||
in, out := &in.Scopes, &out.Scopes
|
||||
@@ -175,6 +184,13 @@ func (in *ApplicationTrait) DeepCopy() *ApplicationTrait {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ApplicationTraitStatus) DeepCopyInto(out *ApplicationTraitStatus) {
|
||||
*out = *in
|
||||
if in.Details != nil {
|
||||
in, out := &in.Details, &out.Details
|
||||
*out = make(map[string]string, len(*in))
|
||||
for key, val := range *in {
|
||||
(*out)[key] = val
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationTraitStatus.
|
||||
|
||||
@@ -60,3 +60,8 @@ func init() {
|
||||
SchemeBuilder.Register(&workflowv1alpha1.Workflow{}, &workflowv1alpha1.WorkflowList{})
|
||||
_ = SchemeBuilder.AddToScheme(k8sscheme.Scheme)
|
||||
}
|
||||
|
||||
// Resource takes an unqualified resource and returns a Group qualified GroupResource
|
||||
func Resource(resource string) schema.GroupResource {
|
||||
return SchemeGroupVersion.WithResource(resource).GroupResource()
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ var (
|
||||
ComponentDefinitionGroupKind = schema.GroupKind{Group: Group, Kind: ComponentDefinitionKind}.String()
|
||||
ComponentDefinitionKindAPIVersion = ComponentDefinitionKind + "." + SchemeGroupVersion.String()
|
||||
ComponentDefinitionGroupVersionKind = SchemeGroupVersion.WithKind(ComponentDefinitionKind)
|
||||
ComponentDefinitionGVR = SchemeGroupVersion.WithResource("componentdefinitions")
|
||||
)
|
||||
|
||||
// WorkloadDefinition type metadata.
|
||||
@@ -65,6 +66,7 @@ var (
|
||||
TraitDefinitionGroupKind = schema.GroupKind{Group: Group, Kind: TraitDefinitionKind}.String()
|
||||
TraitDefinitionKindAPIVersion = TraitDefinitionKind + "." + SchemeGroupVersion.String()
|
||||
TraitDefinitionGroupVersionKind = SchemeGroupVersion.WithKind(TraitDefinitionKind)
|
||||
TraitDefinitionGVR = SchemeGroupVersion.WithResource("traitdefinitions")
|
||||
)
|
||||
|
||||
// PolicyDefinition type metadata.
|
||||
@@ -73,6 +75,7 @@ var (
|
||||
PolicyDefinitionGroupKind = schema.GroupKind{Group: Group, Kind: PolicyDefinitionKind}.String()
|
||||
PolicyDefinitionKindAPIVersion = PolicyDefinitionKind + "." + SchemeGroupVersion.String()
|
||||
PolicyDefinitionGroupVersionKind = SchemeGroupVersion.WithKind(PolicyDefinitionKind)
|
||||
PolicyDefinitionGVR = SchemeGroupVersion.WithResource("policydefinitions")
|
||||
)
|
||||
|
||||
// WorkflowStepDefinition type metadata.
|
||||
@@ -81,6 +84,7 @@ var (
|
||||
WorkflowStepDefinitionGroupKind = schema.GroupKind{Group: Group, Kind: WorkflowStepDefinitionKind}.String()
|
||||
WorkflowStepDefinitionKindAPIVersion = WorkflowStepDefinitionKind + "." + SchemeGroupVersion.String()
|
||||
WorkflowStepDefinitionGroupVersionKind = SchemeGroupVersion.WithKind(WorkflowStepDefinitionKind)
|
||||
WorkflowStepDefinitionGVR = SchemeGroupVersion.WithResource("workflowstepdefinitions")
|
||||
)
|
||||
|
||||
// DefinitionRevision type metadata.
|
||||
@@ -115,6 +119,20 @@ var (
|
||||
ResourceTrackerKindVersionKind = SchemeGroupVersion.WithKind(ResourceTrackerKind)
|
||||
)
|
||||
|
||||
// DefinitionTypeInfo contains the mapping information for a definition type
|
||||
type DefinitionTypeInfo struct {
|
||||
GVR schema.GroupVersionResource
|
||||
Kind string
|
||||
}
|
||||
|
||||
// DefinitionTypeMap maps definition types to their corresponding GVR and Kind
|
||||
var DefinitionTypeMap = map[reflect.Type]DefinitionTypeInfo{
|
||||
reflect.TypeOf(ComponentDefinition{}): {GVR: ComponentDefinitionGVR, Kind: ComponentDefinitionKind},
|
||||
reflect.TypeOf(TraitDefinition{}): {GVR: TraitDefinitionGVR, Kind: TraitDefinitionKind},
|
||||
reflect.TypeOf(PolicyDefinition{}): {GVR: PolicyDefinitionGVR, Kind: PolicyDefinitionKind},
|
||||
reflect.TypeOf(WorkflowStepDefinition{}): {GVR: WorkflowStepDefinitionGVR, Kind: WorkflowStepDefinitionKind},
|
||||
}
|
||||
|
||||
func init() {
|
||||
SchemeBuilder.Register(&ComponentDefinition{}, &ComponentDefinitionList{})
|
||||
SchemeBuilder.Register(&WorkloadDefinition{}, &WorkloadDefinitionList{})
|
||||
|
||||
117
apis/core.oam.dev/v1beta1/register_test.go
Normal file
117
apis/core.oam.dev/v1beta1/register_test.go
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright 2025 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1beta1
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
)
|
||||
|
||||
func TestDefinitionTypeMap(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
defType reflect.Type
|
||||
expectedGVR schema.GroupVersionResource
|
||||
expectedKind string
|
||||
}{
|
||||
{
|
||||
name: "ComponentDefinition",
|
||||
defType: reflect.TypeOf(ComponentDefinition{}),
|
||||
expectedGVR: ComponentDefinitionGVR,
|
||||
expectedKind: ComponentDefinitionKind,
|
||||
},
|
||||
{
|
||||
name: "TraitDefinition",
|
||||
defType: reflect.TypeOf(TraitDefinition{}),
|
||||
expectedGVR: TraitDefinitionGVR,
|
||||
expectedKind: TraitDefinitionKind,
|
||||
},
|
||||
{
|
||||
name: "PolicyDefinition",
|
||||
defType: reflect.TypeOf(PolicyDefinition{}),
|
||||
expectedGVR: PolicyDefinitionGVR,
|
||||
expectedKind: PolicyDefinitionKind,
|
||||
},
|
||||
{
|
||||
name: "WorkflowStepDefinition",
|
||||
defType: reflect.TypeOf(WorkflowStepDefinition{}),
|
||||
expectedGVR: WorkflowStepDefinitionGVR,
|
||||
expectedKind: WorkflowStepDefinitionKind,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
info, ok := DefinitionTypeMap[tt.defType]
|
||||
assert.Truef(t, ok, "Type %v should exist in DefinitionTypeMap", tt.defType)
|
||||
assert.Equal(t, tt.expectedGVR, info.GVR)
|
||||
assert.Equal(t, tt.expectedKind, info.Kind)
|
||||
|
||||
// Verify GVR follows Kubernetes conventions
|
||||
assert.Equal(t, Group, info.GVR.Group)
|
||||
assert.Equal(t, Version, info.GVR.Version)
|
||||
// Resource should be lowercase plural of Kind
|
||||
assert.Equal(t, strings.ToLower(info.Kind)+"s", info.GVR.Resource)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefinitionTypeMapCompleteness(t *testing.T) {
|
||||
// Ensure all expected definition types are in the map
|
||||
expectedTypes := []reflect.Type{
|
||||
reflect.TypeOf(ComponentDefinition{}),
|
||||
reflect.TypeOf(TraitDefinition{}),
|
||||
reflect.TypeOf(PolicyDefinition{}),
|
||||
reflect.TypeOf(WorkflowStepDefinition{}),
|
||||
}
|
||||
|
||||
assert.Equal(t, len(expectedTypes), len(DefinitionTypeMap), "DefinitionTypeMap should contain exactly %d entries", len(expectedTypes))
|
||||
|
||||
for _, expectedType := range expectedTypes {
|
||||
_, ok := DefinitionTypeMap[expectedType]
|
||||
assert.Truef(t, ok, "DefinitionTypeMap should contain %v", expectedType)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefinitionKindValues(t *testing.T) {
|
||||
// Verify that the Kind values match the actual type names
|
||||
tests := []struct {
|
||||
defType interface{}
|
||||
expectedKind string
|
||||
}{
|
||||
{ComponentDefinition{}, "ComponentDefinition"},
|
||||
{TraitDefinition{}, "TraitDefinition"},
|
||||
{PolicyDefinition{}, "PolicyDefinition"},
|
||||
{WorkflowStepDefinition{}, "WorkflowStepDefinition"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.expectedKind, func(t *testing.T) {
|
||||
actualKind := reflect.TypeOf(tt.defType).Name()
|
||||
assert.Equal(t, tt.expectedKind, actualKind)
|
||||
|
||||
// Also verify it matches what's in the map
|
||||
info, ok := DefinitionTypeMap[reflect.TypeOf(tt.defType)]
|
||||
assert.True(t, ok)
|
||||
assert.Equal(t, tt.expectedKind, info.Kind)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -552,6 +552,22 @@ func (in *DefinitionRevisionSpec) DeepCopy() *DefinitionRevisionSpec {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DefinitionTypeInfo) DeepCopyInto(out *DefinitionTypeInfo) {
|
||||
*out = *in
|
||||
out.GVR = in.GVR
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DefinitionTypeInfo.
|
||||
func (in *DefinitionTypeInfo) DeepCopy() *DefinitionTypeInfo {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DefinitionTypeInfo)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *ManagedResource) DeepCopyInto(out *ManagedResource) {
|
||||
*out = *in
|
||||
|
||||
@@ -99,6 +99,8 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
|
||||
| `featureGates.sharedDefinitionStorageForApplicationRevision` | use definition cache to reduce duplicated definition storage for application revision, must be used with InformerCacheFilterUnnecessaryFields | `true` |
|
||||
| `featureGates.disableWorkflowContextConfigMapCache` | disable the workflow context's configmap informer cache | `true` |
|
||||
| `featureGates.enableCueValidation` | enable the strict cue validation for cue required parameter fields | `false` |
|
||||
| `featureGates.enableApplicationStatusMetrics` | enable application status metrics and structured logging | `false` |
|
||||
| `featureGates.validateResourcesExist` | enable webhook validation to check if resource types referenced in definition templates exist in the cluster | `false` |
|
||||
|
||||
### MultiCluster parameters
|
||||
|
||||
@@ -146,14 +148,16 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
|
||||
| `affinity` | Affinity | `{}` |
|
||||
| `rbac.create` | Specifies whether a RBAC role should be created | `true` |
|
||||
| `logDebug` | Enable debug logs for development purpose | `false` |
|
||||
| `devLogs` | Enable formatted logging support for development purpose | `false` |
|
||||
| `logFilePath` | If non-empty, write log files in this path | `""` |
|
||||
| `logFileMaxSize` | Defines the maximum size a log file can grow to. Unit is megabytes. If the value is 0, the maximum file size is unlimited. | `1024` |
|
||||
| `kubeClient.qps` | The qps for reconcile clients | `400` |
|
||||
| `kubeClient.burst` | The burst for reconcile clients | `600` |
|
||||
| `authentication.enabled` | Enable authentication for application | `false` |
|
||||
| `authentication.withUser` | Application authentication will impersonate as the request User | `true` |
|
||||
| `authentication.defaultUser` | Application authentication will impersonate as the User if no user provided in Application | `kubevela:vela-core` |
|
||||
| `authentication.enabled` | Enable authentication framework for applications | `false` |
|
||||
| `authentication.withUser` | Application authentication will impersonate as the request User (must be true for security) | `true` |
|
||||
| `authentication.defaultUser` | Application authentication will impersonate as the User if no user provided or withUser is false | `kubevela:vela-core` |
|
||||
| `authentication.groupPattern` | Application authentication will impersonate as the request Group that matches the pattern | `kubevela:*` |
|
||||
| `authorization.definitionValidationEnabled` | Enable definition permission validation for RBAC checks on definitions | `false` |
|
||||
| `sharding.enabled` | When sharding enabled, the controller will run as master mode. Refer to https://github.com/kubevela/kubevela/blob/master/design/vela-core/sharding.md for details. | `false` |
|
||||
| `sharding.schedulableShards` | The shards available for scheduling. If empty, dynamic discovery will be used. | `""` |
|
||||
| `core.metrics.enabled` | Enable metrics for vela-core | `false` |
|
||||
|
||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
controller-gen.kubebuilder.io/version: v0.16.5
|
||||
name: applicationrevisions.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
@@ -395,7 +395,6 @@ spec:
|
||||
the event) or if no container name is specified "spec.containers[2]" (container with
|
||||
index 2 in this pod). This syntax is chosen only to have some well-defined way of
|
||||
referencing a part of an object.
|
||||
TODO: this design is not final and this field is subject to change in the future.
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
@@ -429,24 +428,8 @@ spec:
|
||||
description: Components record the related Components created
|
||||
by Application Controller
|
||||
items:
|
||||
description: |-
|
||||
ObjectReference contains enough information to let you inspect or modify the referred object.
|
||||
---
|
||||
New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.
|
||||
1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.
|
||||
2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular
|
||||
restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted".
|
||||
Those cannot be well described when embedded.
|
||||
3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.
|
||||
4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity
|
||||
during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple
|
||||
and the version of the actual struct is irrelevant.
|
||||
5. We cannot easily change it. Because this type is embedded in many locations, updates to this type
|
||||
will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.
|
||||
|
||||
|
||||
Instead of using this type, create a locally provided and used type that is well-focused on your reference.
|
||||
For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .
|
||||
description: ObjectReference contains enough information
|
||||
to let you inspect or modify the referred object.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
@@ -460,7 +443,6 @@ spec:
|
||||
the event) or if no container name is specified "spec.containers[2]" (container with
|
||||
index 2 in this pod). This syntax is chosen only to have some well-defined way of
|
||||
referencing a part of an object.
|
||||
TODO: this design is not final and this field is subject to change in the future.
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
@@ -577,6 +559,10 @@ spec:
|
||||
properties:
|
||||
cluster:
|
||||
type: string
|
||||
details:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
env:
|
||||
type: string
|
||||
healthy:
|
||||
@@ -589,24 +575,8 @@ spec:
|
||||
type: string
|
||||
scopes:
|
||||
items:
|
||||
description: |-
|
||||
ObjectReference contains enough information to let you inspect or modify the referred object.
|
||||
---
|
||||
New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.
|
||||
1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.
|
||||
2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular
|
||||
restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted".
|
||||
Those cannot be well described when embedded.
|
||||
3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.
|
||||
4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity
|
||||
during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple
|
||||
and the version of the actual struct is irrelevant.
|
||||
5. We cannot easily change it. Because this type is embedded in many locations, updates to this type
|
||||
will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.
|
||||
|
||||
|
||||
Instead of using this type, create a locally provided and used type that is well-focused on your reference.
|
||||
For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .
|
||||
description: ObjectReference contains enough information
|
||||
to let you inspect or modify the referred object.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
@@ -620,7 +590,6 @@ spec:
|
||||
the event) or if no container name is specified "spec.containers[2]" (container with
|
||||
index 2 in this pod). This syntax is chosen only to have some well-defined way of
|
||||
referencing a part of an object.
|
||||
TODO: this design is not final and this field is subject to change in the future.
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
@@ -655,6 +624,10 @@ spec:
|
||||
description: ApplicationTraitStatus records the trait
|
||||
health status
|
||||
properties:
|
||||
details:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
healthy:
|
||||
type: boolean
|
||||
message:
|
||||
@@ -693,24 +666,8 @@ spec:
|
||||
appRevision:
|
||||
type: string
|
||||
contextBackend:
|
||||
description: |-
|
||||
ObjectReference contains enough information to let you inspect or modify the referred object.
|
||||
---
|
||||
New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.
|
||||
1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.
|
||||
2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular
|
||||
restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted".
|
||||
Those cannot be well described when embedded.
|
||||
3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.
|
||||
4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity
|
||||
during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple
|
||||
and the version of the actual struct is irrelevant.
|
||||
5. We cannot easily change it. Because this type is embedded in many locations, updates to this type
|
||||
will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.
|
||||
|
||||
|
||||
Instead of using this type, create a locally provided and used type that is well-focused on your reference.
|
||||
For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .
|
||||
description: ObjectReference contains enough information
|
||||
to let you inspect or modify the referred object.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
@@ -724,7 +681,6 @@ spec:
|
||||
the event) or if no container name is specified "spec.containers[2]" (container with
|
||||
index 2 in this pod). This syntax is chosen only to have some well-defined way of
|
||||
referencing a part of an object.
|
||||
TODO: this design is not final and this field is subject to change in the future.
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
@@ -1048,6 +1004,11 @@ spec:
|
||||
description: CustomStatus defines the custom status
|
||||
message that could display to user
|
||||
type: string
|
||||
details:
|
||||
description: Details stores a string representation
|
||||
of a CUE status map to be evaluated at runtime for
|
||||
display
|
||||
type: string
|
||||
healthPolicy:
|
||||
description: HealthPolicy defines the health check policy
|
||||
for the abstraction
|
||||
@@ -1650,6 +1611,11 @@ spec:
|
||||
description: CustomStatus defines the custom status
|
||||
message that could display to user
|
||||
type: string
|
||||
details:
|
||||
description: Details stores a string representation
|
||||
of a CUE status map to be evaluated at runtime for
|
||||
display
|
||||
type: string
|
||||
healthPolicy:
|
||||
description: HealthPolicy defines the health check policy
|
||||
for the abstraction
|
||||
@@ -2335,6 +2301,11 @@ spec:
|
||||
description: CustomStatus defines the custom status
|
||||
message that could display to user
|
||||
type: string
|
||||
details:
|
||||
description: Details stores a string representation
|
||||
of a CUE status map to be evaluated at runtime for
|
||||
display
|
||||
type: string
|
||||
healthPolicy:
|
||||
description: HealthPolicy defines the health check policy
|
||||
for the abstraction
|
||||
@@ -2403,24 +2374,8 @@ spec:
|
||||
appRevision:
|
||||
type: string
|
||||
contextBackend:
|
||||
description: |-
|
||||
ObjectReference contains enough information to let you inspect or modify the referred object.
|
||||
---
|
||||
New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.
|
||||
1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.
|
||||
2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular
|
||||
restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted".
|
||||
Those cannot be well described when embedded.
|
||||
3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.
|
||||
4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity
|
||||
during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple
|
||||
and the version of the actual struct is irrelevant.
|
||||
5. We cannot easily change it. Because this type is embedded in many locations, updates to this type
|
||||
will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.
|
||||
|
||||
|
||||
Instead of using this type, create a locally provided and used type that is well-focused on your reference.
|
||||
For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .
|
||||
description: ObjectReference contains enough information to let
|
||||
you inspect or modify the referred object.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
@@ -2434,7 +2389,6 @@ spec:
|
||||
the event) or if no container name is specified "spec.containers[2]" (container with
|
||||
index 2 in this pod). This syntax is chosen only to have some well-defined way of
|
||||
referencing a part of an object.
|
||||
TODO: this design is not final and this field is subject to change in the future.
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
|
||||
@@ -3,7 +3,7 @@ kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
cert-manager.io/inject-ca-from: vela-system/kubevela-vela-core-root-cert
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
controller-gen.kubebuilder.io/version: v0.16.5
|
||||
name: applications.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
@@ -345,7 +345,6 @@ spec:
|
||||
the event) or if no container name is specified "spec.containers[2]" (container with
|
||||
index 2 in this pod). This syntax is chosen only to have some well-defined way of
|
||||
referencing a part of an object.
|
||||
TODO: this design is not final and this field is subject to change in the future.
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
@@ -379,24 +378,8 @@ spec:
|
||||
description: Components record the related Components created by Application
|
||||
Controller
|
||||
items:
|
||||
description: |-
|
||||
ObjectReference contains enough information to let you inspect or modify the referred object.
|
||||
---
|
||||
New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.
|
||||
1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.
|
||||
2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular
|
||||
restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted".
|
||||
Those cannot be well described when embedded.
|
||||
3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.
|
||||
4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity
|
||||
during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple
|
||||
and the version of the actual struct is irrelevant.
|
||||
5. We cannot easily change it. Because this type is embedded in many locations, updates to this type
|
||||
will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.
|
||||
|
||||
|
||||
Instead of using this type, create a locally provided and used type that is well-focused on your reference.
|
||||
For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .
|
||||
description: ObjectReference contains enough information to let
|
||||
you inspect or modify the referred object.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
@@ -410,7 +393,6 @@ spec:
|
||||
the event) or if no container name is specified "spec.containers[2]" (container with
|
||||
index 2 in this pod). This syntax is chosen only to have some well-defined way of
|
||||
referencing a part of an object.
|
||||
TODO: this design is not final and this field is subject to change in the future.
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
@@ -525,6 +507,10 @@ spec:
|
||||
properties:
|
||||
cluster:
|
||||
type: string
|
||||
details:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
env:
|
||||
type: string
|
||||
healthy:
|
||||
@@ -537,24 +523,8 @@ spec:
|
||||
type: string
|
||||
scopes:
|
||||
items:
|
||||
description: |-
|
||||
ObjectReference contains enough information to let you inspect or modify the referred object.
|
||||
---
|
||||
New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.
|
||||
1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.
|
||||
2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular
|
||||
restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted".
|
||||
Those cannot be well described when embedded.
|
||||
3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.
|
||||
4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity
|
||||
during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple
|
||||
and the version of the actual struct is irrelevant.
|
||||
5. We cannot easily change it. Because this type is embedded in many locations, updates to this type
|
||||
will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.
|
||||
|
||||
|
||||
Instead of using this type, create a locally provided and used type that is well-focused on your reference.
|
||||
For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .
|
||||
description: ObjectReference contains enough information to
|
||||
let you inspect or modify the referred object.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
@@ -568,7 +538,6 @@ spec:
|
||||
the event) or if no container name is specified "spec.containers[2]" (container with
|
||||
index 2 in this pod). This syntax is chosen only to have some well-defined way of
|
||||
referencing a part of an object.
|
||||
TODO: this design is not final and this field is subject to change in the future.
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
@@ -603,6 +572,10 @@ spec:
|
||||
description: ApplicationTraitStatus records the trait health
|
||||
status
|
||||
properties:
|
||||
details:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
healthy:
|
||||
type: boolean
|
||||
message:
|
||||
@@ -641,24 +614,8 @@ spec:
|
||||
appRevision:
|
||||
type: string
|
||||
contextBackend:
|
||||
description: |-
|
||||
ObjectReference contains enough information to let you inspect or modify the referred object.
|
||||
---
|
||||
New uses of this type are discouraged because of difficulty describing its usage when embedded in APIs.
|
||||
1. Ignored fields. It includes many fields which are not generally honored. For instance, ResourceVersion and FieldPath are both very rarely valid in actual usage.
|
||||
2. Invalid usage help. It is impossible to add specific help for individual usage. In most embedded usages, there are particular
|
||||
restrictions like, "must refer only to types A and B" or "UID not honored" or "name must be restricted".
|
||||
Those cannot be well described when embedded.
|
||||
3. Inconsistent validation. Because the usages are different, the validation rules are different by usage, which makes it hard for users to predict what will happen.
|
||||
4. The fields are both imprecise and overly precise. Kind is not a precise mapping to a URL. This can produce ambiguity
|
||||
during interpretation and require a REST mapping. In most cases, the dependency is on the group,resource tuple
|
||||
and the version of the actual struct is irrelevant.
|
||||
5. We cannot easily change it. Because this type is embedded in many locations, updates to this type
|
||||
will affect numerous schemas. Don't make new APIs embed an underspecified API type they do not control.
|
||||
|
||||
|
||||
Instead of using this type, create a locally provided and used type that is well-focused on your reference.
|
||||
For example, ServiceReferences for admission registration: https://github.com/kubernetes/api/blob/release-1.17/admissionregistration/v1/types.go#L533 .
|
||||
description: ObjectReference contains enough information to let
|
||||
you inspect or modify the referred object.
|
||||
properties:
|
||||
apiVersion:
|
||||
description: API version of the referent.
|
||||
@@ -672,7 +629,6 @@ spec:
|
||||
the event) or if no container name is specified "spec.containers[2]" (container with
|
||||
index 2 in this pod). This syntax is chosen only to have some well-defined way of
|
||||
referencing a part of an object.
|
||||
TODO: this design is not final and this field is subject to change in the future.
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
|
||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
controller-gen.kubebuilder.io/version: v0.16.5
|
||||
name: componentdefinitions.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
@@ -190,6 +190,10 @@ spec:
|
||||
description: CustomStatus defines the custom status message that
|
||||
could display to user
|
||||
type: string
|
||||
details:
|
||||
description: Details stores a string representation of a CUE status
|
||||
map to be evaluated at runtime for display
|
||||
type: string
|
||||
healthPolicy:
|
||||
description: HealthPolicy defines the health check policy for
|
||||
the abstraction
|
||||
|
||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
controller-gen.kubebuilder.io/version: v0.16.5
|
||||
name: definitionrevisions.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
@@ -236,6 +236,10 @@ spec:
|
||||
description: CustomStatus defines the custom status message
|
||||
that could display to user
|
||||
type: string
|
||||
details:
|
||||
description: Details stores a string representation of
|
||||
a CUE status map to be evaluated at runtime for display
|
||||
type: string
|
||||
healthPolicy:
|
||||
description: HealthPolicy defines the health check policy
|
||||
for the abstraction
|
||||
@@ -773,6 +777,10 @@ spec:
|
||||
description: CustomStatus defines the custom status message
|
||||
that could display to user
|
||||
type: string
|
||||
details:
|
||||
description: Details stores a string representation of
|
||||
a CUE status map to be evaluated at runtime for display
|
||||
type: string
|
||||
healthPolicy:
|
||||
description: HealthPolicy defines the health check policy
|
||||
for the abstraction
|
||||
|
||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
controller-gen.kubebuilder.io/version: v0.16.5
|
||||
name: policies.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
|
||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
controller-gen.kubebuilder.io/version: v0.16.5
|
||||
name: policydefinitions.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
|
||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
controller-gen.kubebuilder.io/version: v0.16.5
|
||||
name: resourcetrackers.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
@@ -96,7 +96,6 @@ spec:
|
||||
the event) or if no container name is specified "spec.containers[2]" (container with
|
||||
index 2 in this pod). This syntax is chosen only to have some well-defined way of
|
||||
referencing a part of an object.
|
||||
TODO: this design is not final and this field is subject to change in the future.
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
|
||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
controller-gen.kubebuilder.io/version: v0.16.5
|
||||
name: traitdefinitions.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
@@ -220,6 +220,10 @@ spec:
|
||||
description: CustomStatus defines the custom status message that
|
||||
could display to user
|
||||
type: string
|
||||
details:
|
||||
description: Details stores a string representation of a CUE status
|
||||
map to be evaluated at runtime for display
|
||||
type: string
|
||||
healthPolicy:
|
||||
description: HealthPolicy defines the health check policy for
|
||||
the abstraction
|
||||
|
||||
@@ -3,7 +3,7 @@ apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.14.0
|
||||
controller-gen.kubebuilder.io/version: v0.16.5
|
||||
name: workflowstepdefinitions.core.oam.dev
|
||||
spec:
|
||||
group: core.oam.dev
|
||||
|
||||
@@ -29,3 +29,36 @@ Welcome to use the KubeVela! Enjoy your shipping application journey!
|
||||
|
||||
|
||||
You can refer to https://kubevela.io for more details.
|
||||
|
||||
{{- if and .Values.authentication.enabled (not .Values.authentication.withUser) }}
|
||||
|
||||
WARNING: Authentication is enabled but withUser is disabled.
|
||||
This configuration provides NO security benefit:
|
||||
- All applications will run as '{{ .Values.authentication.defaultUser }}' regardless of who creates them
|
||||
- User groups matching '{{ .Values.authentication.groupPattern }}' are still collected but not used effectively
|
||||
- Service account annotations are blocked
|
||||
|
||||
To enable true user impersonation for security:
|
||||
--set authentication.withUser=true
|
||||
{{- end }}
|
||||
|
||||
{{- if and (not .Values.authorization.definitionValidationEnabled) (not .Values.authentication.enabled) }}
|
||||
|
||||
SECURITY RECOMMENDATION: Both authentication and definition validation are disabled.
|
||||
If KubeVela is running with cluster-admin or other high-level permissions,
|
||||
consider enabling one or both security features:
|
||||
|
||||
1. Authentication with impersonation (recommended for multi-tenant environments):
|
||||
--set authentication.enabled=true
|
||||
--set authentication.withUser=true
|
||||
This makes KubeVela impersonate the requesting user, applying their RBAC permissions.
|
||||
Note: Both flags must be enabled for user impersonation to work.
|
||||
|
||||
2. Definition permission validation (lightweight RBAC for definitions):
|
||||
--set authorization.definitionValidationEnabled=true
|
||||
This ensures users can only reference definitions they have access to.
|
||||
|
||||
Using both features together provides defense in depth.
|
||||
Without these protections, users can leverage KubeVela's permissions to deploy
|
||||
resources beyond their intended access level.
|
||||
{{- end }}
|
||||
|
||||
@@ -4,7 +4,7 @@ kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ template "kubevela.fullname" . }}-admission
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade,post-rollback
|
||||
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||
labels:
|
||||
app: {{ template "kubevela.name" . }}-admission
|
||||
|
||||
@@ -4,7 +4,7 @@ kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ template "kubevela.fullname" . }}-admission
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade,post-rollback
|
||||
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||
labels:
|
||||
app: {{ template "kubevela.name" . }}-admission
|
||||
|
||||
@@ -5,7 +5,7 @@ metadata:
|
||||
name: {{ template "kubevela.fullname" . }}-admission-patch
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/hook": post-install,post-upgrade
|
||||
"helm.sh/hook": post-install,post-upgrade,post-rollback
|
||||
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||
labels:
|
||||
app: {{ template "kubevela.name" . }}-admission-patch
|
||||
|
||||
@@ -5,7 +5,7 @@ metadata:
|
||||
name: {{ template "kubevela.fullname" . }}-admission
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade,post-rollback
|
||||
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||
labels:
|
||||
app: {{ template "kubevela.name" . }}-admission
|
||||
|
||||
@@ -5,7 +5,7 @@ metadata:
|
||||
name: {{ template "kubevela.fullname" . }}-admission
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade,post-rollback
|
||||
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||
labels:
|
||||
app: {{ template "kubevela.name" . }}-admission
|
||||
|
||||
@@ -5,7 +5,7 @@ metadata:
|
||||
name: {{ template "kubevela.fullname" . }}-admission
|
||||
namespace: {{ .Release.Namespace }}
|
||||
annotations:
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade
|
||||
"helm.sh/hook": pre-install,pre-upgrade,post-install,post-upgrade,post-rollback
|
||||
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||
labels:
|
||||
app: {{ template "kubevela.name" . }}-admission
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
{{- if .Values.admissionWebhooks.enabled -}}
|
||||
{{- /* Preserve existing caBundle on upgrade to avoid breaking admission if hooks fail. */}}
|
||||
{{- $mName := printf "%s-admission" (include "kubevela.fullname" .) -}}
|
||||
{{- $existing := (lookup "admissionregistration.k8s.io/v1" "MutatingWebhookConfiguration" "" $mName) -}}
|
||||
{{- $vals := dict "apps" "" "comps" "" -}}
|
||||
{{- if $existing -}}
|
||||
{{- range $existing.webhooks -}}
|
||||
{{- if eq .name "mutating.core.oam.dev.v1beta1.applications" -}}{{- $_ := set $vals "apps" .clientConfig.caBundle -}}{{- end -}}
|
||||
{{- if eq .name "mutating.core.oam-dev.v1beta1.componentdefinitions" -}}{{- $_ := set $vals "comps" .clientConfig.caBundle -}}{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: MutatingWebhookConfiguration
|
||||
metadata:
|
||||
@@ -10,7 +20,7 @@ metadata:
|
||||
{{- end }}
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
caBundle: {{ default "Cg==" (get $vals "apps") }}
|
||||
service:
|
||||
name: {{ template "kubevela.name" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -36,7 +46,7 @@ webhooks:
|
||||
resources:
|
||||
- applications
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
caBundle: {{ default "Cg==" (get $vals "comps") }}
|
||||
service:
|
||||
name: {{ template "kubevela.name" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
{{- if .Values.admissionWebhooks.enabled -}}
|
||||
{{- /* Preserve existing caBundle on upgrade to avoid breaking admission if hooks fail. */}}
|
||||
{{- $vName := printf "%s-admission" (include "kubevela.fullname" .) -}}
|
||||
{{- $existing := (lookup "admissionregistration.k8s.io/v1" "ValidatingWebhookConfiguration" "" $vName) -}}
|
||||
{{- $vals := dict "traits" "" "apps" "" "comps" "" "policies" "" -}}
|
||||
{{- if $existing -}}
|
||||
{{- range $existing.webhooks -}}
|
||||
{{- if eq .name "validating.core.oam.dev.v1beta1.traitdefinitions" -}}{{- $_ := set $vals "traits" .clientConfig.caBundle -}}{{- end -}}
|
||||
{{- if eq .name "validating.core.oam.dev.v1beta1.applications" -}}{{- $_ := set $vals "apps" .clientConfig.caBundle -}}{{- end -}}
|
||||
{{- if eq .name "validating.core.oam-dev.v1beta1.componentdefinitions" -}}{{- $_ := set $vals "comps" .clientConfig.caBundle -}}{{- end -}}
|
||||
{{- if eq .name "validating.core.oam-dev.v1beta1.policydefinitions" -}}{{- $_ := set $vals "policies" .clientConfig.caBundle -}}{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
@@ -10,7 +22,7 @@ metadata:
|
||||
{{- end }}
|
||||
webhooks:
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
caBundle: {{ default "Cg==" (get $vals "traits") }}
|
||||
service:
|
||||
name: {{ template "kubevela.name" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -37,7 +49,7 @@ webhooks:
|
||||
- traitdefinitions
|
||||
timeoutSeconds: 5
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
caBundle: {{ default "Cg==" (get $vals "apps") }}
|
||||
service:
|
||||
name: {{ template "kubevela.name" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -63,7 +75,7 @@ webhooks:
|
||||
resources:
|
||||
- applications
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
caBundle: {{ default "Cg==" (get $vals "comps") }}
|
||||
service:
|
||||
name: {{ template "kubevela.name" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -89,7 +101,7 @@ webhooks:
|
||||
resources:
|
||||
- componentdefinitions
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
caBundle: {{ default "Cg==" (get $vals "policies") }}
|
||||
service:
|
||||
name: {{ template "kubevela.name" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -114,4 +126,30 @@ webhooks:
|
||||
- UPDATE
|
||||
resources:
|
||||
- policydefinitions
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
service:
|
||||
name: {{ template "kubevela.name" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
path: /validating-core-oam-dev-v1beta1-workflowstepdefinitions
|
||||
{{- if .Values.admissionWebhooks.patch.enabled }}
|
||||
failurePolicy: Ignore
|
||||
{{- else }}
|
||||
failurePolicy: Fail
|
||||
{{- end }}
|
||||
name: validating.core.oam-dev.v1beta1.workflowstepdefinitions
|
||||
sideEffects: None
|
||||
admissionReviewVersions:
|
||||
- v1beta1
|
||||
- v1
|
||||
rules:
|
||||
- apiGroups:
|
||||
- core.oam.dev
|
||||
apiVersions:
|
||||
- v1beta1
|
||||
operations:
|
||||
- CREATE
|
||||
- UPDATE
|
||||
resources:
|
||||
- workflowstepdefinitions
|
||||
{{- end -}}
|
||||
|
||||
@@ -4,7 +4,7 @@ apiVersion: core.oam.dev/v1beta1
|
||||
kind: WorkflowStepDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
custom.definition.oam.dev/category: External Intergration
|
||||
custom.definition.oam.dev/category: External Integration
|
||||
definition.oam.dev/alias: ""
|
||||
definition.oam.dev/description: Send request to the url
|
||||
name: request
|
||||
@@ -14,8 +14,8 @@ spec:
|
||||
cue:
|
||||
template: |
|
||||
import (
|
||||
"vela/op"
|
||||
"vela/http"
|
||||
"vela/builtin"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
@@ -33,14 +33,22 @@ spec:
|
||||
}
|
||||
}
|
||||
}
|
||||
fail: {
|
||||
if http.$returns.response.statusCode > 400 {
|
||||
requestFail: builtin.#Fail & {
|
||||
$params: message: "request of \(parameter.url) is fail: \(http.response.statusCode)"
|
||||
|
||||
wait: op.#ConditionalWait & {
|
||||
continue: req.$returns != _|_
|
||||
message?: "Waiting for response from \(parameter.url)"
|
||||
}
|
||||
|
||||
fail: op.#Steps & {
|
||||
if req.$returns.statusCode > 400 {
|
||||
requestFail: op.#Fail & {
|
||||
message: "request of \(parameter.url) is fail: \(req.$returns.statusCode)"
|
||||
}
|
||||
}
|
||||
}
|
||||
response: json.Unmarshal(http.$returns.response.body)
|
||||
|
||||
response: json.Unmarshal(req.$returns.body)
|
||||
|
||||
parameter: {
|
||||
url: string
|
||||
method: *"GET" | "POST" | "PUT" | "DELETE"
|
||||
|
||||
@@ -17,49 +17,51 @@ spec:
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |2
|
||||
let resourceContent = {
|
||||
resources: {
|
||||
if parameter.cpu != _|_ if parameter.memory != _|_ if parameter.requests == _|_ if parameter.limits == _|_ {
|
||||
// +patchStrategy=retainKeys
|
||||
requests: {
|
||||
cpu: parameter.cpu
|
||||
memory: parameter.memory
|
||||
template: |
|
||||
patch: {
|
||||
let resourceContent = {
|
||||
resources: {
|
||||
if parameter.cpu != _|_ if parameter.memory != _|_ if parameter.requests == _|_ if parameter.limits == _|_ {
|
||||
// +patchStrategy=retainKeys
|
||||
requests: {
|
||||
cpu: parameter.cpu
|
||||
memory: parameter.memory
|
||||
}
|
||||
// +patchStrategy=retainKeys
|
||||
limits: {
|
||||
cpu: parameter.cpu
|
||||
memory: parameter.memory
|
||||
}
|
||||
}
|
||||
// +patchStrategy=retainKeys
|
||||
limits: {
|
||||
cpu: parameter.cpu
|
||||
memory: parameter.memory
|
||||
}
|
||||
}
|
||||
|
||||
if parameter.requests != _|_ {
|
||||
// +patchStrategy=retainKeys
|
||||
requests: {
|
||||
cpu: parameter.requests.cpu
|
||||
memory: parameter.requests.memory
|
||||
if parameter.requests != _|_ {
|
||||
// +patchStrategy=retainKeys
|
||||
requests: {
|
||||
cpu: parameter.requests.cpu
|
||||
memory: parameter.requests.memory
|
||||
}
|
||||
}
|
||||
}
|
||||
if parameter.limits != _|_ {
|
||||
// +patchStrategy=retainKeys
|
||||
limits: {
|
||||
cpu: parameter.limits.cpu
|
||||
memory: parameter.limits.memory
|
||||
if parameter.limits != _|_ {
|
||||
// +patchStrategy=retainKeys
|
||||
limits: {
|
||||
cpu: parameter.limits.cpu
|
||||
memory: parameter.limits.memory
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if context.output.spec != _|_ if context.output.spec.template != _|_ {
|
||||
patch: spec: template: spec: {
|
||||
// +patchKey=name
|
||||
containers: [resourceContent]
|
||||
if context.output.spec != _|_ if context.output.spec.template != _|_ {
|
||||
spec: template: spec: {
|
||||
// +patchKey=name
|
||||
containers: [resourceContent]
|
||||
}
|
||||
}
|
||||
}
|
||||
if context.output.spec != _|_ if context.output.spec.jobTemplate != _|_ {
|
||||
patch: spec: jobTemplate: spec: template: spec: {
|
||||
// +patchKey=name
|
||||
containers: [resourceContent]
|
||||
if context.output.spec != _|_ if context.output.spec.jobTemplate != _|_ {
|
||||
spec: jobTemplate: spec: template: spec: {
|
||||
// +patchKey=name
|
||||
containers: [resourceContent]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,10 @@ spec:
|
||||
if parameter.hostPath != _|_ for v in parameter.hostPath {
|
||||
{
|
||||
name: "hostpath-" + v.name
|
||||
path: v.path
|
||||
hostPath: {
|
||||
path: v.path
|
||||
type: v.type
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
@@ -299,8 +299,8 @@ spec:
|
||||
- "--enable-external-package-for-default-compiler={{ .Values.workflow.enableExternalPackageForDefaultCompiler }}"
|
||||
- "--enable-external-package-watch-for-default-compiler={{ .Values.workflow.enableExternalPackageWatchForDefaultCompiler }}"
|
||||
- "--feature-gates=EnableSuspendOnFailure={{- .Values.workflow.enableSuspendOnFailure | toString -}}"
|
||||
- "--feature-gates=AuthenticateApplication={{- .Values.authentication.enabled | toString -}}"
|
||||
- "--feature-gates=GzipResourceTracker={{- .Values.featureGates.gzipResourceTracker | toString -}}"
|
||||
- "--feature-gates=AuthenticateApplication={{- .Values.authentication.enabled | toString -}}"
|
||||
- "--feature-gates=ZstdResourceTracker={{- .Values.featureGates.zstdResourceTracker | toString -}}"
|
||||
- "--feature-gates=ApplyOnce={{- .Values.featureGates.applyOnce | toString -}}"
|
||||
- "--feature-gates=MultiStageComponentApply= {{- .Values.featureGates.multiStageComponentApply | toString -}}"
|
||||
@@ -312,6 +312,9 @@ spec:
|
||||
- "--feature-gates=SharedDefinitionStorageForApplicationRevision={{- .Values.featureGates.sharedDefinitionStorageForApplicationRevision | toString -}}"
|
||||
- "--feature-gates=DisableWorkflowContextConfigMapCache={{- .Values.featureGates.disableWorkflowContextConfigMapCache | toString -}}"
|
||||
- "--feature-gates=EnableCueValidation={{- .Values.featureGates.enableCueValidation | toString -}}"
|
||||
- "--feature-gates=EnableApplicationStatusMetrics={{- .Values.featureGates.enableApplicationStatusMetrics | toString -}}"
|
||||
- "--feature-gates=ValidateResourcesExist={{- .Values.featureGates.validateResourcesExist | toString -}}"
|
||||
- "--feature-gates=ValidateDefinitionPermissions={{ .Values.authorization.definitionValidationEnabled | toString -}}"
|
||||
{{ if .Values.authentication.enabled }}
|
||||
{{ if .Values.authentication.withUser }}
|
||||
- "--authentication-with-user"
|
||||
@@ -325,6 +328,7 @@ spec:
|
||||
- "--feature-gates=ValidateComponentWhenSharding={{- .Values.featureGates.validateComponentWhenSharding | toString -}}"
|
||||
- "--feature-gates=DisableWebhookAutoSchedule={{- .Values.featureGates.disableWebhookAutoSchedule | toString -}}"
|
||||
{{ end }}
|
||||
- "--dev-logs={{ .Values.devLogs }}"
|
||||
image: {{ .Values.imageRegistry }}{{ .Values.image.repository }}:{{ .Values.image.tag }}
|
||||
imagePullPolicy: {{ quote .Values.image.pullPolicy }}
|
||||
resources:
|
||||
|
||||
@@ -124,6 +124,8 @@ optimize:
|
||||
##@param featureGates.sharedDefinitionStorageForApplicationRevision use definition cache to reduce duplicated definition storage for application revision, must be used with InformerCacheFilterUnnecessaryFields
|
||||
##@param featureGates.disableWorkflowContextConfigMapCache disable the workflow context's configmap informer cache
|
||||
##@param featureGates.enableCueValidation enable the strict cue validation for cue required parameter fields
|
||||
##@param featureGates.enableApplicationStatusMetrics enable application status metrics and structured logging
|
||||
##@param featureGates.validateResourcesExist enable webhook validation to check if resource types referenced in definition templates exist in the cluster
|
||||
##@param
|
||||
featureGates:
|
||||
gzipResourceTracker: false
|
||||
@@ -140,6 +142,8 @@ featureGates:
|
||||
sharedDefinitionStorageForApplicationRevision: true
|
||||
disableWorkflowContextConfigMapCache: true
|
||||
enableCueValidation: false
|
||||
enableApplicationStatusMetrics: false
|
||||
validateResourcesExist: false
|
||||
|
||||
## @section MultiCluster parameters
|
||||
|
||||
@@ -254,6 +258,9 @@ rbac:
|
||||
## @param logDebug Enable debug logs for development purpose
|
||||
logDebug: false
|
||||
|
||||
## @param devLogs Enable formatted logging support for development purpose
|
||||
devLogs: false
|
||||
|
||||
## @param logFilePath If non-empty, write log files in this path
|
||||
logFilePath: ""
|
||||
|
||||
@@ -287,9 +294,12 @@ kubeClient:
|
||||
qps: 400
|
||||
burst: 600
|
||||
|
||||
## @param authentication.enabled Enable authentication for application
|
||||
## @param authentication.withUser Application authentication will impersonate as the request User
|
||||
## @param authentication.defaultUser Application authentication will impersonate as the User if no user provided in Application
|
||||
## @param authentication.enabled Enable authentication framework for applications
|
||||
## SECURITY NOTE: When enabled WITH authentication.withUser=true, KubeVela impersonates the requesting user
|
||||
## when deploying resources, ensuring that users cannot deploy resources beyond their RBAC permissions.
|
||||
## This is strongly recommended when KubeVela has cluster-admin or other high-level permissions.
|
||||
## @param authentication.withUser Application authentication will impersonate as the request User (must be true for security)
|
||||
## @param authentication.defaultUser Application authentication will impersonate as the User if no user provided or withUser is false
|
||||
## @param authentication.groupPattern Application authentication will impersonate as the request Group that matches the pattern
|
||||
authentication:
|
||||
enabled: false
|
||||
@@ -297,6 +307,15 @@ authentication:
|
||||
defaultUser: kubevela:vela-core
|
||||
groupPattern: kubevela:*
|
||||
|
||||
## @param authorization.definitionValidationEnabled Enable definition permission validation for RBAC checks on definitions
|
||||
## SECURITY NOTE: If KubeVela is running with cluster-admin or high-level permissions,
|
||||
## consider enabling this feature and/or authentication.enabled for security:
|
||||
## - This feature: Validates users can only reference definitions they have RBAC access to
|
||||
## - authentication.enabled: Makes KubeVela impersonate users, applying their full RBAC permissions
|
||||
## Both features can be used together for defense in depth.
|
||||
authorization:
|
||||
definitionValidationEnabled: false
|
||||
|
||||
## @param sharding.enabled When sharding enabled, the controller will run as master mode. Refer to https://github.com/kubevela/kubevela/blob/master/design/vela-core/sharding.md for details.
|
||||
## @param sharding.schedulableShards The shards available for scheduling. If empty, dynamic discovery will be used.
|
||||
sharding:
|
||||
|
||||
580
cmd/core/app/color_writer.go
Normal file
580
cmd/core/app/color_writer.go
Normal file
@@ -0,0 +1,580 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
const (
|
||||
ansiReset = "\x1b[0m"
|
||||
ansiDate = "\x1b[36m"
|
||||
ansiInfo = "\x1b[32m"
|
||||
ansiWarn = "\x1b[33m"
|
||||
ansiError = "\x1b[31m"
|
||||
ansiFatal = "\x1b[35m"
|
||||
ansiDebug = "\x1b[34m"
|
||||
ansiThread = "\x1b[34m"
|
||||
ansiLocation = "\x1b[93m"
|
||||
ansiMessage = "\x1b[97m"
|
||||
ansiKey = "\x1b[96m"
|
||||
ansiValue = "\x1b[37m"
|
||||
)
|
||||
|
||||
var methodPatterns = []*regexp.Regexp{
|
||||
regexp.MustCompile(`(?i)\b(?:caller|func|function|method)\s*[:=]\s*"?([a-zA-Z0-9_./()*-]+)`),
|
||||
}
|
||||
|
||||
var srcIdx = newSourceIndex()
|
||||
|
||||
type colorWriter struct {
|
||||
dst io.Writer
|
||||
mu sync.Mutex
|
||||
buf bytes.Buffer
|
||||
}
|
||||
|
||||
func newColorWriter(dst io.Writer) io.Writer {
|
||||
return &colorWriter{dst: dst}
|
||||
}
|
||||
|
||||
func (w *colorWriter) Write(p []byte) (int, error) {
|
||||
w.mu.Lock()
|
||||
defer w.mu.Unlock()
|
||||
|
||||
written := 0
|
||||
for len(p) > 0 {
|
||||
idx := bytes.IndexByte(p, '\n')
|
||||
if idx == -1 {
|
||||
_, _ = w.buf.Write(p)
|
||||
written += len(p)
|
||||
break
|
||||
}
|
||||
_, _ = w.buf.Write(p[:idx])
|
||||
if err := w.flushLineLocked(); err != nil {
|
||||
written += idx
|
||||
return written, err
|
||||
}
|
||||
if _, err := w.dst.Write([]byte{'\n'}); err != nil {
|
||||
written += idx + 1
|
||||
return written, err
|
||||
}
|
||||
p = p[idx+1:]
|
||||
written += idx + 1
|
||||
}
|
||||
return written, nil
|
||||
}
|
||||
|
||||
func (w *colorWriter) flushLineLocked() error {
|
||||
if w.buf.Len() == 0 {
|
||||
return nil
|
||||
}
|
||||
line := w.buf.String()
|
||||
w.buf.Reset()
|
||||
_, err := io.WriteString(w.dst, formatColoredLine(line))
|
||||
return err
|
||||
}
|
||||
|
||||
func formatColoredLine(line string) string {
|
||||
if len(line) == 0 {
|
||||
return line
|
||||
}
|
||||
severity := line[0]
|
||||
rest := line[1:]
|
||||
headerEnd := strings.IndexByte(rest, ']')
|
||||
if headerEnd == -1 {
|
||||
return line
|
||||
}
|
||||
header := rest[:headerEnd]
|
||||
remainder := strings.TrimSpace(rest[headerEnd+1:])
|
||||
fields := strings.Fields(header)
|
||||
if len(fields) < 4 {
|
||||
return line
|
||||
}
|
||||
|
||||
date := fields[0]
|
||||
ts := fields[1]
|
||||
pid := strings.TrimSpace(fields[2])
|
||||
rawLocation := strings.Join(fields[3:], " ")
|
||||
level, levelColor := mapSeverity(severity)
|
||||
location := buildLocation(rawLocation, remainder)
|
||||
|
||||
sb := strings.Builder{}
|
||||
sb.Grow(len(line) + 32)
|
||||
|
||||
sb.WriteString(ansiDate)
|
||||
sb.WriteString("[")
|
||||
sb.WriteString(formatTimestamp(date, ts))
|
||||
sb.WriteString("]")
|
||||
sb.WriteString(ansiReset)
|
||||
sb.WriteString(" ")
|
||||
|
||||
sb.WriteString(levelColor)
|
||||
sb.WriteString("[")
|
||||
sb.WriteString(fmt.Sprintf("%-5s", level))
|
||||
sb.WriteString("]")
|
||||
sb.WriteString(ansiReset)
|
||||
sb.WriteString(" ")
|
||||
|
||||
sb.WriteString(ansiThread)
|
||||
sb.WriteString("[")
|
||||
sb.WriteString(pid)
|
||||
sb.WriteString("]")
|
||||
sb.WriteString(ansiReset)
|
||||
sb.WriteString(" ")
|
||||
|
||||
sb.WriteString(ansiLocation)
|
||||
sb.WriteString("[")
|
||||
sb.WriteString(location)
|
||||
sb.WriteString("]")
|
||||
sb.WriteString(ansiReset)
|
||||
|
||||
if remainder != "" {
|
||||
msg, fields := splitMessageAndFields(remainder)
|
||||
if msg != "" {
|
||||
sb.WriteString(" ")
|
||||
sb.WriteString(ansiMessage)
|
||||
sb.WriteString(msg)
|
||||
sb.WriteString(ansiReset)
|
||||
}
|
||||
for _, field := range fields {
|
||||
sb.WriteString(" ")
|
||||
sb.WriteString(ansiKey)
|
||||
sb.WriteString(field.key)
|
||||
sb.WriteString(ansiReset)
|
||||
sb.WriteString("=")
|
||||
sb.WriteString(ansiValue)
|
||||
sb.WriteString(field.renderValue())
|
||||
sb.WriteString(ansiReset)
|
||||
}
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func mapSeverity(s byte) (string, string) {
|
||||
switch s {
|
||||
case 'I':
|
||||
return "INFO", ansiInfo
|
||||
case 'W':
|
||||
return "WARN", ansiWarn
|
||||
case 'E':
|
||||
return "ERROR", ansiError
|
||||
case 'F':
|
||||
return "FATAL", ansiFatal
|
||||
case 'D':
|
||||
return "DEBUG", ansiDebug
|
||||
default:
|
||||
return string(s), ansiDebug
|
||||
}
|
||||
}
|
||||
|
||||
func formatTimestamp(date, ts string) string {
|
||||
if len(date) == 4 {
|
||||
return fmt.Sprintf("%s-%s %s", date[:2], date[2:], trimMicros(ts))
|
||||
}
|
||||
return strings.TrimSpace(date + " " + trimMicros(ts))
|
||||
}
|
||||
|
||||
func trimMicros(ts string) string {
|
||||
if dot := strings.IndexByte(ts, '.'); dot != -1 && len(ts) > dot+4 {
|
||||
return ts[:dot+4]
|
||||
}
|
||||
return ts
|
||||
}
|
||||
|
||||
func buildLocation(rawLocation, remainder string) string {
|
||||
file, line := splitFileAndLine(rawLocation)
|
||||
method := lookupMethod(file, line)
|
||||
if method == "" {
|
||||
method = extractMethodName(remainder)
|
||||
}
|
||||
if file == "" {
|
||||
return rawLocation
|
||||
}
|
||||
if method == "" {
|
||||
if line != "" {
|
||||
return fmt.Sprintf("%s:%s", file, line)
|
||||
}
|
||||
return file
|
||||
}
|
||||
if line == "" {
|
||||
return fmt.Sprintf("%s:%s", file, method)
|
||||
}
|
||||
return fmt.Sprintf("%s:%s:%s", file, method, line)
|
||||
}
|
||||
|
||||
func splitFileAndLine(raw string) (string, string) {
|
||||
trimmed := strings.TrimSpace(raw)
|
||||
if trimmed == "" {
|
||||
return "", ""
|
||||
}
|
||||
lastColon := strings.LastIndex(trimmed, ":")
|
||||
if lastColon == -1 {
|
||||
return trimmed, ""
|
||||
}
|
||||
return strings.TrimSpace(trimmed[:lastColon]), strings.TrimSpace(trimmed[lastColon+1:])
|
||||
}
|
||||
|
||||
type kvField struct {
|
||||
key string
|
||||
value string
|
||||
quoted bool
|
||||
}
|
||||
|
||||
func (f kvField) renderValue() string {
|
||||
if f.quoted {
|
||||
return fmt.Sprintf("\"%s\"", f.value)
|
||||
}
|
||||
return f.value
|
||||
}
|
||||
|
||||
func splitMessageAndFields(s string) (string, []kvField) {
|
||||
s = strings.TrimSpace(s)
|
||||
if s == "" {
|
||||
return "", nil
|
||||
}
|
||||
idx := findFirstKVIndex(s)
|
||||
if idx == -1 {
|
||||
return s, nil
|
||||
}
|
||||
msg := strings.TrimSpace(s[:idx])
|
||||
fields := parseKeyValues(s[idx:])
|
||||
return msg, fields
|
||||
}
|
||||
|
||||
func findFirstKVIndex(s string) int {
|
||||
inQuotes := false
|
||||
for i := 0; i < len(s); i++ {
|
||||
ch := s[i]
|
||||
if ch == '"' {
|
||||
if i == 0 || s[i-1] != '\\' {
|
||||
inQuotes = !inQuotes
|
||||
}
|
||||
continue
|
||||
}
|
||||
if inQuotes {
|
||||
continue
|
||||
}
|
||||
if ch == '=' {
|
||||
keyEnd := i
|
||||
keyStart := keyEnd - 1
|
||||
for keyStart >= 0 && !unicode.IsSpace(rune(s[keyStart])) {
|
||||
keyStart--
|
||||
}
|
||||
key := strings.TrimSpace(s[keyStart+1 : keyEnd])
|
||||
if isValidKey(key) {
|
||||
return keyStart + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func parseKeyValues(s string) []kvField {
|
||||
fields := make([]kvField, 0)
|
||||
i := 0
|
||||
for i < len(s) {
|
||||
for i < len(s) && unicode.IsSpace(rune(s[i])) {
|
||||
i++
|
||||
}
|
||||
if i >= len(s) {
|
||||
break
|
||||
}
|
||||
keyStart := i
|
||||
for i < len(s) && s[i] != '=' && !unicode.IsSpace(rune(s[i])) {
|
||||
i++
|
||||
}
|
||||
keyEnd := i
|
||||
for keyEnd > keyStart && unicode.IsSpace(rune(s[keyEnd-1])) {
|
||||
keyEnd--
|
||||
}
|
||||
if i >= len(s) || s[i] != '=' {
|
||||
for i < len(s) && !unicode.IsSpace(rune(s[i])) {
|
||||
i++
|
||||
}
|
||||
continue
|
||||
}
|
||||
key := s[keyStart:keyEnd]
|
||||
if !isValidKey(key) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
i++
|
||||
for i < len(s) && unicode.IsSpace(rune(s[i])) {
|
||||
i++
|
||||
}
|
||||
if i >= len(s) {
|
||||
fields = append(fields, kvField{key: key, value: "", quoted: false})
|
||||
break
|
||||
}
|
||||
quoted := false
|
||||
var value string
|
||||
if s[i] == '"' {
|
||||
quoted = true
|
||||
i++
|
||||
start := i
|
||||
for i < len(s) {
|
||||
if s[i] == '"' && (i == start || s[i-1] != '\\') {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
value = s[start:i]
|
||||
if i < len(s) && s[i] == '"' {
|
||||
i++
|
||||
}
|
||||
} else {
|
||||
start := i
|
||||
for i < len(s) && !unicode.IsSpace(rune(s[i])) {
|
||||
i++
|
||||
}
|
||||
value = s[start:i]
|
||||
}
|
||||
fields = append(fields, kvField{key: key, value: value, quoted: quoted})
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
func isValidKey(key string) bool {
|
||||
if key == "" {
|
||||
return false
|
||||
}
|
||||
for _, r := range key {
|
||||
if unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_' || r == '-' || r == '.' {
|
||||
continue
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func extractMethodName(remainder string) string {
|
||||
if remainder == "" {
|
||||
return ""
|
||||
}
|
||||
for _, pattern := range methodPatterns {
|
||||
if matches := pattern.FindStringSubmatch(remainder); len(matches) > 1 {
|
||||
return simplifyMethodName(matches[1])
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func simplifyMethodName(name string) string {
|
||||
if name == "" {
|
||||
return ""
|
||||
}
|
||||
name = strings.Trim(name, "\"' ")
|
||||
if idx := strings.LastIndex(name, "/"); idx != -1 {
|
||||
name = name[idx+1:]
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
func lookupMethod(file, line string) string {
|
||||
if file == "" || line == "" {
|
||||
return ""
|
||||
}
|
||||
ln, err := strconv.Atoi(line)
|
||||
if err != nil || ln <= 0 {
|
||||
return ""
|
||||
}
|
||||
return srcIdx.functionAt(file, ln)
|
||||
}
|
||||
|
||||
type funcInfo struct {
|
||||
name string
|
||||
startLine int
|
||||
endLine int
|
||||
}
|
||||
|
||||
type fileCache struct {
|
||||
once sync.Once
|
||||
funcs []funcInfo
|
||||
}
|
||||
|
||||
type sourceIndex struct {
|
||||
mu sync.Mutex
|
||||
files map[string]*fileCache
|
||||
}
|
||||
|
||||
func newSourceIndex() *sourceIndex {
|
||||
return &sourceIndex{files: make(map[string]*fileCache)}
|
||||
}
|
||||
|
||||
func (s *sourceIndex) functionAt(base string, line int) string {
|
||||
s.mu.Lock()
|
||||
cache, ok := s.files[base]
|
||||
if !ok {
|
||||
cache = &fileCache{}
|
||||
s.files[base] = cache
|
||||
}
|
||||
s.mu.Unlock()
|
||||
|
||||
cache.once.Do(func() {
|
||||
cache.funcs = loadFunctionsFor(base)
|
||||
})
|
||||
for _, fn := range cache.funcs {
|
||||
if line >= fn.startLine && line <= fn.endLine {
|
||||
return fn.name
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func loadFunctionsFor(base string) []funcInfo {
|
||||
paths := findSourceFiles(base)
|
||||
if len(paths) == 0 {
|
||||
return nil
|
||||
}
|
||||
infos := make([]funcInfo, 0, len(paths)*4)
|
||||
for _, path := range paths {
|
||||
fset := token.NewFileSet()
|
||||
fileAst, err := parser.ParseFile(fset, path, nil, 0)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
for _, decl := range fileAst.Decls {
|
||||
fn, ok := decl.(*ast.FuncDecl)
|
||||
if !ok || fn.Name == nil {
|
||||
continue
|
||||
}
|
||||
start := fset.Position(fn.Pos()).Line
|
||||
end := fset.Position(fn.End()).Line
|
||||
name := fn.Name.Name
|
||||
if recv := receiverType(fn); recv != "" {
|
||||
name = fmt.Sprintf("%s.%s", recv, name)
|
||||
}
|
||||
infos = append(infos, funcInfo{name: name, startLine: start, endLine: end})
|
||||
}
|
||||
}
|
||||
return infos
|
||||
}
|
||||
|
||||
func receiverType(fn *ast.FuncDecl) string {
|
||||
if fn.Recv == nil || len(fn.Recv.List) == 0 {
|
||||
return ""
|
||||
}
|
||||
return typeString(fn.Recv.List[0].Type)
|
||||
}
|
||||
|
||||
func typeString(expr ast.Expr) string {
|
||||
switch v := expr.(type) {
|
||||
case *ast.Ident:
|
||||
return v.Name
|
||||
case *ast.StarExpr:
|
||||
return typeString(v.X)
|
||||
case *ast.SelectorExpr:
|
||||
return v.Sel.Name
|
||||
case *ast.IndexExpr:
|
||||
return typeString(v.X)
|
||||
case *ast.IndexListExpr:
|
||||
return typeString(v.X)
|
||||
case *ast.ParenExpr:
|
||||
return typeString(v.X)
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
searchRootsOnce sync.Once
|
||||
cachedRoots []string
|
||||
)
|
||||
|
||||
func findSourceFiles(base string) []string {
|
||||
matches := make([]string, 0)
|
||||
seen := make(map[string]struct{})
|
||||
for _, root := range sourceRoots() {
|
||||
if root == "" {
|
||||
continue
|
||||
}
|
||||
lookupFilesInRoot(root, base, seen, &matches)
|
||||
}
|
||||
return matches
|
||||
}
|
||||
|
||||
func sourceRoots() []string {
|
||||
searchRootsOnce.Do(func() {
|
||||
roots := make([]string, 0, 4)
|
||||
if env := os.Getenv("VELA_SOURCE_ROOT"); env != "" {
|
||||
for _, item := range strings.Split(env, string(os.PathListSeparator)) {
|
||||
if trimmed := strings.TrimSpace(item); trimmed != "" {
|
||||
roots = append(roots, trimmed)
|
||||
}
|
||||
}
|
||||
}
|
||||
if cwd, err := os.Getwd(); err == nil {
|
||||
roots = append(roots, cwd)
|
||||
}
|
||||
cachedRoots = dedupeStrings(roots)
|
||||
})
|
||||
return cachedRoots
|
||||
}
|
||||
|
||||
func lookupFilesInRoot(root, base string, seen map[string]struct{}, matches *[]string) {
|
||||
_ = filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
// Continue scanning on error.
|
||||
//nolint:nilerr
|
||||
return nil
|
||||
}
|
||||
if d.IsDir() {
|
||||
name := d.Name()
|
||||
if name == "vendor" || name == "node_modules" || strings.HasPrefix(name, ".") {
|
||||
if root == path {
|
||||
return nil
|
||||
}
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if d.Name() == base {
|
||||
if _, ok := seen[path]; !ok {
|
||||
seen[path] = struct{}{}
|
||||
*matches = append(*matches, path)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func dedupeStrings(in []string) []string {
|
||||
seen := make(map[string]struct{}, len(in))
|
||||
out := make([]string, 0, len(in))
|
||||
for _, v := range in {
|
||||
if _, ok := seen[v]; ok {
|
||||
continue
|
||||
}
|
||||
seen[v] = struct{}{}
|
||||
out = append(out, v)
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -42,7 +42,7 @@ func TestPreStartHook(t *testing.T) {
|
||||
|
||||
var _ = Describe("Test pre-start hooks", func() {
|
||||
It("Test SystemCRDValidationHook", func() {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(&testing.T{}, utilfeature.DefaultFeatureGate, features.ZstdApplicationRevision, true)()
|
||||
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.ZstdApplicationRevision, true)
|
||||
ctx := context.Background()
|
||||
Expect(k8s.EnsureNamespace(ctx, singleton.KubeClient.Get(), types.DefaultKubeVelaNS)).Should(Succeed())
|
||||
err := hooks.NewSystemCRDValidationHook().Run(ctx)
|
||||
|
||||
@@ -50,6 +50,7 @@ type CoreOptions struct {
|
||||
LogFilePath string
|
||||
LogFileMaxSize uint64
|
||||
LogDebug bool
|
||||
DevLogs bool
|
||||
ControllerArgs *oamcontroller.Args
|
||||
HealthAddr string
|
||||
StorageDriver string
|
||||
@@ -76,6 +77,7 @@ func NewCoreOptions() *CoreOptions {
|
||||
LogFilePath: "",
|
||||
LogFileMaxSize: 1024,
|
||||
LogDebug: false,
|
||||
DevLogs: false,
|
||||
ControllerArgs: &oamcontroller.Args{
|
||||
RevisionLimit: 50,
|
||||
AppRevisionLimit: 10,
|
||||
@@ -116,6 +118,7 @@ func (s *CoreOptions) Flags() cliflag.NamedFlagSets {
|
||||
gfs.StringVar(&s.LogFilePath, "log-file-path", s.LogFilePath, "The file to write logs to.")
|
||||
gfs.Uint64Var(&s.LogFileMaxSize, "log-file-max-size", s.LogFileMaxSize, "Defines the maximum size a log file can grow to, Unit is megabytes.")
|
||||
gfs.BoolVar(&s.LogDebug, "log-debug", s.LogDebug, "Enable debug logs for development purpose")
|
||||
gfs.BoolVar(&s.DevLogs, "dev-logs", s.DevLogs, "Enable ANSI color formatting for console logs (ignored when log-file-path is set)")
|
||||
gfs.StringVar(&s.HealthAddr, "health-addr", s.HealthAddr, "The address the health endpoint binds to.")
|
||||
gfs.DurationVar(&s.InformerSyncPeriod, "informer-sync-period", s.InformerSyncPeriod,
|
||||
"The re-sync period for informer in controller-runtime. This is a system-level configuration.")
|
||||
|
||||
@@ -103,6 +103,17 @@ func run(ctx context.Context, s *options.CoreOptions) error {
|
||||
restConfig.QPS = float32(s.QPS)
|
||||
restConfig.Burst = s.Burst
|
||||
restConfig.Wrap(auth.NewImpersonatingRoundTripper)
|
||||
|
||||
// Set logger (use --dev-logs=true for local development)
|
||||
if s.DevLogs {
|
||||
logOutput := newColorWriter(os.Stdout)
|
||||
klog.LogToStderr(false)
|
||||
klog.SetOutput(logOutput)
|
||||
ctrl.SetLogger(textlogger.NewLogger(textlogger.NewConfig(textlogger.Output(logOutput))))
|
||||
} else {
|
||||
ctrl.SetLogger(textlogger.NewLogger(textlogger.NewConfig()))
|
||||
}
|
||||
|
||||
klog.InfoS("Kubernetes Config Loaded",
|
||||
"UserAgent", restConfig.UserAgent,
|
||||
"QPS", restConfig.QPS,
|
||||
@@ -127,8 +138,6 @@ func run(ctx context.Context, s *options.CoreOptions) error {
|
||||
}
|
||||
}
|
||||
|
||||
ctrl.SetLogger(textlogger.NewLogger(textlogger.NewConfig()))
|
||||
|
||||
if utilfeature.DefaultMutableFeatureGate.Enabled(features.ApplyOnce) {
|
||||
commonconfig.ApplicationReSyncPeriod = s.InformerSyncPeriod
|
||||
}
|
||||
|
||||
191
docs/WEBHOOK_DEBUGGING.md
Normal file
191
docs/WEBHOOK_DEBUGGING.md
Normal file
@@ -0,0 +1,191 @@
|
||||
# KubeVela Webhook Debugging Guide
|
||||
|
||||
This guide explains how to debug KubeVela webhook validation locally, particularly for the feature that validates ComponentDefinitions, TraitDefinitions, and PolicyDefinitions to ensure they don't reference non-existent CRDs.
|
||||
|
||||
## Overview
|
||||
|
||||
The webhook validation feature checks that CUE templates in definitions only reference Kubernetes resources that exist on the cluster. This prevents runtime errors when non-existent CRDs are referenced.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker Desktop or similar container runtime
|
||||
- k3d for local Kubernetes clusters
|
||||
- VS Code with Go extension
|
||||
- kubectl configured
|
||||
- openssl for certificate generation
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Complete setup (cluster + CRDs + webhook)
|
||||
make webhook-debug-setup
|
||||
|
||||
# 2. Start VS Code debugger
|
||||
# Press F5 and select "Debug Webhook Validation"
|
||||
```
|
||||
|
||||
## Detailed Setup Steps
|
||||
|
||||
### 1. Environment Setup
|
||||
|
||||
```bash
|
||||
# Create k3d cluster
|
||||
make k3d-create
|
||||
|
||||
# Install KubeVela CRDs
|
||||
make manifests
|
||||
kubectl apply -f charts/vela-core/crds/
|
||||
```
|
||||
|
||||
### 2. Webhook Certificate Setup
|
||||
|
||||
The webhook requires TLS certificates with proper Subject Alternative Names (SANs) for IP addresses.
|
||||
|
||||
```bash
|
||||
# Generate certificates and create Kubernetes secret
|
||||
make webhook-setup
|
||||
```
|
||||
|
||||
This creates:
|
||||
- CA certificate and key
|
||||
- Server certificate with IP SANs (127.0.0.1, Docker internal IP, local machine IP)
|
||||
- Kubernetes Secret `webhook-server-cert` in `vela-system` namespace
|
||||
- ValidatingWebhookConfiguration pointing to local debugger
|
||||
|
||||
### 3. Start Debugger in VS Code
|
||||
|
||||
#### VS Code Launch Configuration
|
||||
|
||||
If you're using VSCode add this configuration to `.vscode/launch.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug Webhook Validation",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "debug",
|
||||
"program": "${workspaceFolder}/cmd/core",
|
||||
"args": [
|
||||
"--log-debug=true",
|
||||
"--metrics-addr=:8080",
|
||||
"--enable-leader-election=false",
|
||||
"--use-webhook=true",
|
||||
"--webhook-port=9445",
|
||||
"--webhook-cert-dir=${workspaceFolder}/k8s-webhook-server/serving-certs"
|
||||
],
|
||||
"env": {
|
||||
"KUBECONFIG": "${env:HOME}/.kube/config",
|
||||
"POD_NAMESPACE": "vela-system"
|
||||
},
|
||||
"showLog": false,
|
||||
"console": "integratedTerminal"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Set Breakpoints
|
||||
|
||||
Recommended breakpoint locations:
|
||||
- `pkg/webhook/core.oam.dev/v1beta1/componentdefinition/validating_handler.go` - ComponentDefinition handler
|
||||
- `pkg/webhook/core.oam.dev/v1beta1/traitdefinition/validating_handler.go` - TraitDefinition handler
|
||||
- `pkg/webhook/core.oam.dev/v1beta1/policydefinition/validating_handler.go` - PolicyDefinition handler
|
||||
- `pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition/workflowstep_validating_handler.go` - WorkflowDefinition handler
|
||||
|
||||
#### Launch Debugger
|
||||
|
||||
1. Open VS Code
|
||||
2. Press `F5` or go to Run → Start Debugging
|
||||
3. Select **"Debug Webhook Validation"** configuration
|
||||
4. Wait for webhook server to start (look for message about port 9445)
|
||||
|
||||
The debugger configuration includes:
|
||||
- `--use-webhook=true` - Enables webhook server
|
||||
- `--webhook-port=9445` - Port for webhook server
|
||||
- `--webhook-cert-dir` - Path to certificates
|
||||
- `POD_NAMESPACE=vela-system` - Required for finding the secret
|
||||
|
||||
## Make Targets Reference
|
||||
|
||||
| Target | Description |
|
||||
|--------|-------------|
|
||||
| `make webhook-help` | Show webhook debugging help |
|
||||
| `make webhook-debug-setup` | Complete setup (cluster + CRDs + webhook) |
|
||||
| `make k3d-create` | Create k3d cluster |
|
||||
| `make k3d-delete` | Delete k3d cluster |
|
||||
| `make webhook-setup` | Setup certificates and webhook configuration |
|
||||
| `make webhook-clean` | Clean up webhook environment |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Connection Refused Error
|
||||
|
||||
If you get "connection refused" errors:
|
||||
1. Ensure the debugger is running in VS Code
|
||||
2. Check that port 9445 is not blocked by firewall
|
||||
3. Verify the webhook server started (check VS Code console)
|
||||
|
||||
### TLS Certificate Errors
|
||||
|
||||
If you get certificate validation errors:
|
||||
1. Regenerate certificates: `make webhook-setup`
|
||||
2. Restart the debugger
|
||||
3. Ensure IP addresses in certificates match your setup
|
||||
|
||||
### Webhook Not Triggering
|
||||
|
||||
If the webhook doesn't trigger:
|
||||
1. Check ValidatingWebhookConfiguration: `kubectl get validatingwebhookconfiguration`
|
||||
2. Verify the webhook URL matches your debugger's IP
|
||||
3. Check namespace is correct (vela-system)
|
||||
|
||||
### Secret Not Found
|
||||
|
||||
If you see "Wait webhook secret" messages:
|
||||
1. Ensure the secret exists: `kubectl get secret webhook-server-cert -n vela-system`
|
||||
2. Recreate if needed: `make webhook-setup`
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Certificate Generation**: Creates TLS certificates with proper SANs for local IPs
|
||||
2. **Secret Creation**: Stores certificates in Kubernetes secret
|
||||
3. **Webhook Configuration**: Creates ValidatingWebhookConfiguration pointing to local debugger
|
||||
4. **Debugger Startup**: VS Code starts the webhook server on port 9445
|
||||
5. **Validation**: When definitions are applied, Kubernetes calls the webhook
|
||||
6. **Debugging**: Breakpoints allow stepping through validation logic
|
||||
|
||||
## Files and Components
|
||||
|
||||
- **Script**: `hack/debug-webhook-setup.sh` - Main setup script
|
||||
- **Makefile**: `makefiles/develop.mk` - Make targets for debugging
|
||||
- **VS Code Config**: `.vscode/launch.json` - Debugger configuration
|
||||
- **Test Files**: `test/webhook-*.yaml` - Test manifests
|
||||
- **Validation Logic**: `pkg/webhook/utils/utils.go` - Core validation implementation
|
||||
- **Handlers**: `pkg/webhook/core.oam.dev/v1beta1/*/validating_handler.go` - Resource handlers
|
||||
|
||||
## Clean Up
|
||||
|
||||
```bash
|
||||
# Clean up webhook setup
|
||||
make webhook-clean
|
||||
|
||||
# Delete k3d cluster
|
||||
make k3d-delete
|
||||
```
|
||||
|
||||
## Tips
|
||||
|
||||
1. **Always start the debugger before testing** - The webhook configuration points to your local machine
|
||||
2. **Use breakpoints wisely** - Too many breakpoints can cause timeouts
|
||||
3. **Check logs** - VS Code Debug Console shows detailed logs
|
||||
4. **Test both valid and invalid cases** - Ensures validation works correctly
|
||||
5. **Keep certificates updated** - Regenerate if IPs change
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [KubeVela Webhook Implementation](../pkg/webhook/README.md)
|
||||
- [CUE Template Validation](../pkg/webhook/utils/README.md)
|
||||
- [Admission Webhooks](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/)
|
||||
@@ -42,6 +42,6 @@ spec:
|
||||
repoType: helm
|
||||
retries: 3
|
||||
secretRef: kubevela-core
|
||||
url: https://charts.kubevela.net/core
|
||||
url: "https://kubevela.github.io/charts"
|
||||
type: helm
|
||||
```
|
||||
|
||||
@@ -24,9 +24,9 @@ spec:
|
||||
type: helm
|
||||
properties:
|
||||
repoType: helm
|
||||
url: https://charts.kubevela.net/addons
|
||||
url: https://kubevela.github.io/charts
|
||||
chart: terraform-controller
|
||||
version: 0.2.11
|
||||
version: 0.8.0
|
||||
values:
|
||||
image:
|
||||
repository: ghcr.io/kubevela/oamdev/terraform-controller
|
||||
|
||||
@@ -22,7 +22,7 @@ entries:
|
||||
version: 2.0.0
|
||||
annotations:
|
||||
system.vela: ">=1.5.0"
|
||||
system.kubernetes: ">=1.30.0"
|
||||
system.kubernetes: ">=1.32.0"
|
||||
vela-workflow:
|
||||
- annotations:
|
||||
system.vela: '>=v1.6.0-beta.1'
|
||||
@@ -32,8 +32,8 @@ entries:
|
||||
icon: https://static.kubevela.net/images/logos/KubeVela%20-03.png
|
||||
name: vela-workflow
|
||||
urls:
|
||||
- http://127.0.0.1:9098/helm/vela-workflow-v0.3.5.tgz
|
||||
version: v0.3.5
|
||||
- http://127.0.0.1:9098/helm/vela-workflow-v0.6.2.tgz
|
||||
version: v0.6.2
|
||||
foo:
|
||||
- created: "2022-10-29T09:11:16.865230605Z"
|
||||
description: Vela test addon named foo
|
||||
|
||||
Binary file not shown.
BIN
e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.6.2.tgz
Normal file
BIN
e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.6.2.tgz
Normal file
Binary file not shown.
@@ -125,8 +125,8 @@ var helmHandler http.HandlerFunc = func(rw http.ResponseWriter, req *http.Reques
|
||||
_, _ = rw.Write([]byte(err.Error()))
|
||||
}
|
||||
rw.Write(file)
|
||||
case strings.Contains(req.URL.Path, "vela-workflow-v0.3.5.tgz"):
|
||||
file, err := os.ReadFile("./e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.3.5.tgz")
|
||||
case strings.Contains(req.URL.Path, "vela-workflow-v0.6.2.tgz"):
|
||||
file, err := os.ReadFile("./e2e/addon/mock/testrepo/helm-repo/vela-workflow-v0.6.2.tgz")
|
||||
if err != nil {
|
||||
_, _ = rw.Write([]byte(err.Error()))
|
||||
}
|
||||
|
||||
@@ -44,20 +44,23 @@ var (
|
||||
applicationName = "app-basic"
|
||||
traitAlias = "scaler"
|
||||
appNameForInit = "initmyapp"
|
||||
jsonAppFile = `{"name":"nginx-vela","services":{"nginx":{"type":"webservice","image":"nginx:1.9.4","ports":[{port: 80, expose: true}]}}}`
|
||||
testDeleteJsonAppFile = `{"name":"test-vela-delete","services":{"nginx-test":{"type":"webservice","image":"nginx:1.9.4","ports":[{port: 80, expose: true}]}}}`
|
||||
appbasicJsonAppFile = `{"name":"app-basic","services":{"app-basic":{"type":"webservice","image":"nginx:1.9.4","ports":[{port: 80, expose: true}]}}}`
|
||||
appbasicAddTraitJsonAppFile = `{"name":"app-basic","services":{"app-basic":{"type":"webservice","image":"nginx:1.9.4","ports":[{port: 80, expose: true}],"scaler":{"replicas":2}}}}`
|
||||
jsonAppFile = `{"name":"nginx-vela","services":{"nginx":{"type":"webservice","image":"nginx:1.29.0","ports":[{port: 80, expose: true}]}}}`
|
||||
testDeleteJsonAppFile = `{"name":"test-vela-delete","services":{"nginx-test":{"type":"webservice","image":"nginx:1.29.0","ports":[{port: 80, expose: true}]}}}`
|
||||
appbasicJsonAppFile = `{"name":"app-basic","services":{"app-basic":{"type":"webservice","image":"nginx:1.29.0","ports":[{port: 80, expose: true}]}}}`
|
||||
appbasicAddTraitJsonAppFile = `{"name":"app-basic","services":{"app-basic":{"type":"webservice","image":"nginx:1.29.0","ports":[{port: 80, expose: true}],"scaler":{"replicas":2}}}}`
|
||||
velaQL = "test-component-pod-view{appNs=default,appName=nginx-vela,name=nginx}"
|
||||
|
||||
waitAppfileToSuccess = `{"name":"app-wait-success","services":{"app-basic1":{"type":"webservice","image":"nginx:1.9.4","ports":[{port: 80, expose: true}]}}}`
|
||||
waitAppfileToSuccess = `{"name":"app-wait-success","services":{"app-basic1":{"type":"webservice","image":"nginx:1.29.0","ports":[{port: 80, expose: true}]}}}`
|
||||
waitAppfileToFail = `{"name":"app-wait-fail","services":{"app-basic2":{"type":"webservice","image":"nginx:fail","ports":[{port: 80, expose: true}]}}}`
|
||||
|
||||
componentDependsOnFailApp = `{"name":"comp-depends-fail","services":{"failing-db":{"type":"webservice","image": ""},"dependent-service":{"type":"webservice","dependsOn":["failing-db"],"image":"nginx:latest","ports":[{"port":8080,"expose":false}]}}}`
|
||||
componentDependsOnMultipleApp = `{"name":"comp-depends-multiple","services":{"database":{"type":"webservice","image":"nginx:latest","ports":[{"port":3306,"expose":false}]},"cache":{"type":"webservice","image":"nginx:latest","ports":[{"port":6379,"expose":false}]},"backend":{"type":"webservice","dependsOn":["database","cache"],"image":"nginx:latest","ports":[{"port":8080,"expose":false}]}}}`
|
||||
)
|
||||
|
||||
var _ = ginkgo.Describe("Test Vela Application", ginkgo.Ordered, func() {
|
||||
e2e.DeleteEnvFunc("env delete", envName)
|
||||
e2e.JsonAppFileContext("json appfile apply", jsonAppFile)
|
||||
e2e.EnvSetContext("env set default", "default")
|
||||
e2e.DeleteEnvFunc("env delete", envName)
|
||||
e2e.EnvInitContext("env init env-application", envName)
|
||||
e2e.EnvSetContext("env set", envName)
|
||||
e2e.JsonAppFileContext("deploy app-basic", appbasicJsonAppFile)
|
||||
@@ -313,3 +316,61 @@ var VelaQLPodListContext = func(context string, velaQL string) bool {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
var _ = ginkgo.Describe("Test Component Level DependsOn CLI", ginkgo.Ordered, func() {
|
||||
|
||||
e2e.JsonAppFileContext("component dependsOn failure blocking", componentDependsOnFailApp)
|
||||
ComponentDependsOnFailureContext("component dependsOn failure blocking verification", "comp-depends-fail")
|
||||
e2e.WorkloadDeleteContext("delete failure app", "comp-depends-fail")
|
||||
|
||||
e2e.JsonAppFileContext("component dependsOn multiple dependencies", componentDependsOnMultipleApp)
|
||||
ComponentDependsOnMultipleContext("component dependsOn multiple dependencies verification", "comp-depends-multiple")
|
||||
e2e.WorkloadDeleteContext("delete multiple deps app", "comp-depends-multiple")
|
||||
})
|
||||
|
||||
var ComponentDependsOnFailureContext = func(context string, appName string) bool {
|
||||
return ginkgo.It(context+": should block dependent components when dependency fails", func() {
|
||||
ginkgo.By("verify application doesn't reach running state due to component failure")
|
||||
ginkgo.By("wait sufficient time for dependency check")
|
||||
time.Sleep(45 * time.Second)
|
||||
|
||||
cli := fmt.Sprintf("vela status %s", appName)
|
||||
output, err := e2e.Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
ginkgo.By("check that dependent service is blocked")
|
||||
gomega.Expect(strings.ToLower(output)).Should(gomega.ContainSubstring("failed"))
|
||||
// The app should show some indication that components are waiting on dependencies
|
||||
gomega.Expect(strings.ToLower(output)).Should(gomega.SatisfyAny(
|
||||
gomega.ContainSubstring("pending"),
|
||||
gomega.ContainSubstring("progressing"),
|
||||
gomega.ContainSubstring("waiting"),
|
||||
gomega.ContainSubstring("suspend"),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
var ComponentDependsOnMultipleContext = func(context string, appName string) bool {
|
||||
return ginkgo.It(context+": should handle multiple dependencies correctly", func() {
|
||||
ginkgo.By("verify application eventually reaches running state")
|
||||
gomega.Eventually(func() string {
|
||||
cli := fmt.Sprintf("vela status %s", appName)
|
||||
output, err := e2e.Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
return output
|
||||
}, 300*time.Second, 5*time.Second).Should(gomega.ContainSubstring("running"))
|
||||
|
||||
ginkgo.By("wait sufficient time for dependency check")
|
||||
time.Sleep(time.Minute)
|
||||
|
||||
ginkgo.By("verify all components are healthy")
|
||||
cli := fmt.Sprintf("vela status %s --tree", appName)
|
||||
output, err := e2e.Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).Should(gomega.And(
|
||||
gomega.ContainSubstring("database"),
|
||||
gomega.ContainSubstring("cache"),
|
||||
gomega.ContainSubstring("backend"),
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
@@ -425,7 +425,7 @@ spec:
|
||||
}
|
||||
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
apiVersion: "networking.k8s.io/v1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
@@ -436,9 +436,14 @@ spec:
|
||||
paths: [
|
||||
for k, v in parameter.http {
|
||||
path: k
|
||||
pathType: "Prefix"
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: v
|
||||
service: {
|
||||
name: context.name
|
||||
port: {
|
||||
number: v
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
@@ -617,7 +622,7 @@ spec:
|
||||
|
||||
---
|
||||
## From the trait test-ingress
|
||||
apiVersion: networking.k8s.io/v1beta1
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
annotations: {}
|
||||
@@ -637,9 +642,12 @@ spec:
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
serviceName: express-server
|
||||
servicePort: 80
|
||||
service:
|
||||
name: express-server
|
||||
port:
|
||||
number: 80
|
||||
path: /
|
||||
pathType: Prefix
|
||||
|
||||
---
|
||||
`
|
||||
@@ -721,7 +729,7 @@ var livediffResult = `Application (test-vela-app) has been modified(*)
|
||||
- app.oam.dev/component: express-server
|
||||
|
||||
* Component (express-server) / Trait (test-ingress/ingress) has been removed(-)
|
||||
- apiVersion: networking.k8s.io/v1beta1
|
||||
- apiVersion: networking.k8s.io/v1
|
||||
- kind: Ingress
|
||||
- metadata:
|
||||
- labels:
|
||||
@@ -739,9 +747,12 @@ var livediffResult = `Application (test-vela-app) has been modified(*)
|
||||
- http:
|
||||
- paths:
|
||||
- - backend:
|
||||
- serviceName: express-server
|
||||
- servicePort: 80
|
||||
- service:
|
||||
- name: express-server
|
||||
- port:
|
||||
- number: 80
|
||||
- path: /
|
||||
- pathType: Prefix
|
||||
|
||||
* Component (new-express-server) has been added(+)
|
||||
+ apiVersion: apps/v1
|
||||
@@ -796,7 +807,7 @@ var livediffResult = `Application (test-vela-app) has been modified(*)
|
||||
+ app.oam.dev/component: new-express-server
|
||||
|
||||
* Component (new-express-server) / Trait (test-ingress/ingress) has been added(+)
|
||||
+ apiVersion: networking.k8s.io/v1beta1
|
||||
+ apiVersion: networking.k8s.io/v1
|
||||
+ kind: Ingress
|
||||
+ metadata:
|
||||
+ labels:
|
||||
@@ -814,9 +825,12 @@ var livediffResult = `Application (test-vela-app) has been modified(*)
|
||||
+ http:
|
||||
+ paths:
|
||||
+ - backend:
|
||||
+ serviceName: new-express-server
|
||||
+ servicePort: 8080
|
||||
+ service:
|
||||
+ name: new-express-server
|
||||
+ port:
|
||||
+ number: 8080
|
||||
+ path: /
|
||||
+ pathType: Prefix
|
||||
`
|
||||
|
||||
var testShowComponentDef = `
|
||||
|
||||
@@ -87,7 +87,9 @@ var _ = Describe("test registry and trait/comp command", func() {
|
||||
Expect(output).To(ContainSubstring("pvc"))
|
||||
Expect(output).To(ContainSubstring("[deployments.apps]"))
|
||||
})
|
||||
It("list trait from default registry", func() {
|
||||
|
||||
// TODO: enable this test after the default registry has been updated
|
||||
XIt("list trait from default registry", func() {
|
||||
cli := "vela trait --discover"
|
||||
output, err := e2e.Exec(cli)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@@ -100,10 +102,10 @@ var _ = Describe("test registry and trait/comp command", func() {
|
||||
})
|
||||
|
||||
It("test list trait in raw url", func() {
|
||||
cli := "vela trait --discover --url=oss://registry.kubevela.net"
|
||||
cli := "vela trait --discover --url=https://github.com/kubevela/kubevela/tree/master/vela-templates/registry/auto-gen/"
|
||||
output, err := e2e.Exec(cli)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(SatisfyAll(ContainSubstring("Showing trait definition from url"), ContainSubstring("oss://registry.kubevela.net")))
|
||||
Expect(output).To(SatisfyAll(ContainSubstring("Showing trait definition from url"), ContainSubstring("https://github.com/kubevela/kubevela/tree/master/vela-templates/registry/auto-gen/")))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
161
go.mod
161
go.mod
@@ -15,16 +15,15 @@ require (
|
||||
github.com/chartmuseum/helm-push v0.10.4
|
||||
github.com/containerd/log v0.1.0
|
||||
github.com/crossplane/crossplane-runtime v1.16.0
|
||||
github.com/cue-exp/kubevelafix v0.0.0-20220922150317-aead819d979d
|
||||
github.com/dave/jennifer v1.6.1
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
|
||||
github.com/ettle/strcase v0.2.0
|
||||
github.com/fatih/color v1.16.0
|
||||
github.com/fatih/color v1.18.0
|
||||
github.com/fluxcd/helm-controller/api v0.32.2
|
||||
github.com/fluxcd/source-controller/api v0.30.0
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible
|
||||
github.com/gdamore/tcell/v2 v2.6.0
|
||||
github.com/getkin/kin-openapi v0.118.0
|
||||
github.com/getkin/kin-openapi v0.131.0
|
||||
github.com/go-git/go-git/v5 v5.16.0
|
||||
github.com/go-logr/logr v1.4.2
|
||||
github.com/go-resty/resty/v2 v2.8.0
|
||||
@@ -38,29 +37,29 @@ require (
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174
|
||||
github.com/imdario/mergo v0.3.16
|
||||
github.com/jeremywohl/flatten/v2 v2.0.0-20211013061545-07e4a09fb8e4
|
||||
github.com/kubevela/pkg v1.9.3-0.20241203070234-2cf98778c0a9
|
||||
github.com/kubevela/workflow v0.6.2
|
||||
github.com/kubevela/pkg v1.9.3-0.20250625225831-a2894a62a307
|
||||
github.com/kubevela/workflow v0.6.3-0.20250717221743-56b80cee4121
|
||||
github.com/kyokomi/emoji v2.2.4+incompatible
|
||||
github.com/magiconair/properties v1.8.7
|
||||
github.com/mattn/go-runewidth v0.0.15
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/nacos-group/nacos-sdk-go/v2 v2.2.2
|
||||
github.com/oam-dev/cluster-gateway v1.9.1-0.20241120140625-33c8891b781c
|
||||
github.com/oam-dev/cluster-register v1.0.4-0.20230424040021-147f7c1fefe5
|
||||
github.com/oam-dev/terraform-config-inspect v0.0.0-20210418082552-fc72d929aa28
|
||||
github.com/oam-dev/terraform-controller v0.8.0
|
||||
github.com/oam-dev/cluster-gateway v1.9.2-0.20250629203450-2b04dd452b7a
|
||||
github.com/oam-dev/cluster-register v1.0.4-0.20250624042630-618dfa13eb5b
|
||||
github.com/oam-dev/terraform-config-inspect v0.0.0-20250902214508-15aa973b0d00
|
||||
github.com/oam-dev/terraform-controller v0.8.1-0.20250707044258-c0557127de25
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/onsi/ginkgo/v2 v2.19.0
|
||||
github.com/onsi/gomega v1.34.1
|
||||
github.com/onsi/ginkgo/v2 v2.23.3
|
||||
github.com/onsi/gomega v1.36.2
|
||||
github.com/openkruise/kruise-api v1.4.0
|
||||
github.com/openkruise/rollouts v0.3.0
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
github.com/prometheus/client_model v0.5.0
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
github.com/prometheus/client_model v0.6.1
|
||||
github.com/rivo/tview v0.0.0-20221128165837-db36428c92d9
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/cobra v1.8.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
@@ -69,31 +68,31 @@ require (
|
||||
gitlab.com/gitlab-org/api/client-go v0.127.0
|
||||
go.uber.org/multierr v1.11.0
|
||||
golang.org/x/crypto v0.37.0
|
||||
golang.org/x/mod v0.21.0
|
||||
golang.org/x/mod v0.24.0
|
||||
golang.org/x/oauth2 v0.29.0
|
||||
golang.org/x/sync v0.13.0
|
||||
golang.org/x/term v0.31.0
|
||||
golang.org/x/text v0.24.0
|
||||
golang.org/x/tools v0.26.0
|
||||
golang.org/x/tools v0.31.0
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
helm.sh/helm/v3 v3.14.4
|
||||
k8s.io/api v0.29.2
|
||||
k8s.io/apiextensions-apiserver v0.29.2
|
||||
k8s.io/apimachinery v0.29.2
|
||||
k8s.io/apiserver v0.29.2
|
||||
k8s.io/cli-runtime v0.29.2
|
||||
k8s.io/client-go v0.29.2
|
||||
k8s.io/component-base v0.29.2
|
||||
k8s.io/api v0.31.10
|
||||
k8s.io/apiextensions-apiserver v0.31.10
|
||||
k8s.io/apimachinery v0.31.10
|
||||
k8s.io/apiserver v0.31.10
|
||||
k8s.io/cli-runtime v0.31.10
|
||||
k8s.io/client-go v0.31.10
|
||||
k8s.io/component-base v0.31.10
|
||||
k8s.io/helm v2.17.0+incompatible
|
||||
k8s.io/klog/v2 v2.120.1
|
||||
k8s.io/kube-aggregator v0.27.2
|
||||
k8s.io/kubectl v0.29.2
|
||||
k8s.io/metrics v0.29.2
|
||||
k8s.io/utils v0.0.0-20240310230437-4693a0247e57
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
k8s.io/kube-aggregator v0.31.10
|
||||
k8s.io/kubectl v0.31.10
|
||||
k8s.io/metrics v0.31.10
|
||||
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
|
||||
open-cluster-management.io/api v0.11.0
|
||||
sigs.k8s.io/controller-runtime v0.17.6
|
||||
sigs.k8s.io/controller-tools v0.14.0
|
||||
sigs.k8s.io/controller-runtime v0.19.7
|
||||
sigs.k8s.io/controller-tools v0.16.5
|
||||
sigs.k8s.io/gateway-api v0.7.1
|
||||
sigs.k8s.io/kind v0.20.0
|
||||
sigs.k8s.io/yaml v1.4.0
|
||||
@@ -117,15 +116,15 @@ require (
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/alessio/shellescape v1.4.1 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 // indirect
|
||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230305170008-8188dc5388df // indirect
|
||||
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/blang/semver/v4 v4.0.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/cloudflare/circl v1.6.1 // indirect
|
||||
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
|
||||
@@ -135,7 +134,7 @@ require (
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
|
||||
github.com/creack/pty v1.1.18 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
@@ -148,8 +147,8 @@ require (
|
||||
github.com/emicklei/go-restful/v3 v3.12.0 // indirect
|
||||
github.com/emicklei/proto v1.10.0 // indirect
|
||||
github.com/emirpasic/gods v1.18.1 // indirect
|
||||
github.com/evanphx/json-patch v5.9.0+incompatible // indirect
|
||||
github.com/evanphx/json-patch/v5 v5.8.0 // indirect
|
||||
github.com/evanphx/json-patch v5.7.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/felixge/httpsnoop v1.0.4 // indirect
|
||||
@@ -157,7 +156,7 @@ require (
|
||||
github.com/fluxcd/pkg/apis/kustomize v1.0.0 // indirect
|
||||
github.com/fluxcd/pkg/apis/meta v1.0.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/fvbommel/sortorder v1.1.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gdamore/encoding v1.0.0 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
@@ -171,17 +170,17 @@ require (
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/gobuffalo/flect v1.0.2 // indirect
|
||||
github.com/gobuffalo/flect v1.0.3 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/btree v1.1.2 // indirect
|
||||
github.com/google/cel-go v0.17.7 // indirect
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
|
||||
github.com/google/cel-go v0.20.1 // indirect
|
||||
github.com/google/gnostic-models v0.6.9 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
@@ -189,7 +188,7 @@ require (
|
||||
github.com/gorilla/websocket v1.5.0 // indirect
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
@@ -197,7 +196,6 @@ require (
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.4.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/invopop/yaml v0.1.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jellydator/ttlcache/v3 v3.0.1 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
@@ -206,8 +204,9 @@ require (
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
github.com/klauspost/compress v1.17.7 // indirect
|
||||
github.com/klauspost/compress v1.17.10 // indirect
|
||||
github.com/kr/pty v1.1.8 // indirect
|
||||
github.com/kylelemons/godebug v1.1.0 // indirect
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/lib/pq v1.10.9 // indirect
|
||||
@@ -216,14 +215,13 @@ require (
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/locker v1.0.1 // indirect
|
||||
github.com/moby/spdystream v0.2.0 // indirect
|
||||
github.com/moby/spdystream v0.4.0 // indirect
|
||||
github.com/moby/term v0.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
@@ -231,15 +229,17 @@ require (
|
||||
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/oasdiff/yaml v0.0.0-20250309154309-f31be36b4037 // indirect
|
||||
github.com/oasdiff/yaml3 v0.0.0-20250309153720-d2182401db90 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.1.0 // indirect
|
||||
github.com/openshift/library-go v0.0.0-20230327085348-8477ec72b725 // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.4 // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.5 // indirect
|
||||
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||
github.com/pjbgf/sha1cd v0.3.2 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/common v0.45.0 // indirect
|
||||
github.com/prometheus/procfs v0.12.0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/protocolbuffers/txtpbfmt v0.0.0-20230328191034-3462fbc510c0 // indirect
|
||||
github.com/rivo/uniseg v0.4.3 // indirect
|
||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||
@@ -254,23 +254,24 @@ require (
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/vbatts/tar-split v0.11.5 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.3 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/zclconf/go-cty v1.13.0 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.10 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.10 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
|
||||
go.opentelemetry.io/otel v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.21.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.16 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.16 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect
|
||||
go.opentelemetry.io/otel v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.28.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.28.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
|
||||
go.starlark.net v0.0.0-20240329153429-e6e8e7ce1b7a // indirect
|
||||
go.uber.org/automaxprocs v1.5.3 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
@@ -279,12 +280,12 @@ require (
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/time v0.10.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
|
||||
google.golang.org/grpc v1.63.0 // indirect
|
||||
google.golang.org/protobuf v1.35.2 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142 // indirect
|
||||
google.golang.org/grpc v1.67.1 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/evanphx/json-patch.v5 v5.9.0 // indirect
|
||||
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
@@ -292,25 +293,25 @@ require (
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/klog v1.0.0 // indirect
|
||||
k8s.io/kms v0.29.3 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99 // indirect
|
||||
k8s.io/kms v0.31.10 // indirect
|
||||
k8s.io/kube-openapi v0.0.0-20250610211856-8b98d1ed966a // indirect
|
||||
oras.land/oras-go v1.2.5 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy v0.0.30 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.28.0 // indirect
|
||||
sigs.k8s.io/apiserver-runtime v1.1.2-0.20221118041430-0a6394f6dda3 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy v0.31.4 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.31.3 // indirect
|
||||
sigs.k8s.io/apiserver-runtime v1.1.2-0.20250117204231-9282f514a674 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/kustomize/api v0.16.0 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.16.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
|
||||
sigs.k8s.io/kustomize/api v0.17.2 // indirect
|
||||
sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect
|
||||
sigs.k8s.io/randfill v1.0.0 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.6.0 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
cloud.google.com/go => cloud.google.com/go v0.100.2
|
||||
github.com/docker/cli => github.com/docker/cli v24.0.9+incompatible
|
||||
github.com/docker/docker => github.com/docker/docker v25.0.6+incompatible
|
||||
github.com/docker/docker => github.com/docker/docker v28.3.3+incompatible
|
||||
github.com/docker/docker-credential-helpers => github.com/docker/docker-credential-helpers v0.7.0
|
||||
github.com/wercker/stern => github.com/oam-dev/stern v1.13.2
|
||||
k8s.io/kube-openapi => k8s.io/kube-openapi v0.0.0-20231010175941-2dd684a91f00
|
||||
github.com/wercker/stern => github.com/oam-dev/stern v1.13.3-0.20250828063553-e1dd6271d131
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client => sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.36
|
||||
sigs.k8s.io/apiserver-runtime => github.com/kmodules/apiserver-runtime v1.1.2-0.20240303184316-6365e03bf9ac
|
||||
sigs.k8s.io/apiserver-runtime => github.com/kmodules/apiserver-runtime v1.1.2-0.20250422194347-c5ac4abaf2ae
|
||||
)
|
||||
|
||||
@@ -44,22 +44,43 @@ EOF
|
||||
}
|
||||
|
||||
clientGen() {
|
||||
# TODO: better migrate this to kube_codegen.sh (https://github.com/kubernetes/sample-controller/blob/master/hack/update-codegen.sh)
|
||||
chmod +x ./vendor/k8s.io/code-generator/generate-groups.sh
|
||||
# Using kube_codegen.sh as generate-groups.sh has been removed
|
||||
chmod +x ./vendor/k8s.io/code-generator/kube_codegen.sh
|
||||
chmod +x ./vendor/k8s.io/code-generator/generate-internal-groups.sh
|
||||
bash ./vendor/k8s.io/code-generator/generate-groups.sh "${CODEGEN_GENERATORS}" \
|
||||
${OUTPUT_PACKAGE} \
|
||||
${APIS_PACKAGE} \
|
||||
"${CODEGEN_GROUP_VERSIONS}" \
|
||||
--output-base "${OUTPUT_DIR}" \
|
||||
--go-header-file "${BOILERPLATE_FILE}"
|
||||
|
||||
# kube_codegen.sh uses different syntax - call it via the kube_codegen module
|
||||
source ./vendor/k8s.io/code-generator/kube_codegen.sh
|
||||
|
||||
# Generate code using the new API
|
||||
kube::codegen::gen_client \
|
||||
--with-watch \
|
||||
--output-dir "${OUTPUT_DIR}" \
|
||||
--output-pkg "${OUTPUT_PACKAGE}" \
|
||||
--boilerplate "${BOILERPLATE_FILE}" \
|
||||
"./apis"
|
||||
|
||||
rm -rf ./pkg/generated/
|
||||
mkdir -p ./pkg/generated/
|
||||
mv "${WORK_TEMP_DIR}/github.com/oam-dev/kubevela/pkg/generated/client" ./pkg/generated/
|
||||
|
||||
# Move the generated client code
|
||||
if [ -d "${WORK_TEMP_DIR}/clientset" ] || [ -d "${WORK_TEMP_DIR}/informers" ] || [ -d "${WORK_TEMP_DIR}/listers" ]; then
|
||||
mkdir -p ./pkg/generated/client
|
||||
if [ -d "${WORK_TEMP_DIR}/clientset" ]; then
|
||||
mv "${WORK_TEMP_DIR}/clientset" ./pkg/generated/client/
|
||||
fi
|
||||
if [ -d "${WORK_TEMP_DIR}/informers" ]; then
|
||||
mv "${WORK_TEMP_DIR}/informers" ./pkg/generated/client/
|
||||
fi
|
||||
if [ -d "${WORK_TEMP_DIR}/listers" ]; then
|
||||
mv "${WORK_TEMP_DIR}/listers" ./pkg/generated/client/
|
||||
fi
|
||||
else
|
||||
echo "Warning: Generated client directories not found"
|
||||
find "${WORK_TEMP_DIR}" -type d 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
EXPECTED_CONTROLLER_GEN_VERSION=v0.14.0
|
||||
EXPECTED_CONTROLLER_GEN_VERSION=v0.16.5
|
||||
CONTROLLER_GEN="$(go env GOPATH)"/bin/controller-gen
|
||||
|
||||
deepcopyGen() {
|
||||
|
||||
338
hack/debug-webhook-setup.sh
Executable file
338
hack/debug-webhook-setup.sh
Executable file
@@ -0,0 +1,338 @@
|
||||
#!/bin/bash
|
||||
# Webhook debugging setup script for KubeVela
|
||||
# This script sets up everything needed to debug webhooks locally
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
CERT_DIR="k8s-webhook-server/serving-certs"
|
||||
NAMESPACE="vela-system"
|
||||
SECRET_NAME="webhook-server-cert"
|
||||
WEBHOOK_CONFIG_NAME="kubevela-vela-core-admission"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
echo -e "${GREEN}=== KubeVela Webhook Debug Setup ===${NC}"
|
||||
|
||||
# Function to check prerequisites
|
||||
check_prerequisites() {
|
||||
echo -e "${YELLOW}Checking prerequisites...${NC}"
|
||||
|
||||
# Check kubectl
|
||||
if ! command -v kubectl &> /dev/null; then
|
||||
echo -e "${RED}kubectl is not installed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check openssl
|
||||
if ! command -v openssl &> /dev/null; then
|
||||
echo -e "${RED}openssl is not installed${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check cluster connectivity
|
||||
if ! kubectl cluster-info &> /dev/null; then
|
||||
echo -e "${RED}Cannot connect to Kubernetes cluster${NC}"
|
||||
echo "Please ensure your kubeconfig is set up correctly"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Wait for cluster to be ready
|
||||
echo "Waiting for cluster nodes to be ready..."
|
||||
kubectl wait --for=condition=Ready nodes --all --timeout=60s &> /dev/null || true
|
||||
|
||||
echo -e "${GREEN}Prerequisites check passed${NC}"
|
||||
}
|
||||
|
||||
# Function to create namespace if not exists
|
||||
create_namespace() {
|
||||
echo -e "${YELLOW}Creating namespace ${NAMESPACE}...${NC}"
|
||||
kubectl create namespace ${NAMESPACE} --dry-run=client -o yaml | kubectl apply -f -
|
||||
echo -e "${GREEN}Namespace ready${NC}"
|
||||
}
|
||||
|
||||
# Function to generate certificates
|
||||
generate_certificates() {
|
||||
echo -e "${YELLOW}Generating webhook certificates...${NC}"
|
||||
|
||||
# Create directory
|
||||
mkdir -p ${CERT_DIR}
|
||||
|
||||
# Clean old certificates
|
||||
rm -f ${CERT_DIR}/*
|
||||
|
||||
# Generate CA private key
|
||||
openssl genrsa -out ${CERT_DIR}/ca.key 2048
|
||||
|
||||
# Generate CA certificate
|
||||
openssl req -x509 -new -nodes -key ${CERT_DIR}/ca.key -days 365 -out ${CERT_DIR}/ca.crt \
|
||||
-subj "/CN=webhook-ca"
|
||||
|
||||
# Generate server private key
|
||||
openssl genrsa -out ${CERT_DIR}/tls.key 2048
|
||||
|
||||
# Auto-detect host IP for Docker/k3d internal network
|
||||
# This is only for local k3d development environments - DO NOT use this script in production
|
||||
# With failurePolicy: Fail, an unreachable webhook can block CRD operations cluster-wide
|
||||
|
||||
# Try to detect k3d cluster
|
||||
K3D_CLUSTER=$(kubectl config current-context | grep -o 'k3d-[^@]*' | sed 's/k3d-//' || echo "")
|
||||
|
||||
if [ -n "$K3D_CLUSTER" ]; then
|
||||
echo "Detected k3d cluster: $K3D_CLUSTER"
|
||||
|
||||
# Check if k3d is using host network
|
||||
NETWORK_MODE=$(docker inspect "k3d-${K3D_CLUSTER}-server-0" 2>/dev/null | grep -o '"NetworkMode": "[^"]*"' | cut -d'"' -f4 || echo "")
|
||||
|
||||
if [ "$NETWORK_MODE" = "host" ]; then
|
||||
# Host network mode - detect OS
|
||||
if [ "$(uname)" = "Darwin" ]; then
|
||||
# macOS with Docker Desktop - use host.docker.internal
|
||||
echo "Detected k3d with --network host on macOS, using host.docker.internal"
|
||||
HOST_IP="host.docker.internal"
|
||||
else
|
||||
# Linux - true host networking works
|
||||
echo "Detected k3d with --network host, using localhost"
|
||||
HOST_IP="127.0.0.1"
|
||||
fi
|
||||
else
|
||||
# Bridge network mode - get gateway IP
|
||||
NETWORK_NAME="k3d-${K3D_CLUSTER}"
|
||||
HOST_IP=$(docker network inspect "$NETWORK_NAME" -f '{{range .IPAM.Config}}{{.Gateway}}{{end}}' 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$HOST_IP" ]; then
|
||||
# Fallback to common k3d gateway IPs
|
||||
echo "Could not detect gateway IP, trying common defaults..."
|
||||
if docker exec "k3d-${K3D_CLUSTER}-server-0" getent hosts host.k3d.internal 2>/dev/null | awk '{print $1}' | grep -q .; then
|
||||
HOST_IP=$(docker exec "k3d-${K3D_CLUSTER}-server-0" cat /etc/hosts | grep host.k3d.internal | awk '{print $1}')
|
||||
else
|
||||
HOST_IP="172.18.0.1"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Detected k3d with bridge network, using gateway IP: $HOST_IP"
|
||||
fi
|
||||
else
|
||||
# Not k3d, use default
|
||||
echo "Not using k3d, defaulting to 192.168.5.2"
|
||||
HOST_IP="192.168.5.2"
|
||||
fi
|
||||
|
||||
# Get local machine IP for SANs (optional, for reference)
|
||||
if command -v ifconfig &> /dev/null; then
|
||||
LOCAL_IP=$(ifconfig | grep "inet " | grep -v 127.0.0.1 | head -1 | awk '{print $2}')
|
||||
elif command -v ip &> /dev/null; then
|
||||
LOCAL_IP=$(ip -4 addr show | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | grep -v 127.0.0.1 | head -1)
|
||||
else
|
||||
LOCAL_IP=""
|
||||
fi
|
||||
|
||||
# Create certificate config with SANs
|
||||
cat > /tmp/webhook.conf << EOF
|
||||
[req]
|
||||
req_extensions = v3_req
|
||||
distinguished_name = req_distinguished_name
|
||||
[req_distinguished_name]
|
||||
[v3_req]
|
||||
basicConstraints = CA:FALSE
|
||||
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
||||
subjectAltName = @alt_names
|
||||
[alt_names]
|
||||
DNS.1 = localhost
|
||||
DNS.2 = vela-webhook.${NAMESPACE}.svc
|
||||
DNS.3 = vela-webhook.${NAMESPACE}.svc.cluster.local
|
||||
DNS.4 = *.${NAMESPACE}.svc
|
||||
DNS.5 = *.${NAMESPACE}.svc.cluster.local
|
||||
DNS.6 = host.k3d.internal
|
||||
DNS.7 = host.docker.internal
|
||||
DNS.8 = host.lima.internal
|
||||
IP.1 = 127.0.0.1
|
||||
EOF
|
||||
|
||||
# Add HOST_IP - check if it's a hostname or IP
|
||||
if [[ "$HOST_IP" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
# It's an IP address
|
||||
echo "IP.2 = ${HOST_IP}" >> /tmp/webhook.conf
|
||||
else
|
||||
# It's a hostname - already covered by DNS SANs above
|
||||
echo "# HOST_IP is hostname: ${HOST_IP} (already in DNS SANs)" >> /tmp/webhook.conf
|
||||
fi
|
||||
|
||||
# Add LOCAL_IP to SANs only if detected and is an IP
|
||||
if [ -n "$LOCAL_IP" ] && [[ "$LOCAL_IP" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "IP.3 = ${LOCAL_IP}" >> /tmp/webhook.conf
|
||||
fi
|
||||
|
||||
# Generate certificate request
|
||||
openssl req -new -key ${CERT_DIR}/tls.key -out /tmp/server.csr \
|
||||
-subj "/CN=vela-webhook.${NAMESPACE}.svc" -config /tmp/webhook.conf
|
||||
|
||||
# Generate server certificate with SANs
|
||||
openssl x509 -req -in /tmp/server.csr -CA ${CERT_DIR}/ca.crt -CAkey ${CERT_DIR}/ca.key \
|
||||
-CAcreateserial -out ${CERT_DIR}/tls.crt -days 365 \
|
||||
-extensions v3_req -extfile /tmp/webhook.conf
|
||||
|
||||
echo -e "${GREEN}Certificates generated with IP SANs: 127.0.0.1, ${HOST_IP}, ${LOCAL_IP}${NC}"
|
||||
|
||||
# Clean up temp files
|
||||
rm -f /tmp/server.csr /tmp/webhook.conf
|
||||
}
|
||||
|
||||
# Function to create Kubernetes secret
|
||||
create_k8s_secret() {
|
||||
echo -e "${YELLOW}Creating Kubernetes secret...${NC}"
|
||||
|
||||
# Delete old secret if exists
|
||||
kubectl delete secret ${SECRET_NAME} -n ${NAMESPACE} --ignore-not-found
|
||||
|
||||
# Create new secret
|
||||
kubectl create secret tls ${SECRET_NAME} \
|
||||
--cert=${CERT_DIR}/tls.crt \
|
||||
--key=${CERT_DIR}/tls.key \
|
||||
-n ${NAMESPACE}
|
||||
|
||||
echo -e "${GREEN}Secret ${SECRET_NAME} created in namespace ${NAMESPACE}${NC}"
|
||||
}
|
||||
|
||||
# Function to create webhook configuration
|
||||
create_webhook_config() {
|
||||
echo -e "${YELLOW}Creating webhook configuration...${NC}"
|
||||
|
||||
# Get CA bundle
|
||||
CA_BUNDLE=$(cat ${CERT_DIR}/ca.crt | base64 | tr -d '\n')
|
||||
|
||||
# Delete old webhook configuration if exists
|
||||
kubectl delete validatingwebhookconfiguration ${WEBHOOK_CONFIG_NAME} --ignore-not-found
|
||||
|
||||
# Create webhook configuration
|
||||
cat > /tmp/webhook-config.yaml << EOF
|
||||
apiVersion: admissionregistration.k8s.io/v1
|
||||
kind: ValidatingWebhookConfiguration
|
||||
metadata:
|
||||
name: ${WEBHOOK_CONFIG_NAME}
|
||||
webhooks:
|
||||
- name: componentdefinition.core.oam.dev
|
||||
clientConfig:
|
||||
url: https://${HOST_IP}:9445/validating-core-oam-dev-v1beta1-componentdefinitions
|
||||
caBundle: ${CA_BUNDLE}
|
||||
rules:
|
||||
- apiGroups: ["core.oam.dev"]
|
||||
apiVersions: ["v1beta1"]
|
||||
resources: ["componentdefinitions"]
|
||||
operations: ["CREATE", "UPDATE"]
|
||||
admissionReviewVersions: ["v1", "v1beta1"]
|
||||
sideEffects: None
|
||||
failurePolicy: Fail
|
||||
- name: traitdefinition.core.oam.dev
|
||||
clientConfig:
|
||||
url: https://${HOST_IP}:9445/validating-core-oam-dev-v1beta1-traitdefinitions
|
||||
caBundle: ${CA_BUNDLE}
|
||||
rules:
|
||||
- apiGroups: ["core.oam.dev"]
|
||||
apiVersions: ["v1beta1"]
|
||||
resources: ["traitdefinitions"]
|
||||
operations: ["CREATE", "UPDATE"]
|
||||
admissionReviewVersions: ["v1", "v1beta1"]
|
||||
sideEffects: None
|
||||
failurePolicy: Fail
|
||||
- name: policydefinition.core.oam.dev
|
||||
clientConfig:
|
||||
url: https://${HOST_IP}:9445/validating-core-oam-dev-v1beta1-policydefinitions
|
||||
caBundle: ${CA_BUNDLE}
|
||||
rules:
|
||||
- apiGroups: ["core.oam.dev"]
|
||||
apiVersions: ["v1beta1"]
|
||||
resources: ["policydefinitions"]
|
||||
operations: ["CREATE", "UPDATE"]
|
||||
admissionReviewVersions: ["v1", "v1beta1"]
|
||||
sideEffects: None
|
||||
failurePolicy: Fail
|
||||
- name: workflowstepdefinition.core.oam.dev
|
||||
clientConfig:
|
||||
url: https://${HOST_IP}:9445/validating-core-oam-dev-v1beta1-workflowstepdefinitions
|
||||
caBundle: ${CA_BUNDLE}
|
||||
rules:
|
||||
- apiGroups: ["core.oam.dev"]
|
||||
apiVersions: ["v1beta1"]
|
||||
resources: ["workflowstepdefinitions"]
|
||||
operations: ["CREATE", "UPDATE"]
|
||||
admissionReviewVersions: ["v1", "v1beta1"]
|
||||
sideEffects: None
|
||||
failurePolicy: Fail
|
||||
- name: applications.core.oam.dev
|
||||
clientConfig:
|
||||
url: https://${HOST_IP}:9445/validating-core-oam-dev-v1beta1-applications
|
||||
caBundle: ${CA_BUNDLE}
|
||||
rules:
|
||||
- apiGroups: ["core.oam.dev"]
|
||||
apiVersions: ["v1beta1"]
|
||||
resources: ["applications"]
|
||||
operations: ["CREATE", "UPDATE"]
|
||||
admissionReviewVersions: ["v1", "v1beta1"]
|
||||
sideEffects: None
|
||||
failurePolicy: Fail
|
||||
EOF
|
||||
|
||||
kubectl apply -f /tmp/webhook-config.yaml
|
||||
rm -f /tmp/webhook-config.yaml
|
||||
|
||||
echo -e "${GREEN}Webhook configuration created${NC}"
|
||||
}
|
||||
|
||||
# Function to show next steps
|
||||
show_next_steps() {
|
||||
echo -e "${GREEN}"
|
||||
echo "========================================="
|
||||
echo "Webhook debugging setup complete!"
|
||||
echo "========================================="
|
||||
echo -e "${NC}"
|
||||
|
||||
echo "Configuration:"
|
||||
echo " - Webhook URL: https://${HOST_IP}:9445"
|
||||
echo " - Certificate directory: ${CERT_DIR}"
|
||||
|
||||
if [ -n "$K3D_CLUSTER" ]; then
|
||||
echo " - k3d cluster: ${K3D_CLUSTER}"
|
||||
if [ "$NETWORK_MODE" = "host" ]; then
|
||||
echo " - Network mode: host (using ${HOST_IP})"
|
||||
else
|
||||
echo " - Network mode: bridge (using gateway ${HOST_IP})"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Open your IDE (VS Code, GoLand, etc.)"
|
||||
echo "2. Set breakpoints in webhook validation code:"
|
||||
echo " - pkg/webhook/core.oam.dev/v1beta1/application/validating_handler.go:66"
|
||||
echo " - pkg/webhook/core.oam.dev/v1beta1/componentdefinition/component_definition_validating_handler.go:74"
|
||||
echo "3. Start debugging cmd/core/main.go with arguments:"
|
||||
echo " --use-webhook=true"
|
||||
echo " --webhook-port=9445"
|
||||
echo " --webhook-cert-dir=${CERT_DIR}"
|
||||
echo " --leader-elect=false"
|
||||
echo "4. Wait for webhook server to start"
|
||||
echo "5. Test with kubectl apply commands"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Test command:${NC}"
|
||||
echo 'kubectl apply -f <your-application.yaml>'
|
||||
echo ""
|
||||
echo -e "${GREEN}Your breakpoints will hit when kubectl applies resources!${NC}"
|
||||
}
|
||||
|
||||
# Main execution
|
||||
main() {
|
||||
check_prerequisites
|
||||
create_namespace
|
||||
generate_certificates
|
||||
create_k8s_secret
|
||||
create_webhook_config
|
||||
show_next_steps
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
74
hack/utils/golangci-lint-wrapper.sh
Executable file
74
hack/utils/golangci-lint-wrapper.sh
Executable file
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env bash
|
||||
# Wrapper script to run golangci-lint and ignore typecheck errors
|
||||
# This script filters out false positive typecheck errors from golangci-lint v1.60.1
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Create temporary files for output
|
||||
tmpfile=$(mktemp)
|
||||
filtered=$(mktemp)
|
||||
|
||||
# Ensure cleanup on exit
|
||||
cleanup() {
|
||||
rm -f "$tmpfile" "$filtered"
|
||||
}
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
if ${GOLANGCILINT:-golangci-lint} run --config .golangci.yml --fix --verbose --exclude-dirs 'scaffold' > "$tmpfile" 2>&1; then
|
||||
exit_code=0
|
||||
else
|
||||
exit_code=$?
|
||||
fi
|
||||
|
||||
# Keep the original verbose output (level= lines)
|
||||
grep -E "^level=|^[[:space:]]*$" "$tmpfile" > "$filtered" || true
|
||||
|
||||
# Check for non-typecheck errors and add them to output
|
||||
if grep -E "\.go:[0-9]+:[0-9]+:.*\(" "$tmpfile" 2>/dev/null | grep -v "(typecheck)" > /dev/null; then
|
||||
{
|
||||
echo ""
|
||||
echo "Linting errors found:"
|
||||
grep -E "\.go:[0-9]+:[0-9]+:.*\(" "$tmpfile" | grep -v "(typecheck)" || true
|
||||
} >> "$filtered"
|
||||
fi
|
||||
|
||||
cat "$filtered"
|
||||
if [[ $exit_code -eq 0 ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Count non-typecheck errors in .go files
|
||||
non_typecheck_errors=$(grep -E "\.go:[0-9]+:[0-9]+:.*\(" "$tmpfile" 2>/dev/null | grep -v "(typecheck)" | grep -c . || echo "0")
|
||||
|
||||
# Ensure the count is a valid number (remove spaces and newlines)
|
||||
non_typecheck_errors=$(echo "$non_typecheck_errors" | tr -d '[:space:]')
|
||||
|
||||
# Check if golangci-lint itself had a critical failure (not a linting error)
|
||||
# This catches cases like config errors, missing files, etc.
|
||||
if [[ $exit_code -ne 0 ]] && [[ $non_typecheck_errors -eq 0 ]]; then
|
||||
# Check if there are only typecheck errors
|
||||
total_errors=$(grep -E "\.go:[0-9]+:[0-9]+:.*\(" "$tmpfile" 2>/dev/null | grep -c . || echo "0")
|
||||
typecheck_errors=$(grep -E "\.go:[0-9]+:[0-9]+:.*\(typecheck\)" "$tmpfile" 2>/dev/null | grep -c . || echo "0")
|
||||
|
||||
# Clean up the counts
|
||||
total_errors=$(echo "$total_errors" | tr -d '[:space:]')
|
||||
typecheck_errors=$(echo "$typecheck_errors" | tr -d '[:space:]')
|
||||
|
||||
if [[ $total_errors -eq $typecheck_errors ]]; then
|
||||
# Only typecheck errors, ignore them
|
||||
exit 0
|
||||
else
|
||||
# There was a critical failure, show the full output and exit with error
|
||||
echo ""
|
||||
echo "Critical golangci-lint failure detected:"
|
||||
cat "$tmpfile"
|
||||
exit "$exit_code"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $non_typecheck_errors -gt 0 ]]; then
|
||||
exit "$exit_code"
|
||||
else
|
||||
# Only typecheck errors, ignore them
|
||||
exit 0
|
||||
fi
|
||||
@@ -4,7 +4,7 @@ $(LOCALBIN):
|
||||
GOLANGCILINT_VERSION ?= 1.60.1
|
||||
GLOBAL_GOLANGCILINT := $(shell which golangci-lint)
|
||||
GOBIN_GOLANGCILINT:= $(shell which $(GOBIN)/golangci-lint)
|
||||
ENVTEST_K8S_VERSION = 1.29.0
|
||||
ENVTEST_K8S_VERSION = 1.31.0
|
||||
ENVTEST ?= $(LOCALBIN)/setup-envtest
|
||||
|
||||
.PHONY: golangci
|
||||
@@ -31,7 +31,7 @@ ifeq (, $(shell which staticcheck))
|
||||
@{ \
|
||||
set -e ;\
|
||||
echo 'installing honnef.co/go/tools/cmd/staticcheck ' ;\
|
||||
go install honnef.co/go/tools/cmd/staticcheck@v0.5.1 ;\
|
||||
go install honnef.co/go/tools/cmd/staticcheck@v0.6.1 ;\
|
||||
}
|
||||
STATICCHECK=$(GOBIN)/staticcheck
|
||||
else
|
||||
|
||||
@@ -30,3 +30,75 @@ core-run: fmt vet manifests
|
||||
.PHONY: gen-cue
|
||||
gen-cue:
|
||||
./hack/cuegen/cuegen.sh $(DIR) $(FLAGS)
|
||||
|
||||
# ==============================================================================
|
||||
# Webhook Debug and Development Targets
|
||||
|
||||
K3D_CLUSTER_NAME ?= kubevela-debug
|
||||
K3D_VERSION ?= v1.31.5
|
||||
|
||||
## webhook-help: Show webhook debugging help
|
||||
.PHONY: webhook-help
|
||||
webhook-help:
|
||||
@echo "=== KubeVela Webhook Debugging Guide ==="
|
||||
@echo ""
|
||||
@echo "Quick Start (recommended):"
|
||||
@echo " 1. make webhook-debug-setup # Complete setup"
|
||||
@echo " 2. Start VS Code debugger (F5) with 'Debug Webhook Validation'"
|
||||
@echo ""
|
||||
@echo "Individual Commands:"
|
||||
@echo " make k3d-create # Create k3d cluster"
|
||||
@echo " make k3d-delete # Delete k3d cluster"
|
||||
@echo " make webhook-setup # Setup webhook (certs + config)"
|
||||
@echo " make webhook-clean # Clean up webhook setup"
|
||||
|
||||
## k3d-create: Create a k3d cluster for debugging
|
||||
.PHONY: k3d-create
|
||||
k3d-create:
|
||||
@echo "Creating k3d cluster: $(K3D_CLUSTER_NAME)"
|
||||
@if k3d cluster list | grep -q "^$(K3D_CLUSTER_NAME)"; then \
|
||||
echo "k3d cluster $(K3D_CLUSTER_NAME) already exists"; \
|
||||
else \
|
||||
k3d cluster create "$(K3D_CLUSTER_NAME)" \
|
||||
--servers 1 \
|
||||
--agents 1 \
|
||||
--wait || (echo "Failed to create k3d cluster" && exit 1); \
|
||||
fi
|
||||
@kubectl config use-context "k3d-$(K3D_CLUSTER_NAME)"
|
||||
@echo "k3d cluster $(K3D_CLUSTER_NAME) ready"
|
||||
|
||||
## k3d-delete: Delete the k3d cluster
|
||||
.PHONY: k3d-delete
|
||||
k3d-delete:
|
||||
@echo "Deleting k3d cluster: $(K3D_CLUSTER_NAME)"
|
||||
@k3d cluster delete "$(K3D_CLUSTER_NAME)" || true
|
||||
|
||||
## webhook-setup: Setup webhook certificates and configuration
|
||||
.PHONY: webhook-setup
|
||||
webhook-setup:
|
||||
@echo "Setting up webhook certificates and configuration..."
|
||||
@chmod +x hack/debug-webhook-setup.sh
|
||||
@./hack/debug-webhook-setup.sh
|
||||
|
||||
## webhook-debug-setup: Complete webhook debug environment setup
|
||||
.PHONY: webhook-debug-setup
|
||||
webhook-debug-setup:
|
||||
@echo "Setting up complete webhook debug environment..."
|
||||
@$(MAKE) k3d-create
|
||||
@echo "Waiting for cluster to be ready..."
|
||||
@sleep 5
|
||||
@kubectl wait --for=condition=Ready nodes --all --timeout=60s || true
|
||||
@echo "Installing KubeVela CRDs..."
|
||||
@$(MAKE) manifests
|
||||
@kubectl apply -f charts/vela-core/crds/ --validate=false
|
||||
@echo "Setting up webhook..."
|
||||
@$(MAKE) webhook-setup
|
||||
|
||||
## webhook-clean: Clean up webhook debug environment
|
||||
.PHONY: webhook-clean
|
||||
webhook-clean:
|
||||
@echo "Cleaning up webhook debug environment..."
|
||||
@rm -rf k8s-webhook-server/
|
||||
@kubectl delete secret webhook-server-cert -n vela-system --ignore-not-found
|
||||
@kubectl delete validatingwebhookconfiguration kubevela-vela-core-admission --ignore-not-found
|
||||
@echo "Webhook debug environment cleaned"
|
||||
|
||||
@@ -31,6 +31,7 @@ e2e-setup-core-wo-auth:
|
||||
--set multicluster.clusterGateway.image.repository=ghcr.io/oam-dev/cluster-gateway \
|
||||
--set admissionWebhooks.patch.image.repository=ghcr.io/oam-dev/kube-webhook-certgen/kube-webhook-certgen \
|
||||
--set featureGates.enableCueValidation=true \
|
||||
--set featureGates.validateResourcesExist=true \
|
||||
--wait kubevela ./charts/vela-core \
|
||||
--debug
|
||||
|
||||
@@ -48,10 +49,11 @@ e2e-setup-core-w-auth:
|
||||
./charts/vela-core \
|
||||
--set authentication.enabled=true \
|
||||
--set authentication.withUser=true \
|
||||
--set authentication.groupPattern=* \
|
||||
--set authentication.groupPattern='*' \
|
||||
--set featureGates.zstdResourceTracker=true \
|
||||
--set featureGates.zstdApplicationRevision=true \
|
||||
--set featureGates.validateComponentWhenSharding=true \
|
||||
--set featureGates.validateResourcesExist=true \
|
||||
--set multicluster.clusterGateway.enabled=true \
|
||||
--set multicluster.clusterGateway.image.repository=ghcr.io/oam-dev/cluster-gateway \
|
||||
--set admissionWebhooks.patch.image.repository=ghcr.io/oam-dev/kube-webhook-certgen/kube-webhook-certgen \
|
||||
@@ -85,6 +87,32 @@ e2e-test:
|
||||
ginkgo -v ./test/e2e-test
|
||||
@$(OK) tests pass
|
||||
|
||||
# Run e2e tests with k3d and webhook validation
|
||||
.PHONY: e2e-test-local
|
||||
e2e-test-local:
|
||||
# Create k3d cluster if needed
|
||||
@k3d cluster create kubevela-debug --servers 1 --agents 1 || true
|
||||
# Build and load image
|
||||
docker build -t vela-core:e2e-test -f Dockerfile . --build-arg=VERSION=e2e-test --build-arg=GITVERSION=test
|
||||
k3d image import vela-core:e2e-test -c kubevela-debug
|
||||
# Deploy with Helm
|
||||
kubectl delete validatingwebhookconfiguration kubevela-vela-core-admission 2>/dev/null || true
|
||||
helm upgrade --install kubevela ./charts/vela-core \
|
||||
--namespace vela-system --create-namespace \
|
||||
--set image.repository=vela-core \
|
||||
--set image.tag=e2e-test \
|
||||
--set image.pullPolicy=IfNotPresent \
|
||||
--set admissionWebhooks.enabled=true \
|
||||
--set featureGates.enableCueValidation=true \
|
||||
--set featureGates.validateResourcesExist=true \
|
||||
--set applicationRevisionLimit=5 \
|
||||
--set controllerArgs.reSyncPeriod=1m \
|
||||
--wait --timeout 3m
|
||||
# Run tests
|
||||
ginkgo -v ./test/e2e-test
|
||||
@$(OK) tests pass
|
||||
|
||||
|
||||
.PHONY: e2e-addon-test
|
||||
e2e-addon-test:
|
||||
cp bin/vela /tmp/
|
||||
|
||||
@@ -39,7 +39,7 @@ func setupMockServer() *httptest.Server {
|
||||
"index.yaml",
|
||||
"fluxcd-test-version-1.0.0.tgz",
|
||||
"fluxcd-test-version-2.0.0.tgz",
|
||||
"vela-workflow-v0.3.5.tgz",
|
||||
"vela-workflow-v0.6.2.tgz",
|
||||
"foo-v1.0.0.tgz",
|
||||
"bar-v1.0.0.tgz",
|
||||
"bar-v2.0.0.tgz",
|
||||
|
||||
@@ -29,7 +29,6 @@ import (
|
||||
"cuelang.org/go/cue/build"
|
||||
"cuelang.org/go/cue/cuecontext"
|
||||
"cuelang.org/go/cue/parser"
|
||||
"github.com/cue-exp/kubevelafix"
|
||||
"github.com/pkg/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
@@ -184,7 +183,6 @@ func newValueWithMainAndFiles(main string, slaveFiles []string, _ string, opts .
|
||||
builder := &build.Instance{}
|
||||
|
||||
mainFile, err := parser.ParseFile("main.cue", main, parser.ParseComments)
|
||||
mainFile = kubevelafix.Fix(mainFile).(*ast.File)
|
||||
if err != nil {
|
||||
return cue.Value{}, errors.Wrap(err, "parse main file")
|
||||
}
|
||||
@@ -206,7 +204,6 @@ func newValueWithMainAndFiles(main string, slaveFiles []string, _ string, opts .
|
||||
|
||||
for idx, sf := range slaveFiles {
|
||||
cueSF, err := parser.ParseFile("sf-"+strconv.Itoa(idx)+".cue", sf, parser.ParseComments)
|
||||
cueSF = kubevelafix.Fix(cueSF).(*ast.File)
|
||||
if err != nil {
|
||||
return cue.Value{}, errors.Wrap(err, "parse added file "+strconv.Itoa(idx)+" \n"+sf)
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/cue/definition/health"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
|
||||
"github.com/kubevela/pkg/util/slices"
|
||||
@@ -110,21 +112,12 @@ func (comp *Component) GetTemplateContext(ctx process.Context, client client.Cli
|
||||
}
|
||||
|
||||
// EvalStatus eval workload status
|
||||
func (comp *Component) EvalStatus(templateContext map[string]interface{}) (string, error) {
|
||||
func (comp *Component) EvalStatus(templateContext map[string]interface{}) (*health.StatusResult, error) {
|
||||
// if the standard workload is managed by trait always return empty message
|
||||
if comp.SkipApplyWorkload {
|
||||
return "", nil
|
||||
return nil, nil
|
||||
}
|
||||
return comp.engine.Status(templateContext, comp.FullTemplate.CustomStatus, comp.Params)
|
||||
}
|
||||
|
||||
// EvalHealth eval workload health check
|
||||
func (comp *Component) EvalHealth(templateContext map[string]interface{}) (bool, error) {
|
||||
// if the health of template is not set or standard workload is managed by trait always return true
|
||||
if comp.SkipApplyWorkload {
|
||||
return true, nil
|
||||
}
|
||||
return comp.engine.HealthCheck(templateContext, comp.FullTemplate.Health, comp.Params)
|
||||
return comp.engine.Status(templateContext, comp.FullTemplate.AsStatusRequest(comp.Params))
|
||||
}
|
||||
|
||||
// Trait is ComponentTrait
|
||||
@@ -135,7 +128,6 @@ type Trait struct {
|
||||
Params map[string]interface{}
|
||||
|
||||
Template string
|
||||
HealthCheckPolicy string
|
||||
CustomStatusFormat string
|
||||
|
||||
// RequiredSecrets stores secret names which the trait needs from cloud resource component and its context
|
||||
@@ -159,14 +151,9 @@ func (trait *Trait) GetTemplateContext(ctx process.Context, client client.Client
|
||||
return templateContext, err
|
||||
}
|
||||
|
||||
// EvalStatus eval trait status
|
||||
func (trait *Trait) EvalStatus(templateContext map[string]interface{}) (string, error) {
|
||||
return trait.engine.Status(templateContext, trait.CustomStatusFormat, trait.Params)
|
||||
}
|
||||
|
||||
// EvalHealth eval trait health check
|
||||
func (trait *Trait) EvalHealth(templateContext map[string]interface{}) (bool, error) {
|
||||
return trait.engine.HealthCheck(templateContext, trait.HealthCheckPolicy, trait.Params)
|
||||
// EvalStatus eval trait status (including health)
|
||||
func (trait *Trait) EvalStatus(templateContext map[string]interface{}) (*health.StatusResult, error) {
|
||||
return trait.engine.Status(templateContext, trait.FullTemplate.AsStatusRequest(trait.Params))
|
||||
}
|
||||
|
||||
// Appfile describes application
|
||||
|
||||
@@ -109,12 +109,23 @@ func (d *Option) ValidateApp(ctx context.Context, filename string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespace := oamutil.GetDefinitionNamespaceWithCtx(ctx)
|
||||
|
||||
if namespace != "" {
|
||||
app.SetNamespace(namespace)
|
||||
} else if len(app.GetNamespace()) == 0 {
|
||||
// Verify if namespace exists in cluster
|
||||
ns := &corev1.Namespace{}
|
||||
if err := d.Client.Get(ctx, client.ObjectKey{Name: namespace}, ns); err != nil {
|
||||
if client.IgnoreNotFound(err) != nil {
|
||||
// Non-NotFound error (RBAC, connectivity, etc.) - return the error
|
||||
return err
|
||||
}
|
||||
// Namespace doesn't exist, set default
|
||||
app.SetNamespace(corev1.NamespaceDefault)
|
||||
} else {
|
||||
// Namespace exists, use it
|
||||
app.SetNamespace(namespace)
|
||||
}
|
||||
} else {
|
||||
// Namespace is empty, set default
|
||||
app.SetNamespace(corev1.NamespaceDefault)
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,20 @@ var _ = Describe("Test DryRun", func() {
|
||||
diff := cmp.Diff(&expC, comps[0])
|
||||
Expect(diff).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("Test ValidateApp forces default namespace (validation object) but ExecuteDryRun keeps app namespace", func() {
|
||||
err := dryrunOpt.ValidateApp(context.Background(), "./testdata/dryrun-app-with-ns.yaml")
|
||||
Expect(err).Should(BeNil())
|
||||
appYAML := readDataFromFile("./testdata/dryrun-app-with-ns.yaml")
|
||||
app := &v1beta1.Application{}
|
||||
b, err2 := yaml.YAMLToJSON([]byte(appYAML))
|
||||
Expect(err2).Should(BeNil())
|
||||
err2 = json.Unmarshal(b, app)
|
||||
Expect(err2).Should(BeNil())
|
||||
comps, _, err3 := dryrunOpt.ExecuteDryRun(context.Background(), app)
|
||||
Expect(err3).Should(BeNil())
|
||||
Expect(comps[0].ComponentOutput.GetNamespace()).Should(Equal("custom-ns"))
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("Test dry run with policies", func() {
|
||||
|
||||
14
pkg/appfile/dryrun/testdata/dryrun-app-with-ns.yaml
vendored
Normal file
14
pkg/appfile/dryrun/testdata/dryrun-app-with-ns.yaml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-dryrun-ns
|
||||
namespace: custom-ns
|
||||
spec:
|
||||
components:
|
||||
- name: myweb
|
||||
type: myworker
|
||||
properties:
|
||||
image: busybox
|
||||
cmd:
|
||||
- sleep
|
||||
- "1000"
|
||||
@@ -704,7 +704,6 @@ func (p *Parser) convertTemplate2Trait(name string, properties map[string]interf
|
||||
CapabilityCategory: templ.CapabilityCategory,
|
||||
Params: properties,
|
||||
Template: templ.TemplateStr,
|
||||
HealthCheckPolicy: templ.Health,
|
||||
CustomStatusFormat: templ.CustomStatus,
|
||||
FullTemplate: templ,
|
||||
engine: definition.NewTraitAbstractEngine(traitName),
|
||||
|
||||
@@ -31,6 +31,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/cue/definition/health"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
@@ -51,6 +53,7 @@ type Template struct {
|
||||
TemplateStr string
|
||||
Health string
|
||||
CustomStatus string
|
||||
Details string
|
||||
CapabilityCategory types.CapabilityCategory
|
||||
Reference common.WorkloadTypeDescriptor
|
||||
Terraform *common.Terraform
|
||||
@@ -350,6 +353,7 @@ func loadSchematicToTemplate(tmpl *Template, status *common.Status, schematic *c
|
||||
if status != nil {
|
||||
tmpl.CustomStatus = status.CustomStatus
|
||||
tmpl.Health = status.HealthPolicy
|
||||
tmpl.Details = status.Details
|
||||
}
|
||||
|
||||
if schematic != nil {
|
||||
@@ -398,3 +402,12 @@ func ConvertTemplateJSON2Object(capabilityName string, in *runtime.RawExtension,
|
||||
}
|
||||
return t, nil
|
||||
}
|
||||
|
||||
func (t *Template) AsStatusRequest(parameter map[string]interface{}) *health.StatusRequest {
|
||||
return &health.StatusRequest{
|
||||
Health: t.Health,
|
||||
Custom: t.CustomStatus,
|
||||
Details: t.Details,
|
||||
Parameter: parameter,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,7 +155,7 @@ func TestLoadTraitTemplate(t *testing.T) {
|
||||
}
|
||||
|
||||
outputs: ingress: {
|
||||
apiVersion: "networking.k8s.io/v1beta1"
|
||||
apiVersion: "networking.k8s.io/v1"
|
||||
kind: "Ingress"
|
||||
metadata:
|
||||
name: context.name
|
||||
@@ -166,9 +166,14 @@ func TestLoadTraitTemplate(t *testing.T) {
|
||||
paths: [
|
||||
for k, v in parameter.http {
|
||||
path: k
|
||||
pathType: "Prefix"
|
||||
backend: {
|
||||
serviceName: context.name
|
||||
servicePort: v
|
||||
service: {
|
||||
name: context.name
|
||||
port: {
|
||||
number: v
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
@@ -55,7 +55,24 @@ func (p *Parser) ValidateCUESchematicAppfile(a *Appfile) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Collect workflow-supplied params for this component upfront
|
||||
workflowParams := getWorkflowAndPolicySuppliedParams(a)
|
||||
|
||||
// Only augment if component has traits AND workflow supplies params (issue 7022)
|
||||
originalParams := wl.Params
|
||||
if len(wl.Traits) > 0 && len(workflowParams) > 0 {
|
||||
shouldSkip, augmented := p.augmentComponentParamsForValidation(wl, workflowParams, ctxData)
|
||||
if shouldSkip {
|
||||
// Component has complex validation that can't be handled, skip trait validation
|
||||
fmt.Printf("INFO: Skipping trait validation for component %q due to workflow-supplied parameters with complex validation\n", wl.Name)
|
||||
continue
|
||||
}
|
||||
wl.Params = augmented
|
||||
}
|
||||
|
||||
pCtx, err := newValidationProcessContext(wl, ctxData)
|
||||
wl.Params = originalParams // Restore immediately
|
||||
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "cannot create the validation process context of app=%s in namespace=%s", a.Name, a.Namespace)
|
||||
}
|
||||
@@ -329,3 +346,200 @@ func validateAuxiliaryNameUnique() process.AuxiliaryHook {
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// getWorkflowAndPolicySuppliedParams returns a set of parameter keys that will be
|
||||
// supplied by workflow steps or override policies at runtime.
|
||||
func getWorkflowAndPolicySuppliedParams(app *Appfile) map[string]bool {
|
||||
result := make(map[string]bool)
|
||||
|
||||
// Collect from workflow step inputs
|
||||
for _, step := range app.WorkflowSteps {
|
||||
for _, in := range step.Inputs {
|
||||
result[in.ParameterKey] = true
|
||||
}
|
||||
}
|
||||
|
||||
// Collect from override policies
|
||||
for _, p := range app.Policies {
|
||||
if p.Type != "override" {
|
||||
continue
|
||||
}
|
||||
|
||||
var spec overrideSpec
|
||||
if err := json.Unmarshal(p.Properties.Raw, &spec); err != nil {
|
||||
continue // Skip if we can't parse
|
||||
}
|
||||
|
||||
for _, c := range spec.Components {
|
||||
if len(c.Properties) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
flat, err := flatten.Flatten(c.Properties, "", flatten.DotStyle)
|
||||
if err != nil {
|
||||
continue // Skip if we can't flatten
|
||||
}
|
||||
|
||||
for k := range flat {
|
||||
result[k] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// getDefaultForMissingParameter checks if a parameter can be defaulted for validation
|
||||
// and returns an appropriate placeholder value.
|
||||
func getDefaultForMissingParameter(v cue.Value) (bool, any) {
|
||||
if v.IsConcrete() {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if defaultVal, hasDefault := v.Default(); hasDefault {
|
||||
return true, defaultVal
|
||||
}
|
||||
|
||||
// Use Expr() to inspect the operation tree for complex validation
|
||||
op, args := v.Expr()
|
||||
|
||||
switch op {
|
||||
case cue.NoOp, cue.SelectorOp:
|
||||
// No operation or field selector - simple type
|
||||
// Use IncompleteKind for non-concrete values to get the correct type
|
||||
return true, getTypeDefault(v.IncompleteKind())
|
||||
|
||||
case cue.AndOp:
|
||||
// Conjunction (e.g., int & >0 & <100)
|
||||
if len(args) > 1 {
|
||||
// Check if any arg is NOT just a basic kind (indicates complex validation)
|
||||
for _, arg := range args {
|
||||
if arg.Kind() == cue.BottomKind {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, getTypeDefault(v.IncompleteKind())
|
||||
|
||||
case cue.OrOp:
|
||||
// Disjunction (e.g., "value1" | "value2" | "value3") - likely an enum
|
||||
if len(args) > 0 {
|
||||
firstVal := args[0]
|
||||
if firstVal.IsConcrete() {
|
||||
var result any
|
||||
if err := firstVal.Decode(&result); err == nil {
|
||||
return true, result
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
|
||||
default:
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// getTypeDefault returns a simple default value based on the CUE Kind.
|
||||
func getTypeDefault(kind cue.Kind) any {
|
||||
switch kind {
|
||||
case cue.StringKind:
|
||||
return "__workflow_supplied__"
|
||||
case cue.FloatKind:
|
||||
return 0.0
|
||||
case cue.IntKind, cue.NumberKind:
|
||||
return 0
|
||||
case cue.BoolKind:
|
||||
return false
|
||||
case cue.ListKind:
|
||||
return []any{}
|
||||
case cue.StructKind:
|
||||
return map[string]any{}
|
||||
default:
|
||||
return "__workflow_supplied__"
|
||||
}
|
||||
}
|
||||
|
||||
// augmentComponentParamsForValidation checks if workflow-supplied parameters
|
||||
// need to be augmented for trait validation. Returns (shouldSkip, augmentedParams).
|
||||
// If shouldSkip=true, the component has complex validation and should skip trait validation.
|
||||
// If shouldSkip=false, augmentedParams contains the original params plus simple defaults.
|
||||
func (p *Parser) augmentComponentParamsForValidation(wl *Component, workflowParams map[string]bool, ctxData velaprocess.ContextData) (bool, map[string]any) {
|
||||
// Build CUE value to inspect the component's parameter schema
|
||||
ctx := velaprocess.NewContext(ctxData)
|
||||
baseCtx, err := ctx.BaseContextFile()
|
||||
if err != nil {
|
||||
return false, wl.Params // Can't inspect, proceed normally
|
||||
}
|
||||
|
||||
paramSnippet, err := cueParamBlock(wl.Params)
|
||||
if err != nil {
|
||||
return false, wl.Params
|
||||
}
|
||||
|
||||
cueSrc := strings.Join([]string{
|
||||
renderTemplate(wl.FullTemplate.TemplateStr),
|
||||
paramSnippet,
|
||||
baseCtx,
|
||||
}, "\n")
|
||||
|
||||
val, err := cuex.DefaultCompiler.Get().CompileString(ctx.GetCtx(), cueSrc)
|
||||
if err != nil {
|
||||
return false, wl.Params // Can't compile, proceed normally
|
||||
}
|
||||
|
||||
// Get the parameter schema
|
||||
paramVal := val.LookupPath(value.FieldPath(velaprocess.ParameterFieldName))
|
||||
|
||||
// Collect default values for workflow-supplied params that are missing
|
||||
workflowParamDefaults := make(map[string]any)
|
||||
|
||||
for paramKey := range workflowParams {
|
||||
// Skip if already provided
|
||||
if _, exists := wl.Params[paramKey]; exists {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check the field in the schema
|
||||
fieldVal := paramVal.LookupPath(cue.ParsePath(paramKey))
|
||||
if !fieldVal.Exists() {
|
||||
continue // Not a parameter field
|
||||
}
|
||||
|
||||
canDefault, defaultVal := getDefaultForMissingParameter(fieldVal)
|
||||
if !canDefault {
|
||||
// complex validation - skip
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if defaultVal != nil {
|
||||
workflowParamDefaults[paramKey] = defaultVal
|
||||
}
|
||||
}
|
||||
|
||||
if len(workflowParamDefaults) == 0 {
|
||||
return false, wl.Params
|
||||
}
|
||||
|
||||
// Create augmented params map
|
||||
augmented := make(map[string]any)
|
||||
for k, v := range wl.Params {
|
||||
augmented[k] = v
|
||||
}
|
||||
for k, v := range workflowParamDefaults {
|
||||
augmented[k] = v
|
||||
}
|
||||
|
||||
fmt.Printf("INFO: Augmented component %q with workflow-supplied defaults for trait validation: %v\n",
|
||||
wl.Name, getMapKeys(workflowParamDefaults))
|
||||
|
||||
return false, augmented
|
||||
}
|
||||
|
||||
// getMapKeys returns the keys from a map as a slice
|
||||
func getMapKeys(m map[string]any) []string {
|
||||
keys := make([]string, 0, len(m))
|
||||
for k := range m {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user