Compare commits

..

5 Commits

Author SHA1 Message Date
Brian Kane
a2fe0b9fdc Fix: Backport commits to 1.10 (#7040) 2026-02-12 09:09:48 -08:00
github-actions[bot]
217a71e598 Fix: 7018 Ensure Component removals are correctly persisted and reflected in status (#7027) (#7029)
(cherry picked from commit 555e4416f4)

Signed-off-by: Brian Kane <briankane1@gmail.com>
Co-authored-by: Brian Kane <briankane1@gmail.com>
2026-02-09 05:12:32 -08:00
github-actions[bot]
bbbdd0d299 Fix: Enhance shared resource handling to avoid last-applied-configuration pollution (#6998) (#7001)
Some checks failed
Webhook Upgrade Validation / webhook-upgrade-check (push) Failing after 16m4s
(cherry picked from commit 552764d48f)

Signed-off-by: Brian Kane <briankane1@gmail.com>
Co-authored-by: Ayush Kumar <65535504+roguepikachu@users.noreply.github.com>
2025-11-26 08:06:58 -08:00
github-actions[bot]
f89622eec7 Fix: Fix issue with imports/packages in status validations (#6963) (#6971)
(cherry picked from commit 8e3749f970)

Signed-off-by: Brian Kane <briankane1@gmail.com>
Co-authored-by: Brian Kane <briankane1@gmail.com>
2025-11-06 18:56:43 -08:00
Ayush Kumar
8401ff4d85 Fix: Prevent namespace admins from accessing vela-system definitions without explicit permissions (#6967)
* fix: webhook validation to check definition existence in namespaces and privilege checks

Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com>
Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

* fix: make reviewable changes

Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

* Update Ingress API version and enhance output validation tests

- Changed Ingress API version from v1beta1 to v1 in multiple test files to align with Kubernetes API updates.
- Added pathType specification to Ingress rules for better compatibility.
- Introduced a new e2e test for validating outputs in ComponentDefinition, TraitDefinition, PolicyDefinition, and WorkflowStepDefinition, ensuring proper handling of valid and invalid resources.
- Enhanced existing tests to check for non-existent CRDs in outputs and validate definitions with mixed valid and invalid resources.

Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

* fix: update comment for expected error count in definition permissions test

Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

* fix: improve error handling message in definitionExistsInNamespace function

Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

* fix: enhance definition permission checks and add corresponding test cases

Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

* fix: clarify comment for definition permission check in ValidateComponents

Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

* fix: add existing definitions to validation permissions tests for improved coverage

Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>

---------

Signed-off-by: Reetika Malhotra <malhotra.reetika25@gmail.com>
Signed-off-by: Ayush Kumar <ayushshyamkumar888@gmail.com>
Co-authored-by: Reetika Malhotra <malhotra.reetika25@gmail.com>
2025-11-06 06:31:05 -08:00
358 changed files with 5447 additions and 60321 deletions

30
.github/CODEOWNERS vendored
View File

@@ -1,35 +1,35 @@
# This file is a github code protect rule follow the codeowners https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners#example-of-a-codeowners-file
* @barnettZQG @wonderflow @leejanee @Somefive @jefree-cat @FogDong @wangyikewxgm @chivalryq @anoop2811 @briankane @jguionnet
design/ @barnettZQG @leejanee @wonderflow @Somefive @jefree-cat @FogDong @anoop2811 @briankane @jguionnet
* @barnettZQG @wonderflow @leejanee @Somefive @jefree-cat @FogDong @wangyikewxgm @chivalryq @anoop2811
design/ @barnettZQG @leejanee @wonderflow @Somefive @jefree-cat @FogDong @anoop2811
# Owner of Core Controllers
pkg/controller/core.oam.dev @Somefive @FogDong @barnettZQG @wonderflow @wangyikewxgm @chivalryq @anoop2811 @briankane @jguionnet
pkg/controller/core.oam.dev @Somefive @FogDong @barnettZQG @wonderflow @wangyikewxgm @chivalryq @anoop2811
# Owner of Standard Controllers
pkg/controller/standard.oam.dev @wangyikewxgm @barnettZQG @wonderflow @Somefive @anoop2811 @FogDong @briankane @jguionnet
pkg/controller/standard.oam.dev @wangyikewxgm @barnettZQG @wonderflow @Somefive @anoop2811 @FogDong
# Owner of CUE
pkg/cue @leejanee @FogDong @Somefive @anoop2811 @briankane @jguionnet
pkg/stdlib @leejanee @FogDong @Somefive @anoop2811 @briankane @jguionnet
pkg/cue @leejanee @FogDong @Somefive @anoop2811
pkg/stdlib @leejanee @FogDong @Somefive @anoop2811
# Owner of Workflow
pkg/workflow @leejanee @FogDong @Somefive @wangyikewxgm @chivalryq @anoop2811 @briankane @jguionnet
pkg/workflow @leejanee @FogDong @Somefive @wangyikewxgm @chivalryq @anoop2811
# Owner of vela templates
vela-templates/ @Somefive @barnettZQG @wonderflow @FogDong @wangyikewxgm @chivalryq @anoop2811 @briankane @jguionnet
vela-templates/ @Somefive @barnettZQG @wonderflow @FogDong @wangyikewxgm @chivalryq @anoop2811
# Owner of vela CLI
references/cli/ @Somefive @StevenLeiZhang @charlie0129 @wangyikewxgm @chivalryq @anoop2811 @FogDong @briankane @jguionnet
references/cli/ @Somefive @StevenLeiZhang @charlie0129 @wangyikewxgm @chivalryq @anoop2811 @FogDong
# Owner of vela addon framework
pkg/addon/ @wangyikewxgm @wonderflow @charlie0129 @anoop2811 @FogDong @briankane @jguionnet
pkg/addon/ @wangyikewxgm @wonderflow @charlie0129 @anoop2811 @FogDong
# Owner of resource keeper and tracker
pkg/resourcekeeper @Somefive @FogDong @chivalryq @anoop2811 @briankane @jguionnet
pkg/resourcetracker @Somefive @FogDong @chivalryq @anoop2811 @briankane @jguionnet
pkg/resourcekeeper @Somefive @FogDong @chivalryq @anoop2811
pkg/resourcetracker @Somefive @FogDong @chivalryq @anoop2811
.github/ @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811 @briankane @jguionnet
makefiles @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811 @briankane @jguionnet
go.* @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811 @briankane @jguionnet
.github/ @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811
makefiles @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811
go.* @chivalryq @wonderflow @Somefive @FogDong @wangyikewxgm @anoop2811

View File

@@ -19,10 +19,6 @@ runs:
# ========================================================================
- name: Configure environment setup
uses: ./.github/actions/env-setup
with:
install-ginkgo: 'true'
install-setup-envtest: 'false'
install-kustomize: 'false'
- name: Build project
shell: bash

View File

@@ -1,27 +1,11 @@
name: 'Kubevela Test Environment Setup'
description: 'Sets up complete testing environment for Kubevela with Go, Kubernetes tools, and testing frameworks.'
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'
install-ginkgo:
description: 'Install Ginkgo testing framework'
required: false
default: 'true'
install-setup-envtest:
description: 'Install setup-envtest for integration testing'
required: false
default: 'false'
install-kustomize:
description: 'Install kustomize for manifest management'
required: false
default: 'false'
kustomize-version:
description: 'Kustomize version to install'
required: false
default: '4.5.4'
runs:
@@ -48,22 +32,20 @@ runs:
run: |
# Detect architecture
ARCH=$(uname -m | sed 's/x86_64/amd64/' | sed 's/aarch64/arm64/')
# Install kubectl using a known stable version to avoid network issues
# The dl.k8s.io/release/stable.txt endpoint can return garbage due to CDN issues
KUBECTL_VERSION="v1.31.0"
echo "Installing kubectl version: $KUBECTL_VERSION for architecture: $ARCH"
curl -LO --retry 3 --fail "https://dl.k8s.io/release/${KUBECTL_VERSION}/bin/linux/${ARCH}/kubectl"
# 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
# Install helm using the official script (more reliable)
echo "Installing Helm using official script..."
curl -fsSL --retry 3 -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3
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
@@ -84,37 +66,7 @@ runs:
go mod verify
- name: Install Ginkgo testing framework
if: ${{ inputs.install-ginkgo == 'true' }}
shell: bash
run: |
echo "Installing Ginkgo testing framework..."
go install github.com/onsi/ginkgo/v2/ginkgo@v2.14.0
echo "Ginkgo installed successfully"
- name: Install setup-envtest
if: ${{ inputs.install-setup-envtest == 'true' }}
shell: bash
run: |
echo "Installing setup-envtest for integration testing..."
mkdir -p ./bin
GOBIN=$(pwd)/bin go install sigs.k8s.io/controller-runtime/tools/setup-envtest@v0.0.0-20240522175850-2e9781e9fc60
echo "setup-envtest installed successfully at ./bin/setup-envtest"
ls -la ./bin/setup-envtest
# Download and cache the Kubernetes binaries for envtest
echo "Downloading Kubernetes binaries for envtest..."
KUBEBUILDER_ASSETS=$(./bin/setup-envtest use 1.31.0 --bin-dir ./bin -p path)
echo "Kubernetes binaries downloaded successfully"
echo "KUBEBUILDER_ASSETS=${KUBEBUILDER_ASSETS}"
# Export for subsequent steps
echo "KUBEBUILDER_ASSETS=${KUBEBUILDER_ASSETS}" >> $GITHUB_ENV
- name: Install kustomize
if: ${{ inputs.install-kustomize == 'true' }}
shell: bash
run: |
echo "Installing kustomize version ${{ inputs.kustomize-version }}..."
mkdir -p ./bin
curl -sS https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh | bash -s ${{ inputs.kustomize-version }} $(pwd)/bin
echo "kustomize installed successfully at ./bin/kustomize"
./bin/kustomize version

View File

@@ -20,10 +20,6 @@ runs:
# ========================================================================
- name: Configure environment setup
uses: ./.github/actions/env-setup
with:
install-ginkgo: 'true'
install-setup-envtest: 'false'
install-kustomize: 'false'
# ========================================================================
# E2E Test Execution

View File

@@ -19,10 +19,6 @@ runs:
# ========================================================================
- name: Configure environment setup
uses: ./.github/actions/env-setup
with:
install-ginkgo: 'true'
install-setup-envtest: 'true'
install-kustomize: 'true'
# ========================================================================
# Unit Test Execution

View File

@@ -11,7 +11,4 @@ wangyuan249
chivalryq
FogDong
leejanee
barnettZQG
anoop2811
briankane
jguionnet
barnettZQG

View File

@@ -97,21 +97,6 @@ jobs:
with:
submodules: true
- name: Free Disk Space
run: |
echo "Disk space before cleanup:"
df -h
# Remove unnecessary software to free up disk space
sudo rm -rf /usr/share/dotnet
sudo rm -rf /usr/local/lib/android
sudo rm -rf /opt/ghc
sudo rm -rf /opt/hostedtoolcache/CodeQL
sudo docker image prune --all --force
echo "Disk space after cleanup:"
df -h
- name: Setup Env
uses: ./.github/actions/env-setup
@@ -126,24 +111,6 @@ jobs:
- name: Run cross-build
run: make cross-build
- name: Free Disk Space After Cross-Build
run: |
echo "Disk space before cleanup:"
df -h
# Remove cross-build artifacts to free up space
# (make build will rebuild binaries for current platform)
rm -rf _bin
# Clean Go build cache and test cache
go clean -cache -testcache
# Remove Docker build cache
sudo docker builder prune --all --force || true
echo "Disk space after cleanup:"
df -h
- name: Check Diff
run: |
export PATH=$(pwd)/bin/:$PATH

View File

@@ -111,9 +111,16 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
- name: Update kubectl plugin version in krew-index
uses: rajatjindal/krew-release-bot@df3eb197549e3568be8b4767eec31c5e8e8e6ad8 # v0.0.46
- name: Update Homebrew formula
uses: dawidd6/action-homebrew-bump-formula@d3667e5ae14df19579e4414897498e3e88f2f458 # v3.10.0
with:
token: ${{ secrets.HOMEBREW_TOKEN }}
formula: kubevela
tag: ${{ github.ref }}
revision: ${{ github.sha }}
force: false
provenance-vela-bins:
name: generate provenance for binaries

View File

@@ -28,15 +28,10 @@ jobs:
- name: Install Go tools
run: |
make goimports
- name: Build CLI
run: make vela-cli
- name: Setup KinD
uses: ./.github/actions/setup-kind-cluster
with:
name: sync-sdk
- name: Get the version
id: get_version
run: echo "VERSION=${GITHUB_REF}" >> $GITHUB_OUTPUT

View File

@@ -29,7 +29,7 @@ linters-settings:
gocyclo:
# minimal code complexity to report, 30 by default (but we recommend 10-20)
min-complexity: 35
min-complexity: 30
dupl:
@@ -144,14 +144,6 @@ issues:
linters:
- gocritic
# The preferFprint suggestion (sb.WriteString(fmt.Sprintf(...)) -> fmt.Fprintf(sb, ...))
# is a micro-optimization. The defkit package generates CUE code infrequently,
# so the performance difference is negligible and the current style is more readable.
- path: pkg/definition/defkit/
text: "preferFprint"
linters:
- gocritic
# Gosmopolitan complains of internationalization issues on the file that actually defines
# the translation.
- path: i18n\.go

View File

@@ -230,7 +230,7 @@ spec:
1. Workflow support specify Order Steps by Field Tag (#2022)
2. support application policy (#2011)
3. add OCM multi cluster demo (#1992)
4. Fix(volume): separate volume to trait (#2027)
4. Fix(volume): seperate volume to trait (#2027)
5. allow application skip gc resource and leave workload ownerReference controlled by rollout(#2024)
6. Store component parameters in context (#2030)
7. Allow specify chart values for helm trait(#2033)

View File

@@ -64,8 +64,8 @@ lint: golangci
@GOLANGCILINT=$(GOLANGCILINT) ./hack/utils/golangci-lint-wrapper.sh
## reviewable: Run the reviewable
## Run make build to compile vela binary before running this target to ensure all generated definitions are up to date.
reviewable: build manifests fmt vet lint staticcheck helm-doc-gen sdk_fmt
reviewable: manifests fmt vet lint staticcheck helm-doc-gen sdk_fmt
go mod tidy
# check-diff: Execute auto-gen code commands and ensure branch is clean.
check-diff: reviewable
@@ -103,7 +103,7 @@ manager:
$(GOBUILD_ENV) go build -o bin/manager -a -ldflags $(LDFLAGS) ./cmd/core/main.go
## manifests: Generate manifests e.g. CRD, RBAC etc.
manifests: tidy installcue kustomize sync-crds
manifests: installcue kustomize
go generate $(foreach t,pkg apis,./$(t)/...)
# TODO(yangsoon): kustomize will merge all CRD into a whole file, it may not work if we want patch more than one CRD in this way
$(KUSTOMIZE) build config/crd -o config/crd/base/core.oam.dev_applications.yaml

View File

@@ -107,7 +107,7 @@ Check out [KubeVela videos](https://kubevela.io/videos/talks/en/oam-dapr) for th
## Contributing
Check out [CONTRIBUTING](https://kubevela.io/docs/contributor/overview) to see how to develop with KubeVela
Check out [CONTRIBUTING](https://kubevela.io/docs/contributor/overview) to see how to develop with KubeVela.
## Report Vulnerability

View File

@@ -26,7 +26,6 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
wfTypesv1alpha1 "github.com/kubevela/pkg/apis/oam/v1alpha1"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
@@ -174,15 +173,12 @@ type ApplicationComponentStatus struct {
Cluster string `json:"cluster,omitempty"`
Env string `json:"env,omitempty"`
// WorkloadDefinition is the definition of a WorkloadDefinition, such as deployments/apps.v1
WorkloadDefinition WorkloadGVK `json:"workloadDefinition,omitempty"`
Healthy bool `json:"healthy"`
// WorkloadHealthy indicates the workload health without considering trait health.
// +optional
WorkloadHealthy bool `json:"workloadHealthy,omitempty"`
Details map[string]string `json:"details,omitempty"`
Message string `json:"message,omitempty"`
Traits []ApplicationTraitStatus `json:"traits,omitempty"`
Scopes []corev1.ObjectReference `json:"scopes,omitempty"`
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"`
}
// Equal check if two ApplicationComponentStatus are equal
@@ -195,7 +191,6 @@ func (in ApplicationComponentStatus) Equal(r ApplicationComponentStatus) bool {
type ApplicationTraitStatus struct {
Type string `json:"type"`
Healthy bool `json:"healthy"`
Pending bool `json:"pending,omitempty"`
Details map[string]string `json:"details,omitempty"`
Message string `json:"message,omitempty"`
}
@@ -230,12 +225,6 @@ type AppStatus struct {
// Workflow record the status of workflow
Workflow *WorkflowStatus `json:"workflow,omitempty"`
// WorkflowRestartScheduledAt schedules a workflow restart at the specified time.
// This field is automatically set when the app.oam.dev/restart-workflow annotation is present,
// and is cleared after the restart is triggered. Use RFC3339 format or set to current time for immediate restart.
// +optional
WorkflowRestartScheduledAt *metav1.Time `json:"workflowRestartScheduledAt,omitempty"`
// LatestRevision of the application configuration it generates
// +optional
LatestRevision *Revision `json:"latestRevision,omitempty"`
@@ -312,9 +301,9 @@ type ApplicationComponent struct {
// +kubebuilder:pruning:PreserveUnknownFields
Properties *runtime.RawExtension `json:"properties,omitempty"`
DependsOn []string `json:"dependsOn,omitempty"`
Inputs wfTypesv1alpha1.StepInputs `json:"inputs,omitempty"`
Outputs wfTypesv1alpha1.StepOutputs `json:"outputs,omitempty"`
DependsOn []string `json:"dependsOn,omitempty"`
Inputs workflowv1alpha1.StepInputs `json:"inputs,omitempty"`
Outputs workflowv1alpha1.StepOutputs `json:"outputs,omitempty"`
// Traits define the trait of one component, the type must be array to keep the order.
Traits []ApplicationTrait `json:"traits,omitempty"`

View File

@@ -21,7 +21,6 @@ limitations under the License.
package common
import (
oamv1alpha1 "github.com/kubevela/pkg/apis/oam/v1alpha1"
"github.com/kubevela/workflow/api/v1alpha1"
crossplane_runtime "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
v1 "k8s.io/api/core/v1"
@@ -49,10 +48,6 @@ func (in *AppStatus) DeepCopyInto(out *AppStatus) {
*out = new(WorkflowStatus)
(*in).DeepCopyInto(*out)
}
if in.WorkflowRestartScheduledAt != nil {
in, out := &in.WorkflowRestartScheduledAt, &out.WorkflowRestartScheduledAt
*out = (*in).DeepCopy()
}
if in.LatestRevision != nil {
in, out := &in.LatestRevision, &out.LatestRevision
*out = new(Revision)
@@ -97,12 +92,12 @@ func (in *ApplicationComponent) DeepCopyInto(out *ApplicationComponent) {
}
if in.Inputs != nil {
in, out := &in.Inputs, &out.Inputs
*out = make(oamv1alpha1.StepInputs, len(*in))
*out = make(v1alpha1.StepInputs, len(*in))
copy(*out, *in)
}
if in.Outputs != nil {
in, out := &in.Outputs, &out.Outputs
*out = make(oamv1alpha1.StepOutputs, len(*in))
*out = make(v1alpha1.StepOutputs, len(*in))
copy(*out, *in)
}
if in.Traits != nil {

View File

@@ -21,7 +21,7 @@ import (
k8sscheme "k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/scheme"
wfTypesv1alpha1 "github.com/kubevela/pkg/apis/oam/v1alpha1"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
)
@@ -57,7 +57,7 @@ var (
func init() {
SchemeBuilder.Register(&Policy{}, &PolicyList{})
SchemeBuilder.Register(&wfTypesv1alpha1.Workflow{}, &wfTypesv1alpha1.WorkflowList{})
SchemeBuilder.Register(&workflowv1alpha1.Workflow{}, &workflowv1alpha1.WorkflowList{})
_ = SchemeBuilder.AddToScheme(k8sscheme.Scheme)
}

View File

@@ -23,7 +23,7 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
wfTypesv1alpha1 "github.com/kubevela/pkg/apis/oam/v1alpha1"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
@@ -42,9 +42,9 @@ type AppPolicy struct {
// Workflow defines workflow steps and other attributes
type Workflow struct {
Ref string `json:"ref,omitempty"`
Mode *wfTypesv1alpha1.WorkflowExecuteMode `json:"mode,omitempty"`
Steps []wfTypesv1alpha1.WorkflowStep `json:"steps,omitempty"`
Ref string `json:"ref,omitempty"`
Mode *workflowv1alpha1.WorkflowExecuteMode `json:"mode,omitempty"`
Steps []workflowv1alpha1.WorkflowStep `json:"steps,omitempty"`
}
// ApplicationSpec is the spec of Application

View File

@@ -19,8 +19,8 @@ package v1beta1
import (
"encoding/json"
wfTypesv1alpha1 "github.com/kubevela/pkg/apis/oam/v1alpha1"
"github.com/kubevela/pkg/util/compression"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
@@ -63,7 +63,7 @@ type ApplicationRevisionCompressibleFields struct {
Policies map[string]v1alpha1.Policy `json:"policies,omitempty"`
// Workflow records the external workflow
Workflow *wfTypesv1alpha1.Workflow `json:"workflow,omitempty"`
Workflow *workflowv1alpha1.Workflow `json:"workflow,omitempty"`
// ReferredObjects records the referred objects used in the ref-object typed components
// +kubebuilder:pruning:PreserveUnknownFields

View File

@@ -21,7 +21,7 @@ limitations under the License.
package v1beta1
import (
"github.com/kubevela/pkg/apis/oam/v1alpha1"
"github.com/kubevela/workflow/api/v1alpha1"
"k8s.io/apimachinery/pkg/runtime"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"

View File

@@ -148,15 +148,6 @@ const (
// TypeLegacy defines legacy commands
TypeLegacy = "Legacy Commands"
// TypeDefManagement defines definition management commands
TypeDefManagement = "Definition Management"
// TypeDefGeneration defines definition generation commands
TypeDefGeneration = "Code Generation"
// TypeDefModule defines Go definition module commands
TypeDefModule = "Go Definition Modules"
)
// LabelArg is the argument `label` of a definition

View File

@@ -151,7 +151,6 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
| `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` |
| `admissionWebhookTimeout` | Timeout seconds for admission webhooks | `10` |
| `kubeClient.qps` | The qps for reconcile clients | `400` |
| `kubeClient.burst` | The burst for reconcile clients | `600` |
| `authentication.enabled` | Enable authentication framework for applications | `false` |

View File

@@ -632,8 +632,6 @@ spec:
type: boolean
message:
type: string
pending:
type: boolean
type:
type: string
required:
@@ -653,10 +651,6 @@ spec:
- apiVersion
- kind
type: object
workloadHealthy:
description: WorkloadHealthy indicates the workload
health without considering trait health.
type: boolean
required:
- healthy
- name
@@ -823,13 +817,6 @@ spec:
- suspend
- terminated
type: object
workflowRestartScheduledAt:
description: |-
WorkflowRestartScheduledAt schedules a workflow restart at the specified time.
This field is automatically set when the app.oam.dev/restart-workflow annotation is present,
and is cleared after the restart is triggered. Use RFC3339 format or set to current time for immediate restart.
format: date-time
type: string
type: object
type: object
componentDefinitions:

View File

@@ -580,8 +580,6 @@ spec:
type: boolean
message:
type: string
pending:
type: boolean
type:
type: string
required:
@@ -601,10 +599,6 @@ spec:
- apiVersion
- kind
type: object
workloadHealthy:
description: WorkloadHealthy indicates the workload health without
considering trait health.
type: boolean
required:
- healthy
- name
@@ -766,13 +760,6 @@ spec:
- suspend
- terminated
type: object
workflowRestartScheduledAt:
description: |-
WorkflowRestartScheduledAt schedules a workflow restart at the specified time.
This field is automatically set when the app.oam.dev/restart-workflow annotation is present,
and is cleared after the restart is triggered. Use RFC3339 format or set to current time for immediate restart.
format: date-time
type: string
type: object
type: object
served: true

View File

@@ -3,7 +3,8 @@ apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.16.5
controller-gen.kubebuilder.io/version: v0.9.0
creationTimestamp: null
name: workflows.core.oam.dev
spec:
group: core.oam.dev
@@ -22,19 +23,14 @@ spec:
description: Workflow is the Schema for the workflow API
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
@@ -63,7 +59,6 @@ spec:
inputs:
description: Inputs is the inputs of the step
items:
description: InputItem defines an input variable of WorkflowStep
properties:
from:
type: string
@@ -71,6 +66,7 @@ spec:
type: string
required:
- from
- parameterKey
type: object
type: array
meta:
@@ -79,18 +75,12 @@ spec:
alias:
type: string
type: object
mode:
description: Mode is only valid for sub steps, it defines the mode
of the sub steps
nullable: true
type: string
name:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: Outputs is the outputs of the step
items:
description: OutputItem defines an output variable of WorkflowStep
properties:
name:
type: string
@@ -120,7 +110,6 @@ spec:
inputs:
description: Inputs is the inputs of the step
items:
description: InputItem defines an input variable of WorkflowStep
properties:
from:
type: string
@@ -128,6 +117,7 @@ spec:
type: string
required:
- from
- parameterKey
type: object
type: array
meta:
@@ -142,7 +132,6 @@ spec:
outputs:
description: Outputs is the outputs of the step
items:
description: OutputItem defines an output variable of WorkflowStep
properties:
name:
type: string
@@ -164,6 +153,7 @@ spec:
description: Type is the type of the workflow step.
type: string
required:
- name
- type
type: object
type: array
@@ -174,6 +164,7 @@ spec:
description: Type is the type of the workflow step.
type: string
required:
- name
- type
type: object
type: array

View File

@@ -45,7 +45,6 @@ webhooks:
- UPDATE
resources:
- applications
timeoutSeconds: {{ .Values.admissionWebhookTimeout }}
- clientConfig:
caBundle: {{ default "Cg==" (get $vals "comps") }}
service:
@@ -72,6 +71,5 @@ webhooks:
- UPDATE
resources:
- componentdefinitions
timeoutSeconds: {{ .Values.admissionWebhookTimeout }}
{{- end -}}

View File

@@ -47,7 +47,7 @@ webhooks:
- UPDATE
resources:
- traitdefinitions
timeoutSeconds: {{ .Values.admissionWebhookTimeout }}
timeoutSeconds: 5
- clientConfig:
caBundle: {{ default "Cg==" (get $vals "apps") }}
service:
@@ -74,7 +74,6 @@ webhooks:
- UPDATE
resources:
- applications
timeoutSeconds: {{ .Values.admissionWebhookTimeout }}
- clientConfig:
caBundle: {{ default "Cg==" (get $vals "comps") }}
service:
@@ -101,7 +100,6 @@ webhooks:
- UPDATE
resources:
- componentdefinitions
timeoutSeconds: {{ .Values.admissionWebhookTimeout }}
- clientConfig:
caBundle: {{ default "Cg==" (get $vals "policies") }}
service:
@@ -128,7 +126,6 @@ webhooks:
- UPDATE
resources:
- policydefinitions
timeoutSeconds: {{ .Values.admissionWebhookTimeout }}
- clientConfig:
caBundle: Cg==
service:
@@ -155,5 +152,4 @@ webhooks:
- UPDATE
resources:
- workflowstepdefinitions
timeoutSeconds: {{ .Values.admissionWebhookTimeout }}
{{- end -}}

View File

@@ -15,7 +15,9 @@ spec:
schematic:
cue:
template: |
import "vela/op"
import (
"vela/op"
)
output: op.#ApplyApplicationInParallel & {}

View File

@@ -16,7 +16,9 @@ spec:
schematic:
cue:
template: |
import "vela/op"
import (
"vela/op"
)
// apply application
output: op.#ApplyApplication & {}

View File

@@ -13,8 +13,12 @@ spec:
schematic:
cue:
template: |
import "vela/kube"
import "vela/builtin"
import (
"strconv"
"strings"
"vela/kube"
"vela/builtin"
)
output: kube.#Apply & {
$params: {

View File

@@ -12,7 +12,9 @@ spec:
schematic:
cue:
template: |
import "vela/kube"
import (
"vela/kube"
)
apply: kube.#Apply & {
$params: parameter

View File

@@ -16,7 +16,9 @@ spec:
schematic:
cue:
template: |
import "vela/op"
import (
"vela/op"
)
// apply remaining components and traits
apply: op.#ApplyRemaining & {

View File

@@ -13,8 +13,10 @@ spec:
schematic:
cue:
template: |
import "vela/kube"
import "vela/builtin"
import (
"vela/kube"
"vela/builtin"
)
apply: kube.#Apply & {
$params: value: {

View File

@@ -13,9 +13,12 @@ spec:
schematic:
cue:
template: |
import "vela/config"
import "vela/kube"
import "vela/builtin"
import (
"vela/config"
"vela/kube"
"vela/builtin"
"strings"
)
cfg: config.#CreateConfig & {
$params: {
@@ -84,9 +87,9 @@ spec:
}
}
providerBasic: {
accessKey!: string
secretKey!: string
region!: string
accessKey: string
secretKey: string
region: string
}
#AlibabaProvider: {
providerBasic
@@ -138,5 +141,5 @@ spec:
type: "ucloud"
name: *"ucloud-provider" | string
}
parameter: #AlibabaProvider | #AWSProvider | #AzureProvider | #BaiduProvider | #ECProvider | #GCPProvider | #TencentProvider | #UCloudProvider
parameter: *#AlibabaProvider | #AWSProvider | #AzureProvider | #BaiduProvider | #ECProvider | #GCPProvider | #TencentProvider | #UCloudProvider

View File

@@ -13,10 +13,13 @@ spec:
schematic:
cue:
template: |
import "vela/builtin"
import "vela/kube"
import "vela/util"
import "strings"
import (
"vela/builtin"
"vela/kube"
"vela/util"
"encoding/json"
"strings"
)
url: {
if parameter.context.git != _|_ {

View File

@@ -14,8 +14,10 @@ spec:
schematic:
cue:
template: |
import "vela/metrics"
import "vela/builtin"
import (
"vela/metrics"
"vela/builtin"
)
check: metrics.#PromCheck & {
$params: {

View File

@@ -12,7 +12,9 @@ spec:
schematic:
cue:
template: |
import "vela/kube"
import (
"vela/kube"
)
parameter: {
labelselector?: {...}

View File

@@ -12,9 +12,11 @@ spec:
schematic:
cue:
template: |
import "vela/builtin"
import "vela/query"
import "strconv"
import (
"vela/builtin"
"vela/query"
"strconv"
)
collect: query.#CollectServiceEndpoints & {
$params: app: {

View File

@@ -16,8 +16,6 @@ spec:
schematic:
cue:
template: |
import "list"
#PatchParams: {
// +usage=Specify the name of the target container, if not set, use the component name
containerName: *"" | string
@@ -75,7 +73,7 @@ spec:
}
// +patchStrategy=replace
args: list.Concat([[for a in _args if _delArgs[a] == _|_ {a}], [for a in _addArgs if _delArgs[a] == _|_ && _argsMap[a] == _|_ {a}]])
args: [for a in _args if _delArgs[a] == _|_ {a}] + [for a in _addArgs if _delArgs[a] == _|_ && _argsMap[a] == _|_ {a}]
}
}
// +patchStrategy=open

View File

@@ -17,9 +17,10 @@ spec:
schematic:
cue:
template: |
import "strconv"
import "strings"
import "list"
import (
"strconv"
"strings"
)
#PatchParams: {
// +usage=Specify the name of the target container, if not set, use the component name
@@ -66,7 +67,7 @@ spec:
_basePortsMap: {for _basePort in _basePorts {(strings.ToLower(_basePort.protocol) + strconv.FormatInt(_basePort.containerPort, 10)): _basePort}}
_portsMap: {for port in _params.ports {(strings.ToLower(port.protocol) + strconv.FormatInt(port.containerPort, 10)): port}}
// +patchStrategy=replace
ports: list.Concat([[for portVar in _basePorts {
ports: [for portVar in _basePorts {
containerPort: portVar.containerPort
protocol: portVar.protocol
name: portVar.name
@@ -79,7 +80,7 @@ spec:
hostIP: _portsMap[_uniqueKey].hostIP
}
}
}], [for port in _params.ports if _basePortsMap[strings.ToLower(port.protocol)+strconv.FormatInt(port.containerPort, 10)] == _|_ {
}] + [for port in _params.ports if _basePortsMap[strings.ToLower(port.protocol)+strconv.FormatInt(port.containerPort, 10)] == _|_ {
if port.containerPort != _|_ {
containerPort: port.containerPort
}
@@ -92,7 +93,7 @@ spec:
if port.hostIP != _|_ {
hostIP: port.hostIP
}
}]])
}]
}
}
}

View File

@@ -12,7 +12,9 @@ spec:
schematic:
cue:
template: |
import "vela/config"
import (
"vela/config"
)
deploy: config.#CreateConfig & {
$params: parameter

View File

@@ -11,8 +11,6 @@ spec:
schematic:
cue:
template: |
import "list"
mountsArray: {
pvc: *[
for v in parameter.volumeMounts.pvc {
@@ -132,7 +130,7 @@ spec:
},
] | []
}
volumesList: list.Concat([volumesArray.pvc, volumesArray.configMap, volumesArray.secret, volumesArray.emptyDir, volumesArray.hostPath])
volumesList: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath
deDupVolumesArray: [
for val in [
for i, vi in volumesList {

View File

@@ -11,7 +11,9 @@ spec:
schematic:
cue:
template: |
import "strconv"
import (
"strconv"
)
mountsArray: [
if parameter.volumeMounts != _|_ && parameter.volumeMounts.pvc != _|_ for v in parameter.volumeMounts.pvc {

View File

@@ -12,7 +12,9 @@ spec:
schematic:
cue:
template: |
import "vela/config"
import (
"vela/config"
)
deploy: config.#DeleteConfig & {
$params: parameter

View File

@@ -12,9 +12,11 @@ spec:
schematic:
cue:
template: |
import "vela/kube"
import "vela/builtin"
import "encoding/yaml"
import (
"vela/kube"
"vela/builtin"
"encoding/yaml"
)
dependsOn: kube.#Read & {
$params: value: {

View File

@@ -14,7 +14,9 @@ spec:
schematic:
cue:
template: |
import "vela/op"
import (
"vela/op"
)
app: op.#DeployCloudResource & {
env: parameter.env

View File

@@ -14,9 +14,10 @@ spec:
schematic:
cue:
template: |
import "vela/multicluster"
import "vela/builtin"
import (
"vela/multicluster"
"vela/builtin"
)
if parameter.auto == false {
suspend: builtin.#Suspend & {$params: message: "Waiting approval to the deploy step \"\(context.stepName)\""}

View File

@@ -15,7 +15,9 @@ spec:
schematic:
cue:
template: |
import "vela/op"
import (
"vela/op"
)
app: op.#ApplyEnvBindApp & {
env: parameter.env

View File

@@ -15,7 +15,9 @@ spec:
schematic:
cue:
template: |
import "vela/op"
import (
"vela/op"
)
app: op.#Steps & {
load: op.#Load

View File

@@ -16,8 +16,6 @@ spec:
schematic:
cue:
template: |
import "list"
#PatchParams: {
// +usage=Specify the name of the target container, if not set, use the component name
containerName: *"" | string
@@ -51,7 +49,7 @@ spec:
if _baseEnv != _|_ {
_baseEnvMap: {for envVar in _baseEnv {(envVar.name): envVar}}
// +patchStrategy=replace
env: list.Concat([[for envVar in _baseEnv if _delKeys[envVar.name] == _|_ && !_params.replace {
env: [for envVar in _baseEnv if _delKeys[envVar.name] == _|_ && !_params.replace {
name: envVar.name
if _params.env[envVar.name] != _|_ {
value: _params.env[envVar.name]
@@ -64,10 +62,10 @@ spec:
valueFrom: envVar.valueFrom
}
}
}], [for k, v in _params.env if _delKeys[k] == _|_ && (_params.replace || _baseEnvMap[k] == _|_) {
}] + [for k, v in _params.env if _delKeys[k] == _|_ && (_params.replace || _baseEnvMap[k] == _|_) {
name: k
value: v
}]])
}]
}
}
}

View File

@@ -14,8 +14,10 @@ spec:
schematic:
cue:
template: |
import "vela/op"
import "vela/kube"
import (
"vela/op"
"vela/kube"
)
object: {
apiVersion: "v1"

View File

@@ -14,8 +14,10 @@ spec:
schematic:
cue:
template: |
import "vela/op"
import "vela/kube"
import (
"vela/op"
"vela/kube"
)
meta: {
name: *context.name | string

View File

@@ -12,7 +12,9 @@ spec:
schematic:
cue:
template: |
import "vela/kube"
import (
"vela/kube"
)
apply: kube.#Apply & {
$params: {

View File

@@ -12,9 +12,11 @@ spec:
schematic:
cue:
template: |
import "vela/kube"
import "encoding/base64"
import "encoding/json"
import (
"vela/kube"
"encoding/base64"
"encoding/json"
)
secret: {
data: *parameter.data | {}

View File

@@ -15,8 +15,10 @@ spec:
schematic:
cue:
template: |
import "strconv"
import "strings"
import (
"strconv"
"strings"
)
outputs: service: {
apiVersion: "v1"
@@ -94,17 +96,21 @@ spec:
stage: PostDispatch
status:
customStatus: |-
service: context.outputs.service
message: *"" | string
service: context.outputs.service
if service.spec.type == "ClusterIP" {
message: "ClusterIP: \(service.spec.clusterIP)"
}
if service.spec.type == "LoadBalancer" {
status: service.status
isHealth: *false | bool
message: *"ExternalIP: Pending" | string
if status != _|_ if status.loadBalancer != _|_ if status.loadBalancer.ingress != _|_ if len(status.loadBalancer.ingress) > 0 if status.loadBalancer.ingress[0].ip != _|_ {
isHealth: true
}
if !isHealth {
message: "ExternalIP: Pending"
}
if isHealth {
message: "ExternalIP: \(status.loadBalancer.ingress[0].ip)"
}
}

View File

@@ -17,7 +17,6 @@ spec:
template: |
import "strconv"
let nameSuffix = {
if parameter.name != _|_ {"-" + parameter.name}
if parameter.name == _|_ {""}
@@ -161,17 +160,13 @@ spec:
if parameter.name == _|_ { "" }
}
let ingressMetaName = context.name + nameSuffix
let igList = [for i in context.outputs if (i.kind == "Ingress") && (i.metadata.name == ingressMetaName) {i}]
ig: *_|_ | _
if len(igList) > 0 {
ig: igList[0]
}
let ig = [for i in context.outputs if (i.kind == "Ingress") && (i.metadata.name == ingressMetaName) {i}][0]
igs: *{} | {}
if ig != _|_ if ig.status != _|_ if ig.status.loadbalancer != _|_ if len(ig.status.loadbalancer.ingress) > 0 {
if ig != _|_ if ig.status != _|_ if ig.status.loadbalancer != _|_ {
igs: ig.status.loadbalancer.ingress[0]
}
igr: *{} | {}
if ig != _|_ if ig.spec != _|_ if len(ig.spec.rules) > 0 {
if ig != _|_ if ig.spec != _|_ {
igr: ig.spec.rules[0]
}
if igs == _|_ {

View File

@@ -12,9 +12,11 @@ spec:
schematic:
cue:
template: |
import "vela/kube"
import "vela/util"
import "encoding/base64"
import (
"vela/kube"
"vela/util"
"encoding/base64"
)
output: kube.#Read & {
$params: value: {

View File

@@ -69,16 +69,11 @@ spec:
message: "No loadBalancer found, visiting by using 'vela port-forward " + context.appName + "'\n"
}
if len(igs) > 0 {
let rules = context.outputs.ingress.spec.rules
host: *"" | string
if rules != _|_ if len(rules) > 0 if rules[0].host != _|_ {
host: rules[0].host
}
if igs[0].ip != _|_ {
message: "Visiting URL: " + host + ", IP: " + igs[0].ip
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
}
if igs[0].ip == _|_ {
message: "Visiting URL: " + host
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host
}
}
healthPolicy: 'isHealth: len(context.outputs.service.spec.clusterIP) > 0'

View File

@@ -62,16 +62,11 @@ spec:
message: "No loadBalancer found, visiting by using 'vela port-forward " + context.appName + "'\n"
}
if len(igs) > 0 {
let rules = context.outputs.ingress.spec.rules
host: *"" | string
if rules != _|_ if len(rules) > 0 if rules[0].host != _|_ {
host: rules[0].host
}
if igs[0].ip != _|_ {
message: "Visiting URL: " + host + ", IP: " + igs[0].ip
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
}
if igs[0].ip == _|_ {
message: "Visiting URL: " + host
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host
}
}
healthPolicy: 'isHealth: len(context.outputs.service.spec.clusterIP) > 0'

View File

@@ -17,8 +17,6 @@ spec:
schematic:
cue:
template: |
import "list"
patch: spec: template: spec: {
// +patchKey=name
containers: [{
@@ -45,10 +43,10 @@ spec:
}
// +patchKey=name
volumeMounts: list.Concat([[{
volumeMounts: [{
name: parameter.mountName
mountPath: parameter.initMountPath
}], parameter.extraVolumeMounts])
}] + parameter.extraVolumeMounts
}]
// +patchKey=name
volumes: [{

View File

@@ -11,12 +11,7 @@ spec:
schematic:
cue:
template: |
output: {
if len(parameter.objects) > 0 {
parameter.objects[0]
}
...
}
output: parameter.objects[0]
outputs: {
for i, v in parameter.objects {

View File

@@ -12,7 +12,9 @@ spec:
schematic:
cue:
template: |
import "vela/config"
import (
"vela/config"
)
output: config.#ListConfig & {
$params: parameter

View File

@@ -19,7 +19,9 @@ spec:
schematic:
cue:
template: |
import "encoding/json"
import (
"encoding/json"
)
outputs: nocalhostService: {
apiVersion: "v1"

View File

@@ -12,12 +12,14 @@ spec:
schematic:
cue:
template: |
import "vela/http"
import "vela/email"
import "vela/kube"
import "vela/util"
import "encoding/base64"
import "encoding/json"
import (
"vela/http"
"vela/email"
"vela/kube"
"vela/util"
"encoding/base64"
"encoding/json"
)
parameter: {
// +usage=Please fulfill its url and message if you want to send Lark messages

View File

@@ -12,7 +12,9 @@ spec:
schematic:
cue:
template: |
import "vela/builtin"
import (
"vela/builtin"
)
parameter: message: string

View File

@@ -49,16 +49,11 @@ spec:
message: "No loadBalancer found, visiting by using 'vela port-forward " + context.appName + " --route'\n"
}
if len(igs) > 0 {
let rules = context.outputs.ingress.spec.rules
host: *"" | string
if rules != _|_ if len(rules) > 0 if rules[0].host != _|_ {
host: rules[0].host
}
if igs[0].ip != _|_ {
message: "Visiting URL: " + host + ", IP: " + igs[0].ip
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host + ", IP: " + igs[0].ip
}
if igs[0].ip == _|_ {
message: "Visiting URL: " + host
message: "Visiting URL: " + context.outputs.ingress.spec.rules[0].host
}
}
workloadRefPath: ""

View File

@@ -12,7 +12,9 @@ spec:
schematic:
cue:
template: |
import "vela/config"
import (
"vela/config"
)
output: config.#ReadConfig & {
$params: parameter

View File

@@ -12,7 +12,9 @@ spec:
schematic:
cue:
template: |
import "vela/kube"
import (
"vela/kube"
)
output: kube.#Read & {
$params: {

View File

@@ -13,9 +13,11 @@ spec:
schematic:
cue:
template: |
import "vela/op"
import "vela/http"
import "encoding/json"
import (
"vela/op"
"vela/http"
"encoding/json"
)
req: http.#HTTPDo & {
$params: {

View File

@@ -1,115 +0,0 @@
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
# Definition source cue file: vela-templates/definitions/internal/restart-workflow.cue
apiVersion: core.oam.dev/v1beta1
kind: WorkflowStepDefinition
metadata:
annotations:
custom.definition.oam.dev/category: Workflow Control
definition.oam.dev/description: Schedule the current Application's workflow to restart at a specific time, after a duration, or at recurring intervals
labels:
custom.definition.oam.dev/scope: Application
name: restart-workflow
namespace: {{ include "systemDefinitionNamespace" . }}
spec:
schematic:
cue:
template: |
import "vela/kube"
import "vela/builtin"
// Count how many parameters are provided
_paramCount: len([
if parameter.at != _|_ {1},
if parameter.after != _|_ {1},
if parameter.every != _|_ {1},
])
// Fail if not exactly one parameter is provided
if _paramCount != 1 {
validateParams: builtin.#Fail & {
$params: message: "Exactly one of 'at', 'after', or 'every' parameters must be specified (found \(_paramCount))"
}
}
// Build the bash script to calculate annotation value
_script: string
if parameter.at != _|_ {
// Fixed timestamp mode - use as-is
_script: """
VALUE="\(parameter.at)"
kubectl annotate application \(context.name) -n \(context.namespace) app.oam.dev/restart-workflow="$VALUE" --overwrite
"""
}
if parameter.after != _|_ {
// Relative time mode - calculate timestamp using date
// Convert duration format (5m, 1h, 2d) to seconds, then calculate
_script: """
DURATION="\(parameter.after)"
# Convert duration to seconds
SECONDS=0
if [[ "$DURATION" =~ ^([0-9]+)m$ ]]; then
SECONDS=$((${BASH_REMATCH[1]} * 60))
elif [[ "$DURATION" =~ ^([0-9]+)h$ ]]; then
SECONDS=$((${BASH_REMATCH[1]} * 3600))
elif [[ "$DURATION" =~ ^([0-9]+)d$ ]]; then
SECONDS=$((${BASH_REMATCH[1]} * 86400))
else
echo "ERROR: Invalid duration format: $DURATION (expected format: 5m, 1h, or 2d)"
exit 1
fi
# Calculate future timestamp using seconds offset
VALUE=$(date -u -d "@$(($(date +%s) + SECONDS))" +%Y-%m-%dT%H:%M:%SZ)
echo "Calculated timestamp for after '$DURATION' ($SECONDS seconds): $VALUE"
kubectl annotate application \(context.name) -n \(context.namespace) app.oam.dev/restart-workflow="$VALUE" --overwrite
"""
}
if parameter.every != _|_ {
// Recurring interval mode - pass duration directly
_script: """
VALUE="\(parameter.every)"
kubectl annotate application \(context.name) -n \(context.namespace) app.oam.dev/restart-workflow="$VALUE" --overwrite
"""
}
// Run kubectl to annotate the Application
job: kube.#Apply & {
$params: value: {
apiVersion: "batch/v1"
kind: "Job"
metadata: {
name: "\(context.name)-restart-workflow-\(context.stepSessionID)"
namespace: "vela-system"
}
spec: {
backoffLimit: 3
template: spec: {
containers: [{
name: "kubectl-annotate"
image: "bitnami/kubectl:latest"
command: ["/bin/sh", "-c"]
args: [_script]
}]
restartPolicy: "Never"
serviceAccountName: "kubevela-vela-core"
}
}
}
}
wait: builtin.#ConditionalWait & {
if job.$returns.value.status != _|_ if job.$returns.value.status.succeeded != _|_ {
$params: continue: job.$returns.value.status.succeeded > 0
}
}
parameter: {
// +usage=Schedule restart at a specific RFC3339 timestamp (e.g., "2025-01-15T14:30:00Z")
at?: string & =~"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?(Z|[+-][0-9]{2}:[0-9]{2})$"
// +usage=Schedule restart after a relative duration from now (e.g., "5m", "1h", "2d")
after?: string & =~"^[0-9]+(m|h|d)$"
// +usage=Schedule recurring restarts every specified duration (e.g., "5m", "1h", "24h")
every?: string & =~"^[0-9]+(m|h|d)$"
}

View File

@@ -14,7 +14,9 @@ spec:
schematic:
cue:
template: |
import "vela/op"
import (
"vela/op"
)
app: op.#ShareCloudResource & {
env: parameter.env

View File

@@ -11,8 +11,10 @@ spec:
schematic:
cue:
template: |
import "strconv"
import "strings"
import (
"strconv"
"strings"
)
mountsArray: [
if parameter.volumeMounts != _|_ if parameter.volumeMounts.pvc != _|_ for v in parameter.volumeMounts.pvc {

View File

@@ -12,7 +12,9 @@ spec:
schematic:
cue:
template: |
import "vela/builtin"
import (
"vela/builtin"
)
suspend: builtin.#Suspend & {
$params: parameter

View File

@@ -12,9 +12,11 @@ spec:
schematic:
cue:
template: |
import "vela/kube"
import "vela/builtin"
import "vela/util"
import (
"vela/kube"
"vela/builtin"
"vela/util"
)
mountsArray: [
if parameter.storage != _|_ && parameter.storage.secret != _|_ for v in parameter.storage.secret {
@@ -124,6 +126,8 @@ spec:
}
parameter: {
// +usage=Specify the name of the addon.
addonName: string
// +usage=Specify the vela command
command: [...string]
// +usage=Specify the image

View File

@@ -12,11 +12,13 @@ spec:
schematic:
cue:
template: |
import "vela/http"
import "vela/kube"
import "vela/util"
import "encoding/json"
import "encoding/base64"
import (
"vela/http"
"vela/kube"
"vela/util"
"encoding/json"
"encoding/base64"
)
data: {
if parameter.data == _|_ {

View File

@@ -11,8 +11,10 @@ spec:
schematic:
cue:
template: |
import "strconv"
import "strings"
import (
"strconv"
"strings"
)
mountsArray: [
if parameter.volumeMounts != _|_ && parameter.volumeMounts.pvc != _|_ for v in parameter.volumeMounts.pvc {

View File

@@ -267,9 +267,6 @@ logFilePath: ""
## @param 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.
logFileMaxSize: 1024
## @param admissionWebhookTimeout Timeout seconds for admission webhooks
admissionWebhookTimeout: 10
## @skip admissionWebhooks
admissionWebhooks:
enabled: true

View File

@@ -1,51 +0,0 @@
/*
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 app
import (
"k8s.io/klog/v2"
)
// bootstrapProviderRegistry registers framework-level providers that need
// to be available globally. This is called early in prepareRun before
// controllers are initialized.
//
// The provider registry is a fallback mechanism for breaking import cycles
// that block development. Providers registered here enable immediate feature
// work while longer-term refactoring efforts can be planned.
//
// Best practices when adding a provider:
// 1. Document which packages have the cycle (in comments below)
// 2. Define narrow, focused interfaces (< 5 methods)
// 3. Consider opportunities for future refactoring to eliminate the cycle
// 4. Prefer constructor injection for new code without cycles
//
// See pkg/registry/README.md for feature overview and pkg/registry package docs for guidelines.
func bootstrapProviderRegistry() {
klog.V(2).InfoS("Bootstrapping provider registry")
// ────────────────────────────────────────────────────────────────────
// Add providers below following this pattern:
// ────────────────────────────────────────────────────────────────────
//
// ProviderInterface - Brief description
// Cycle: pkg/foo ↔ pkg/bar (explain the circular dependency)
// Note: Consider refactoring to extract shared interfaces
// registry.RegisterAs[ProviderInterface](implementation)
klog.V(2).InfoS("Provider registry bootstrap complete")
}

View File

@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package logging
package app
import (
"bytes"
@@ -60,12 +60,7 @@ type colorWriter struct {
buf bytes.Buffer
}
// NewColorWriter creates a new writer that adds ANSI color codes to klog output.
// It wraps the provided writer and colorizes log messages based on severity level,
// enhances location information with function names, and formats structured fields.
// This is primarily intended for development mode (--dev-logs=true) to improve
// log readability in terminal output.
func NewColorWriter(dst io.Writer) io.Writer {
func newColorWriter(dst io.Writer) io.Writer {
return &colorWriter{dst: dst}
}

View File

@@ -1,38 +0,0 @@
/*
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 config
import (
"github.com/spf13/pflag"
standardcontroller "github.com/oam-dev/kubevela/pkg/controller"
)
// AdmissionConfig contains admission control configuration.
type AdmissionConfig struct {
// Fields will be populated based on what standardcontroller.AddAdmissionFlags sets
}
// NewAdmissionConfig creates a new AdmissionConfig with defaults.
func NewAdmissionConfig() *AdmissionConfig {
return &AdmissionConfig{}
}
// AddFlags registers admission configuration flags.
func (c *AdmissionConfig) AddFlags(fs *pflag.FlagSet) {
standardcontroller.AddAdmissionFlags(fs)
}

View File

@@ -1,56 +0,0 @@
/*
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 config
import (
"time"
"github.com/spf13/pflag"
commonconfig "github.com/oam-dev/kubevela/pkg/controller/common"
)
// ApplicationConfig contains application-specific configuration.
type ApplicationConfig struct {
ReSyncPeriod time.Duration
}
// NewApplicationConfig creates a new ApplicationConfig with defaults.
func NewApplicationConfig() *ApplicationConfig {
return &ApplicationConfig{
ReSyncPeriod: commonconfig.ApplicationReSyncPeriod,
}
}
// AddFlags registers application configuration flags.
func (c *ApplicationConfig) AddFlags(fs *pflag.FlagSet) {
fs.DurationVar(&c.ReSyncPeriod,
"application-re-sync-period",
c.ReSyncPeriod,
"Re-sync period for application to re-sync, also known as the state-keep interval.")
}
// SyncToApplicationGlobals syncs the parsed configuration values to application package global variables.
// This should be called after flag parsing to ensure the application controller uses the configured values.
//
// NOTE: This method exists for backward compatibility with legacy code that depends on global
// variables in the commonconfig package. Ideally, configuration should be injected rather than using globals.
//
// The flow is: CLI flags -> ApplicationConfig struct fields -> commonconfig globals (via this method)
func (c *ApplicationConfig) SyncToApplicationGlobals() {
commonconfig.ApplicationReSyncPeriod = c.ReSyncPeriod
}

View File

@@ -1,40 +0,0 @@
/*
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 config
import (
pkgclient "github.com/kubevela/pkg/controller/client"
"github.com/spf13/pflag"
)
// ClientConfig contains controller client configuration.
// This wraps the external package's client configuration flags.
type ClientConfig struct {
// Note: The actual configuration is managed by the pkgclient package
// This is a wrapper to maintain consistency with our config pattern
}
// NewClientConfig creates a new ClientConfig with defaults.
func NewClientConfig() *ClientConfig {
return &ClientConfig{}
}
// AddFlags registers client configuration flags.
// Delegates to the external package's flag registration.
func (c *ClientConfig) AddFlags(fs *pflag.FlagSet) {
pkgclient.AddTimeoutControllerClientFlags(fs)
}

View File

@@ -1,67 +0,0 @@
/*
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 config
import (
"github.com/spf13/pflag"
oamcontroller "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
)
// ControllerConfig wraps the oamcontroller.Args configuration.
// While this appears to duplicate the Args struct, it serves as the new home for
// controller flag registration after the AddFlags method was moved here from
// the oamcontroller package during refactoring.
type ControllerConfig struct {
// Embed the existing Args struct to reuse its fields
oamcontroller.Args
}
// NewControllerConfig creates a new ControllerConfig with defaults.
func NewControllerConfig() *ControllerConfig {
return &ControllerConfig{
Args: oamcontroller.Args{
RevisionLimit: 50,
AppRevisionLimit: 10,
DefRevisionLimit: 20,
AutoGenWorkloadDefinition: true,
ConcurrentReconciles: 4,
IgnoreAppWithoutControllerRequirement: false,
IgnoreDefinitionWithoutControllerRequirement: false,
},
}
}
// AddFlags registers controller configuration flags.
// This method was moved here from oamcontroller.Args during refactoring
// to centralize configuration management.
func (c *ControllerConfig) AddFlags(fs *pflag.FlagSet) {
fs.IntVar(&c.RevisionLimit, "revision-limit", c.RevisionLimit,
"RevisionLimit is the maximum number of revisions that will be maintained. The default value is 50.")
fs.IntVar(&c.AppRevisionLimit, "application-revision-limit", c.AppRevisionLimit,
"application-revision-limit is the maximum number of application useless revisions that will be maintained, if the useless revisions exceed this number, older ones will be GCed first.The default value is 10.")
fs.IntVar(&c.DefRevisionLimit, "definition-revision-limit", c.DefRevisionLimit,
"definition-revision-limit is the maximum number of component/trait definition useless revisions that will be maintained, if the useless revisions exceed this number, older ones will be GCed first.The default value is 20.")
fs.BoolVar(&c.AutoGenWorkloadDefinition, "autogen-workload-definition", c.AutoGenWorkloadDefinition,
"Automatic generated workloadDefinition which componentDefinition refers to.")
fs.IntVar(&c.ConcurrentReconciles, "concurrent-reconciles", c.ConcurrentReconciles,
"concurrent-reconciles is the concurrent reconcile number of the controller. The default value is 4")
fs.BoolVar(&c.IgnoreAppWithoutControllerRequirement, "ignore-app-without-controller-version", c.IgnoreAppWithoutControllerRequirement,
"If true, application controller will not process the app without 'app.oam.dev/controller-version-require' annotation")
fs.BoolVar(&c.IgnoreDefinitionWithoutControllerRequirement, "ignore-definition-without-controller-version", c.IgnoreDefinitionWithoutControllerRequirement,
"If true, trait/component/workflowstep definition controller will not process the definition without 'definition.oam.dev/controller-version-require' annotation")
}

View File

@@ -1,61 +0,0 @@
/*
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 config
import (
"github.com/kubevela/pkg/cue/cuex"
"github.com/spf13/pflag"
)
// CUEConfig contains CUE language configuration.
type CUEConfig struct {
EnableExternalPackage bool
EnableExternalPackageWatch bool
}
// NewCUEConfig creates a new CUEConfig with defaults.
func NewCUEConfig() *CUEConfig {
return &CUEConfig{
EnableExternalPackage: cuex.EnableExternalPackageForDefaultCompiler,
EnableExternalPackageWatch: cuex.EnableExternalPackageWatchForDefaultCompiler,
}
}
// AddFlags registers CUE configuration flags.
func (c *CUEConfig) AddFlags(fs *pflag.FlagSet) {
fs.BoolVar(&c.EnableExternalPackage,
"enable-external-package-for-default-compiler",
c.EnableExternalPackage,
"Enable loading third-party CUE packages into the default CUE compiler. When enabled, external CUE packages can be imported and used in CUE templates.")
fs.BoolVar(&c.EnableExternalPackageWatch,
"enable-external-package-watch-for-default-compiler",
c.EnableExternalPackageWatch,
"Enable watching for changes in external CUE packages and automatically reload them when modified. Requires enable-external-package-for-default-compiler to be enabled.")
}
// SyncToCUEGlobals syncs the parsed configuration values to CUE package global variables.
// This should be called after flag parsing to ensure the CUE compiler uses the configured values.
//
// NOTE: This method exists for backward compatibility with legacy code that depends on global
// variables in the cuex package. Ideally, the CUE compiler configuration should be injected
// rather than relying on globals.
//
// The flow is: CLI flags -> CUEConfig struct fields -> cuex globals (via this method)
func (c *CUEConfig) SyncToCUEGlobals() {
cuex.EnableExternalPackageForDefaultCompiler = c.EnableExternalPackage
cuex.EnableExternalPackageWatchForDefaultCompiler = c.EnableExternalPackageWatch
}

View File

@@ -1,40 +0,0 @@
/*
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 config
import (
"github.com/spf13/pflag"
utilfeature "k8s.io/apiserver/pkg/util/feature"
)
// FeatureConfig contains feature gate configuration.
// This wraps the Kubernetes feature gate system.
type FeatureConfig struct {
// Note: The actual configuration is managed by the utilfeature package
// This is a wrapper to maintain consistency with our config pattern
}
// NewFeatureConfig creates a new FeatureConfig with defaults.
func NewFeatureConfig() *FeatureConfig {
return &FeatureConfig{}
}
// AddFlags registers feature gate configuration flags.
// Delegates to the Kubernetes feature gate system.
func (c *FeatureConfig) AddFlags(fs *pflag.FlagSet) {
utilfeature.DefaultMutableFeatureGate.AddFlag(fs)
}

View File

@@ -1,42 +0,0 @@
/*
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 config
import (
utillog "github.com/kubevela/pkg/util/log"
"github.com/spf13/pflag"
)
// KLogConfig contains klog configuration.
// This wraps the Kubernetes logging configuration.
type KLogConfig struct {
// Reference to observability config for log settings
observability *ObservabilityConfig
}
// NewKLogConfig creates a new KLogConfig.
func NewKLogConfig(observability *ObservabilityConfig) *KLogConfig {
return &KLogConfig{
observability: observability,
}
}
// AddFlags registers klog configuration flags.
func (c *KLogConfig) AddFlags(fs *pflag.FlagSet) {
// Add base klog flags
utillog.AddFlags(fs)
}

View File

@@ -1,49 +0,0 @@
/*
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 config
import (
"time"
"github.com/spf13/pflag"
)
// KubernetesConfig contains Kubernetes API client configuration.
type KubernetesConfig struct {
QPS float64
Burst int
InformerSyncPeriod time.Duration
}
// NewKubernetesConfig creates a new KubernetesConfig with defaults.
func NewKubernetesConfig() *KubernetesConfig {
return &KubernetesConfig{
QPS: 50,
Burst: 100,
InformerSyncPeriod: 10 * time.Hour,
}
}
// AddFlags registers Kubernetes configuration flags.
func (c *KubernetesConfig) AddFlags(fs *pflag.FlagSet) {
fs.Float64Var(&c.QPS, "kube-api-qps", c.QPS,
"the qps for reconcile clients. Low qps may lead to low throughput. High qps may give stress to api-server. Raise this value if concurrent-reconciles is set to be high.")
fs.IntVar(&c.Burst, "kube-api-burst", c.Burst,
"the burst for reconcile clients. Recommend setting it qps*2.")
fs.DurationVar(&c.InformerSyncPeriod, "informer-sync-period", c.InformerSyncPeriod,
"The re-sync period for informer in controller-runtime. This is a system-level configuration.")
}

View File

@@ -1,53 +0,0 @@
/*
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 config
import (
"time"
pkgmulticluster "github.com/kubevela/pkg/multicluster"
"github.com/spf13/pflag"
)
// MultiClusterConfig contains multi-cluster configuration.
type MultiClusterConfig struct {
EnableClusterGateway bool
EnableClusterMetrics bool
ClusterMetricsInterval time.Duration
}
// NewMultiClusterConfig creates a new MultiClusterConfig with defaults.
func NewMultiClusterConfig() *MultiClusterConfig {
return &MultiClusterConfig{
EnableClusterGateway: false,
EnableClusterMetrics: false,
ClusterMetricsInterval: 15 * time.Second,
}
}
// AddFlags registers multi-cluster configuration flags.
func (c *MultiClusterConfig) AddFlags(fs *pflag.FlagSet) {
fs.BoolVar(&c.EnableClusterGateway, "enable-cluster-gateway", c.EnableClusterGateway,
"Enable cluster-gateway to use multicluster, disabled by default.")
fs.BoolVar(&c.EnableClusterMetrics, "enable-cluster-metrics", c.EnableClusterMetrics,
"Enable cluster-metrics-management to collect metrics from clusters with cluster-gateway, disabled by default. When this param is enabled, enable-cluster-gateway should be enabled")
fs.DurationVar(&c.ClusterMetricsInterval, "cluster-metrics-interval", c.ClusterMetricsInterval,
"The interval that ClusterMetricsMgr will collect metrics from clusters, default value is 15 seconds.")
// Also register additional multicluster flags from external package
pkgmulticluster.AddFlags(fs)
}

View File

@@ -1,54 +0,0 @@
/*
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 config
import (
"github.com/spf13/pflag"
"github.com/oam-dev/kubevela/pkg/oam"
)
// OAMConfig contains OAM-specific configuration.
type OAMConfig struct {
SystemDefinitionNamespace string
}
// NewOAMConfig creates a new OAMConfig with defaults.
func NewOAMConfig() *OAMConfig {
return &OAMConfig{
SystemDefinitionNamespace: "vela-system",
}
}
// AddFlags registers OAM configuration flags.
func (c *OAMConfig) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&c.SystemDefinitionNamespace,
"system-definition-namespace",
c.SystemDefinitionNamespace,
"Define the namespace of the system-level definition")
}
// SyncToOAMGlobals syncs the parsed configuration values to OAM package global variables.
// This should be called after flag parsing to ensure the OAM runtime uses the configured values.
//
// NOTE: This method exists for backward compatibility with legacy code that depends on global
// variables in the oam package. Ideally, configuration should be injected rather than using globals.
//
// The flow is: CLI flags -> OAMConfig struct fields -> oam globals (via this method)
func (c *OAMConfig) SyncToOAMGlobals() {
oam.SystemDefinitionNamespace = c.SystemDefinitionNamespace
}

View File

@@ -1,55 +0,0 @@
/*
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 config
import (
"github.com/spf13/pflag"
)
// ObservabilityConfig contains metrics and logging configuration.
type ObservabilityConfig struct {
MetricsAddr string
LogFilePath string
LogFileMaxSize uint64
LogDebug bool
DevLogs bool
}
// NewObservabilityConfig creates a new ObservabilityConfig with defaults.
func NewObservabilityConfig() *ObservabilityConfig {
return &ObservabilityConfig{
MetricsAddr: ":8080",
LogFilePath: "",
LogFileMaxSize: 1024,
LogDebug: false,
DevLogs: false,
}
}
// AddFlags registers observability configuration flags.
func (c *ObservabilityConfig) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&c.MetricsAddr, "metrics-addr", c.MetricsAddr,
"The address the metric endpoint binds to.")
fs.StringVar(&c.LogFilePath, "log-file-path", c.LogFilePath,
"The file to write logs to.")
fs.Uint64Var(&c.LogFileMaxSize, "log-file-max-size", c.LogFileMaxSize,
"Defines the maximum size a log file can grow to, Unit is megabytes.")
fs.BoolVar(&c.LogDebug, "log-debug", c.LogDebug,
"Enable debug logs for development purpose")
fs.BoolVar(&c.DevLogs, "dev-logs", c.DevLogs,
"Enable ANSI color formatting for console logs (ignored when log-file-path is set)")
}

View File

@@ -1,58 +0,0 @@
/*
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 config
import (
"github.com/spf13/pflag"
standardcontroller "github.com/oam-dev/kubevela/pkg/controller"
commonconfig "github.com/oam-dev/kubevela/pkg/controller/common"
)
// PerformanceConfig contains performance and optimization configuration.
type PerformanceConfig struct {
PerfEnabled bool
}
// NewPerformanceConfig creates a new PerformanceConfig with defaults.
func NewPerformanceConfig() *PerformanceConfig {
return &PerformanceConfig{
PerfEnabled: commonconfig.PerfEnabled,
}
}
// AddFlags registers performance configuration flags.
func (c *PerformanceConfig) AddFlags(fs *pflag.FlagSet) {
fs.BoolVar(&c.PerfEnabled,
"perf-enabled",
c.PerfEnabled,
"Enable performance logging for controllers, disabled by default.")
// Add optimization flags from the standard controller
standardcontroller.AddOptimizeFlags(fs)
}
// SyncToPerformanceGlobals syncs the parsed configuration values to performance package global variables.
// This should be called after flag parsing to ensure the performance monitoring uses the configured values.
//
// NOTE: This method exists for backward compatibility with legacy code that depends on global
// variables in the commonconfig package. Ideally, configuration should be injected rather than using globals.
//
// The flow is: CLI flags -> PerformanceConfig struct fields -> commonconfig globals (via this method)
func (c *PerformanceConfig) SyncToPerformanceGlobals() {
commonconfig.PerfEnabled = c.PerfEnabled
}

View File

@@ -1,40 +0,0 @@
/*
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 config
import (
"github.com/kubevela/pkg/util/profiling"
"github.com/spf13/pflag"
)
// ProfilingConfig contains profiling configuration.
// This wraps the external package's profiling configuration flags.
type ProfilingConfig struct {
// Note: The actual configuration is managed by the profiling package
// This is a wrapper to maintain consistency with our config pattern
}
// NewProfilingConfig creates a new ProfilingConfig with defaults.
func NewProfilingConfig() *ProfilingConfig {
return &ProfilingConfig{}
}
// AddFlags registers profiling configuration flags.
// Delegates to the external package's flag registration.
func (c *ProfilingConfig) AddFlags(fs *pflag.FlagSet) {
profiling.AddFlags(fs)
}

View File

@@ -1,40 +0,0 @@
/*
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 config
import (
ctrlrec "github.com/kubevela/pkg/controller/reconciler"
"github.com/spf13/pflag"
)
// ReconcileConfig contains controller reconciliation configuration.
// This wraps the external package's reconciler configuration flags.
type ReconcileConfig struct {
// Note: The actual configuration is managed by the ctrlrec package
// This is a wrapper to maintain consistency with our config pattern
}
// NewReconcileConfig creates a new ReconcileConfig with defaults.
func NewReconcileConfig() *ReconcileConfig {
return &ReconcileConfig{}
}
// AddFlags registers reconcile configuration flags.
// Delegates to the external package's flag registration.
func (c *ReconcileConfig) AddFlags(fs *pflag.FlagSet) {
ctrlrec.AddFlags(fs)
}

View File

@@ -1,55 +0,0 @@
/*
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 config
import (
"github.com/spf13/pflag"
"github.com/oam-dev/kubevela/pkg/resourcekeeper"
)
// ResourceConfig contains resource management configuration.
type ResourceConfig struct {
MaxDispatchConcurrent int
}
// NewResourceConfig creates a new ResourceConfig with defaults.
func NewResourceConfig() *ResourceConfig {
return &ResourceConfig{
MaxDispatchConcurrent: 10,
}
}
// AddFlags registers resource configuration flags.
func (c *ResourceConfig) AddFlags(fs *pflag.FlagSet) {
fs.IntVar(&c.MaxDispatchConcurrent,
"max-dispatch-concurrent",
c.MaxDispatchConcurrent,
"Set the max dispatch concurrent number, default is 10")
}
// SyncToResourceGlobals syncs the parsed configuration values to resource package global variables.
// This should be called after flag parsing to ensure the resource keeper uses the configured values.
//
// NOTE: This method exists for backward compatibility with legacy code that depends on global
// variables in the resourcekeeper package. The long-term goal should be to refactor to use
// dependency injection rather than globals.
//
// The flow is: CLI flags -> ResourceConfig struct fields -> resourcekeeper globals (via this method)
func (c *ResourceConfig) SyncToResourceGlobals() {
resourcekeeper.MaxDispatchConcurrent = c.MaxDispatchConcurrent
}

View File

@@ -1,65 +0,0 @@
/*
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 config
import (
"time"
"github.com/spf13/pflag"
)
// ServerConfig contains server-level configuration.
type ServerConfig struct {
HealthAddr string
StorageDriver string
EnableLeaderElection bool
LeaderElectionNamespace string
LeaseDuration time.Duration
RenewDeadline time.Duration
RetryPeriod time.Duration
}
// NewServerConfig creates a new ServerConfig with defaults.
func NewServerConfig() *ServerConfig {
return &ServerConfig{
HealthAddr: ":9440",
StorageDriver: "Local",
EnableLeaderElection: false,
LeaderElectionNamespace: "",
LeaseDuration: 15 * time.Second,
RenewDeadline: 10 * time.Second,
RetryPeriod: 2 * time.Second,
}
}
// AddFlags registers server configuration flags.
func (c *ServerConfig) AddFlags(fs *pflag.FlagSet) {
fs.StringVar(&c.HealthAddr, "health-addr", c.HealthAddr,
"The address the health endpoint binds to.")
fs.StringVar(&c.StorageDriver, "storage-driver", c.StorageDriver,
"Application storage driver.")
fs.BoolVar(&c.EnableLeaderElection, "enable-leader-election", c.EnableLeaderElection,
"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager.")
fs.StringVar(&c.LeaderElectionNamespace, "leader-election-namespace", c.LeaderElectionNamespace,
"Determines the namespace in which the leader election configmap will be created.")
fs.DurationVar(&c.LeaseDuration, "leader-election-lease-duration", c.LeaseDuration,
"The duration that non-leader candidates will wait to force acquire leadership")
fs.DurationVar(&c.RenewDeadline, "leader-election-renew-deadline", c.RenewDeadline,
"The duration that the acting controlplane will retry refreshing leadership before giving up")
fs.DurationVar(&c.RetryPeriod, "leader-election-retry-period", c.RetryPeriod,
"The duration the LeaderElector clients should wait between tries of actions")
}

View File

@@ -1,40 +0,0 @@
/*
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 config
import (
"github.com/kubevela/pkg/controller/sharding"
"github.com/spf13/pflag"
)
// ShardingConfig contains controller sharding configuration.
// This wraps the external package's sharding configuration flags.
type ShardingConfig struct {
// Note: The actual configuration is managed by the sharding package
// This is a wrapper to maintain consistency with our config pattern
}
// NewShardingConfig creates a new ShardingConfig with defaults.
func NewShardingConfig() *ShardingConfig {
return &ShardingConfig{}
}
// AddFlags registers sharding configuration flags.
// Delegates to the external package's flag registration.
func (c *ShardingConfig) AddFlags(fs *pflag.FlagSet) {
sharding.AddFlags(fs)
}

View File

@@ -1,47 +0,0 @@
/*
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 config
import (
"github.com/spf13/pflag"
)
// WebhookConfig contains webhook configuration.
type WebhookConfig struct {
UseWebhook bool
CertDir string
WebhookPort int
}
// NewWebhookConfig creates a new WebhookConfig with defaults.
func NewWebhookConfig() *WebhookConfig {
return &WebhookConfig{
UseWebhook: false,
CertDir: "/k8s-webhook-server/serving-certs",
WebhookPort: 9443,
}
}
// AddFlags registers webhook configuration flags.
func (c *WebhookConfig) AddFlags(fs *pflag.FlagSet) {
fs.BoolVar(&c.UseWebhook, "use-webhook", c.UseWebhook,
"Enable Admission Webhook")
fs.StringVar(&c.CertDir, "webhook-cert-dir", c.CertDir,
"Admission webhook cert/key dir.")
fs.IntVar(&c.WebhookPort, "webhook-port", c.WebhookPort,
"admission webhook listen address")
}

View File

@@ -1,69 +0,0 @@
/*
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 config
import (
"github.com/spf13/pflag"
wfTypes "github.com/kubevela/workflow/pkg/types"
)
// WorkflowConfig contains workflow engine configuration.
type WorkflowConfig struct {
MaxWaitBackoffTime int
MaxFailedBackoffTime int
MaxStepErrorRetryTimes int
}
// NewWorkflowConfig creates a new WorkflowConfig with defaults.
func NewWorkflowConfig() *WorkflowConfig {
return &WorkflowConfig{
MaxWaitBackoffTime: 60,
MaxFailedBackoffTime: 300,
MaxStepErrorRetryTimes: 10,
}
}
// AddFlags registers workflow configuration flags.
func (c *WorkflowConfig) AddFlags(fs *pflag.FlagSet) {
fs.IntVar(&c.MaxWaitBackoffTime,
"max-workflow-wait-backoff-time",
c.MaxWaitBackoffTime,
"Set the max workflow wait backoff time, default is 60")
fs.IntVar(&c.MaxFailedBackoffTime,
"max-workflow-failed-backoff-time",
c.MaxFailedBackoffTime,
"Set the max workflow failed backoff time, default is 300")
fs.IntVar(&c.MaxStepErrorRetryTimes,
"max-workflow-step-error-retry-times",
c.MaxStepErrorRetryTimes,
"Set the max workflow step error retry times, default is 10")
}
// SyncToWorkflowGlobals syncs the parsed configuration values to workflow package global variables.
// This should be called after flag parsing to ensure the workflow engine uses the configured values.
//
// NOTE: This method exists for backward compatibility with legacy code that depends on global
// variables in the wfTypes package. The long-term goal should be to refactor the workflow
// package to accept configuration via dependency injection rather than globals.
//
// The flow is: CLI flags -> WorkflowConfig struct fields -> wfTypes globals (via this method)
func (c *WorkflowConfig) SyncToWorkflowGlobals() {
wfTypes.MaxWorkflowWaitBackoffTime = c.MaxWaitBackoffTime
wfTypes.MaxWorkflowFailedBackoffTime = c.MaxFailedBackoffTime
wfTypes.MaxWorkflowStepErrorRetryTimes = c.MaxStepErrorRetryTimes
}

View File

@@ -1,229 +0,0 @@
/*
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 crdvalidation
import (
"context"
"fmt"
"time"
"github.com/kubevela/pkg/util/compression"
"github.com/kubevela/pkg/util/k8s"
"github.com/kubevela/pkg/util/singleton"
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/cmd/core/app/hooks"
"github.com/oam-dev/kubevela/pkg/features"
"github.com/oam-dev/kubevela/pkg/oam"
)
// Hook validates that CRDs installed in the cluster are compatible with
// enabled feature gates. This prevents silent data corruption by failing
// fast at startup if CRDs are out of date.
type Hook struct {
client.Client
}
// NewHook creates a new CRD validation hook with the default singleton client
func NewHook() hooks.PreStartHook {
klog.V(3).InfoS("Initializing CRD validation hook", "client", "singleton")
return NewHookWithClient(singleton.KubeClient.Get())
}
// NewHookWithClient creates a new CRD validation hook with a specified client
// for improved testability and dependency injection
func NewHookWithClient(c client.Client) hooks.PreStartHook {
klog.V(3).InfoS("Initializing CRD validation hook with custom client")
return &Hook{Client: c}
}
// Name returns the hook name for logging
func (h *Hook) Name() string {
return "CRDValidation"
}
// Run executes the CRD validation logic. It checks if compression-related
// feature gates are enabled and validates that the ApplicationRevision CRD
// supports the required compression fields.
func (h *Hook) Run(ctx context.Context) error {
klog.InfoS("Starting CRD validation hook")
// Add a reasonable timeout to prevent indefinite hanging while allowing
// sufficient time for slower clusters or API servers under load.
// 2 minutes should be more than enough for any reasonable cluster setup
// while still protecting against indefinite hangs.
timeout := 2 * time.Minute
ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()
zstdEnabled := feature.DefaultMutableFeatureGate.Enabled(features.ZstdApplicationRevision)
gzipEnabled := feature.DefaultMutableFeatureGate.Enabled(features.GzipApplicationRevision)
klog.V(2).InfoS("Checking compression feature gates",
"zstdEnabled", zstdEnabled,
"gzipEnabled", gzipEnabled)
if !zstdEnabled && !gzipEnabled {
klog.InfoS("No compression features enabled, skipping CRD validation")
return nil
}
klog.InfoS("Compression features enabled, validating ApplicationRevision CRD compatibility")
if err := h.validateApplicationRevisionCRD(ctx, zstdEnabled, gzipEnabled); err != nil {
// Check if the error was due to context timeout
if ctx.Err() == context.DeadlineExceeded {
klog.ErrorS(err, "CRD validation timed out - API server may be slow or unresponsive",
"timeout", timeout.String(),
"suggestion", "Check API server health and network connectivity")
return fmt.Errorf("CRD validation timed out after %v: %w. API server may be slow or under heavy load", timeout, err)
}
klog.ErrorS(err, "CRD validation failed")
return fmt.Errorf("CRD validation failed: %w", err)
}
klog.InfoS("CRD validation completed successfully")
return nil
}
// validateApplicationRevisionCRD performs a round-trip test to ensure the
// ApplicationRevision CRD supports compression fields
func (h *Hook) validateApplicationRevisionCRD(ctx context.Context, zstdEnabled, gzipEnabled bool) error {
// Generate test resource
testName := fmt.Sprintf("core.pre-check.%d", time.Now().UnixNano())
namespace := k8s.GetRuntimeNamespace()
klog.V(2).InfoS("Creating test ApplicationRevision for CRD validation",
"name", testName,
"namespace", namespace)
// Ensure the namespace exists before attempting to create resources
if err := k8s.EnsureNamespace(ctx, h.Client, namespace); err != nil {
klog.ErrorS(err, "Failed to ensure runtime namespace exists",
"namespace", namespace)
return fmt.Errorf("runtime namespace %q does not exist or is not accessible: %w", namespace, err)
}
appRev := &v1beta1.ApplicationRevision{}
appRev.Name = testName
appRev.Namespace = namespace
appRev.SetLabels(map[string]string{oam.LabelPreCheck: types.VelaCoreName})
appRev.Spec.Application.Name = testName
appRev.Spec.Application.Spec.Components = []common.ApplicationComponent{}
// Set compression type based on enabled features
var compressionType compression.Type
if zstdEnabled {
compressionType = compression.Zstd
appRev.Spec.Compression.SetType(compression.Zstd)
klog.V(3).InfoS("Setting compression type", "type", "zstd")
} else if gzipEnabled {
compressionType = compression.Gzip
appRev.Spec.Compression.SetType(compression.Gzip)
klog.V(3).InfoS("Setting compression type", "type", "gzip")
}
// Register cleanup function
defer func() {
klog.V(2).InfoS("Cleaning up test ApplicationRevisions",
"namespace", namespace,
"label", oam.LabelPreCheck)
if err := h.Client.DeleteAllOf(ctx, &v1beta1.ApplicationRevision{},
client.InNamespace(namespace),
client.MatchingLabels{oam.LabelPreCheck: types.VelaCoreName}); err != nil {
klog.ErrorS(err, "Failed to clean up test ApplicationRevision resources",
"namespace", namespace)
} else {
klog.V(3).InfoS("Successfully cleaned up test ApplicationRevision resources")
}
}()
// Create test resource
klog.V(2).InfoS("Writing test ApplicationRevision to cluster")
if err := h.Client.Create(ctx, appRev); err != nil {
klog.ErrorS(err, "Failed to create test ApplicationRevision",
"name", testName,
"namespace", namespace)
return fmt.Errorf("failed to create test ApplicationRevision: %w", err)
}
klog.V(3).InfoS("Test ApplicationRevision created successfully")
// Read back the resource
key := client.ObjectKeyFromObject(appRev)
klog.V(2).InfoS("Reading back test ApplicationRevision from cluster",
"key", key.String())
if err := h.Client.Get(ctx, key, appRev); err != nil {
klog.ErrorS(err, "Failed to read back test ApplicationRevision",
"key", key.String())
return fmt.Errorf("failed to read test ApplicationRevision: %w", err)
}
klog.V(3).InfoS("Test ApplicationRevision read successfully")
// Validate round-trip integrity
klog.V(2).InfoS("Validating round-trip data integrity",
"expectedName", testName,
"actualName", appRev.Spec.Application.Name,
"expectedCompression", compressionType,
"actualCompression", appRev.Spec.Compression.Type)
// First check that basic data survived
if appRev.Spec.Application.Name != testName {
klog.ErrorS(nil, "CRD round-trip validation failed - basic data corruption detected",
"expectedName", testName,
"actualName", appRev.Spec.Application.Name,
"compressionType", compressionType,
"issue", "The ApplicationRevision CRD does not support compression fields")
return fmt.Errorf("the ApplicationRevision CRD is not updated. Compression cannot be used. Please upgrade your CRD to latest ones")
}
// Validate that compression fields survived the round-trip
switch compressionType {
case compression.Zstd:
if appRev.Spec.Compression.Type != compression.Zstd {
klog.ErrorS(nil, "CRD round-trip validation failed - zstd compression type lost",
"expected", compression.Zstd,
"actual", appRev.Spec.Compression.Type,
"issue", "The ApplicationRevision CRD does not support zstd compression fields")
return fmt.Errorf("ApplicationRevision CRD missing zstd compression support after round-trip; got=%v. Please upgrade your CRD to latest ones", appRev.Spec.Compression.Type)
}
case compression.Gzip:
if appRev.Spec.Compression.Type != compression.Gzip {
klog.ErrorS(nil, "CRD round-trip validation failed - gzip compression type lost",
"expected", compression.Gzip,
"actual", appRev.Spec.Compression.Type,
"issue", "The ApplicationRevision CRD does not support gzip compression fields")
return fmt.Errorf("ApplicationRevision CRD missing gzip compression support after round-trip; got=%v. Please upgrade your CRD to latest ones", appRev.Spec.Compression.Type)
}
case compression.Uncompressed:
// This case should never happen as we only set Zstd or Gzip above,
// but we need to handle it to satisfy the exhaustive linter
klog.V(3).InfoS("Compression type is uncompressed, which is unexpected in validation",
"compressionType", compressionType)
}
klog.V(2).InfoS("Round-trip validation passed - CRD supports compression",
"compressionType", compressionType)
return nil
}

View File

@@ -1,274 +0,0 @@
/*
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 crdvalidation_test
import (
"context"
"errors"
"testing"
"github.com/kubevela/pkg/util/compression"
"github.com/kubevela/pkg/util/k8s"
"github.com/kubevela/pkg/util/singleton"
"github.com/kubevela/pkg/util/test/bootstrap"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
utilfeature "k8s.io/apiserver/pkg/util/feature"
featuregatetesting "k8s.io/component-base/featuregate/testing"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
"strconv"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/cmd/core/app/hooks/crdvalidation"
"github.com/oam-dev/kubevela/pkg/features"
"github.com/oam-dev/kubevela/pkg/oam"
)
var _ = bootstrap.InitKubeBuilderForTest(bootstrap.WithCRDPath("./testdata"))
func TestCRDValidationHook(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "CRD Validation Hook Suite")
}
var _ = Describe("CRD validation hook", func() {
Context("with old CRD that lacks compression support", func() {
It("should detect incompatible CRD when zstd compression is enabled", func() {
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.ZstdApplicationRevision, true)
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.GzipApplicationRevision, false)
ctx := context.Background()
Expect(k8s.EnsureNamespace(ctx, singleton.KubeClient.Get(), types.DefaultKubeVelaNS)).Should(Succeed())
hook := crdvalidation.NewHook()
Expect(hook.Name()).Should(Equal("CRDValidation"))
err := hook.Run(ctx)
Expect(err).ShouldNot(Succeed())
// The old CRD doesn't preserve the application data at all, so we get a basic corruption error
Expect(err.Error()).Should(ContainSubstring("the ApplicationRevision CRD is not updated"))
})
It("should detect incompatible CRD when gzip compression is enabled", func() {
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.ZstdApplicationRevision, false)
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.GzipApplicationRevision, true)
ctx := context.Background()
Expect(k8s.EnsureNamespace(ctx, singleton.KubeClient.Get(), types.DefaultKubeVelaNS)).Should(Succeed())
hook := crdvalidation.NewHook()
err := hook.Run(ctx)
Expect(err).ShouldNot(Succeed())
// The old CRD doesn't preserve the application data at all, so we get a basic corruption error
Expect(err.Error()).Should(ContainSubstring("the ApplicationRevision CRD is not updated"))
})
})
It("should skip validation when compression features are disabled", func() {
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.ZstdApplicationRevision, false)
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.GzipApplicationRevision, false)
ctx := context.Background()
hook := crdvalidation.NewHook()
err := hook.Run(ctx)
Expect(err).Should(Succeed())
})
Context("with dependency injection", func() {
It("should use custom client when provided", func() {
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.ZstdApplicationRevision, true)
ctx := context.Background()
// Create a fake client that simulates a CRD with compression support
fakeClient := fake.NewClientBuilder().WithScheme(singleton.KubeClient.Get().Scheme()).Build()
// Pre-create the namespace
ns := &corev1.Namespace{}
ns.Name = types.DefaultKubeVelaNS
Expect(fakeClient.Create(ctx, ns)).Should(Succeed())
// Use NewHookWithClient to inject the fake client
hook := crdvalidation.NewHookWithClient(fakeClient)
Expect(hook.Name()).Should(Equal("CRDValidation"))
// Since fake client preserves all fields, validation should pass
err := hook.Run(ctx)
Expect(err).Should(Succeed())
})
})
Context("error scenarios", func() {
It("should handle Create errors gracefully", func() {
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.ZstdApplicationRevision, true)
ctx := context.Background()
// Create a client that fails on Create operations
mockClient := &mockFailingClient{
Client: fake.NewClientBuilder().WithScheme(singleton.KubeClient.Get().Scheme()).Build(),
failCreate: true,
}
hook := crdvalidation.NewHookWithClient(mockClient)
err := hook.Run(ctx)
Expect(err).ShouldNot(Succeed())
Expect(err.Error()).Should(ContainSubstring("failed to create test ApplicationRevision"))
})
It("should handle Get errors gracefully", func() {
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.GzipApplicationRevision, true)
ctx := context.Background()
// Create a client that fails on Get operations
mockClient := &mockFailingClient{
Client: fake.NewClientBuilder().WithScheme(singleton.KubeClient.Get().Scheme()).Build(),
failGet: true,
}
// Pre-create the namespace
ns := &corev1.Namespace{}
ns.Name = types.DefaultKubeVelaNS
Expect(mockClient.Client.Create(ctx, ns)).Should(Succeed())
hook := crdvalidation.NewHookWithClient(mockClient)
err := hook.Run(ctx)
Expect(err).ShouldNot(Succeed())
Expect(err.Error()).Should(ContainSubstring("failed to read test ApplicationRevision"))
})
It("should handle namespace creation errors", func() {
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.ZstdApplicationRevision, true)
ctx := context.Background()
// Create a client that fails namespace operations
mockClient := &mockFailingClient{
Client: fake.NewClientBuilder().WithScheme(singleton.KubeClient.Get().Scheme()).Build(),
failNamespaceOps: true,
}
hook := crdvalidation.NewHookWithClient(mockClient)
err := hook.Run(ctx)
Expect(err).ShouldNot(Succeed())
Expect(err.Error()).Should(ContainSubstring("runtime namespace"))
Expect(err.Error()).Should(ContainSubstring("does not exist or is not accessible"))
})
})
Context("cleanup verification", func() {
It("should clean up test resources after validation", func() {
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.ZstdApplicationRevision, true)
ctx := context.Background()
fakeClient := fake.NewClientBuilder().WithScheme(singleton.KubeClient.Get().Scheme()).Build()
// Pre-create the namespace
ns := &corev1.Namespace{}
ns.Name = types.DefaultKubeVelaNS
Expect(fakeClient.Create(ctx, ns)).Should(Succeed())
hook := crdvalidation.NewHookWithClient(fakeClient)
_ = hook.Run(ctx)
// Verify that test ApplicationRevisions are cleaned up
appRevList := &v1beta1.ApplicationRevisionList{}
err := fakeClient.List(ctx, appRevList,
client.InNamespace(types.DefaultKubeVelaNS),
client.MatchingLabels{oam.LabelPreCheck: types.VelaCoreName})
Expect(err).Should(Succeed())
Expect(appRevList.Items).Should(HaveLen(0))
})
It("should clean up multiple test resources with same label", func() {
featuregatetesting.SetFeatureGateDuringTest(GinkgoT(), utilfeature.DefaultFeatureGate, features.GzipApplicationRevision, true)
ctx := context.Background()
fakeClient := fake.NewClientBuilder().WithScheme(singleton.KubeClient.Get().Scheme()).Build()
// Pre-create the namespace
ns := &corev1.Namespace{}
ns.Name = types.DefaultKubeVelaNS
Expect(fakeClient.Create(ctx, ns)).Should(Succeed())
// Pre-create multiple test ApplicationRevisions with the precheck label
for i := 0; i < 3; i++ {
appRev := &v1beta1.ApplicationRevision{}
appRev.Name = "old-test-" + strconv.Itoa(i)
appRev.Namespace = types.DefaultKubeVelaNS
appRev.SetLabels(map[string]string{oam.LabelPreCheck: types.VelaCoreName})
appRev.Spec.Compression.Type = compression.Gzip
Expect(fakeClient.Create(ctx, appRev)).Should(Succeed())
}
// Verify pre-existing resources
appRevList := &v1beta1.ApplicationRevisionList{}
err := fakeClient.List(ctx, appRevList,
client.InNamespace(types.DefaultKubeVelaNS),
client.MatchingLabels{oam.LabelPreCheck: types.VelaCoreName})
Expect(err).Should(Succeed())
Expect(appRevList.Items).Should(HaveLen(3))
// Run the hook
hook := crdvalidation.NewHookWithClient(fakeClient)
_ = hook.Run(ctx)
// Verify all test resources are cleaned up
err = fakeClient.List(ctx, appRevList,
client.InNamespace(types.DefaultKubeVelaNS),
client.MatchingLabels{oam.LabelPreCheck: types.VelaCoreName})
Expect(err).Should(Succeed())
Expect(appRevList.Items).Should(HaveLen(0))
})
})
})
// mockFailingClient is a test client that can simulate various failure scenarios
type mockFailingClient struct {
client.Client
failCreate bool
failGet bool
failNamespaceOps bool
}
func (m *mockFailingClient) Create(ctx context.Context, obj client.Object, opts ...client.CreateOption) error {
if m.failCreate {
if _, ok := obj.(*v1beta1.ApplicationRevision); ok {
return errors.New("simulated create failure")
}
}
if m.failNamespaceOps {
if _, ok := obj.(*corev1.Namespace); ok {
return errors.New("simulated namespace creation failure")
}
}
return m.Client.Create(ctx, obj, opts...)
}
func (m *mockFailingClient) Get(ctx context.Context, key client.ObjectKey, obj client.Object, opts ...client.GetOption) error {
if m.failGet {
if _, ok := obj.(*v1beta1.ApplicationRevision); ok {
return errors.New("simulated get failure")
}
}
if m.failNamespaceOps {
if _, ok := obj.(*corev1.Namespace); ok {
return apierrors.NewNotFound(corev1.SchemeGroupVersion.WithResource("namespaces").GroupResource(), key.Name)
}
}
return m.Client.Get(ctx, key, obj, opts...)
}

View File

@@ -1,31 +0,0 @@
/*
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 hooks
import "context"
// PreStartHook defines a hook that should be run before the controller starts working.
// Pre-start hooks are used for validation, initialization, and safety checks that must
// pass before the controller begins processing resources.
type PreStartHook interface {
// Run executes the hook's logic. If an error is returned, the controller
// startup will be aborted.
Run(ctx context.Context) error
// Name returns a human-readable name for the hook, used in logging.
Name() string
}

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