mirror of
https://github.com/kubevela/kubevela.git
synced 2026-03-02 01:30:47 +00:00
Compare commits
1 Commits
v1.10.1
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d18d0d4463 |
2
.github/workflows/e2e-multicluster-test.yml
vendored
2
.github/workflows/e2e-multicluster-test.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
e2e-multi-cluster-tests:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: self-hosted
|
||||
needs: [ detect-noop ]
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
strategy:
|
||||
|
||||
2
.github/workflows/e2e-test.yml
vendored
2
.github/workflows/e2e-test.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
continue-on-error: true
|
||||
|
||||
e2e-tests:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: self-hosted
|
||||
needs: [ detect-noop ]
|
||||
if: needs.detect-noop.outputs.noop != 'true'
|
||||
strategy:
|
||||
|
||||
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
@@ -176,7 +176,7 @@ jobs:
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
|
||||
- name: Build Test for vela core
|
||||
uses: docker/build-push-action@1a162644f9a7e87d8f4b053101d1d9a712edc18c # v6.3.0
|
||||
with:
|
||||
@@ -196,7 +196,7 @@ jobs:
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
|
||||
- name: Build Test for CLI
|
||||
uses: docker/build-push-action@1a162644f9a7e87d8f4b053101d1d9a712edc18c # v6.3.0
|
||||
with:
|
||||
|
||||
2
.github/workflows/registry.yml
vendored
2
.github/workflows/registry.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0
|
||||
- uses: docker/setup-buildx-action@6524bf65af31da8d45b59e8c27de4bd072b392f5 # v3.8.0
|
||||
- uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
|
||||
with:
|
||||
driver-opts: image=moby/buildkit:master
|
||||
|
||||
|
||||
@@ -27,9 +27,6 @@ import (
|
||||
|
||||
// ComponentDefinitionSpec defines the desired state of ComponentDefinition
|
||||
type ComponentDefinitionSpec struct {
|
||||
// +optional
|
||||
Version string `json:"version,omitempty"`
|
||||
|
||||
// Workload is a workload type descriptor
|
||||
Workload common.WorkloadTypeDescriptor `json:"workload"`
|
||||
|
||||
|
||||
@@ -164,9 +164,6 @@ type TraitDefinitionSpec struct {
|
||||
// pre-process and post-process respectively.
|
||||
// +optional
|
||||
Stage StageType `json:"stage,omitempty"`
|
||||
|
||||
// +optional
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// StageType describes how the manifests should be dispatched.
|
||||
|
||||
@@ -37,9 +37,6 @@ type PolicyDefinitionSpec struct {
|
||||
// ManageHealthCheck means the policy will handle health checking and skip application controller
|
||||
// built-in health checking.
|
||||
ManageHealthCheck bool `json:"manageHealthCheck,omitempty"`
|
||||
|
||||
//+optional
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// PolicyDefinitionStatus is the status of PolicyDefinition
|
||||
|
||||
@@ -33,9 +33,6 @@ type WorkflowStepDefinitionSpec struct {
|
||||
// Only CUE schematic is supported for now.
|
||||
// +optional
|
||||
Schematic *common.Schematic `json:"schematic,omitempty"`
|
||||
|
||||
// +optional
|
||||
Version string `json:"version,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowStepDefinitionStatus is the status of WorkflowStepDefinition
|
||||
|
||||
@@ -1053,8 +1053,6 @@ spec:
|
||||
for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workload:
|
||||
description: Workload is a workload type descriptor
|
||||
properties:
|
||||
@@ -1358,8 +1356,6 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: PolicyDefinitionStatus is the status of PolicyDefinition
|
||||
@@ -1655,8 +1651,6 @@ spec:
|
||||
for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workloadRefPath:
|
||||
description: WorkloadRefPath indicates where/if a trait
|
||||
accepts a workloadRef object
|
||||
@@ -2065,8 +2059,6 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: WorkflowStepDefinitionStatus is the status of WorkflowStepDefinition
|
||||
|
||||
@@ -195,8 +195,6 @@ spec:
|
||||
the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workload:
|
||||
description: Workload is a workload type descriptor
|
||||
properties:
|
||||
|
||||
@@ -241,8 +241,6 @@ spec:
|
||||
for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workload:
|
||||
description: Workload is a workload type descriptor
|
||||
properties:
|
||||
@@ -491,8 +489,6 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: PolicyDefinitionStatus is the status of PolicyDefinition
|
||||
@@ -778,8 +774,6 @@ spec:
|
||||
for the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workloadRefPath:
|
||||
description: WorkloadRefPath indicates where/if a trait accepts
|
||||
a workloadRef object
|
||||
@@ -998,8 +992,6 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: WorkflowStepDefinitionStatus is the status of WorkflowStepDefinition
|
||||
|
||||
@@ -156,8 +156,6 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: PolicyDefinitionStatus is the status of PolicyDefinition
|
||||
|
||||
@@ -225,8 +225,6 @@ spec:
|
||||
the abstraction
|
||||
type: string
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
workloadRefPath:
|
||||
description: WorkloadRefPath indicates where/if a trait accepts a
|
||||
workloadRef object
|
||||
|
||||
@@ -152,8 +152,6 @@ spec:
|
||||
- configuration
|
||||
type: object
|
||||
type: object
|
||||
version:
|
||||
type: string
|
||||
type: object
|
||||
status:
|
||||
description: WorkflowStepDefinitionStatus is the status of WorkflowStepDefinition
|
||||
|
||||
@@ -14,13 +14,13 @@ webhooks:
|
||||
service:
|
||||
name: {{ template "kubevela.name" . }}-webhook
|
||||
namespace: {{ .Release.Namespace }}
|
||||
path: /validating-core-oam-dev-v1beta1-traitdefinitions
|
||||
path: /validating-core-oam-dev-v1alpha2-traitdefinitions
|
||||
{{- if .Values.admissionWebhooks.patch.enabled }}
|
||||
failurePolicy: Ignore
|
||||
{{- else }}
|
||||
failurePolicy: {{ .Values.admissionWebhooks.failurePolicy }}
|
||||
{{- end }}
|
||||
name: validating.core.oam.dev.v1beta1.traitdefinitions
|
||||
name: validating.core.oam.dev.v1alpha2.traitdefinitions
|
||||
sideEffects: None
|
||||
admissionReviewVersions:
|
||||
- v1beta1
|
||||
@@ -35,6 +35,7 @@ webhooks:
|
||||
- UPDATE
|
||||
resources:
|
||||
- traitdefinitions
|
||||
scope: Cluster
|
||||
timeoutSeconds: 5
|
||||
- clientConfig:
|
||||
caBundle: Cg==
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/podsecuritycontext.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Adds security context to the pod spec in path 'spec.template.spec.securityContext'.
|
||||
name: podsecuritycontext
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
patch: spec: template: spec: securityContext: {
|
||||
if parameter.appArmorProfile != _|_ {
|
||||
appArmorProfile: parameter.appArmorProfile
|
||||
}
|
||||
if parameter.fsGroup != _|_ {
|
||||
fsGroup: parameter.fsGroup
|
||||
}
|
||||
if parameter.runAsGroup != _|_ {
|
||||
runAsGroup: parameter.runAsGroup
|
||||
}
|
||||
if parameter.runAsUser != _|_ {
|
||||
runAsUser: parameter.runAsUser
|
||||
}
|
||||
if parameter.seccompProfile != _|_ {
|
||||
seccompProfile: parameter.seccompProfile
|
||||
}
|
||||
runAsNonRoot: parameter.runAsNonRoot
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Specify the AppArmor profile for the pod
|
||||
appArmorProfile?: {
|
||||
type: "RuntimeDefault" | "Unconfined" | "Localhost"
|
||||
localhostProfile: string
|
||||
}
|
||||
fsGroup?: int
|
||||
runAsGroup?: int
|
||||
// +usage=Specify the UID to run the entrypoint of the container process
|
||||
runAsUser?: int
|
||||
// +usage=Specify if the container runs as a non-root user
|
||||
runAsNonRoot: *true | bool
|
||||
// +usage=Specify the seccomp profile for the pod
|
||||
seccompProfile?: {
|
||||
type: "RuntimeDefault" | "Unconfined" | "Localhost"
|
||||
localhostProfile: string
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/securitycontext.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: TraitDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Adds security context to the container spec in path 'spec.template.spec.containers.[].securityContext'.
|
||||
name: securitycontext
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
appliesToWorkloads:
|
||||
- deployments.apps
|
||||
- statefulsets.apps
|
||||
- daemonsets.apps
|
||||
- jobs.batch
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
#PatchParams: {
|
||||
// +usage=Specify the name of the target container, if not set, use the component name
|
||||
containerName: *"" | string
|
||||
addCapabilities?: [...string]
|
||||
allowPrivilegeEscalation: *false | bool
|
||||
dropCapabilities?: [...string]
|
||||
privileged: *false | bool
|
||||
readOnlyRootFilesystem: *false | bool
|
||||
runAsNonRoot: *true | bool
|
||||
runAsUser?: int
|
||||
runAsGroup?: int
|
||||
}
|
||||
|
||||
PatchContainer: {
|
||||
_params: #PatchParams
|
||||
name: _params.containerName
|
||||
_baseContainers: context.output.spec.template.spec.containers
|
||||
_matchContainers_: [for _container_ in _baseContainers if _container_.name == name {_container_}]
|
||||
_baseContainer: *_|_ | {...}
|
||||
if len(_matchContainers_) == 0 {
|
||||
err: "container \(name) not found"
|
||||
}
|
||||
if len(_matchContainers_) > 0 {
|
||||
securityContext: {
|
||||
capabilities: {
|
||||
if _params.addCapabilities != _|_ {
|
||||
add: _params.addCapabilities
|
||||
}
|
||||
if _params.dropCapabilities != _|_ {
|
||||
drop: _params.dropCapabilities
|
||||
}
|
||||
}
|
||||
if _params.runAsUser != _|_ {
|
||||
runAsUser: _params.runAsUser
|
||||
}
|
||||
if _params.runAsGroup != _|_ {
|
||||
runAsGroup: _params.runAsGroup
|
||||
}
|
||||
allowPrivilegeEscalation: _params.allowPrivilegeEscalation
|
||||
readOnlyRootFilesystem: _params.readOnlyRootFilesystem
|
||||
privileged: _params.privileged
|
||||
runAsNonRoot: _params.runAsNonRoot
|
||||
}
|
||||
}
|
||||
}
|
||||
patch: spec: template: spec: {
|
||||
if parameter.containers == _|_ {
|
||||
// +patchKey=name
|
||||
containers: [{
|
||||
PatchContainer & {_params: {
|
||||
if parameter.containerName == "" {
|
||||
containerName: context.name
|
||||
}
|
||||
if parameter.containerName != "" {
|
||||
containerName: parameter.containerName
|
||||
}
|
||||
allowPrivilegeEscalation: parameter.allowPrivilegeEscalation
|
||||
readOnlyRootFilesystem: parameter.readOnlyRootFilesystem
|
||||
privileged: parameter.privileged
|
||||
runAsNonRoot: parameter.runAsNonRoot
|
||||
runAsUser: parameter.runAsUser
|
||||
runAsGroup: parameter.runAsGroup
|
||||
addCapabilities: parameter.addCapabilities
|
||||
dropCapabilities: parameter.dropCapabilities
|
||||
}}
|
||||
}]
|
||||
}
|
||||
|
||||
if parameter.containers != _|_ {
|
||||
// +patchKey=name
|
||||
containers: [for c in parameter.containers {
|
||||
if c.containerName == "" {
|
||||
err: "containerName must be set for containers"
|
||||
}
|
||||
if c.containerName != "" {
|
||||
PatchContainer & {_params: c}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
parameter: #PatchParams | close({
|
||||
// +usage=Specify the container image for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
errs: [for c in patch.spec.template.spec.containers if c.err != _|_ {c.err}]
|
||||
|
||||
@@ -296,4 +296,4 @@ authentication:
|
||||
## @param sharding.schedulableShards The shards available for scheduling. If empty, dynamic discovery will be used.
|
||||
sharding:
|
||||
enabled: false
|
||||
schedulableShards: ""
|
||||
schedulableShards: ""
|
||||
@@ -1,321 +0,0 @@
|
||||
# Versioning Support for KubeVela Definitions
|
||||
|
||||
<!-- toc -->
|
||||
- [Versioning Support for KubeVela Definitions](#versioning-support-for-kubevela-definitions)
|
||||
- [Summary](#summary)
|
||||
- [Scope](#scope)
|
||||
- [Motivation](#motivation)
|
||||
- [Goals](#goals)
|
||||
- [Non-Goals](#non-goals)
|
||||
- [Acceptance Criteria](#acceptance-criteria)
|
||||
- [Current Implementation](#current-implementation)
|
||||
- [Versioning](#versioning)
|
||||
- [Auto Upgrade](#auto-upgrade)
|
||||
- [Reference:](#reference)
|
||||
- [Proposal](#proposal)
|
||||
- [Details](#details)
|
||||
- [Issues](#issues)
|
||||
- [Examples](#examples)
|
||||
<!-- /toc -->
|
||||
|
||||
## Summary
|
||||
|
||||
Support Semantic versioning for KubeVela Components and a way to allow fine control over auto-upgrades of KubeVela Applications to new versions of a Component. The implementation should include support for consistent versioning across environments/clusters, meaning specific Revisions/Versions of a Component should have consistent behaviour.
|
||||
|
||||
## Scope
|
||||
|
||||
Although, this document limits the scope of discussion to ComponentDefinition Revisions/Versions, due to the current implementation, the changes will most likely apply to all [`Definition`](https://kubevela.io/docs/getting-started/definition/) types. These changes are planned to be explored and validated as part of the implementation.
|
||||
|
||||
## Motivation
|
||||
|
||||
OAM/KubeVela Definitions (referred to as ComponentDefinitions of Components in the rest
|
||||
of the document) are the basic building blocks of the KubeVela platform. They
|
||||
expose a contract similar to an API contract, which evolves from minor to major
|
||||
versions. Applications are composed of Components that the KubeVela engine stitches
|
||||
together.
|
||||
|
||||
KubeVela creates a `DefinitionRevision` for all changes in a Component `spec`.
|
||||
Currently, Applications can refer to a particular Revision of a Component.
|
||||
But, this versioning scheme has the following issues:
|
||||
|
||||
- The `DefinitionRevision` does not denote the type of the change (patch/bug, minor or major). This hinders automation of automatic upgrades.
|
||||
- The current scheme also doesn't allow much control over automatic upgrades to new Component Revisions. KubeVela automatically upgrades/reconciles the Application to the
|
||||
latest when no Component Revision is specified.
|
||||
> While we don't ideally want Application developers to bother with such details, there are use cases where
|
||||
> an automatic upgrade to the latest Component version is not desired.
|
||||
|
||||
|
||||
### Goals
|
||||
|
||||
- Support Component versioning with Semantic Versions.
|
||||
- Allow pinning specific and non-specific versions of a Component in the
|
||||
KubeVela Application.
|
||||
|
||||
### Non-Goals
|
||||
|
||||
- Support for version range in Application. For eg. "type: my-component@>1.2.0"
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
**User Story: Component version specification**
|
||||
|
||||
>**AS A** Component author\
|
||||
>**I SHOULD** be able to publish every version of my Component with the Semantic Versioning scheme\
|
||||
>**SO THAT** an Application developer can use a specific version of the Component.
|
||||
|
||||
**BDD Acceptance Criteria**
|
||||
|
||||
>**GIVEN** an updated ComponentDefinition Specification \
|
||||
>**AND** a version denoted by the ComponentDefinition is set to V\
|
||||
>**WHEN** the Component is applied to KubeVela\
|
||||
>**THEN** `V` should be listed as one of the many versions in the DefinitionRevision list
|
||||
|
||||
**User Story: Application Component version specification**
|
||||
|
||||
>**AS AN** Application developer\
|
||||
>**I SHOULD** be able to specify a version (complete or partial) for every Component used\
|
||||
>**SO THAT** I can control which version are deployed.
|
||||
|
||||
**BDD Acceptance Criteria**
|
||||
|
||||
>Scenario 1: Use the version specified in the Application manifest when deploying the service\
|
||||
>**GIVEN** a Component A with versions 1.2.2 | 1.2.3\
|
||||
>**AND** a Component B with versions 4.4.2 | 4.5.6\
|
||||
>**AND** an Application composed of A 1.2.2 and B 4.4.2\
|
||||
>**WHEN** the Application is deployed\
|
||||
>**THEN** it uses Component A 1.2.2 and B 4.4.2
|
||||
>
|
||||
>**Variant:** Use the latest version for the part of the SemVer that is not specified.\
|
||||
>**GIVEN** component A latest version is 1.2.3
|
||||
>**AND** Component B latest version is 4.5.6
|
||||
>**AND** an Application composed of A 1.2 and B 4\
|
||||
>**WHEN** the Application is deployed\
|
||||
>**THEN** it uses Component A 1.2.3 and B 4.5.6
|
||||
|
||||
> Scenario 2: Behaviour when auto-upgrade is disabled \
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** an Application composed of A-1.2.3\
|
||||
> **IF** Auto-upgrade is disabled\
|
||||
> **WHEN** a new version of Component A (A-1.2.5) is released\
|
||||
> **THEN** the Application should continue to use A-1.2.3
|
||||
>
|
||||
> **Variant** Behaviour when auto-upgrade is disabled and exact version is unavailable.\
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** a new Application composed of A-1.2.2\
|
||||
> **IF** Auto-upgrade is disabled\
|
||||
> **WHEN** the Application is applied\
|
||||
> **THEN** the Application deployment should fail.
|
||||
>
|
||||
> **Variant** Behaviour when auto-upgrade is disabled and exact version is unavailable.\
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** a new Application composed of A-1.2\
|
||||
> **IF** Auto-upgrade is disabled\
|
||||
> **WHEN** the Application is applied\
|
||||
> **THEN** the Application deployment should fail.
|
||||
|
||||
> Scenario 3: Behaviour when auto-upgrade is enabled \
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** an Application composed of A-1.2\
|
||||
> **IF** Auto-upgrade is enabled\
|
||||
> **THEN** the Application should use A-1.2.3
|
||||
> **AND WHEN** a new version of Component A (A-1.2.5) is released\
|
||||
> **THEN** the Application should update to use A-1.2.5
|
||||
>
|
||||
> **Variant** Behaviour when auto-upgrade is enabled and exact version is unavailable \
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** a new Application composed of A-1.2.2\
|
||||
> **IF** Auto-upgrade is enabled\
|
||||
> **WHEN** the Application is applied\
|
||||
> **THEN** the Application deployment should fail.
|
||||
>
|
||||
> **Variant** Behaviour when auto-upgrade is enabled and exact version is unavailable \
|
||||
> **GIVEN** a component A with version 1.2.3\
|
||||
> **AND** a new Application composed of A-1.2\
|
||||
> **IF** Auto-upgrade is enabled\
|
||||
> **WHEN** the Application is applied\
|
||||
> **THEN** the Application deployment should use A-1.2.3.
|
||||
|
||||
> Scenario 4: Expectations of consistent versioning across Environments/Clusters. \
|
||||
> **GIVEN** a component A with versions 1.2.1|1.2.2|2.2.1\
|
||||
> **AND** an Application composed of A-1.2.2\
|
||||
> **IF** the Application needs to be deployed across Environments (Dev, Prod etc)\
|
||||
> **OR** the Application needs to be deployed in multiple clusters managed independently\
|
||||
> **WHEN** the Application is deployed across Environments/Clusters \
|
||||
> **THEN** The Application should behave consistently, as in all the clusters A-1.2.2 map to the same ComponentDefinition changes.
|
||||
|
||||
## Current Implementation
|
||||
|
||||
### Versioning
|
||||
|
||||
Currently, KubeVela has some support for controlling Definition versions based on K8s annotations and DefinitionRevisions. The annotation `definitionrevision.oam.dev/name` can be used to version the ComponentDefinition. For example if the following annotation is added to a ComponentDefinition, it produces a new DefinitionRevision and names the ComponentDefinition as `component-name-v4.4` .
|
||||
|
||||
> definitionrevision.oam.dev/name: "4.4"
|
||||
|
||||
This Component can then be referred in the Application as follows:
|
||||
|
||||
>"component-name@v4.4" - `NamedDefinitionRevision`
|
||||
|
||||
Alternatively, since DefinitionRevisions are maintained even if a **"named"** Revision is not specified via the annotation `definitionrevision.oam.dev/name`, Applications can still refer to a particular Revision of a Component via the auto-incrementing Revision numbers.
|
||||
|
||||
>"component-name@v2" - `DefinitionRevision`
|
||||
|
||||

|
||||
|
||||
This versioning scheme, although convenient, has the following issues:
|
||||
|
||||
- Applications which do not explicitly specify a target Revision of a ComponentDefinition, the "latest" applied revision of the ComponentDefinition is used. In scenarios where a cluster has to be replicated or re-created, this means that the sequence in which revisions of a ComponentDefinition are applied becomes important. Implicitly, this also means that the Component maintainers need to keep all Revisions of a ComponentDefinition in their deployment pipeline.\
|
||||
If `definitionrevision.oam.dev/name` annotation is not added to ComponentDefinitions, even if the Applications are explicit about a Component Revision, there is currently no guarantee that the Application behaviour will be consistent across Environments/Clusters. For example, a `Dev` environment will typically have more churn in Revisions than a `Prod` one and a reference to Component Revision `v3` in an Application will not be the same in both environments.
|
||||
|
||||
|
||||
### Auto Upgrade
|
||||
KubeVela utilises the annotation `app.oam.dev/autoUpdate` for automatic upgrade.
|
||||
|
||||
Application reconciliation behaviour when the `app.oam.dev/autoUpdate` annotation is specified in the Application:
|
||||
- If a ComponentDefinition Revision is not specified, the Application will always use the latest available Revision.
|
||||
- If a ComponentDefinition Revision is specified and a new Revision is released after the Application was created, the latest changes will not reflect in the Application.
|
||||
|
||||
Note: This feature is not documented in KubeVela documentation.
|
||||
|
||||
#### Reference:
|
||||
|
||||
- https://kubevela.io/docs/platform-engineers/x-def-version/
|
||||
- [Auto Upgrade PR](https://github.com/kubevela/kubevela/pull/3217)
|
||||
|
||||
|
||||
## Proposal
|
||||
|
||||
### Introduce `spec.version` as an optional field in the Definition
|
||||
|
||||
- Add an optional field `version` in the Definition `spec` and use it to generate the ComponentDefinition Revisions.
|
||||
|
||||
- Update the auto-upgrade behaviour to also allow limiting upgrades for an Application within a specified Definition version range. The existing annotation `app.oam.dev/autoUpdate` for enabling automatic updates will be used for this new behaviour and will maintain backward compatibility.
|
||||
|
||||
- Implement Validating webhook to:
|
||||
- Ensure that the values of the annotation `definitionrevision.oam.dev/version`, `definitionrevision.oam.dev/name` or `spec.version` field adhere to semantic versioning.
|
||||
- Ensure that the `definitionrevision.oam.dev/name` annotation and the `spec.version` field are not present together in the ComponentDefinition to avoid conflicts.
|
||||
- Ensure that `app.oam.dev/publishVersion` and `app.oam.dev/autoUpdate` both annotation are not present in Application to avoid conflicts.
|
||||
|
||||
### Issues
|
||||
|
||||
The following issues assume adherence to strict backward compatibility, meaning the `definitionrevision.oam.dev/name` annotation should continue to work as is.
|
||||
|
||||
- It does not resolve inconsistent versioning behaviour across Environments/Clusters when explicit versions are not specified or named DefinitionRevisions are not used.
|
||||
|
||||
## Examples
|
||||
1. Create a `configmap-component` ComponentDefinition with `1.2.5` version
|
||||
```
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: configmap-component
|
||||
namespace: vela-system
|
||||
spec:
|
||||
version: 1.2.5
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: "comptest"
|
||||
}
|
||||
data: {
|
||||
version: "125"
|
||||
}
|
||||
}
|
||||
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
```
|
||||
|
||||
2. Create a `configmap-component` ComponentDefinition with `2.0.5` version
|
||||
```apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: configmap-component
|
||||
namespace: vela-system
|
||||
spec:
|
||||
version: 2.5.0
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: "comptest"
|
||||
}
|
||||
data: {
|
||||
version: "250"
|
||||
}
|
||||
}
|
||||
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
```
|
||||
3. List DefinitionRevisions
|
||||
```
|
||||
kubectl get definitionrevision -n vela-system | grep -i my-component
|
||||
my-component-v1.2.5 1 1a4f3ac77e4fcfef Component
|
||||
my-component-v2.5.0 2 e61e9b5e55b01c2b Component
|
||||
```
|
||||
|
||||
4. Create Application using `configmap-component@v1.2` version and enable the Auto Update using `app.oam.dev/autoUpdate` annotation.
|
||||
```apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: test-app
|
||||
namespace: test
|
||||
annotations:
|
||||
app.oam.dev/autoUpdate: "true"
|
||||
spec:
|
||||
components:
|
||||
- name: test
|
||||
type: my-component@v1
|
||||
```
|
||||
|
||||
Expected Behavior:
|
||||
- Application will use `configmap-component@v1.2.5`, as `1.2.5` is highest version in specified range(`1`).
|
||||
|
||||
5. Create a `configmap-component` ComponentDefinition with `1.2.7` version
|
||||
```
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
name: configmap-component
|
||||
namespace: vela-system
|
||||
spec:
|
||||
version: 1.2.7
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: {
|
||||
name: "comptest"
|
||||
}
|
||||
data: {
|
||||
version: "127"
|
||||
}
|
||||
}
|
||||
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
```
|
||||
|
||||
Expected Behavior:
|
||||
- After the Application is reconciled, it will use `configmap-component@v1.2.7`, as `1.2.7` is the latest version within the specified range (1).
|
||||
|
||||
6. List Definitionrevision
|
||||
```kubectl get definitionrevision -n vela-system | grep -i my-component
|
||||
my-component-v1.2.5 1 1a4f3ac77e4fcfef Component
|
||||
my-component-v1.2.7 3 86d7fb1a36566dea Component
|
||||
my-component-v2.5.0 2 e61e9b5e55b01c2b Component```
|
||||
@@ -1,249 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 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 e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
oamcommon "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/e2e"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
|
||||
var _ = Describe("Application Auto update", Ordered, func() {
|
||||
ctx := context.Background()
|
||||
var k8sClient client.Client
|
||||
var namespace string
|
||||
var ns corev1.Namespace
|
||||
var err error
|
||||
var velaCommandPrefix string
|
||||
|
||||
BeforeEach(func() {
|
||||
k8sClient, err = common.NewK8sClient()
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Create namespace for app-autoupdate-e2e-test")
|
||||
namespace = randomNamespaceName("app-autoupdate-e2e-test")
|
||||
ns = corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
|
||||
k8sClient.Create(ctx, &ns)
|
||||
velaCommandPrefix = fmt.Sprintf("vela -n %s", namespace)
|
||||
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
By("Clean up resources after a test")
|
||||
k8sClient.DeleteAllOf(ctx, &v1beta1.Application{}, client.InNamespace(namespace))
|
||||
k8sClient.DeleteAllOf(ctx, &v1beta1.ComponentDefinition{}, client.InNamespace(namespace))
|
||||
k8sClient.DeleteAllOf(ctx, &v1beta1.DefinitionRevision{}, client.InNamespace(namespace))
|
||||
Expect(k8sClient.Delete(ctx, &ns)).Should(BeNil())
|
||||
})
|
||||
|
||||
It("dry-run command", func() {
|
||||
By("Create configmap-component with 1.2.0 version")
|
||||
component := configMapComponent.DeepCopy()
|
||||
component.SetNamespace(namespace)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
|
||||
By("Execute a dry-run for application having configmap-component@v1 component")
|
||||
output, err := e2e.Exec(fmt.Sprintf("%s dry-run -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring(fmt.Sprintf(dryRunResult1, namespace)))
|
||||
|
||||
By("Create application using configmap-component@v1 component")
|
||||
_, err = e2e.Exec(fmt.Sprintf("%s up -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Create configmap-component with 1.4.0 version")
|
||||
updatedComponent := new(v1beta1.ComponentDefinition)
|
||||
updatedComponentVersion := "1.4.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "configmap-component", Namespace: namespace}, updatedComponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedComponent.Spec.Schematic.CUE.Template = strings.Replace(configMapOutputTemplate, updatedComponent.Spec.Version, updatedComponentVersion, 1)
|
||||
updatedComponent.Spec.Version = updatedComponentVersion
|
||||
return k8sClient.Update(ctx, updatedComponent)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("Execute a dry-run for application having configmap-component@v1 component")
|
||||
output, err = e2e.Exec(fmt.Sprintf("%s dry-run -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring(fmt.Sprintf(dryRunResult2, namespace, namespace)))
|
||||
})
|
||||
|
||||
It("live-diff between application file and revision", func() {
|
||||
By("Create configmap-component with 1.2.0 version")
|
||||
component := configMapComponent.DeepCopy()
|
||||
component.SetNamespace(namespace)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
|
||||
By("Create application using configmap-component@v1 component")
|
||||
_, err = e2e.Exec(fmt.Sprintf("%s up -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Create configmap-component with 1.4.0 version")
|
||||
updatedComponent := new(v1beta1.ComponentDefinition)
|
||||
updatedComponentVersion := "1.4.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "configmap-component", Namespace: namespace}, updatedComponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedComponent.Spec.Schematic.CUE.Template = strings.Replace(configMapOutputTemplate, updatedComponent.Spec.Version, updatedComponentVersion, 1)
|
||||
updatedComponent.Spec.Version = updatedComponentVersion
|
||||
return k8sClient.Update(ctx, updatedComponent)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("Execute a live-diff command for application file and previous application")
|
||||
output, err := e2e.Exec(fmt.Sprintf("%s live-diff -f data/app.yaml -r app-with-auto-update-v1", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring(liveDiffResult))
|
||||
})
|
||||
|
||||
It("live-diff between revisions", func() {
|
||||
By("Create configmap-component with 1.2.0 version")
|
||||
component := configMapComponent.DeepCopy()
|
||||
component.SetNamespace(namespace)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
|
||||
By("Create application using configmap-component@v1 component")
|
||||
_, err = e2e.Exec(fmt.Sprintf("%s up -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Create configmap-component with 1.4.0 version")
|
||||
updatedComponent := new(v1beta1.ComponentDefinition)
|
||||
updatedComponentVersion := "1.4.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "configmap-component", Namespace: namespace}, updatedComponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedComponent.Spec.Schematic.CUE.Template = strings.Replace(configMapOutputTemplate, updatedComponent.Spec.Version, updatedComponentVersion, 1)
|
||||
updatedComponent.Spec.Version = updatedComponentVersion
|
||||
return k8sClient.Update(ctx, updatedComponent)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("Create application using configmap-component@v1 component")
|
||||
_, err = e2e.Exec(fmt.Sprintf("%s up -f data/app.yaml", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
By("Execute a live-diff command for previous two application versions")
|
||||
output, err := e2e.Exec(fmt.Sprintf("%s live-diff --revision app-with-auto-update-v2,app-with-auto-update-v1", velaCommandPrefix))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("Application (app-with-auto-update) has no change"))
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
var configMapComponent = &v1beta1.ComponentDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ComponentDefinition",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "configmap-component",
|
||||
},
|
||||
Spec: v1beta1.ComponentDefinitionSpec{
|
||||
Version: "1.2.0",
|
||||
Schematic: &oamcommon.Schematic{
|
||||
CUE: &oamcommon.CUE{
|
||||
Template: configMapOutputTemplate,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var configMapOutputTemplate = `output: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: name: "comptest"
|
||||
data: {
|
||||
expectedVersion: "1.2.0"
|
||||
}
|
||||
}`
|
||||
|
||||
func randomNamespaceName(basic string) string {
|
||||
return fmt.Sprintf("%s-%s", basic, strconv.FormatInt(rand.Int63(), 16))
|
||||
}
|
||||
|
||||
var dryRunResult1 = `---
|
||||
# Application(app-with-auto-update) -- Component(test)
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
data:
|
||||
expectedVersion: 1.2.0
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/autoUpdate: "true"
|
||||
labels:
|
||||
app.oam.dev/appRevision: ""
|
||||
app.oam.dev/component: test
|
||||
app.oam.dev/name: app-with-auto-update
|
||||
app.oam.dev/namespace: %[1]s
|
||||
app.oam.dev/resourceType: WORKLOAD
|
||||
workload.oam.dev/type: configmap-component-v1
|
||||
name: comptest
|
||||
namespace: %[1]s
|
||||
|
||||
---`
|
||||
|
||||
var dryRunResult2 = `---
|
||||
# Application(app-with-auto-update) -- Component(test)
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
data:
|
||||
expectedVersion: 1.4.0
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
annotations:
|
||||
app.oam.dev/autoUpdate: "true"
|
||||
labels:
|
||||
app.oam.dev/appRevision: ""
|
||||
app.oam.dev/component: test
|
||||
app.oam.dev/name: app-with-auto-update
|
||||
app.oam.dev/namespace: %[1]s
|
||||
app.oam.dev/resourceType: WORKLOAD
|
||||
workload.oam.dev/type: configmap-component-v1
|
||||
name: comptest
|
||||
namespace: %[1]s
|
||||
|
||||
---
|
||||
|
||||
|
||||
`
|
||||
|
||||
var liveDiffResult = `
|
||||
- expectedVersion: 1.2.0
|
||||
+ expectedVersion: 1.4.0
|
||||
`
|
||||
@@ -184,10 +184,8 @@ var ApplicationInitIntercativeCliContext = func(context string, appName string,
|
||||
})
|
||||
}
|
||||
|
||||
// debug test
|
||||
var ApplicationDeleteWithWaitOptions = func(context string, appName string) bool {
|
||||
return ginkgo.It(context+": should print successful deletion information ", func() {
|
||||
time.Sleep(1 * time.Minute)
|
||||
return ginkgo.It(context+": should print successful deletion information", func() {
|
||||
cli := fmt.Sprintf("vela delete %s --wait -y", appName)
|
||||
output, err := e2e.LongTimeExec(cli, 10*time.Second)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-with-auto-update
|
||||
annotations:
|
||||
app.oam.dev/autoUpdate: "true"
|
||||
spec:
|
||||
components:
|
||||
- name: test
|
||||
type: configmap-component@v1
|
||||
@@ -56,7 +56,7 @@ func ExecAndTerminate(cli string) (string, error) {
|
||||
if err != nil {
|
||||
return string(output), err
|
||||
}
|
||||
time.Sleep(10 * time.Second)
|
||||
time.Sleep(3 * time.Second)
|
||||
s := session.Terminate()
|
||||
return string(s.Out.Contents()) + string(s.Err.Contents()), nil
|
||||
}
|
||||
|
||||
@@ -462,26 +462,24 @@ spec:
|
||||
- backend
|
||||
podDisruptive: true
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
output: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata: {
|
||||
name: "my-service"
|
||||
}
|
||||
spec:{
|
||||
ports: [{
|
||||
protocol: "TCP"
|
||||
kube:
|
||||
template:
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: parameters.targetPort
|
||||
}]
|
||||
}
|
||||
parameters:{
|
||||
//+usage=target port num for service provider
|
||||
targetPort: *9376 | int
|
||||
}
|
||||
}
|
||||
targetPort: 9376
|
||||
parameters:
|
||||
- name: targetPort
|
||||
required: true
|
||||
type: number
|
||||
fieldPaths:
|
||||
- "spec.template.spec.ports[0].targetPort"
|
||||
description: "target port num for service provider."
|
||||
`
|
||||
|
||||
var componentWithDeepCue = `
|
||||
|
||||
63
go.mod
63
go.mod
@@ -6,7 +6,6 @@ require (
|
||||
cuelang.org/go v0.9.2
|
||||
github.com/AlecAivazis/survey/v2 v2.1.1
|
||||
github.com/FogDong/uitable v0.0.5
|
||||
github.com/Masterminds/semver v1.5.0
|
||||
github.com/Masterminds/semver/v3 v3.2.1
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8
|
||||
github.com/aryann/difflib v0.0.0-20210328193216-ff5ff6dc229b
|
||||
@@ -25,7 +24,7 @@ require (
|
||||
github.com/form3tech-oss/jwt-go v3.2.5+incompatible
|
||||
github.com/gdamore/tcell/v2 v2.6.0
|
||||
github.com/getkin/kin-openapi v0.118.0
|
||||
github.com/go-git/go-git/v5 v5.13.1
|
||||
github.com/go-git/go-git/v5 v5.8.1
|
||||
github.com/go-logr/logr v1.4.1
|
||||
github.com/go-resty/resty/v2 v2.8.0
|
||||
github.com/golang/mock v1.6.0
|
||||
@@ -49,8 +48,8 @@ require (
|
||||
github.com/oam-dev/terraform-config-inspect v0.0.0-20210418082552-fc72d929aa28
|
||||
github.com/oam-dev/terraform-controller v0.8.0
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/onsi/ginkgo/v2 v2.19.0
|
||||
github.com/onsi/gomega v1.34.1
|
||||
github.com/onsi/ginkgo/v2 v2.14.0
|
||||
github.com/onsi/gomega v1.30.0
|
||||
github.com/openkruise/kruise-api v1.4.0
|
||||
github.com/openkruise/rollouts v0.3.0
|
||||
github.com/pelletier/go-toml v1.9.5
|
||||
@@ -61,19 +60,19 @@ require (
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/stretchr/testify v1.10.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
github.com/tidwall/gjson v1.14.4
|
||||
github.com/wercker/stern v0.0.0-20190705090245-4fa46dd6987f
|
||||
github.com/xanzy/go-gitlab v0.91.1
|
||||
github.com/xlab/treeprint v1.2.0
|
||||
go.uber.org/multierr v1.11.0
|
||||
golang.org/x/crypto v0.32.0
|
||||
golang.org/x/mod v0.19.0
|
||||
golang.org/x/crypto v0.25.0
|
||||
golang.org/x/mod v0.17.0
|
||||
golang.org/x/oauth2 v0.20.0
|
||||
golang.org/x/sync v0.10.0
|
||||
golang.org/x/term v0.28.0
|
||||
golang.org/x/text v0.21.0
|
||||
golang.org/x/tools v0.23.0
|
||||
golang.org/x/sync v0.7.0
|
||||
golang.org/x/term v0.22.0
|
||||
golang.org/x/text v0.16.0
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d
|
||||
gomodules.xyz/jsonpatch/v2 v2.4.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
helm.sh/helm/v3 v3.14.4
|
||||
@@ -106,13 +105,15 @@ require (
|
||||
github.com/BurntSushi/toml v1.3.2 // indirect
|
||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible // indirect
|
||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
||||
github.com/Masterminds/squirrel v1.5.4 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.2 // indirect
|
||||
github.com/Microsoft/hcsshim v0.12.2 // indirect
|
||||
github.com/NYTimes/gziphandler v1.1.1 // indirect
|
||||
github.com/ProtonMail/go-crypto v1.1.3 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.4 // indirect
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/alessio/shellescape v1.4.1 // indirect
|
||||
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1704 // indirect
|
||||
@@ -128,14 +129,16 @@ require (
|
||||
github.com/chai2010/gettext-go v1.0.2 // indirect
|
||||
github.com/cloudflare/circl v1.3.7 // indirect
|
||||
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
|
||||
github.com/containerd/containerd v1.7.14 // indirect
|
||||
github.com/containerd/containerd v1.7.24 // indirect
|
||||
github.com/containerd/errdefs v0.3.0 // indirect
|
||||
github.com/containerd/platforms v0.2.1 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect
|
||||
github.com/coreos/go-semver v0.3.1 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3 // indirect
|
||||
github.com/creack/pty v1.1.18 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 // indirect
|
||||
github.com/distribution/reference v0.5.0 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||
github.com/distribution/reference v0.6.0 // indirect
|
||||
github.com/docker/cli v26.0.0+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||
github.com/docker/docker v26.0.0+incompatible // indirect
|
||||
@@ -160,7 +163,7 @@ require (
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-errors/errors v1.5.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.1 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.4.1 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-logr/zapr v1.3.0 // indirect
|
||||
@@ -168,7 +171,7 @@ require (
|
||||
github.com/go-openapi/jsonreference v0.21.0 // indirect
|
||||
github.com/go-openapi/swag v0.23.0 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/gobuffalo/flect v1.0.2 // indirect
|
||||
github.com/gobwas/glob v0.2.3 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
@@ -179,7 +182,7 @@ require (
|
||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
|
||||
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 // indirect
|
||||
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 // indirect
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
@@ -245,9 +248,9 @@ require (
|
||||
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||
github.com/rubenv/sql-migrate v1.5.2 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
|
||||
github.com/sergi/go-diff v1.1.0 // indirect
|
||||
github.com/shopspring/decimal v1.3.1 // indirect
|
||||
github.com/skeema/knownhosts v1.3.0 // indirect
|
||||
github.com/skeema/knownhosts v1.2.0 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/stoewer/go-strcase v1.2.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
@@ -261,27 +264,27 @@ require (
|
||||
go.etcd.io/etcd/api/v3 v3.5.10 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.10 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.10 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 // indirect
|
||||
go.opentelemetry.io/otel v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.19.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.21.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v1.0.0 // indirect
|
||||
go.starlark.net v0.0.0-20240329153429-e6e8e7ce1b7a // indirect
|
||||
go.uber.org/automaxprocs v1.5.3 // indirect
|
||||
go.uber.org/zap v1.26.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/sys v0.29.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect
|
||||
golang.org/x/net v0.25.0 // indirect
|
||||
golang.org/x/sys v0.22.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
|
||||
google.golang.org/grpc v1.63.0 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
google.golang.org/protobuf v1.33.0 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/evanphx/json-patch.v5 v5.9.0 // indirect
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
|
||||
|
||||
151
go.sum
151
go.sum
@@ -53,8 +53,8 @@ github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBa
|
||||
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
|
||||
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
|
||||
github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
|
||||
github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
|
||||
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
|
||||
github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/Microsoft/hcsshim v0.12.2 h1:AcXy+yfRvrx20g9v7qYaJv5Rh+8GaHOS6b8G6Wx/nKs=
|
||||
github.com/Microsoft/hcsshim v0.12.2/go.mod h1:RZV12pcHCXQ42XnlQ3pz6FZfmrC1C+R4gaOHhRNML1g=
|
||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||
@@ -63,12 +63,14 @@ github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMo
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8 h1:xzYJEypr/85nBpB11F9br+3HUrpgb+fcm5iADzXXYEw=
|
||||
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
|
||||
github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs=
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
|
||||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
||||
github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
|
||||
github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
|
||||
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/agext/levenshtein v1.2.2/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
|
||||
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
|
||||
@@ -134,6 +136,7 @@ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembj
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
|
||||
@@ -154,6 +157,7 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWR
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
|
||||
github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
|
||||
github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
@@ -174,14 +178,16 @@ github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u9
|
||||
github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM=
|
||||
github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0=
|
||||
github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE=
|
||||
github.com/containerd/containerd v1.7.14 h1:H/XLzbnGuenZEGK+v0RkwTdv2u1QFAruMe5N0GNPJwA=
|
||||
github.com/containerd/containerd v1.7.14/go.mod h1:YMC9Qt5yzNqXx/fO4j/5yYVIHXSRrlB3H7sxkUTvspg=
|
||||
github.com/containerd/containerd v1.7.24 h1:zxszGrGjrra1yYJW/6rhm9cJ1ZQ8rkKBR48brqsa7nA=
|
||||
github.com/containerd/containerd v1.7.24/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw=
|
||||
github.com/containerd/continuity v0.4.2 h1:v3y/4Yz5jwnvqPKJJ+7Wf93fyWoCB3F5EclWG023MDM=
|
||||
github.com/containerd/continuity v0.4.2/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ=
|
||||
github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM=
|
||||
github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0=
|
||||
github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4=
|
||||
github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
|
||||
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU=
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
@@ -209,8 +215,8 @@ github.com/crossplane/crossplane-runtime v1.16.0 h1:lz+l0wEB3qowdTmN7t0PZkfuNSvf
|
||||
github.com/crossplane/crossplane-runtime v1.16.0/go.mod h1:Pz2tdGVMF6KDGzHZOkvKro0nKc8EzK0sb/nSA7pH4Dc=
|
||||
github.com/cue-exp/kubevelafix v0.0.0-20220922150317-aead819d979d h1:VNJA1nSKA8Xna5wjUIMItHlWmEej8Bb9fZ3vCNtIAX0=
|
||||
github.com/cue-exp/kubevelafix v0.0.0-20220922150317-aead819d979d/go.mod h1:SyTryzw/zYJIogw3H2IRcYdV5gsSoVMJiKGElcQK09I=
|
||||
github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM=
|
||||
github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/dave/jennifer v1.6.1 h1:T4T/67t6RAA5AIV6+NP8Uk/BIsXgDoqEowgycdQQLuk=
|
||||
github.com/dave/jennifer v1.6.1/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -220,8 +226,8 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2 h1:aBfCb7iqHmDEIp6fBvC/hQUddQfg+3qdYjwzaiP9Hnc=
|
||||
github.com/distribution/distribution/v3 v3.0.0-20221208165359-362910506bc2/go.mod h1:WHNsWjnIn2V1LYOrME7e8KxSeKunYHsxEm4am0BUtcI=
|
||||
github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0=
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
|
||||
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/docker/cli v24.0.9+incompatible h1:OxbimnP/z+qVjDLpq9wbeFU3Nc30XhSe+LkwYQisD50=
|
||||
github.com/docker/cli v24.0.9+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
|
||||
github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk=
|
||||
@@ -245,8 +251,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||
github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ=
|
||||
github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64=
|
||||
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0=
|
||||
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
@@ -324,18 +330,18 @@ github.com/getkin/kin-openapi v0.118.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BH
|
||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
|
||||
github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU=
|
||||
github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
|
||||
github.com/gliderlabs/ssh v0.3.5/go.mod h1:8XB4KraRrX39qHhT6yxPsHedjA08I/uBVwj4xC+/+z4=
|
||||
github.com/go-errors/errors v1.5.1 h1:ZwEMSLRCapFLflTpT7NKaAc7ukJ8ZPEjzlxt8rPN8bk=
|
||||
github.com/go-errors/errors v1.5.1/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
|
||||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
|
||||
github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA=
|
||||
github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
|
||||
github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M=
|
||||
github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
|
||||
github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
|
||||
github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f/go.mod h1:8LHG1a3SRW71ettAD/jW13h8c6AqjVSeL11RAdgaqpo=
|
||||
github.com/go-git/go-git/v5 v5.8.1 h1:Zo79E4p7TRk0xoRgMq0RShiTHGKcKI4+DI6BfJc/Q+A=
|
||||
github.com/go-git/go-git/v5 v5.8.1/go.mod h1:FHFuoD6yGz5OSKEBK+aWN9Oah0q54Jxl0abmj6GnqAo=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
|
||||
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
|
||||
@@ -387,8 +393,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
|
||||
github.com/go-stack/stack v1.8.1 h1:ntEHSVwIt7PNXNpgPmVfMrNhLtgjlmnZha2kOpuRiDw=
|
||||
github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
@@ -485,8 +491,8 @@ github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
|
||||
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
|
||||
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815 h1:WzfWbQz/Ze8v6l++GGbGNFZnUShVpP/0xffCPLL+ax8=
|
||||
github.com/google/pprof v0.0.0-20240117000934-35fc243c5815/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI=
|
||||
github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2/go.mod h1:Tv1PlzqC9t8wNnpPdctvtSUOPUUg4SHeE6vR1Ir2hmg=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
@@ -677,6 +683,8 @@ github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY
|
||||
github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI=
|
||||
github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/matryer/is v1.2.0 h1:92UTHpy8CDwaJ08GqLDzhhuixiBUUD1p3AU6PHddz4A=
|
||||
github.com/matryer/is v1.2.0/go.mod h1:2fLPjFQM9rhQ15aVEtbuwhJinnOqrmgXPNdZsdwlWXA=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
@@ -735,6 +743,8 @@ github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78=
|
||||
github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI=
|
||||
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
|
||||
github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
|
||||
@@ -793,8 +803,8 @@ github.com/onsi/ginkgo/v2 v2.3.0/go.mod h1:Eew0uilEqZmIEZr8JrvYlvOM7Rr6xzTmMV8Ay
|
||||
github.com/onsi/ginkgo/v2 v2.4.0/go.mod h1:iHkDK1fKGcBoEHT5W7YBq4RFWaQulw+caOMkAt4OrFo=
|
||||
github.com/onsi/ginkgo/v2 v2.5.0/go.mod h1:Luc4sArBICYCS8THh8v3i3i5CuSZO+RaQRaJoeNwomw=
|
||||
github.com/onsi/ginkgo/v2 v2.6.0/go.mod h1:63DOGlLAH8+REH8jUGdL3YpCpu7JODesutUjdENfUAc=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA=
|
||||
github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To=
|
||||
github.com/onsi/ginkgo/v2 v2.14.0 h1:vSmGj2Z5YPb9JwCWT6z6ihcUvDhuXLc3sJiqd3jMKAY=
|
||||
github.com/onsi/ginkgo/v2 v2.14.0/go.mod h1:JkUdW7JkN0V6rFvsHcJ478egV3XH9NxpD27Hal/PhZw=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
@@ -805,8 +815,8 @@ github.com/onsi/gomega v1.22.1/go.mod h1:x6n7VNe4hw0vkyYUM4mjIXx3JbLiPaBPNgB7PRQ
|
||||
github.com/onsi/gomega v1.23.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||
github.com/onsi/gomega v1.24.0/go.mod h1:Z/NWtiqwBrwUt4/2loMmHL63EDLnYHmVbuBpDr2vQAg=
|
||||
github.com/onsi/gomega v1.24.1/go.mod h1:3AOiACssS3/MajrniINInwbfOOtfZvplPzuRSmvt1jM=
|
||||
github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
|
||||
github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
|
||||
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
|
||||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
|
||||
github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
|
||||
@@ -909,8 +919,8 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
|
||||
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
|
||||
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
|
||||
@@ -922,8 +932,8 @@ github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
|
||||
github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
|
||||
github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM=
|
||||
github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
@@ -970,8 +980,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
@@ -1022,8 +1032,8 @@ github.com/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0
|
||||
github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
|
||||
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
||||
go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0=
|
||||
go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/api/v3 v3.5.5/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8=
|
||||
go.etcd.io/etcd/api/v3 v3.5.10 h1:szRajuUUbLyppkhs9K6BRtjY37l66XQQmw7oZRANE4k=
|
||||
@@ -1060,8 +1070,8 @@ go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUz
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.35.0/go.mod h1:h8TWwRAhQpOd0aM5nYsRD8+flnkj+526GEIVlarH7eY=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0 h1:RsQi0qJ2imFfCvZabqzM9cNXBG8k6gXMv1A0cXRmH6A=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.45.0/go.mod h1:vsh3ySueQCiKPxFLvjWC4Z135gIa34TQ/NSqkDTZYUM=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1 h1:SpGay3w+nEwMpfVnbqOLH5gY52/foP8RE8UzTZ1pdSE=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.46.1/go.mod h1:4UoMYEZOC0yN/sPGH76KPkkU7zgiEWYWL9vwmbnTJPE=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.35.0/go.mod h1:9NiG9I2aHTKkcxqCILhjtyNA1QEiCjdBACv4IvrFQ+c=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.45.0 h1:x8Z78aZx8cOF0+Kkazoc7lwUNMGy0LrzEMxTm4BbTxg=
|
||||
@@ -1070,8 +1080,8 @@ go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzox
|
||||
go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU=
|
||||
go.opentelemetry.io/otel v1.8.0/go.mod h1:2pkj+iMj0o03Y+cW6/m8Y4WkRdYN3AvCXCnzRMp9yvM=
|
||||
go.opentelemetry.io/otel v1.10.0/go.mod h1:NbvWjCthWHKBEUMpf0/v8ZRZlni86PpGFEMA9pnQSnQ=
|
||||
go.opentelemetry.io/otel v1.19.0 h1:MuS/TNf4/j4IXsZuJegVzI1cwut7Qc00344rgH7p8bs=
|
||||
go.opentelemetry.io/otel v1.19.0/go.mod h1:i0QyjOq3UPoTzff0PJB2N66fb4S0+rSbSB15/oyH9fY=
|
||||
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
|
||||
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.10.0/go.mod h1:78XhIg8Ht9vR4tbLNUhXsiOnE2HOuSeKAiAcoVQEpOY=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw=
|
||||
@@ -1084,22 +1094,22 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0 h1:3d+S2
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.19.0/go.mod h1:0+KuTDyKL4gjKCF75pHOX4wuzYDUZYfAQdSu43o+Z2I=
|
||||
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
|
||||
go.opentelemetry.io/otel/metric v0.31.0/go.mod h1:ohmwj9KTSIeBnDBm/ZwH2PSZxZzoOaG2xZeekTRzL5A=
|
||||
go.opentelemetry.io/otel/metric v1.19.0 h1:aTzpGtV0ar9wlV4Sna9sdJyII5jTVJEvKETPiOKwvpE=
|
||||
go.opentelemetry.io/otel/metric v1.19.0/go.mod h1:L5rUsV9kM1IxCj1MmSdS+JQAcVm319EUrDVLrt7jqt8=
|
||||
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
|
||||
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
|
||||
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
|
||||
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
|
||||
go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI=
|
||||
go.opentelemetry.io/otel/sdk v1.10.0/go.mod h1:vO06iKzD5baltJz1zarxMCNHFpUlUiOy4s65ECtn6kE=
|
||||
go.opentelemetry.io/otel/sdk v1.19.0 h1:6USY6zH+L8uMH8L3t1enZPR3WFEmSTADlqldyHtJi3o=
|
||||
go.opentelemetry.io/otel/sdk v1.19.0/go.mod h1:NedEbbS4w3C6zElbLdPJKOpJQOrGUJ+GfzpjUvI0v1A=
|
||||
go.opentelemetry.io/otel/sdk v1.21.0 h1:FTt8qirL1EysG6sTQRZ5TokkU8d0ugCj8htOgThZXQ8=
|
||||
go.opentelemetry.io/otel/sdk v1.21.0/go.mod h1:Nna6Yv7PWTdgJHVRD9hIYywQBRx7pbox6nwBnZIxl/E=
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
|
||||
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
|
||||
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
||||
go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk=
|
||||
go.opentelemetry.io/otel/trace v1.8.0/go.mod h1:0Bt3PXY8w+3pheS3hQUt+wow8b1ojPaTBoTCh2zIFI4=
|
||||
go.opentelemetry.io/otel/trace v1.10.0/go.mod h1:Sij3YYczqAdz+EhmGhE6TpTxUO5/F/AzrK+kxfGqySM=
|
||||
go.opentelemetry.io/otel/trace v1.19.0 h1:DFVQmlVbfVeOuBRrwdtaehRrWiL1JoVs9CPIQ1Dzxpg=
|
||||
go.opentelemetry.io/otel/trace v1.19.0/go.mod h1:mfaSyvGyEJEI0nyV2I4qhNQnbBOUUmYZpYojqMnX2vo=
|
||||
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
|
||||
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg=
|
||||
go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
|
||||
@@ -1149,14 +1159,16 @@ golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30=
|
||||
golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o=
|
||||
golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -1177,8 +1189,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91
|
||||
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
|
||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
|
||||
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
|
||||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1226,10 +1238,11 @@ golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.3.1-0.20221206200815-1e63c2f08a10/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -1255,8 +1268,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -1328,8 +1341,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -1339,10 +1352,11 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk=
|
||||
golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
@@ -1352,10 +1366,11 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
|
||||
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -1393,8 +1408,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc
|
||||
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
|
||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
|
||||
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@@ -1486,8 +1501,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
|
||||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
|
||||
|
||||
@@ -24,14 +24,13 @@ e2e-setup-core-wo-auth:
|
||||
--namespace vela-system \
|
||||
--set image.pullPolicy=IfNotPresent \
|
||||
--set image.repository=vela-core-test \
|
||||
--set applicationRevisionLimit=5 \
|
||||
--set controllerArgs.reSyncPeriod=1m \
|
||||
--set applicationRevisionLimit=5 \
|
||||
--set optimize.disableComponentRevision=false \
|
||||
--set image.tag=$(GIT_COMMIT) \
|
||||
--set multicluster.clusterGateway.image.repository=ghcr.io/oam-dev/cluster-gateway \
|
||||
--set admissionWebhooks.patch.image.repository=ghcr.io/oam-dev/kube-webhook-certgen/kube-webhook-certgen \
|
||||
--set multicluster.clusterGateway.image.repository=ghcr.io/oam-dev/cluster-gateway \
|
||||
--set admissionWebhooks.patch.image.repository=ghcr.io/oam-dev/kube-webhook-certgen/kube-webhook-certgen \
|
||||
--wait kubevela ./charts/vela-core \
|
||||
--debug
|
||||
--debug
|
||||
|
||||
.PHONY: e2e-setup-core-w-auth
|
||||
e2e-setup-core-w-auth:
|
||||
@@ -110,4 +109,4 @@ end-e2e-core-shards: end-e2e-core
|
||||
|
||||
.PHONY: end-e2e
|
||||
end-e2e:
|
||||
sh ./hack/e2e/end_e2e.sh
|
||||
sh ./hack/e2e/end_e2e.sh
|
||||
@@ -37,7 +37,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
oamutil "github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
)
|
||||
|
||||
// NewLiveDiffOption creates a live-diff option
|
||||
@@ -119,11 +118,9 @@ func (l *LiveDiffOption) RenderlessDiff(ctx context.Context, base, comparor Live
|
||||
switch {
|
||||
case obj.Application != nil:
|
||||
app = obj.Application.DeepCopy()
|
||||
ctx = context.WithValue(ctx, oamutil.AppDefinitionNamespace, app.Namespace)
|
||||
af, err = l.Parser.GenerateAppFileFromApp(ctx, obj.Application)
|
||||
case obj.ApplicationRevision != nil:
|
||||
app = obj.ApplicationRevision.Spec.Application.DeepCopy()
|
||||
ctx = context.WithValue(ctx, oamutil.AppDefinitionNamespace, app.Namespace)
|
||||
af, err = l.Parser.GenerateAppFileFromRevision(obj.ApplicationRevision)
|
||||
default:
|
||||
err = errors.Errorf("either application or application revision should be set for LiveDiffObject")
|
||||
|
||||
@@ -109,15 +109,9 @@ func (d *Option) ValidateApp(ctx context.Context, filename string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
namespace := oamutil.GetDefinitionNamespaceWithCtx(ctx)
|
||||
|
||||
if namespace != "" {
|
||||
app.SetNamespace(namespace)
|
||||
} else if len(app.GetNamespace()) == 0 {
|
||||
if len(app.GetNamespace()) == 0 {
|
||||
app.SetNamespace(corev1.NamespaceDefault)
|
||||
}
|
||||
|
||||
app2 := app.DeepCopy()
|
||||
|
||||
err = d.Client.Get(ctx, client.ObjectKey{Namespace: app.GetNamespace(), Name: app.GetName()}, app2)
|
||||
|
||||
@@ -52,11 +52,11 @@ import (
|
||||
)
|
||||
|
||||
// TemplateLoaderFn load template of a capability definition
|
||||
type TemplateLoaderFn func(context.Context, client.Client, string, types.CapType, map[string]string) (*Template, error)
|
||||
type TemplateLoaderFn func(context.Context, client.Client, string, types.CapType) (*Template, error)
|
||||
|
||||
// LoadTemplate load template of a capability definition
|
||||
func (fn TemplateLoaderFn) LoadTemplate(ctx context.Context, c client.Client, capName string, capType types.CapType, annotations map[string]string) (*Template, error) {
|
||||
return fn(ctx, c, capName, capType, annotations)
|
||||
func (fn TemplateLoaderFn) LoadTemplate(ctx context.Context, c client.Client, capName string, capType types.CapType) (*Template, error) {
|
||||
return fn(ctx, c, capName, capType)
|
||||
}
|
||||
|
||||
// Parser is an application parser
|
||||
@@ -253,8 +253,7 @@ func (p *Parser) parseWorkflowStepsForLegacyRevision(ctx context.Context, af *Ap
|
||||
continue
|
||||
}
|
||||
def := &v1beta1.WorkflowStepDefinition{}
|
||||
|
||||
if err := util.GetCapabilityDefinition(ctx, p.client, def, workflowStep.Type, af.app.Annotations); err != nil {
|
||||
if err := util.GetCapabilityDefinition(ctx, p.client, def, workflowStep.Type); err != nil {
|
||||
return errors.Wrapf(err, "failed to get workflow step definition %s", workflowStep.Type)
|
||||
}
|
||||
af.RelatedWorkflowStepDefinitions[workflowStep.Type] = def
|
||||
@@ -384,7 +383,7 @@ func (p *Parser) parsePolicies(ctx context.Context, af *Appfile) (err error) {
|
||||
af.RelatedTraitDefinitions[def.Name] = def
|
||||
}
|
||||
default:
|
||||
w, err := p.makeComponent(ctx, policy.Name, policy.Type, types.TypePolicy, policy.Properties, af.app.Annotations)
|
||||
w, err := p.makeComponent(ctx, policy.Name, policy.Type, types.TypePolicy, policy.Properties)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -472,15 +471,15 @@ func (p *Parser) fetchAndSetWorkflowStepDefinition(ctx context.Context, af *Appf
|
||||
return nil
|
||||
}
|
||||
def := &v1beta1.WorkflowStepDefinition{}
|
||||
if err := util.GetCapabilityDefinition(ctx, p.client, def, workflowStepType, af.AppAnnotations); err != nil {
|
||||
if err := util.GetCapabilityDefinition(ctx, p.client, def, workflowStepType); err != nil {
|
||||
return errors.Wrapf(err, "failed to get workflow step definition %s", workflowStepType)
|
||||
}
|
||||
af.RelatedWorkflowStepDefinitions[workflowStepType] = def
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Parser) makeComponent(ctx context.Context, name, typ string, capType types.CapType, props *runtime.RawExtension, annotations map[string]string) (*Component, error) {
|
||||
templ, err := p.tmplLoader.LoadTemplate(ctx, p.client, typ, capType, annotations)
|
||||
func (p *Parser) makeComponent(ctx context.Context, name, typ string, capType types.CapType, props *runtime.RawExtension) (*Component, error) {
|
||||
templ, err := p.tmplLoader.LoadTemplate(ctx, p.client, typ, capType)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "fetch component/policy type of %s", name)
|
||||
}
|
||||
@@ -520,7 +519,7 @@ func (p *Parser) convertTemplate2Component(name, typ string, props *runtime.RawE
|
||||
func (p *Parser) parseComponents(ctx context.Context, af *Appfile) error {
|
||||
var comps []*Component
|
||||
for _, c := range af.app.Spec.Components {
|
||||
comp, err := p.parseComponent(ctx, c, af.app.Annotations)
|
||||
comp, err := p.parseComponent(ctx, c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -569,25 +568,25 @@ func setComponentDefinitionsFromRevision(af *Appfile) {
|
||||
|
||||
// parseComponent resolve an ApplicationComponent and generate a Component
|
||||
// containing ALL information required by an Appfile.
|
||||
func (p *Parser) parseComponent(ctx context.Context, comp common.ApplicationComponent, annotations map[string]string) (*Component, error) {
|
||||
workload, err := p.makeComponent(ctx, comp.Name, comp.Type, types.TypeComponentDefinition, comp.Properties, annotations)
|
||||
func (p *Parser) parseComponent(ctx context.Context, comp common.ApplicationComponent) (*Component, error) {
|
||||
workload, err := p.makeComponent(ctx, comp.Name, comp.Type, types.TypeComponentDefinition, comp.Properties)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = p.parseTraits(ctx, workload, comp, annotations); err != nil {
|
||||
if err = p.parseTraits(ctx, workload, comp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return workload, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseTraits(ctx context.Context, workload *Component, comp common.ApplicationComponent, annotations map[string]string) error {
|
||||
func (p *Parser) parseTraits(ctx context.Context, workload *Component, comp common.ApplicationComponent) error {
|
||||
for _, traitValue := range comp.Traits {
|
||||
properties, err := util.RawExtension2Map(traitValue.Properties)
|
||||
if err != nil {
|
||||
return errors.Errorf("fail to parse properties of %s for %s", traitValue.Type, comp.Name)
|
||||
}
|
||||
trait, err := p.parseTrait(ctx, traitValue.Type, properties, annotations)
|
||||
trait, err := p.parseTrait(ctx, traitValue.Type, properties)
|
||||
if err != nil {
|
||||
return errors.WithMessagef(err, "component(%s) parse trait(%s)", comp.Name, traitValue.Type)
|
||||
}
|
||||
@@ -650,7 +649,7 @@ func (p *Parser) parseTraitsFromRevision(comp common.ApplicationComponent, appRe
|
||||
func (p *Parser) ParseComponentFromRevisionAndClient(ctx context.Context, c common.ApplicationComponent, appRev *v1beta1.ApplicationRevision) (*Component, error) {
|
||||
comp, err := p.makeComponentFromRevision(c.Name, c.Type, types.TypeComponentDefinition, c.Properties, appRev)
|
||||
if IsNotFoundInAppRevision(err) {
|
||||
comp, err = p.makeComponent(ctx, c.Name, c.Type, types.TypeComponentDefinition, c.Properties, appRev.Annotations)
|
||||
comp, err = p.makeComponent(ctx, c.Name, c.Type, types.TypeComponentDefinition, c.Properties)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -663,7 +662,7 @@ func (p *Parser) ParseComponentFromRevisionAndClient(ctx context.Context, c comm
|
||||
}
|
||||
trait, err := p.parseTraitFromRevision(traitValue.Type, properties, appRev)
|
||||
if IsNotFoundInAppRevision(err) {
|
||||
trait, err = p.parseTrait(ctx, traitValue.Type, properties, appRev.Annotations)
|
||||
trait, err = p.parseTrait(ctx, traitValue.Type, properties)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "component(%s) parse trait(%s)", c.Name, traitValue.Type)
|
||||
@@ -675,8 +674,8 @@ func (p *Parser) ParseComponentFromRevisionAndClient(ctx context.Context, c comm
|
||||
return comp, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseTrait(ctx context.Context, name string, properties map[string]interface{}, annotations map[string]string) (*Trait, error) {
|
||||
templ, err := p.tmplLoader.LoadTemplate(ctx, p.client, name, types.TypeTrait, annotations)
|
||||
func (p *Parser) parseTrait(ctx context.Context, name string, properties map[string]interface{}) (*Trait, error) {
|
||||
templ, err := p.tmplLoader.LoadTemplate(ctx, p.client, name, types.TypeTrait)
|
||||
if kerrors.IsNotFound(err) {
|
||||
return nil, errors.Errorf("trait definition of %s not found", name)
|
||||
}
|
||||
|
||||
@@ -559,7 +559,7 @@ func TestParser_parseTraits(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
mockTemplateLoaderFn: func(context.Context, client.Client, string, types.CapType, map[string]string) (*Template, error) {
|
||||
mockTemplateLoaderFn: func(context.Context, client.Client, string, types.CapType) (*Template, error) {
|
||||
return nil, fmt.Errorf("unsupported key not found")
|
||||
},
|
||||
wantErr: assert.Error,
|
||||
@@ -580,7 +580,7 @@ func TestParser_parseTraits(t *testing.T) {
|
||||
workload: &Component{},
|
||||
},
|
||||
wantErr: assert.NoError,
|
||||
mockTemplateLoaderFn: func(ctx context.Context, reader client.Client, s string, capType types.CapType, annotations map[string]string) (*Template, error) {
|
||||
mockTemplateLoaderFn: func(ctx context.Context, reader client.Client, s string, capType types.CapType) (*Template, error) {
|
||||
return &Template{
|
||||
TemplateStr: "template",
|
||||
CapabilityCategory: "network",
|
||||
@@ -598,8 +598,7 @@ func TestParser_parseTraits(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
p.tmplLoader = tt.mockTemplateLoaderFn
|
||||
annotations := make(map[string]string)
|
||||
err := p.parseTraits(context.Background(), tt.args.workload, tt.args.comp, annotations)
|
||||
err := p.parseTraits(context.Background(), tt.args.workload, tt.args.comp)
|
||||
tt.wantErr(t, err, fmt.Sprintf("parseTraits(%v, %v)", tt.args.workload, tt.args.comp))
|
||||
if tt.validateFunc != nil {
|
||||
assert.True(t, tt.validateFunc(tt.args.workload))
|
||||
|
||||
@@ -66,13 +66,13 @@ type Template struct {
|
||||
// LoadTemplate gets the capability definition from cluster and resolve it.
|
||||
// It returns a helper struct, Template, which will be used for further
|
||||
// processing.
|
||||
func LoadTemplate(ctx context.Context, cli client.Client, capName string, capType types.CapType, annotations map[string]string) (*Template, error) {
|
||||
func LoadTemplate(ctx context.Context, cli client.Client, capName string, capType types.CapType) (*Template, error) {
|
||||
ctx = multicluster.WithCluster(ctx, multicluster.Local)
|
||||
// Application Controller only loads template from ComponentDefinition and TraitDefinition
|
||||
switch capType {
|
||||
case types.TypeComponentDefinition, types.TypeWorkload:
|
||||
cd := new(v1beta1.ComponentDefinition)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, cd, capName, annotations)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, cd, capName)
|
||||
if err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
wd := new(v1beta1.WorkloadDefinition)
|
||||
@@ -108,7 +108,7 @@ func LoadTemplate(ctx context.Context, cli client.Client, capName string, capTyp
|
||||
|
||||
case types.TypeTrait:
|
||||
td := new(v1beta1.TraitDefinition)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, td, capName, annotations)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, td, capName)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "load template from trait definition [%s] ", capName)
|
||||
}
|
||||
@@ -119,7 +119,7 @@ func LoadTemplate(ctx context.Context, cli client.Client, capName string, capTyp
|
||||
return tmpl, nil
|
||||
case types.TypePolicy:
|
||||
d := new(v1beta1.PolicyDefinition)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, d, capName, annotations)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, d, capName)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "load template from policy definition [%s] ", capName)
|
||||
}
|
||||
@@ -130,7 +130,7 @@ func LoadTemplate(ctx context.Context, cli client.Client, capName string, capTyp
|
||||
return tmpl, nil
|
||||
case types.TypeWorkflowStep:
|
||||
d := new(v1beta1.WorkflowStepDefinition)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, d, capName, annotations)
|
||||
err := oamutil.GetCapabilityDefinition(ctx, cli, d, capName)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "load template from workflow step definition [%s] ", capName)
|
||||
}
|
||||
@@ -252,7 +252,7 @@ func verifyRevisionName(capName string, capType types.CapType, apprev *v1beta1.A
|
||||
// LoadTemplate, but load template from provided ones before loading from
|
||||
// cluster through LoadTemplate
|
||||
func DryRunTemplateLoader(defs []*unstructured.Unstructured) TemplateLoaderFn {
|
||||
return func(ctx context.Context, r client.Client, capName string, capType types.CapType, annotations map[string]string) (*Template, error) {
|
||||
return func(ctx context.Context, r client.Client, capName string, capType types.CapType) (*Template, error) {
|
||||
// retrieve provided cap definitions
|
||||
for _, def := range defs {
|
||||
if def.GetKind() == v1beta1.ComponentDefinitionKind &&
|
||||
@@ -282,7 +282,7 @@ func DryRunTemplateLoader(defs []*unstructured.Unstructured) TemplateLoaderFn {
|
||||
}
|
||||
// not found in provided cap definitions
|
||||
// then try to retrieve from cluster
|
||||
tmpl, err := LoadTemplate(ctx, r, capName, capType, annotations)
|
||||
tmpl, err := LoadTemplate(ctx, r, capName, capType)
|
||||
if err != nil {
|
||||
return nil, errors.WithMessagef(err, "cannot load template %q from cluster and provided ones", capName)
|
||||
}
|
||||
|
||||
@@ -111,8 +111,8 @@ spec:
|
||||
return nil
|
||||
},
|
||||
}
|
||||
var annotations = make(map[string]string)
|
||||
temp, err := LoadTemplate(context.TODO(), &tclient, "worker", types.TypeComponentDefinition, annotations)
|
||||
|
||||
temp, err := LoadTemplate(context.TODO(), &tclient, "worker", types.TypeComponentDefinition)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -219,8 +219,8 @@ spec:
|
||||
return nil
|
||||
},
|
||||
}
|
||||
var annotations = make(map[string]string)
|
||||
temp, err := LoadTemplate(context.TODO(), &tclient, "ingress", types.TypeTrait, annotations)
|
||||
|
||||
temp, err := LoadTemplate(context.TODO(), &tclient, "ingress", types.TypeTrait)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
@@ -362,9 +362,8 @@ spec:
|
||||
TraitDefinition: traitDef,
|
||||
}
|
||||
|
||||
var annotations = make(map[string]string)
|
||||
dryRunLoadTemplate := DryRunTemplateLoader([]*unstructured.Unstructured{unstrctCompDef, unstrctTraitDef})
|
||||
compTmpl, err := dryRunLoadTemplate(nil, nil, "myworker", types.TypeComponentDefinition, annotations)
|
||||
compTmpl, err := dryRunLoadTemplate(nil, nil, "myworker", types.TypeComponentDefinition)
|
||||
if err != nil {
|
||||
t.Error("failed load template of component defintion", err)
|
||||
}
|
||||
@@ -372,7 +371,7 @@ spec:
|
||||
t.Fatal("failed load template of component defintion", diff)
|
||||
}
|
||||
|
||||
traitTmpl, err := dryRunLoadTemplate(nil, nil, "myingress", types.TypeTrait, annotations)
|
||||
traitTmpl, err := dryRunLoadTemplate(nil, nil, "myingress", types.TypeTrait)
|
||||
if err != nil {
|
||||
t.Error("failed load template of component defintion", err)
|
||||
}
|
||||
|
||||
@@ -58,17 +58,17 @@ var _ = Describe("Test dispatch stage", func() {
|
||||
},
|
||||
},
|
||||
}
|
||||
var annotations = make(map[string]string)
|
||||
stage, err := getTraitDispatchStage(k8sClient, "kruise-rollout", &appRev, annotations)
|
||||
|
||||
stage, err := getTraitDispatchStage(k8sClient, "kruise-rollout", &appRev)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(stage).Should(BeEquivalentTo(PreDispatch))
|
||||
stage, err = getTraitDispatchStage(k8sClient, "gateway", &appRev, annotations)
|
||||
stage, err = getTraitDispatchStage(k8sClient, "gateway", &appRev)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(stage).Should(BeEquivalentTo(PostDispatch))
|
||||
stage, err = getTraitDispatchStage(k8sClient, "hpa", &appRev, annotations)
|
||||
stage, err = getTraitDispatchStage(k8sClient, "hpa", &appRev)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(stage).Should(BeEquivalentTo(DefaultDispatch))
|
||||
stage, err = getTraitDispatchStage(k8sClient, "not-exist", &appRev, annotations)
|
||||
stage, err = getTraitDispatchStage(k8sClient, "not-exist", &appRev)
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
Expect(stage).Should(BeEquivalentTo(DefaultDispatch))
|
||||
})
|
||||
|
||||
@@ -112,7 +112,7 @@ type manifestDispatcher struct {
|
||||
healthCheck func(ctx context.Context, c *appfile.Component, appRev *v1beta1.ApplicationRevision) (bool, error)
|
||||
}
|
||||
|
||||
func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, readyWorkload *unstructured.Unstructured, readyTraits []*unstructured.Unstructured, overrideNamespace string, annotations map[string]string) ([]*manifestDispatcher, error) {
|
||||
func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, readyWorkload *unstructured.Unstructured, readyTraits []*unstructured.Unstructured, overrideNamespace string) ([]*manifestDispatcher, error) {
|
||||
dispatcherGenerator := func(options DispatchOptions) *manifestDispatcher {
|
||||
assembleManifestFn := func(skipApplyWorkload bool) (bool, []*unstructured.Unstructured) {
|
||||
manifests := options.Traits
|
||||
@@ -138,13 +138,7 @@ func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, rea
|
||||
}
|
||||
dispatcher.run = func(ctx context.Context, comp *appfile.Component, appRev *v1beta1.ApplicationRevision, clusterName string) (bool, error) {
|
||||
skipWorkload, dispatchManifests := assembleManifestFn(comp.SkipApplyWorkload)
|
||||
|
||||
var isAutoUpdateEnabled bool
|
||||
if annotations[oam.AnnotationAutoUpdate] == "true" {
|
||||
isAutoUpdateEnabled = true
|
||||
}
|
||||
|
||||
if isHealth, err := dispatcher.healthCheck(ctx, comp, appRev); !isHealth || err != nil || (!comp.SkipApplyWorkload && isAutoUpdateEnabled) {
|
||||
if isHealth, err := dispatcher.healthCheck(ctx, comp, appRev); !isHealth || err != nil {
|
||||
if err := h.Dispatch(ctx, h.Client, clusterName, common.WorkflowResourceCreator, dispatchManifests...); err != nil {
|
||||
return false, errors.WithMessage(err, "Dispatch")
|
||||
}
|
||||
@@ -185,7 +179,7 @@ func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, rea
|
||||
traitType = splitName
|
||||
}
|
||||
}
|
||||
stageType, err = getTraitDispatchStage(h.Client, traitType, appRev, annotations)
|
||||
stageType, err = getTraitDispatchStage(h.Client, traitType, appRev)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -216,11 +210,11 @@ func (h *AppHandler) generateDispatcher(appRev *v1beta1.ApplicationRevision, rea
|
||||
return manifestDispatchers, nil
|
||||
}
|
||||
|
||||
func getTraitDispatchStage(client client.Client, traitType string, appRev *v1beta1.ApplicationRevision, annotations map[string]string) (StageType, error) {
|
||||
func getTraitDispatchStage(client client.Client, traitType string, appRev *v1beta1.ApplicationRevision) (StageType, error) {
|
||||
trait, ok := appRev.Spec.TraitDefinitions[traitType]
|
||||
if !ok {
|
||||
trait = &v1beta1.TraitDefinition{}
|
||||
err := oamutil.GetCapabilityDefinition(context.Background(), client, trait, traitType, annotations)
|
||||
err := oamutil.GetCapabilityDefinition(context.Background(), client, trait, traitType)
|
||||
if err != nil {
|
||||
return DefaultDispatch, err
|
||||
}
|
||||
|
||||
@@ -372,7 +372,7 @@ func (h *AppHandler) applyComponentFunc(appParser *appfile.Parser, af *appfile.A
|
||||
|
||||
isHealth := true
|
||||
if utilfeature.DefaultMutableFeatureGate.Enabled(features.MultiStageComponentApply) {
|
||||
manifestDispatchers, err := h.generateDispatcher(appRev, readyWorkload, readyTraits, overrideNamespace, af.AppAnnotations)
|
||||
manifestDispatchers, err := h.generateDispatcher(appRev, readyWorkload, readyTraits, overrideNamespace)
|
||||
if err != nil {
|
||||
return nil, nil, false, errors.WithMessage(err, "generateDispatcher")
|
||||
}
|
||||
|
||||
@@ -194,18 +194,6 @@ var _ = Describe("Test DefinitionRevision created by ComponentDefinition", func(
|
||||
Expect(defRev1.Spec.RevisionHash).Should(Equal(defRev2.Spec.RevisionHash))
|
||||
})
|
||||
|
||||
It("Test ComponentDefinition with name specified in spec.version, Should create definitaion with specified name", func() {
|
||||
cd := cdWithNoTemplate.DeepCopy()
|
||||
cd.Name = "test-cd-with-custom-version"
|
||||
cd.Spec.Version = "1.3.0"
|
||||
cd.Spec.Schematic.CUE.Template = fmt.Sprintf(cdTemplate, "test-defrev")
|
||||
|
||||
defRev, _, err := coredef.GenerateDefinitionRevision(ctx, r.Client, cd)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(defRev.Name).Should(Equal("test-cd-with-custom-version-v1.3.0"))
|
||||
|
||||
})
|
||||
|
||||
It("Test only update ComponentDefinition Labels, Shouldn't create new revision", func() {
|
||||
cd := cdWithNoTemplate.DeepCopy()
|
||||
cdName := "test-cd"
|
||||
@@ -270,29 +258,6 @@ var _ = Describe("Test DefinitionRevision created by ComponentDefinition", func(
|
||||
By("check the DefinitionRevision's RevisionNum")
|
||||
Expect(cdRev.Spec.Revision).Should(Equal(int64(1)))
|
||||
})
|
||||
|
||||
It("Test specified DefinitionRevision name in spec.version", func() {
|
||||
cdName := "test-specified-defrev1-name"
|
||||
req := reconcile.Request{NamespacedName: client.ObjectKey{Name: cdName, Namespace: namespace}}
|
||||
|
||||
cd := cdWithNoTemplate.DeepCopy()
|
||||
cd.Name = cdName
|
||||
cd.Spec.Schematic.CUE.Template = fmt.Sprintf(cdTemplate, "test")
|
||||
cd.Spec.Version = "1.1.3"
|
||||
By("create componentDefinition")
|
||||
Expect(k8sClient.Create(ctx, cd)).Should(SatisfyAll(BeNil()))
|
||||
testutil.ReconcileRetry(&r, req)
|
||||
|
||||
By("check whether DefinitionRevision is created")
|
||||
cdRevName := fmt.Sprintf("%s-v1.1.3", cdName)
|
||||
var cdRev v1beta1.DefinitionRevision
|
||||
Eventually(func() error {
|
||||
return k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: cdRevName}, &cdRev)
|
||||
}, 10*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("check the DefinitionRevision's RevisionNum")
|
||||
Expect(cdRev.Spec.Revision).Should(Equal(int64(1)))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test ComponentDefinition Controller clean up", func() {
|
||||
@@ -416,7 +381,7 @@ var _ = Describe("Test DefinitionRevision created by ComponentDefinition", func(
|
||||
}, time.Second*30, time.Microsecond*300).Should(BeNil())
|
||||
})
|
||||
|
||||
It("Test clean up definitionRevision contains definitionRevision with custom name using annotation", func() {
|
||||
It("Test clean up definitionRevision contains definitionRevision with custom name", func() {
|
||||
var revKey client.ObjectKey
|
||||
var defRev v1beta1.DefinitionRevision
|
||||
revisionNames := []string{"1.3.1", "", "1.3.3", "", "prod"}
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
coredef "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1beta1/core"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/testutil"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
@@ -129,17 +128,6 @@ var _ = Describe("Test DefinitionRevision created by PolicyDefinition", func() {
|
||||
newRevKey := client.ObjectKey{Namespace: namespace, Name: newDefRevName}
|
||||
Expect(k8sClient.Get(ctx, newRevKey, &defRev)).Should(HaveOccurred())
|
||||
})
|
||||
It("Test Policy Definition with name specified in spec.version, Should create definitaion with specified name", func() {
|
||||
def := defWithNoTemplate.DeepCopy()
|
||||
def.Name = "test-policy-def-custom-version"
|
||||
def.Spec.Version = "1.3.0"
|
||||
def.Spec.Schematic.CUE.Template = fmt.Sprintf(defTemplate, "test-defrev")
|
||||
|
||||
defRev, _, err := coredef.GenerateDefinitionRevision(ctx, r.Client, def)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(defRev.Name).Should(Equal("test-policy-def-custom-version-v1.3.0"))
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test PolicyDefinition Controller clean up", func() {
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/event"
|
||||
"github.com/pkg/errors"
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
@@ -45,20 +44,12 @@ import (
|
||||
// GenerateDefinitionRevision will generate a definition revision the generated revision
|
||||
// will be compare with the last revision to see if there's any difference.
|
||||
func GenerateDefinitionRevision(ctx context.Context, cli client.Client, def runtime.Object) (*v1beta1.DefinitionRevision, bool, error) {
|
||||
isSpecVersion, defRevNamespacedName, err := isSpecVersionRevision(def)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if isSpecVersion {
|
||||
return generateDefinitionRevision(ctx, cli, def, defRevNamespacedName)
|
||||
}
|
||||
|
||||
isNamedRev, defRevNamespacedName, err := isNameAnnotationRevision(def)
|
||||
isNamedRev, defRevNamespacedName, err := isNamedRevision(def)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if isNamedRev {
|
||||
return generateDefinitionRevision(ctx, cli, def, defRevNamespacedName)
|
||||
return generateNamedDefinitionRevision(ctx, cli, def, defRevNamespacedName)
|
||||
}
|
||||
|
||||
defRev, lastRevision, err := GatherRevisionInfo(def)
|
||||
@@ -77,9 +68,7 @@ func GenerateDefinitionRevision(ctx context.Context, cli client.Client, def runt
|
||||
return defRev, isNewRev, nil
|
||||
}
|
||||
|
||||
// isNameAnnotationRevision is for Definition Version specified in the
|
||||
// Definition's "definitionrevision.oam.dev/name" annotation.
|
||||
func isNameAnnotationRevision(def runtime.Object) (bool, types.NamespacedName, error) {
|
||||
func isNamedRevision(def runtime.Object) (bool, types.NamespacedName, error) {
|
||||
defMap, err := runtime.DefaultUnstructuredConverter.ToUnstructured(def)
|
||||
if err != nil {
|
||||
return false, types.NamespacedName{}, err
|
||||
@@ -97,42 +86,7 @@ func isNameAnnotationRevision(def runtime.Object) (bool, types.NamespacedName, e
|
||||
return true, types.NamespacedName{Name: defRevName, Namespace: defNs}, nil
|
||||
}
|
||||
|
||||
// isSpecVersionRevision is for Definition Version specified in the Definition spec.Version
|
||||
func isSpecVersionRevision(def runtime.Object) (bool, types.NamespacedName, error) {
|
||||
|
||||
var definitionVersion, definitionNamespace, definitionName string
|
||||
switch definition := def.(type) {
|
||||
case *v1beta1.ComponentDefinition:
|
||||
definitionVersion = definition.Spec.Version
|
||||
definitionNamespace = definition.Namespace
|
||||
definitionName = definition.Name
|
||||
case *v1beta1.TraitDefinition:
|
||||
definitionVersion = definition.Spec.Version
|
||||
definitionNamespace = definition.Namespace
|
||||
definitionName = definition.Name
|
||||
case *v1beta1.PolicyDefinition:
|
||||
definitionVersion = definition.Spec.Version
|
||||
definitionNamespace = definition.Namespace
|
||||
definitionName = definition.Name
|
||||
case *v1beta1.WorkflowStepDefinition:
|
||||
definitionVersion = definition.Spec.Version
|
||||
definitionNamespace = definition.Namespace
|
||||
definitionName = definition.Name
|
||||
}
|
||||
|
||||
if definitionVersion == "" {
|
||||
return false, types.NamespacedName{}, nil
|
||||
}
|
||||
semVersion, err := semver.NewVersion(definitionVersion)
|
||||
if err != nil {
|
||||
return false, types.NamespacedName{}, err
|
||||
}
|
||||
|
||||
definitionRevisionName := ConstructDefinitionRevisionName(definitionName, semVersion.String())
|
||||
return true, types.NamespacedName{Name: definitionRevisionName, Namespace: definitionNamespace}, nil
|
||||
}
|
||||
|
||||
func generateDefinitionRevision(ctx context.Context, cli client.Client, def runtime.Object, defRevNamespacedName types.NamespacedName) (*v1beta1.DefinitionRevision, bool, error) {
|
||||
func generateNamedDefinitionRevision(ctx context.Context, cli client.Client, def runtime.Object, defRevNamespacedName types.NamespacedName) (*v1beta1.DefinitionRevision, bool, error) {
|
||||
oldDefRev := new(v1beta1.DefinitionRevision)
|
||||
|
||||
// definitionRevision is immutable, if the requested definitionRevision already exists, return directly.
|
||||
@@ -276,27 +230,24 @@ func DeepEqualDefRevision(old, new *v1beta1.DefinitionRevision) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func getDefNextRevision(definitionRevision *v1beta1.DefinitionRevision, lastRevision *common.Revision) (string, int64) {
|
||||
func getDefNextRevision(defRev *v1beta1.DefinitionRevision, lastRevision *common.Revision) (string, int64) {
|
||||
var nextRevision int64 = 1
|
||||
var definitionRevisionName string
|
||||
if lastRevision != nil {
|
||||
nextRevision = lastRevision.Revision + 1
|
||||
}
|
||||
var name string
|
||||
switch definitionRevision.Spec.DefinitionType {
|
||||
switch defRev.Spec.DefinitionType {
|
||||
case common.ComponentType:
|
||||
name = definitionRevision.Spec.ComponentDefinition.Name
|
||||
name = defRev.Spec.ComponentDefinition.Name
|
||||
case common.TraitType:
|
||||
name = definitionRevision.Spec.TraitDefinition.Name
|
||||
name = defRev.Spec.TraitDefinition.Name
|
||||
case common.PolicyType:
|
||||
name = definitionRevision.Spec.PolicyDefinition.Name
|
||||
name = defRev.Spec.PolicyDefinition.Name
|
||||
case common.WorkflowStepType:
|
||||
name = definitionRevision.Spec.WorkflowStepDefinition.Name
|
||||
name = defRev.Spec.WorkflowStepDefinition.Name
|
||||
}
|
||||
|
||||
definitionRevisionName = strings.Join([]string{name, fmt.Sprintf("v%v", nextRevision)}, "-")
|
||||
|
||||
return definitionRevisionName, nextRevision
|
||||
defRevName := strings.Join([]string{name, fmt.Sprintf("v%d", nextRevision)}, "-")
|
||||
return defRevName, nextRevision
|
||||
}
|
||||
|
||||
// ConstructDefinitionRevisionName construct the name of DefinitionRevision.
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
coredef "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1beta1/core"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/testutil"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
@@ -129,17 +128,6 @@ var _ = Describe("Test DefinitionRevision created by TraitDefinition", func() {
|
||||
newRevKey := client.ObjectKey{Namespace: namespace, Name: newDefRevName}
|
||||
Expect(k8sClient.Get(ctx, newRevKey, &defRev)).Should(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Test Trait Definition with name specified in spec.version, Should create definitaion with specified name", func() {
|
||||
td := tdWithNoTemplate.DeepCopy()
|
||||
td.Name = "test-trait-def-custom-version"
|
||||
td.Spec.Version = "1.3.0"
|
||||
td.Spec.Schematic.CUE.Template = fmt.Sprintf(tdTemplate, fmt.Sprintf("test-v%d", 1))
|
||||
defRev, _, err := coredef.GenerateDefinitionRevision(ctx, r.Client, td)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(defRev.Name).Should(Equal("test-trait-def-custom-version-v1.3.0"))
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test TraitDefinition Controller clean up", func() {
|
||||
|
||||
@@ -32,7 +32,6 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
coredef "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1beta1/core"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/testutil"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
@@ -129,16 +128,6 @@ var _ = Describe("Test DefinitionRevision created by WorkflowStepDefinition", fu
|
||||
newRevKey := client.ObjectKey{Namespace: namespace, Name: newDefRevName}
|
||||
Expect(k8sClient.Get(ctx, newRevKey, &defRev)).Should(HaveOccurred())
|
||||
})
|
||||
It("Test WorkflowStep Definition with name specified in spec.version, Should create definitaion with specified name", func() {
|
||||
def := defWithNoTemplate.DeepCopy()
|
||||
def.Name = "test-workflow-def-custom-version"
|
||||
def.Spec.Version = "1.3.0"
|
||||
def.Spec.Schematic.CUE.Template = fmt.Sprintf(defTemplate, fmt.Sprintf("test-v%d", 1))
|
||||
defRev, _, err := coredef.GenerateDefinitionRevision(ctx, r.Client, def)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(defRev.Name).Should(Equal("test-workflow-def-custom-version-v1.3.0"))
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
Context("Test WorkflowStepDefinition Controller clean up", func() {
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"fmt"
|
||||
"hash"
|
||||
"hash/fnv"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
@@ -40,8 +39,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/validation"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/Masterminds/semver"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
@@ -125,14 +122,6 @@ const (
|
||||
XDefinitionNamespace
|
||||
)
|
||||
|
||||
// DefinitionKindToNameLabel records DefinitionRevision types and labels to search its name
|
||||
var DefinitionKindToNameLabel = map[common.DefinitionType]string{
|
||||
common.ComponentType: oam.LabelComponentDefinitionName,
|
||||
common.TraitType: oam.LabelTraitDefinitionName,
|
||||
common.PolicyType: oam.LabelPolicyDefinitionName,
|
||||
common.WorkflowStepType: oam.LabelWorkflowStepDefinitionName,
|
||||
}
|
||||
|
||||
// A ConditionedObject is an Object type with condition field
|
||||
type ConditionedObject interface {
|
||||
client.Object
|
||||
@@ -203,7 +192,6 @@ func GetDefinition(ctx context.Context, cli client.Reader, definition client.Obj
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -225,17 +213,12 @@ func GetDefinitionFromNamespace(ctx context.Context, cli client.Reader, definiti
|
||||
|
||||
// GetCapabilityDefinition can get different versions of ComponentDefinition/TraitDefinition
|
||||
func GetCapabilityDefinition(ctx context.Context, cli client.Reader, definition client.Object,
|
||||
definitionName string, annotations map[string]string) error {
|
||||
definitionType, err := getDefinitionType(definition)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isLatestRevision, defRev, err := fetchDefinitionRevision(ctx, cli, definitionName, definitionType, annotations)
|
||||
definitionName string) error {
|
||||
isLatestRevision, defRev, err := fetchDefinitionRev(ctx, cli, definitionName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if isLatestRevision {
|
||||
|
||||
return GetDefinition(ctx, cli, definition, definitionName)
|
||||
}
|
||||
switch def := definition.(type) {
|
||||
@@ -252,24 +235,7 @@ func GetCapabilityDefinition(ctx context.Context, cli client.Reader, definition
|
||||
return nil
|
||||
}
|
||||
|
||||
func getDefinitionType(definition client.Object) (common.DefinitionType, error) {
|
||||
var definitionType common.DefinitionType
|
||||
switch definition.(type) {
|
||||
case *v1beta1.ComponentDefinition:
|
||||
definitionType = common.ComponentType
|
||||
case *v1beta1.TraitDefinition:
|
||||
definitionType = common.TraitType
|
||||
case *v1beta1.PolicyDefinition:
|
||||
definitionType = common.PolicyType
|
||||
case *v1beta1.WorkflowStepDefinition:
|
||||
definitionType = common.WorkflowStepType
|
||||
default:
|
||||
return definitionType, fmt.Errorf("invalid definition type for %v", definition.GetName())
|
||||
}
|
||||
return definitionType, nil
|
||||
}
|
||||
|
||||
func fetchDefinitionRevision(ctx context.Context, cli client.Reader, definitionName string, definitionType common.DefinitionType, annotations map[string]string) (bool, *v1beta1.DefinitionRevision, error) {
|
||||
func fetchDefinitionRev(ctx context.Context, cli client.Reader, definitionName string) (bool, *v1beta1.DefinitionRevision, error) {
|
||||
// if the component's type doesn't contain '@' means user want to use the latest Definition.
|
||||
if !strings.Contains(definitionName, "@") {
|
||||
return true, nil, nil
|
||||
@@ -279,93 +245,13 @@ func fetchDefinitionRevision(ctx context.Context, cli client.Reader, definitionN
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
defName := strings.Split(definitionName, "@")[0]
|
||||
autoUpdate, ok := annotations[oam.AnnotationAutoUpdate]
|
||||
if ok && autoUpdate == "true" {
|
||||
latestRevisionName, err := GetLatestDefinitionRevisionName(ctx, cli.(client.Client), defName, defRevName, definitionType)
|
||||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
defRevName = latestRevisionName
|
||||
}
|
||||
|
||||
defRev := new(v1beta1.DefinitionRevision)
|
||||
if err := GetDefinition(ctx, cli, defRev, defRevName); err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
|
||||
return false, defRev, nil
|
||||
}
|
||||
|
||||
// GetLatestDefinitionRevisionName returns the latest definition revision name in specified version range.
|
||||
func GetLatestDefinitionRevisionName(ctx context.Context, cli client.Client, definitionName, revisionName string, definitionType common.DefinitionType) (string, error) {
|
||||
for _, ns := range []string{GetDefinitionNamespaceWithCtx(ctx), oam.SystemDefinitionNamespace} {
|
||||
|
||||
revisionListForDefinition, err := fetchAllRevisionsForDefinitionName(ctx, cli, ns, definitionName, definitionType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
matchedDefinitionRevision, err := getMatchingDefinitionRevision(revisionName, definitionName, revisionListForDefinition, definitionType)
|
||||
if err == nil && matchedDefinitionRevision != "" {
|
||||
return matchedDefinitionRevision, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("error finding definition revision for Name: %v, Type: %v", definitionName, definitionType)
|
||||
|
||||
}
|
||||
|
||||
func fetchAllRevisionsForDefinitionName(ctx context.Context, cli client.Client, ns, definitionName string, definitionType common.DefinitionType) (*v1beta1.DefinitionRevisionList, error) {
|
||||
var listOptions []client.ListOption
|
||||
listOptions = append(listOptions, client.InNamespace(ns),
|
||||
client.MatchingLabels{
|
||||
DefinitionKindToNameLabel[definitionType]: definitionName,
|
||||
})
|
||||
|
||||
revisionList := v1beta1.DefinitionRevisionList{}
|
||||
revisionList.SetGroupVersionKind(schema.GroupVersionKind{
|
||||
Group: v1beta1.Group,
|
||||
Version: v1beta1.Version,
|
||||
Kind: v1beta1.DefinitionRevisionKind,
|
||||
})
|
||||
|
||||
err := cli.List(ctx, &revisionList, listOptions...)
|
||||
|
||||
return &revisionList, err
|
||||
}
|
||||
|
||||
func getMatchingDefinitionRevision(exactRevisionName, definitionName string, revisionList *v1beta1.DefinitionRevisionList, definitionType common.DefinitionType) (string, error) {
|
||||
var definitionVersions []*semver.Version
|
||||
revisionPrefix := exactRevisionName + "."
|
||||
orignalVersions := make(map[string]string)
|
||||
|
||||
for _, revision := range revisionList.Items {
|
||||
if definitionType != "" && definitionType != revision.Spec.DefinitionType {
|
||||
continue
|
||||
}
|
||||
if revision.Name == exactRevisionName {
|
||||
return exactRevisionName, nil
|
||||
}
|
||||
// Only get the revisions that the user expects
|
||||
if strings.HasPrefix(revision.Name, revisionPrefix) {
|
||||
version := strings.Split(revision.Name, definitionName+"-")[1]
|
||||
v, err := semver.NewVersion(version)
|
||||
orignalVersions[v.String()] = version
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
definitionVersions = append(definitionVersions, v)
|
||||
}
|
||||
}
|
||||
if len(definitionVersions) == 0 {
|
||||
return "", nil
|
||||
}
|
||||
sort.Sort(semver.Collection(definitionVersions))
|
||||
latestVersion := definitionVersions[len(definitionVersions)-1]
|
||||
return definitionName + "-" + orignalVersions[latestVersion.String()], nil
|
||||
}
|
||||
|
||||
// ConvertDefinitionRevName can help convert definition type defined in Application to DefinitionRevision Name
|
||||
// e.g., worker@v1.3.1 will be convert to worker-v1.3.1
|
||||
func ConvertDefinitionRevName(definitionName string) (string, error) {
|
||||
|
||||
@@ -980,339 +980,3 @@ func TestXDefinitionNamespaceInCtx(t *testing.T) {
|
||||
assert.Equal(t, tc.expectedNamespace, ns)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetLatestDefinitionRevisionName(t *testing.T) {
|
||||
componetListCli := test.MockClient{MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
|
||||
defRevisionList := getComponentDefRevisionList()
|
||||
defRevisionList.DeepCopyInto(list.(*v1beta1.DefinitionRevisionList))
|
||||
return nil
|
||||
}}
|
||||
traitListCli := test.MockClient{MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
|
||||
defRevisionList := getTraitDefRevisionList()
|
||||
defRevisionList.DeepCopyInto(list.(*v1beta1.DefinitionRevisionList))
|
||||
return nil
|
||||
}}
|
||||
|
||||
testcases := []struct {
|
||||
name string
|
||||
inputRevisionName string
|
||||
definitionName string
|
||||
definitionType string
|
||||
expectedDefRevisionName string
|
||||
revisionList *v1beta1.DefinitionRevisionList
|
||||
client client.Client
|
||||
err error
|
||||
}{
|
||||
{
|
||||
name: "Complete Component version name specified",
|
||||
inputRevisionName: "configmap-component-v1.3.0",
|
||||
definitionName: "configmap-component",
|
||||
definitionType: "Component",
|
||||
expectedDefRevisionName: "configmap-component-v1.3.0",
|
||||
client: &componetListCli,
|
||||
err: nil,
|
||||
}, {
|
||||
name: "Partial Component version name specified",
|
||||
inputRevisionName: "configmap-component-v1.2",
|
||||
definitionName: "configmap-component",
|
||||
definitionType: "Component",
|
||||
expectedDefRevisionName: "configmap-component-v1.2.4",
|
||||
client: &componetListCli,
|
||||
err: nil,
|
||||
}, {
|
||||
name: "Component version not present",
|
||||
inputRevisionName: "configmap-component-v1.6",
|
||||
definitionName: "configmap-component",
|
||||
definitionType: "Component",
|
||||
expectedDefRevisionName: "",
|
||||
client: &componetListCli,
|
||||
err: fmt.Errorf("error finding definition revision for Name: configmap-component, Type: Component"),
|
||||
}, {
|
||||
name: "Complete Trait version name specified",
|
||||
inputRevisionName: "scaler-trait-v1.3.0",
|
||||
definitionName: "scaler-trait",
|
||||
definitionType: "Trait",
|
||||
expectedDefRevisionName: "scaler-trait-v1.3.0",
|
||||
client: &traitListCli,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
name: "Partial Trait version name specified",
|
||||
inputRevisionName: "scaler-trait-v1.2",
|
||||
definitionName: "scaler-trait",
|
||||
definitionType: "Trait",
|
||||
expectedDefRevisionName: "scaler-trait-v1.2.4",
|
||||
client: &traitListCli,
|
||||
err: nil,
|
||||
}, {
|
||||
name: "Trait version name not present",
|
||||
inputRevisionName: "scaler-trait-v1.5",
|
||||
definitionName: "scaler-trait",
|
||||
definitionType: "Trait",
|
||||
expectedDefRevisionName: "",
|
||||
client: &traitListCli,
|
||||
err: fmt.Errorf("error finding definition revision for Name: scaler-trait, Type: Trait"),
|
||||
},
|
||||
}
|
||||
ctx := context.Background()
|
||||
for _, tc := range testcases {
|
||||
defRevisionName, err := util.GetLatestDefinitionRevisionName(ctx, tc.client, tc.definitionName, tc.inputRevisionName, common.DefinitionType(tc.definitionType))
|
||||
assert.Equal(t, defRevisionName, tc.expectedDefRevisionName)
|
||||
assert.Equal(t, err, tc.err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionComponentAutoUpdateEnabled(t *testing.T) {
|
||||
cli := test.MockClient{MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
|
||||
defRevisionList := getComponentDefRevisionList()
|
||||
defRevisionList.DeepCopyInto(list.(*v1beta1.DefinitionRevisionList))
|
||||
return nil
|
||||
}, MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
componentDefinitionRevision.DeepCopyInto(obj.(*v1beta1.DefinitionRevision))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "true"
|
||||
definitionName := "configmap-component@v1"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.ComponentDefinition)
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, definition.Spec.Version, "1.0.0")
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionOfTraitAutoUpdateEnabled(t *testing.T) {
|
||||
cli := test.MockClient{MockList: func(ctx context.Context, list client.ObjectList, opts ...client.ListOption) error {
|
||||
defRevisionList := getTraitDefRevisionList()
|
||||
defRevisionList.DeepCopyInto(list.(*v1beta1.DefinitionRevisionList))
|
||||
return nil
|
||||
}, MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
traitDefinitionRevision.DeepCopyInto(obj.(*v1beta1.DefinitionRevision))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "true"
|
||||
definitionName := "scaler-trait@v1"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.TraitDefinition)
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, definition.Spec.Version, "1.0.0")
|
||||
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionComponentAutoUpdateDisabled(t *testing.T) {
|
||||
cli := test.MockClient{MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
componentDefinitionRevision.Spec.ComponentDefinition.DeepCopyInto(obj.(*v1beta1.ComponentDefinition))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
definitionName := "configmap-component"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.ComponentDefinition)
|
||||
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
assert.Equal(t, definition.Spec.Version, "1.0.0")
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionPolicyAutoUpdateDisabled(t *testing.T) {
|
||||
cli := test.MockClient{MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
policydefinition := &v1beta1.PolicyDefinition{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mock-policy-definition",
|
||||
Namespace: "vela-system",
|
||||
},
|
||||
}
|
||||
policydefinition.DeepCopyInto(obj.(*v1beta1.PolicyDefinition))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
definitionName := "mock-policy-definition"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.PolicyDefinition)
|
||||
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionWorkflowStepAutoUpdateDisabled(t *testing.T) {
|
||||
cli := test.MockClient{MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
workflowStepDefinition := &v1beta1.WorkflowStepDefinition{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mock-workflow-definition",
|
||||
Namespace: "vela-system",
|
||||
},
|
||||
}
|
||||
workflowStepDefinition.DeepCopyInto(obj.(*v1beta1.WorkflowStepDefinition))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
definitionName := "mock-workflow-definition"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.WorkflowStepDefinition)
|
||||
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionInvalidDefinition(t *testing.T) {
|
||||
cli := test.MockClient{MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
workflowStepDefinition := &v1beta1.WorkloadDefinition{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "mock-workload-definition",
|
||||
Namespace: "vela-system",
|
||||
},
|
||||
}
|
||||
workflowStepDefinition.DeepCopyInto(obj.(*v1beta1.WorkloadDefinition))
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
definitionName := "mock-workload-definition"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.WorkloadDefinition)
|
||||
definition.ObjectMeta.Name = "mock-workload-definition"
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err.Error(), "invalid definition type for mock-workload-definition")
|
||||
}
|
||||
|
||||
func TestGetCapabilityDefinitionOfTraitAutoUpdateDisabled(t *testing.T) {
|
||||
cli := test.MockClient{MockGet: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
|
||||
o := new(v1beta1.TraitDefinition)
|
||||
*o = traitDefinitionRevision.Spec.TraitDefinition
|
||||
return nil
|
||||
}}
|
||||
annotations := make(map[string]string)
|
||||
annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
definitionName := "scaler-trait"
|
||||
ctx := context.Background()
|
||||
definition := new(v1beta1.TraitDefinition)
|
||||
err := util.GetCapabilityDefinition(ctx, &cli, definition, definitionName, annotations)
|
||||
assert.Equal(t, err, nil)
|
||||
|
||||
}
|
||||
|
||||
func getComponentDefRevisionList() v1beta1.DefinitionRevisionList {
|
||||
compDefRevision1 := componentDefinitionRevision.DeepCopy()
|
||||
compDefRevision1.Spec.ComponentDefinition.Spec.Version = "1.2.0"
|
||||
compDefRevision1.Name = "configmap-component-v1.2.0"
|
||||
|
||||
compDefRevision2 := componentDefinitionRevision.DeepCopy()
|
||||
compDefRevision2.Spec.ComponentDefinition.Spec.Version = "1.2.4"
|
||||
compDefRevision2.Name = "configmap-component-v1.2.4"
|
||||
|
||||
compDefRevision3 := componentDefinitionRevision.DeepCopy()
|
||||
compDefRevision3.Spec.ComponentDefinition.Spec.Version = "1.3.0"
|
||||
compDefRevision3.Name = "configmap-component-v1.3.0"
|
||||
|
||||
compRevisionList := v1beta1.DefinitionRevisionList{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DefinitionRevision",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
Items: []v1beta1.DefinitionRevision{
|
||||
*compDefRevision1, *compDefRevision2, *compDefRevision3,
|
||||
},
|
||||
}
|
||||
return compRevisionList
|
||||
}
|
||||
|
||||
func getTraitDefRevisionList() v1beta1.DefinitionRevisionList {
|
||||
traitDefRevision1 := traitDefinitionRevision.DeepCopy()
|
||||
traitDefRevision1.Spec.TraitDefinition.Spec.Version = "1.2.0"
|
||||
traitDefRevision1.Name = "scaler-trait-v1.2.0"
|
||||
|
||||
traitDefRevision2 := traitDefinitionRevision.DeepCopy()
|
||||
traitDefRevision2.Spec.TraitDefinition.Spec.Version = "1.2.4"
|
||||
traitDefRevision2.Name = "scaler-trait-v1.2.4"
|
||||
|
||||
traitDefRevision3 := traitDefinitionRevision.DeepCopy()
|
||||
traitDefRevision3.Spec.TraitDefinition.Spec.Version = "1.3.0"
|
||||
traitDefRevision3.Name = "scaler-trait-v1.3.0"
|
||||
|
||||
traitRevisionList := v1beta1.DefinitionRevisionList{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DefinitionRevision",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
Items: []v1beta1.DefinitionRevision{
|
||||
*traitDefRevision1, *traitDefRevision2, *traitDefRevision3,
|
||||
},
|
||||
}
|
||||
return traitRevisionList
|
||||
}
|
||||
|
||||
var traitDefinitionRevision = v1beta1.DefinitionRevision{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DefinitionRevision",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "scaler-trait",
|
||||
Labels: map[string]string{
|
||||
"trait.oam.dev/name": "scaler-trait",
|
||||
},
|
||||
},
|
||||
Spec: v1beta1.DefinitionRevisionSpec{
|
||||
Revision: 1,
|
||||
RevisionHash: "5ceecfbe58dde83a",
|
||||
DefinitionType: "Trait",
|
||||
TraitDefinition: v1beta1.TraitDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "TraitDefinition",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "scaler-trait",
|
||||
},
|
||||
Spec: v1beta1.TraitDefinitionSpec{
|
||||
Version: "1.0.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// debug unit tests
|
||||
var componentDefinitionRevision = v1beta1.DefinitionRevision{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "DefinitionRevision",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "configmap-component",
|
||||
Labels: map[string]string{
|
||||
"componentdefinition.oam.dev/name": "configmap-component",
|
||||
},
|
||||
},
|
||||
Spec: v1beta1.DefinitionRevisionSpec{
|
||||
Revision: 1,
|
||||
RevisionHash: "5ceecfbe58dde83a",
|
||||
DefinitionType: "Component",
|
||||
ComponentDefinition: v1beta1.ComponentDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ComponentDefinition",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "configmap-component",
|
||||
},
|
||||
Spec: v1beta1.ComponentDefinitionSpec{
|
||||
Version: "1.0.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import (
|
||||
|
||||
"github.com/kubevela/pkg/cue/cuex"
|
||||
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
|
||||
"github.com/kubevela/workflow/pkg/cue/model/sets"
|
||||
"github.com/kubevela/workflow/pkg/cue/model/value"
|
||||
providertypes "github.com/kubevela/workflow/pkg/providers/types"
|
||||
|
||||
@@ -127,9 +128,20 @@ func ValidateView(ctx context.Context, viewStr string) error {
|
||||
|
||||
// Make sure `status` or `export` field exists
|
||||
vStatus := val.LookupPath(cue.ParsePath(DefaultExportValue))
|
||||
errStatus := vStatus.Err()
|
||||
vExport := val.LookupPath(cue.ParsePath(KeyWordExport))
|
||||
if !vStatus.Exists() && !vExport.Exists() {
|
||||
return errors.Errorf("no `status` or `export` field found in view")
|
||||
errExport := vExport.Err()
|
||||
if errStatus != nil && errExport != nil {
|
||||
return errors.Errorf("no `status` or `export` field found in view: %v, %v", errStatus, errExport)
|
||||
}
|
||||
if errStatus == nil {
|
||||
_, errStatus = sets.ToString(vStatus)
|
||||
}
|
||||
if errExport == nil {
|
||||
_, errExport = sets.ToString(vExport)
|
||||
}
|
||||
if errStatus != nil && errExport != nil {
|
||||
return errors.Errorf("connot get string from` status` or `export`: %v, %v", errStatus, errExport)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -25,7 +25,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev/v1beta1/componentdefinition"
|
||||
"github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev/v1beta1/policydefinition"
|
||||
"github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev/v1beta1/traitdefinition"
|
||||
"github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev/v1beta1/workflowstepdefinition"
|
||||
)
|
||||
|
||||
// Register will be called in main and register all validation handlers
|
||||
@@ -36,7 +35,6 @@ func Register(mgr manager.Manager, args controller.Args) {
|
||||
componentdefinition.RegisterValidatingHandler(mgr)
|
||||
traitdefinition.RegisterValidatingHandler(mgr, args)
|
||||
policydefinition.RegisterValidatingHandler(mgr)
|
||||
workflowstepdefinition.RegisterValidatingHandler(mgr)
|
||||
server := mgr.GetWebhookServer()
|
||||
server.Register("/convert", conversion.NewWebhookHandler(mgr.GetScheme()))
|
||||
}
|
||||
|
||||
@@ -66,10 +66,6 @@ func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) a
|
||||
if err := h.Decoder.Decode(req, app); err != nil {
|
||||
return admission.Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
if req.Namespace != "" {
|
||||
app.Namespace = req.Namespace
|
||||
}
|
||||
|
||||
ctx = util.SetNamespaceInCtx(ctx, app.Namespace)
|
||||
switch req.Operation {
|
||||
case admissionv1.Create:
|
||||
|
||||
@@ -207,52 +207,4 @@ var _ = Describe("Test Application Validator", func() {
|
||||
resp := handler.Handle(ctx, req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
})
|
||||
|
||||
It("Test Application with PublishVersion and Autoupdate annotations", func() {
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: metav1.GroupVersionResource{Group: "core.oam.dev", Version: "v1alpha2", Resource: "applications"},
|
||||
Object: runtime.RawExtension{
|
||||
Raw: []byte(`
|
||||
{"apiVersion":"core.oam.dev/v1beta1","kind":"Application","metadata":{"name":"workflow-timeout","namespace":"default","annotations":{"app.oam.dev/publishVersion":"v1.0.0","app.oam.dev/autoUpdate":"true"}},"spec":{"components":[{"name":"comp","type":"worker","properties":{"image":"crccheck/hello-world"}}],"workflow":{"steps":[{"name":"group","type":"suspend","timeout":"1s"}]}}}
|
||||
`),
|
||||
},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(ctx, req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
})
|
||||
|
||||
It("Test Application Publishversion Annotation", func() {
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: metav1.GroupVersionResource{Group: "core.oam.dev", Version: "v1alpha2", Resource: "applications"},
|
||||
Object: runtime.RawExtension{
|
||||
Raw: []byte(`
|
||||
{"apiVersion":"core.oam.dev/v1beta1","kind":"Application","metadata":{"name":"workflow-timeout","namespace":"default","annotations":{"app.oam.dev/publishVersion":"v1.0.0"}},"spec":{"components":[{"name":"comp","type":"worker","properties":{"image":"crccheck/hello-world"}}],"workflow":{"steps":[{"name":"group","type":"suspend","timeout":"1s"}]}}}
|
||||
`),
|
||||
},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(ctx, req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("Test Application Autoupdate Annotation", func() {
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: metav1.GroupVersionResource{Group: "core.oam.dev", Version: "v1alpha2", Resource: "applications"},
|
||||
Object: runtime.RawExtension{
|
||||
Raw: []byte(`
|
||||
{"apiVersion":"core.oam.dev/v1beta1","kind":"Application","metadata":{"name":"workflow-timeout","namespace":"default","annotations":{"app.oam.dev/autoUpdate":"true"}},"spec":{"components":[{"name":"comp","type":"worker","properties":{"image":"crccheck/hello-world"}}],"workflow":{"steps":[{"name":"group","type":"suspend","timeout":"1s"}]}}}
|
||||
`),
|
||||
},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(ctx, req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,7 +30,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/features"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
)
|
||||
|
||||
// ValidateWorkflow validates the Application workflow
|
||||
@@ -108,24 +107,10 @@ func (h *ValidatingHandler) ValidateComponents(ctx context.Context, app *v1beta1
|
||||
return componentErrs
|
||||
}
|
||||
|
||||
// ValidateAnnotations validates whether the application has both autoupdate and publish version annotations
|
||||
func (h *ValidatingHandler) ValidateAnnotations(_ context.Context, app *v1beta1.Application) field.ErrorList {
|
||||
var annotationsErrs field.ErrorList
|
||||
|
||||
hasPublishVersion := app.Annotations[oam.AnnotationPublishVersion]
|
||||
hasAutoUpdate := app.Annotations[oam.AnnotationAutoUpdate]
|
||||
if hasAutoUpdate == "true" && hasPublishVersion != "" {
|
||||
annotationsErrs = append(annotationsErrs, field.Invalid(field.NewPath("metadata", "annotations"), app,
|
||||
"Application has both autoUpdate and publishVersion annotations. Only one can be present"))
|
||||
}
|
||||
return annotationsErrs
|
||||
}
|
||||
|
||||
// ValidateCreate validates the Application on creation
|
||||
func (h *ValidatingHandler) ValidateCreate(ctx context.Context, app *v1beta1.Application) field.ErrorList {
|
||||
var errs field.ErrorList
|
||||
|
||||
errs = append(errs, h.ValidateAnnotations(ctx, app)...)
|
||||
errs = append(errs, h.ValidateWorkflow(ctx, app)...)
|
||||
errs = append(errs, h.ValidateComponents(ctx, app)...)
|
||||
return errs
|
||||
|
||||
@@ -46,7 +46,7 @@ type ValidatingHandler struct {
|
||||
|
||||
var _ admission.Handler = &ValidatingHandler{}
|
||||
|
||||
// Handle validate ComponentDefinition Spec here
|
||||
// Handle validate component definition
|
||||
func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) admission.Response {
|
||||
obj := &v1beta1.ComponentDefinition{}
|
||||
if req.Resource.String() != componentDefGVR.String() {
|
||||
@@ -71,13 +71,6 @@ func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) a
|
||||
}
|
||||
}
|
||||
|
||||
if obj.Spec.Version != "" {
|
||||
err = webhookutils.ValidateSemanticVersion(obj.Spec.Version)
|
||||
if err != nil {
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
revisionName := obj.GetAnnotations()[oam.AnnotationDefinitionRevisionName]
|
||||
if len(revisionName) != 0 {
|
||||
defRevName := fmt.Sprintf("%s-v%s", obj.Name, revisionName)
|
||||
@@ -86,12 +79,6 @@ func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) a
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
version := obj.Spec.Version
|
||||
err = webhookutils.ValidateMultipleDefVersionsNotPresent(version, revisionName, obj.Kind)
|
||||
if err != nil {
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
}
|
||||
return admission.ValidationResponse(true, "")
|
||||
}
|
||||
|
||||
@@ -234,172 +234,5 @@ var _ = Describe("Test ComponentDefinition validating handler", func() {
|
||||
Expect(resp.Result.Reason).Should(Equal(metav1.StatusReason(http.StatusText(http.StatusForbidden))))
|
||||
Expect(resp.Result.Message).Should(ContainSubstring("hello: reference \"world\" not found"))
|
||||
})
|
||||
|
||||
It("Test Version field validation passed", func() {
|
||||
cd := v1beta1.ComponentDefinition{}
|
||||
cd.SetGroupVersionKind(v1beta1.ComponentDefinitionGroupVersionKind)
|
||||
cd.SetName("CorrectCd")
|
||||
cd.Spec = v1beta1.ComponentDefinitionSpec{
|
||||
Version: "1.10.0",
|
||||
Workload: common.WorkloadTypeDescriptor{
|
||||
Type: "deployments.apps",
|
||||
Definition: common.WorkloadGVK{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
},
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
cdRaw, _ := json.Marshal(cd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: cdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("Test Version field validation failed", func() {
|
||||
wrongCd := v1beta1.ComponentDefinition{}
|
||||
wrongCd.SetGroupVersionKind(v1beta1.ComponentDefinitionGroupVersionKind)
|
||||
wrongCd.SetName("wrongCd")
|
||||
wrongCd.Spec = v1beta1.ComponentDefinitionSpec{
|
||||
Version: "1.10..0",
|
||||
Workload: common.WorkloadTypeDescriptor{
|
||||
Type: "deployments.apps",
|
||||
Definition: common.WorkloadGVK{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
},
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
correctCdRaw, _ := json.Marshal(wrongCd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: correctCdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
Expect(string(resp.Result.Message)).Should(ContainSubstring("Not a valid version"))
|
||||
})
|
||||
|
||||
It("Test ComponentDefintion has both spec.version and revision name annotation", func() {
|
||||
wrongCd := v1beta1.ComponentDefinition{}
|
||||
wrongCd.SetGroupVersionKind(v1beta1.ComponentDefinitionGroupVersionKind)
|
||||
wrongCd.SetName("wrongCd")
|
||||
annotations := map[string]string{
|
||||
"definitionrevision.oam.dev/name": "1.0.0",
|
||||
}
|
||||
wrongCd.SetAnnotations(annotations)
|
||||
wrongCd.SetNamespace("default")
|
||||
wrongCd.Spec = v1beta1.ComponentDefinitionSpec{
|
||||
Version: "1.10.0",
|
||||
Workload: common.WorkloadTypeDescriptor{
|
||||
Type: "deployments.apps",
|
||||
Definition: common.WorkloadGVK{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
},
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
wrongCdRaw, _ := json.Marshal(wrongCd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: wrongCdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
Expect(string(resp.Result.Message)).Should(ContainSubstring("Only one can be present"))
|
||||
})
|
||||
|
||||
It("Test ComponentDefintion with spec.version and without revision name annotation", func() {
|
||||
cd := v1beta1.ComponentDefinition{}
|
||||
cd.SetGroupVersionKind(v1beta1.ComponentDefinitionGroupVersionKind)
|
||||
cd.SetName("cd")
|
||||
cd.Spec = v1beta1.ComponentDefinitionSpec{
|
||||
// Version: "1.10.0",
|
||||
Workload: common.WorkloadTypeDescriptor{
|
||||
Type: "deployments.apps",
|
||||
Definition: common.WorkloadGVK{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
},
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
cdRaw, _ := json.Marshal(cd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: cdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("Test ComponentDefintion with revision name annotation and wihout spec.version", func() {
|
||||
cd := v1beta1.ComponentDefinition{}
|
||||
cd.SetGroupVersionKind(v1beta1.ComponentDefinitionGroupVersionKind)
|
||||
cd.SetName("cd")
|
||||
annotations := map[string]string{
|
||||
"definitionrevision.oam.dev/name": "1.0.0",
|
||||
}
|
||||
cd.SetAnnotations(annotations)
|
||||
cd.SetNamespace("default")
|
||||
cd.Spec = v1beta1.ComponentDefinitionSpec{
|
||||
Workload: common.WorkloadTypeDescriptor{
|
||||
Type: "deployments.apps",
|
||||
Definition: common.WorkloadGVK{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
},
|
||||
},
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
cdRaw, _ := json.Marshal(cd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: cdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
@@ -64,13 +64,6 @@ func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) a
|
||||
}
|
||||
}
|
||||
|
||||
if obj.Spec.Version != "" {
|
||||
err = webhookutils.ValidateSemanticVersion(obj.Spec.Version)
|
||||
if err != nil {
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
revisionName := obj.GetAnnotations()[oam.AnnotationDefinitionRevisionName]
|
||||
if len(revisionName) != 0 {
|
||||
defRevName := fmt.Sprintf("%s-v%s", obj.Name, revisionName)
|
||||
@@ -79,12 +72,6 @@ func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) a
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
version := obj.Spec.Version
|
||||
err = webhookutils.ValidateMultipleDefVersionsNotPresent(version, revisionName, obj.Kind)
|
||||
if err != nil {
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
}
|
||||
return admission.ValidationResponse(true, "")
|
||||
}
|
||||
|
||||
@@ -19,10 +19,7 @@ package policydefinition
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
@@ -32,9 +29,6 @@ import (
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
)
|
||||
|
||||
@@ -45,10 +39,8 @@ var decoder *admission.Decoder
|
||||
var pd v1beta1.PolicyDefinition
|
||||
var pdRaw []byte
|
||||
var scheme = runtime.NewScheme()
|
||||
var testEnv *envtest.Environment
|
||||
var validCueTemplate string
|
||||
var inValidCueTemplate string
|
||||
var cfg *rest.Config
|
||||
|
||||
func TestPolicydefinition(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
@@ -62,37 +54,19 @@ var _ = BeforeSuite(func() {
|
||||
|
||||
pd = v1beta1.PolicyDefinition{}
|
||||
pd.SetGroupVersionKind(v1beta1.PolicyDefinitionGroupVersionKind)
|
||||
|
||||
decoder = admission.NewDecoder(scheme)
|
||||
var err error
|
||||
var yamlPath string
|
||||
if _, set := os.LookupEnv("COMPATIBILITY_TEST"); set {
|
||||
yamlPath = "../../../../../test/compatibility-test/testdata"
|
||||
} else {
|
||||
yamlPath = filepath.Join("../../../../..", "charts", "vela-core", "crds")
|
||||
}
|
||||
testEnv = &envtest.Environment{
|
||||
ControlPlaneStartTimeout: time.Minute,
|
||||
ControlPlaneStopTimeout: time.Minute,
|
||||
CRDDirectoryPaths: []string{yamlPath},
|
||||
}
|
||||
cfg, err = testEnv.Start()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cfg).ToNot(BeNil())
|
||||
})
|
||||
|
||||
var _ = Describe("Test PolicyDefinition validating handler", func() {
|
||||
BeforeEach(func() {
|
||||
cli, err := client.New(cfg, client.Options{})
|
||||
Expect(err).Should(BeNil())
|
||||
reqResource = metav1.GroupVersionResource{
|
||||
Group: v1beta1.Group,
|
||||
Version: v1beta1.Version,
|
||||
Resource: "policydefinitions"}
|
||||
handler = ValidatingHandler{
|
||||
Decoder: decoder,
|
||||
Client: cli,
|
||||
}
|
||||
|
||||
})
|
||||
|
||||
It("Test wrong resource of admission request", func() {
|
||||
@@ -164,139 +138,5 @@ var _ = Describe("Test PolicyDefinition validating handler", func() {
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
})
|
||||
|
||||
It("Test Version field validation passed", func() {
|
||||
pd := v1beta1.PolicyDefinition{}
|
||||
pd.SetGroupVersionKind(v1beta1.PolicyDefinitionGroupVersionKind)
|
||||
pd.SetName("CorrectPd")
|
||||
pd.Spec = v1beta1.PolicyDefinitionSpec{
|
||||
Version: "1.10.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
pdRaw, _ := json.Marshal(pd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: pdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("Test Version field validation failed", func() {
|
||||
wrongPd := v1beta1.PolicyDefinition{}
|
||||
wrongPd.SetGroupVersionKind(v1beta1.PolicyDefinitionGroupVersionKind)
|
||||
wrongPd.SetName("WrongPd")
|
||||
wrongPd.Spec = v1beta1.PolicyDefinitionSpec{
|
||||
Version: "1.10..0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
wrongPdRaw, _ := json.Marshal(wrongPd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: wrongPdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
Expect(string(resp.Result.Message)).Should(ContainSubstring("Not a valid version"))
|
||||
})
|
||||
|
||||
It("Test PolicyDefintion has both spec.version and revision name annotation", func() {
|
||||
wrongPd := v1beta1.PolicyDefinition{}
|
||||
|
||||
wrongPd.SetGroupVersionKind(v1beta1.PolicyDefinitionGroupVersionKind)
|
||||
wrongPd.SetName("wrongPd")
|
||||
annotations := map[string]string{
|
||||
"definitionrevision.oam.dev/name": "v1.0.0",
|
||||
}
|
||||
wrongPd.SetAnnotations(annotations)
|
||||
wrongPd.SetNamespace("default")
|
||||
wrongPd.Spec = v1beta1.PolicyDefinitionSpec{
|
||||
Version: "1.10.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
wrongPdRaw, _ := json.Marshal(wrongPd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: wrongPdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
Expect(string(resp.Result.Message)).Should(ContainSubstring("Only one can be present"))
|
||||
})
|
||||
|
||||
It("Test PolicyDefintion with spec.version and without revision name annotation", func() {
|
||||
pd := v1beta1.PolicyDefinition{}
|
||||
|
||||
pd.SetGroupVersionKind(v1beta1.PolicyDefinitionGroupVersionKind)
|
||||
pd.SetName("pd")
|
||||
pd.Spec = v1beta1.PolicyDefinitionSpec{
|
||||
Version: "1.10.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
pdRaw, _ := json.Marshal(pd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: pdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("Test PolicyDefintion without spec.version and with revision name annotation", func() {
|
||||
pd := v1beta1.PolicyDefinition{}
|
||||
|
||||
pd.SetGroupVersionKind(v1beta1.PolicyDefinitionGroupVersionKind)
|
||||
pd.SetName("pd")
|
||||
annotations := map[string]string{
|
||||
"definitionrevision.oam.dev/name": "v1.0.0",
|
||||
}
|
||||
pd.SetAnnotations(annotations)
|
||||
pd.SetNamespace("default")
|
||||
pd.Spec = v1beta1.PolicyDefinitionSpec{
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
pdRaw, _ := json.Marshal(pd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: pdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -97,13 +97,6 @@ func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) a
|
||||
}
|
||||
}
|
||||
|
||||
if obj.Spec.Version != "" {
|
||||
err = webhookutils.ValidateSemanticVersion(obj.Spec.Version)
|
||||
if err != nil {
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
revisionName := obj.GetAnnotations()[oam.AnnotationDefinitionRevisionName]
|
||||
if len(revisionName) != 0 {
|
||||
defRevName := fmt.Sprintf("%s-v%s", obj.Name, revisionName)
|
||||
@@ -112,12 +105,6 @@ func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) a
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
version := obj.Spec.Version
|
||||
err = webhookutils.ValidateMultipleDefVersionsNotPresent(version, revisionName, obj.Kind)
|
||||
if err != nil {
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
klog.Info("validation passed ", " name: ", obj.Name, " operation: ", string(req.Operation))
|
||||
}
|
||||
return admission.ValidationResponse(true, "")
|
||||
@@ -126,7 +113,7 @@ func (h *ValidatingHandler) Handle(ctx context.Context, req admission.Request) a
|
||||
// RegisterValidatingHandler will register TraitDefinition validation to webhook
|
||||
func RegisterValidatingHandler(mgr manager.Manager, _ controller.Args) {
|
||||
server := mgr.GetWebhookServer()
|
||||
server.Register("/validating-core-oam-dev-v1beta1-traitdefinitions", &webhook.Admission{Handler: &ValidatingHandler{
|
||||
server.Register("/validating-core-oam-dev-v1alpha2-traitdefinitions", &webhook.Admission{Handler: &ValidatingHandler{
|
||||
Client: mgr.GetClient(),
|
||||
Decoder: admission.NewDecoder(mgr.GetScheme()),
|
||||
Validators: []TraitDefValidator{
|
||||
|
||||
@@ -20,10 +20,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
@@ -31,9 +28,6 @@ import (
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
@@ -47,10 +41,8 @@ var decoder *admission.Decoder
|
||||
var td v1beta1.TraitDefinition
|
||||
var tdRaw []byte
|
||||
var scheme = runtime.NewScheme()
|
||||
var testEnv *envtest.Environment
|
||||
var validCueTemplate string
|
||||
var inValidCueTemplate string
|
||||
var cfg *rest.Config
|
||||
|
||||
func TestTraitdefinition(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
@@ -66,37 +58,16 @@ var _ = BeforeSuite(func() {
|
||||
td.SetGroupVersionKind(v1beta1.TraitDefinitionGroupVersionKind)
|
||||
|
||||
decoder = admission.NewDecoder(scheme)
|
||||
var err error
|
||||
var yamlPath string
|
||||
if _, set := os.LookupEnv("COMPATIBILITY_TEST"); set {
|
||||
yamlPath = "../../../../../test/compatibility-test/testdata"
|
||||
} else {
|
||||
yamlPath = filepath.Join("../../../../..", "charts", "vela-core", "crds")
|
||||
}
|
||||
testEnv = &envtest.Environment{
|
||||
ControlPlaneStartTimeout: time.Minute,
|
||||
ControlPlaneStopTimeout: time.Minute,
|
||||
CRDDirectoryPaths: []string{yamlPath},
|
||||
}
|
||||
cfg, err = testEnv.Start()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cfg).ToNot(BeNil())
|
||||
decoder = admission.NewDecoder(scheme)
|
||||
Expect(err).Should(BeNil())
|
||||
})
|
||||
|
||||
var _ = Describe("Test TraitDefinition validating handler", func() {
|
||||
BeforeEach(func() {
|
||||
cli, err := client.New(cfg, client.Options{})
|
||||
Expect(err).Should(BeNil())
|
||||
reqResource = metav1.GroupVersionResource{
|
||||
Group: v1beta1.Group,
|
||||
Version: v1beta1.Version,
|
||||
Resource: "traitdefinitions"}
|
||||
|
||||
handler = ValidatingHandler{
|
||||
Decoder: decoder,
|
||||
Client: cli,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -210,136 +181,5 @@ var _ = Describe("Test TraitDefinition validating handler", func() {
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
})
|
||||
|
||||
It("Test Version field validation passed", func() {
|
||||
td := v1beta1.TraitDefinition{}
|
||||
td.SetGroupVersionKind(v1beta1.TraitDefinitionGroupVersionKind)
|
||||
td.SetName("Correcttd")
|
||||
td.Spec = v1beta1.TraitDefinitionSpec{
|
||||
Version: "1.10.1",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
tdRaw, _ := json.Marshal(td)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: tdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("Test Version validation failed", func() {
|
||||
wrongtd := v1beta1.TraitDefinition{}
|
||||
wrongtd.SetGroupVersionKind(v1beta1.TraitDefinitionGroupVersionKind)
|
||||
wrongtd.SetName("Wrongtd")
|
||||
wrongtd.Spec = v1beta1.TraitDefinitionSpec{
|
||||
Version: "a.b.c",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
wrongtdRaw, _ := json.Marshal(wrongtd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: wrongtdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
Expect(string(resp.Result.Message)).Should(ContainSubstring("Not a valid version"))
|
||||
})
|
||||
|
||||
It("Test TraitDefintion has both spec.version and revision name annotation", func() {
|
||||
wrongtd := v1beta1.TraitDefinition{}
|
||||
wrongtd.SetGroupVersionKind(v1beta1.TraitDefinitionGroupVersionKind)
|
||||
wrongtd.SetName("Wrongtd")
|
||||
annotations := map[string]string{
|
||||
"definitionrevision.oam.dev/name": "v1.0.0",
|
||||
}
|
||||
wrongtd.SetAnnotations(annotations)
|
||||
wrongtd.SetNamespace("default")
|
||||
wrongtd.Spec = v1beta1.TraitDefinitionSpec{
|
||||
Version: "1.10.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
wrongtdRaw, _ := json.Marshal(wrongtd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: wrongtdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
Expect(string(resp.Result.Message)).Should(ContainSubstring("Only one can be present"))
|
||||
})
|
||||
|
||||
It("Test TraitDefintion with spec.version and without revision name annotation", func() {
|
||||
td := v1beta1.TraitDefinition{}
|
||||
td.SetGroupVersionKind(v1beta1.TraitDefinitionGroupVersionKind)
|
||||
td.SetName("td")
|
||||
td.Spec = v1beta1.TraitDefinitionSpec{
|
||||
Version: "1.10.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
tdRaw, _ := json.Marshal(td)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: tdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("Test TraitDefintion without spec.version and with revision name annotation", func() {
|
||||
td := v1beta1.TraitDefinition{}
|
||||
td.SetGroupVersionKind(v1beta1.TraitDefinitionGroupVersionKind)
|
||||
td.SetName("td")
|
||||
annotations := map[string]string{
|
||||
"definitionrevision.oam.dev/name": "v1.0.0",
|
||||
}
|
||||
td.SetAnnotations(annotations)
|
||||
td.SetNamespace("default")
|
||||
td.Spec = v1beta1.TraitDefinitionSpec{
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
tdRaw, _ := json.Marshal(td)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: tdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 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 workflowstepdefinition
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/manager"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
webhookutils "github.com/oam-dev/kubevela/pkg/webhook/utils"
|
||||
)
|
||||
|
||||
var workflowStepDefGVR = v1beta1.SchemeGroupVersion.WithResource("workflowstepdefinitions")
|
||||
|
||||
// ValidatingHandler handles validation of workflow step definition
|
||||
type ValidatingHandler struct {
|
||||
// Decoder decodes object
|
||||
Decoder *admission.Decoder
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
// InjectClient injects the client into the ValidatingHandler
|
||||
func (h *ValidatingHandler) InjectClient(c client.Client) error {
|
||||
h.Client = c
|
||||
return nil
|
||||
}
|
||||
|
||||
// InjectDecoder injects the decoder into the ValidatingHandler
|
||||
func (h *ValidatingHandler) InjectDecoder(d *admission.Decoder) error {
|
||||
h.Decoder = d
|
||||
return nil
|
||||
}
|
||||
|
||||
// Handle validate WorkflowStepDefinition Spec here
|
||||
func (h *ValidatingHandler) Handle(_ context.Context, req admission.Request) admission.Response {
|
||||
obj := &v1beta1.WorkflowStepDefinition{}
|
||||
if req.Resource.String() != workflowStepDefGVR.String() {
|
||||
return admission.Errored(http.StatusBadRequest, fmt.Errorf("expect resource to be %s", workflowStepDefGVR))
|
||||
}
|
||||
|
||||
if req.Operation == admissionv1.Create || req.Operation == admissionv1.Update {
|
||||
err := h.Decoder.Decode(req, obj)
|
||||
if err != nil {
|
||||
return admission.Errored(http.StatusBadRequest, err)
|
||||
}
|
||||
|
||||
if obj.Spec.Version != "" {
|
||||
err = webhookutils.ValidateSemanticVersion(obj.Spec.Version)
|
||||
if err != nil {
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
}
|
||||
revisionName := obj.Annotations[oam.AnnotationDefinitionRevisionName]
|
||||
version := obj.Spec.Version
|
||||
err = webhookutils.ValidateMultipleDefVersionsNotPresent(version, revisionName, obj.Kind)
|
||||
if err != nil {
|
||||
return admission.Denied(err.Error())
|
||||
}
|
||||
}
|
||||
return admission.ValidationResponse(true, "")
|
||||
}
|
||||
|
||||
// RegisterValidatingHandler will register WorkflowStepDefinition validation to webhook
|
||||
func RegisterValidatingHandler(mgr manager.Manager) {
|
||||
server := mgr.GetWebhookServer()
|
||||
server.Register("/validating-core-oam-dev-v1beta1-workflowstepdefinitions", &webhook.Admission{Handler: &ValidatingHandler{}})
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 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 workflowstepdefinition
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/rest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
"sigs.k8s.io/controller-runtime/pkg/envtest"
|
||||
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
|
||||
|
||||
core "github.com/oam-dev/kubevela/apis/core.oam.dev"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
)
|
||||
|
||||
var handler ValidatingHandler
|
||||
var reqResource metav1.GroupVersionResource
|
||||
var decoder *admission.Decoder
|
||||
var td v1beta1.WorkflowStepDefinition
|
||||
var validCueTemplate string
|
||||
var inValidCueTemplate string
|
||||
var cfg *rest.Config
|
||||
var testScheme = runtime.NewScheme()
|
||||
var testEnv *envtest.Environment
|
||||
|
||||
func TestWorkflowStepDefinition(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Traitdefinition Suite")
|
||||
}
|
||||
|
||||
var _ = BeforeSuite(func() {
|
||||
|
||||
validCueTemplate = "{hello: 'world'}"
|
||||
inValidCueTemplate = "{hello: world}"
|
||||
|
||||
var yamlPath string
|
||||
if _, set := os.LookupEnv("COMPATIBILITY_TEST"); set {
|
||||
yamlPath = "../../../../../test/compatibility-test/testdata"
|
||||
} else {
|
||||
yamlPath = filepath.Join("../../../../..", "charts", "vela-core", "crds")
|
||||
}
|
||||
|
||||
testEnv = &envtest.Environment{
|
||||
ControlPlaneStartTimeout: time.Minute,
|
||||
ControlPlaneStopTimeout: time.Minute,
|
||||
CRDDirectoryPaths: []string{yamlPath},
|
||||
}
|
||||
|
||||
err := core.AddToScheme(testScheme)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
cfg, err = testEnv.Start()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(cfg).ToNot(BeNil())
|
||||
decoder = admission.NewDecoder(testScheme)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
td = v1beta1.WorkflowStepDefinition{}
|
||||
td.SetGroupVersionKind(v1beta1.WorkflowStepDefinitionGroupVersionKind)
|
||||
})
|
||||
|
||||
var _ = Describe("Test workflowstepdefinition validating handler", func() {
|
||||
BeforeEach(func() {
|
||||
cli, err := client.New(cfg, client.Options{})
|
||||
Expect(err).Should(BeNil())
|
||||
reqResource = metav1.GroupVersionResource{
|
||||
Group: v1beta1.Group,
|
||||
Version: v1beta1.Version,
|
||||
Resource: "workflowstepdefinitions"}
|
||||
handler = ValidatingHandler{Client: cli}
|
||||
handler.InjectDecoder(decoder)
|
||||
})
|
||||
|
||||
Context("Test create/update operation admission request", func() {
|
||||
It("Test Version validation passed", func() {
|
||||
wsd := v1beta1.WorkflowStepDefinition{}
|
||||
wsd.SetGroupVersionKind(v1beta1.WorkflowStepDefinitionGroupVersionKind)
|
||||
wsd.SetName("Correctwsd")
|
||||
wsd.Spec = v1beta1.WorkflowStepDefinitionSpec{
|
||||
Reference: common.DefinitionReference{Name: "testname", Version: "1"},
|
||||
Version: "1.10.1",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
wsdRaw, _ := json.Marshal(wsd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: wsdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("Test Version validation passed", func() {
|
||||
wrongWsd := v1beta1.WorkflowStepDefinition{}
|
||||
wrongWsd.SetGroupVersionKind(v1beta1.WorkflowStepDefinitionGroupVersionKind)
|
||||
wrongWsd.SetName("wrongwsd")
|
||||
wrongWsd.Spec = v1beta1.WorkflowStepDefinitionSpec{
|
||||
Version: "1.B.1",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
wrongWsdRaw, _ := json.Marshal(wrongWsd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: wrongWsdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
Expect(string(resp.Result.Message)).Should(ContainSubstring("Not a valid version"))
|
||||
})
|
||||
|
||||
It("Test workflowstepdefinition has both spec.version and revision name annotation", func() {
|
||||
wrongWsd := v1beta1.WorkflowStepDefinition{}
|
||||
wrongWsd.SetGroupVersionKind(v1beta1.WorkflowStepDefinitionGroupVersionKind)
|
||||
wrongWsd.SetName("wrongwsd")
|
||||
annotations := map[string]string{
|
||||
"definitionrevision.oam.dev/name": "v1.0.0",
|
||||
}
|
||||
wrongWsd.SetAnnotations(annotations)
|
||||
wrongWsd.SetNamespace("default")
|
||||
wrongWsd.Spec = v1beta1.WorkflowStepDefinitionSpec{
|
||||
Version: "1.10.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
wrongWsdRaw, _ := json.Marshal(wrongWsd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: wrongWsdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeFalse())
|
||||
Expect(string(resp.Result.Message)).Should(ContainSubstring("Only one can be present"))
|
||||
})
|
||||
|
||||
It("Test workflowstepdefinition without spec.version and with revision name annotation", func() {
|
||||
wsd := v1beta1.WorkflowStepDefinition{}
|
||||
wsd.SetGroupVersionKind(v1beta1.WorkflowStepDefinitionGroupVersionKind)
|
||||
wsd.SetName("wsd")
|
||||
annotations := map[string]string{
|
||||
"definitionrevision.oam.dev/name": "v1.0.0",
|
||||
}
|
||||
wsd.SetAnnotations(annotations)
|
||||
wsd.SetNamespace("default")
|
||||
wsd.Spec = v1beta1.WorkflowStepDefinitionSpec{
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
wsdRaw, _ := json.Marshal(wsd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: wsdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("Test workflowstepdefinition with spec.version and without revision name annotation", func() {
|
||||
wsd := v1beta1.WorkflowStepDefinition{}
|
||||
wsd.SetGroupVersionKind(v1beta1.WorkflowStepDefinitionGroupVersionKind)
|
||||
wsd.SetName("wsd")
|
||||
wsd.Spec = v1beta1.WorkflowStepDefinitionSpec{
|
||||
Version: "1.10.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: validCueTemplate,
|
||||
},
|
||||
},
|
||||
}
|
||||
wsdRaw, _ := json.Marshal(wsd)
|
||||
req := admission.Request{
|
||||
AdmissionRequest: admissionv1.AdmissionRequest{
|
||||
Operation: admissionv1.Create,
|
||||
Resource: reqResource,
|
||||
Object: runtime.RawExtension{Raw: wsdRaw},
|
||||
},
|
||||
}
|
||||
resp := handler.Handle(context.TODO(), req)
|
||||
Expect(resp.Allowed).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -18,9 +18,7 @@ package utils
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"cuelang.org/go/cue/cuecontext"
|
||||
@@ -43,6 +41,7 @@ func ValidateDefinitionRevision(ctx context.Context, cli client.Client, def runt
|
||||
if errs := validation.IsQualifiedName(defRevNamespacedName.Name); len(errs) != 0 {
|
||||
return errors.Errorf("invalid definitionRevision name %s:%s", defRevNamespacedName.Name, strings.Join(errs, ","))
|
||||
}
|
||||
|
||||
defRev := new(v1beta1.DefinitionRevision)
|
||||
if err := cli.Get(ctx, defRevNamespacedName, defRev); err != nil {
|
||||
return client.IgnoreNotFound(err)
|
||||
@@ -85,29 +84,3 @@ func checkError(err error) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateSemanticVersion validates if a Definition's version includes all of
|
||||
// major,minor & patch version values.
|
||||
func ValidateSemanticVersion(version string) error {
|
||||
if version != "" {
|
||||
versionParts := strings.Split(version, ".")
|
||||
if len(versionParts) != 3 {
|
||||
return errors.New("Not a valid version")
|
||||
}
|
||||
|
||||
for _, versionPart := range versionParts {
|
||||
if _, err := strconv.Atoi(versionPart); err != nil {
|
||||
return errors.New("Not a valid version")
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateMultipleDefVersionsNotPresent validates that both Name Annotation Revision and Spec.Version are not present
|
||||
func ValidateMultipleDefVersionsNotPresent(version, revisionName, objectType string) error {
|
||||
if version != "" && revisionName != "" {
|
||||
return fmt.Errorf("%s has both spec.version and revision name annotation. Only one can be present", objectType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,13 +17,11 @@ limitations under the License.
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"cuelang.org/go/cue/errors"
|
||||
"github.com/crossplane/crossplane-runtime/pkg/test"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestValidateCueTemplate(t *testing.T) {
|
||||
@@ -69,69 +67,3 @@ func TestValidateCueTemplate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateSemanticVersion(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
version string
|
||||
want error
|
||||
}{
|
||||
"validVersion": {
|
||||
version: "1.2.3",
|
||||
want: nil,
|
||||
},
|
||||
"versionWithAlphabets": {
|
||||
version: "1.2.3-alpha",
|
||||
want: errors.New("Not a valid version"),
|
||||
},
|
||||
"invalidVersion": {
|
||||
version: "1.2",
|
||||
want: errors.New("Not a valid version"),
|
||||
},
|
||||
}
|
||||
for caseName, cs := range cases {
|
||||
t.Run(caseName, func(t *testing.T) {
|
||||
err := ValidateSemanticVersion(cs.version)
|
||||
if cs.want != nil {
|
||||
assert.Equal(t, err.Error(), cs.want.Error())
|
||||
} else {
|
||||
assert.Equal(t, err, cs.want)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateMultipleDefVersionsNotPresent(t *testing.T) {
|
||||
cases := map[string]struct {
|
||||
version string
|
||||
revisionName string
|
||||
want error
|
||||
}{
|
||||
"versionPresent": {
|
||||
version: "1.2.3",
|
||||
revisionName: "",
|
||||
want: nil,
|
||||
},
|
||||
"revisionNamePresent": {
|
||||
version: "",
|
||||
revisionName: "2.3",
|
||||
want: nil,
|
||||
},
|
||||
"versionAndRevisionNamePresent": {
|
||||
version: "1.2.3",
|
||||
revisionName: "2.3",
|
||||
want: fmt.Errorf("ComponentDefinition has both spec.version and revision name annotation. Only one can be present"),
|
||||
},
|
||||
}
|
||||
for caseName, cs := range cases {
|
||||
t.Run(caseName, func(t *testing.T) {
|
||||
err := ValidateMultipleDefVersionsNotPresent(cs.version, cs.revisionName, "ComponentDefinition")
|
||||
if cs.want != nil {
|
||||
assert.Equal(t, err.Error(), cs.want.Error())
|
||||
} else {
|
||||
assert.Equal(t, err, cs.want)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,10 +79,10 @@ func (loader *WorkflowStepLoader) LoadTemplate(ctx context.Context, name string)
|
||||
}
|
||||
|
||||
// NewWorkflowStepTemplateLoader create a task template loader.
|
||||
func NewWorkflowStepTemplateLoader(client client.Client, annotations map[string]string) template.Loader {
|
||||
func NewWorkflowStepTemplateLoader(client client.Client) template.Loader {
|
||||
return &WorkflowStepLoader{
|
||||
loadCapabilityDefinition: func(ctx context.Context, capName string) (*appfile.Template, error) {
|
||||
return appfile.LoadTemplate(ctx, client, capName, types.TypeWorkflowStep, annotations)
|
||||
return appfile.LoadTemplate(ctx, client, capName, types.TypeWorkflowStep)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ func TestLoad(t *testing.T) {
|
||||
return nil
|
||||
},
|
||||
}
|
||||
loader := NewWorkflowStepTemplateLoader(cli, make(map[string]string))
|
||||
loader := NewWorkflowStepTemplateLoader(cli)
|
||||
|
||||
tmpl, err := loader.LoadTemplate(context.Background(), "builtin-apply-component")
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -25,8 +25,6 @@ import (
|
||||
wfv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
|
||||
@@ -274,11 +272,6 @@ var _ = Describe("Testing dry-run", func() {
|
||||
c := common2.Args{}
|
||||
c.SetConfig(cfg)
|
||||
c.SetClient(k8sClient)
|
||||
|
||||
ns := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: appNamespace}}
|
||||
err := k8sClient.Create(context.Background(), &ns)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
opt := DryRunCmdOptions{ApplicationFiles: []string{"test-data/dry-run/testing-dry-run-1.yaml"}, OfflineMode: false}
|
||||
buff, err := DryRunApplication(&opt, c, appNamespace)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
@@ -199,9 +199,6 @@ func (o *LiveDiffCmdOptions) renderlessDiff(cli client.Client, option *dryrun.Li
|
||||
if err := cli.Get(ctx, client.ObjectKey{Name: o.AppName, Namespace: o.Namespace}, app); err != nil {
|
||||
return buf, errors.Wrapf(err, "cannot get application %s/%s", o.Namespace, o.AppName)
|
||||
}
|
||||
if app.Namespace == "" {
|
||||
app.SetNamespace(o.Namespace)
|
||||
}
|
||||
base = dryrun.LiveDiffObject{Application: app}
|
||||
if o.Revision == "" {
|
||||
if app.Status.LatestRevision == nil {
|
||||
@@ -214,18 +211,12 @@ func (o *LiveDiffCmdOptions) renderlessDiff(cli client.Client, option *dryrun.Li
|
||||
if err := cli.Get(ctx, client.ObjectKey{Name: o.Revision, Namespace: o.Namespace}, rev); err != nil {
|
||||
return buf, errors.Wrapf(err, "cannot get application revision %s/%s", o.Namespace, o.Revision)
|
||||
}
|
||||
if rev.Namespace == "" {
|
||||
rev.SetNamespace(o.Namespace)
|
||||
}
|
||||
if o.SecondaryRevision == "" {
|
||||
comparor = dryrun.LiveDiffObject{ApplicationRevision: rev}
|
||||
} else {
|
||||
if err := cli.Get(ctx, client.ObjectKey{Name: o.SecondaryRevision, Namespace: o.Namespace}, secondaryRev); err != nil {
|
||||
return buf, errors.Wrapf(err, "cannot get application revision %s/%s", o.Namespace, o.SecondaryRevision)
|
||||
}
|
||||
if secondaryRev.Namespace == "" {
|
||||
secondaryRev.SetNamespace(o.Namespace)
|
||||
}
|
||||
base = dryrun.LiveDiffObject{ApplicationRevision: rev}
|
||||
comparor = dryrun.LiveDiffObject{ApplicationRevision: secondaryRev}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: podtato-head
|
||||
spec:
|
||||
components:
|
||||
- name: podtato-head-frontend
|
||||
type: webservice
|
||||
properties:
|
||||
image: ghcr.io/podtato-head/podtato-server:v0.3.1
|
||||
ports:
|
||||
- port: 8080
|
||||
expose: true
|
||||
cpu: "0.1"
|
||||
memory: "32Mi"
|
||||
traits:
|
||||
- type: podsecuritycontext
|
||||
properties:
|
||||
# runs pod as non-root user
|
||||
runAsNonRoot: true
|
||||
# runs the pod as user with uid 65532
|
||||
runAsUser: 65532
|
||||
```
|
||||
@@ -1,29 +0,0 @@
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: podtato-head
|
||||
spec:
|
||||
components:
|
||||
- name: podtato-head-frontend
|
||||
type: webservice
|
||||
properties:
|
||||
image: ghcr.io/podtato-head/podtato-server:v0.3.1
|
||||
ports:
|
||||
- port: 8080
|
||||
expose: true
|
||||
cpu: "0.1"
|
||||
memory: "32Mi"
|
||||
traits:
|
||||
- type: securitycontext
|
||||
properties:
|
||||
# drops all capabilities
|
||||
dropCapabilities:
|
||||
- ALL
|
||||
# runs container as non-root user
|
||||
runAsNonRoot: true
|
||||
# ensures that the container runs unprivileged
|
||||
privileged: false
|
||||
# runs container in read-only mode
|
||||
readOnlyRootFilesystem: false
|
||||
```
|
||||
@@ -701,9 +701,9 @@ func GetBaseResourceKinds(cueStr string, mapper meta.RESTMapper) (string, error)
|
||||
GroupAndVersion = append([]string{""}, GroupAndVersion...)
|
||||
}
|
||||
mapping, err := mapper.RESTMapping(schema.GroupKind{Group: GroupAndVersion[0], Kind: kind}, GroupAndVersion[1])
|
||||
gvr := mapping.Resource
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
gvr := mapping.Resource
|
||||
return fmt.Sprintf("- %s.%s", gvr.Resource, gvr.Group), nil
|
||||
}
|
||||
|
||||
@@ -1,664 +0,0 @@
|
||||
/*
|
||||
Copyright 2024 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 controllers_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"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/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
)
|
||||
|
||||
var _ = Describe("Application AutoUpdate", func() {
|
||||
ctx := context.Background()
|
||||
var namespace string
|
||||
var ns corev1.Namespace
|
||||
var reconcileSleepTime = 70 * time.Second
|
||||
var sleepTime = 5 * time.Second
|
||||
|
||||
BeforeEach(func() {
|
||||
By("Create namespace for app-autoupdate-e2e-test")
|
||||
namespace = randomNamespaceName("app-autoupdate-e2e-test")
|
||||
ns = corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
|
||||
Eventually(func() error {
|
||||
return k8sClient.Create(ctx, &ns)
|
||||
}, time.Second*3, time.Microsecond*300).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
|
||||
|
||||
})
|
||||
|
||||
AfterEach(func() {
|
||||
By("Clean up resources after a test")
|
||||
k8sClient.DeleteAllOf(ctx, &v1beta1.Application{}, client.InNamespace(namespace))
|
||||
k8sClient.DeleteAllOf(ctx, &v1beta1.ComponentDefinition{}, client.InNamespace(namespace))
|
||||
k8sClient.DeleteAllOf(ctx, &v1beta1.TraitDefinition{}, client.InNamespace(namespace))
|
||||
k8sClient.DeleteAllOf(ctx, &v1beta1.DefinitionRevision{}, client.InNamespace(namespace))
|
||||
Expect(k8sClient.Delete(ctx, &ns)).Should(BeNil())
|
||||
})
|
||||
|
||||
Context("Enabled", func() {
|
||||
It("When specified exact component version available. App should use exact specified version.", func() {
|
||||
By("Create configmap-component with 1.0.0 version")
|
||||
componentVersion := "1.0.0"
|
||||
componentType := "configmap-component"
|
||||
component := createComponent(componentVersion, namespace, componentType)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
|
||||
By("Create configmap-component with 1.2.0 version")
|
||||
updatedComponent := new(v1beta1.ComponentDefinition)
|
||||
updatedComponentVersion := "1.2.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: componentType, Namespace: namespace}, updatedComponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedComponent.Spec.Version = updatedComponentVersion
|
||||
updatedComponent.Spec.Schematic.CUE.Template = createOutputConfigMap(updatedComponentVersion)
|
||||
return k8sClient.Update(ctx, updatedComponent)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
time.Sleep(sleepTime)
|
||||
|
||||
By("Create application using configmap-component@1.2.0")
|
||||
app := updateAppComponent(appTemplate, "app1", namespace, componentType, "first-component", componentVersion)
|
||||
Expect(k8sClient.Create(ctx, app)).Should(Succeed())
|
||||
cm := new(corev1.ConfigMap)
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "comptest", Namespace: namespace}, cm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
Expect(cm.Data["expectedVersion"]).To(BeEquivalentTo(componentVersion))
|
||||
|
||||
By("Create configmap-component with 1.4.0 version")
|
||||
updatedComponentVersion = "1.4.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: componentType, Namespace: namespace}, updatedComponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedComponent.Spec.Version = updatedComponentVersion
|
||||
updatedComponent.Spec.Schematic.CUE.Template = createOutputConfigMap(componentVersion)
|
||||
return k8sClient.Update(ctx, updatedComponent)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("Wait for application to reconcile")
|
||||
time.Sleep(reconcileSleepTime)
|
||||
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "comptest", Namespace: namespace}, cm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
Expect(cm.Data["expectedVersion"]).To(BeEquivalentTo(componentVersion))
|
||||
|
||||
})
|
||||
|
||||
It("When speicified component version is unavailable. App should use latest version in specified range.", func() {
|
||||
By("Create configmap-component with 1.4.5 version")
|
||||
componentVersion := "1.4.5"
|
||||
componentType := "configmap-component"
|
||||
component := createComponent(componentVersion, namespace, componentType)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
time.Sleep(sleepTime)
|
||||
|
||||
By("Create application using configmap-component@1.4")
|
||||
app := updateAppComponent(appTemplate, "app1", namespace, componentType, "first-component", "1.4")
|
||||
Expect(k8sClient.Create(ctx, app)).Should(Succeed())
|
||||
cm := new(corev1.ConfigMap)
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "comptest", Namespace: namespace}, cm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
Expect(cm.Data["expectedVersion"]).To(BeEquivalentTo(componentVersion))
|
||||
|
||||
})
|
||||
|
||||
It("When new component version release after app creation, app should use new version during reconciliation", func() {
|
||||
By("Create configmap-component with 2.2.0 version")
|
||||
componentVersion := "2.2.0"
|
||||
componentType := "configmap-component"
|
||||
component := createComponent(componentVersion, namespace, componentType)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
|
||||
By("Create configmap-component with 2.3.0 version")
|
||||
updatedComponent := new(v1beta1.ComponentDefinition)
|
||||
updatedComponentVersion := "2.3.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: componentType, Namespace: namespace}, updatedComponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedComponent.Spec.Version = updatedComponentVersion
|
||||
updatedComponent.Spec.Schematic.CUE.Template = createOutputConfigMap(updatedComponentVersion)
|
||||
return k8sClient.Update(ctx, updatedComponent)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
time.Sleep(sleepTime)
|
||||
|
||||
By("Create application using configmap-component@2")
|
||||
app := updateAppComponent(appTemplate, "app1", namespace, componentType, "first-component", "2")
|
||||
Expect(k8sClient.Create(ctx, app)).Should(Succeed())
|
||||
cm := new(corev1.ConfigMap)
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "comptest", Namespace: namespace}, cm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
Expect(cm.Data["expectedVersion"]).To(BeEquivalentTo(updatedComponentVersion))
|
||||
|
||||
By("Create configmap-component with 2.4.0 version")
|
||||
updatedComponentVersion = "2.4.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: componentType, Namespace: namespace}, updatedComponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedComponent.Spec.Version = updatedComponentVersion
|
||||
updatedComponent.Spec.Schematic.CUE.Template = createOutputConfigMap(updatedComponentVersion)
|
||||
return k8sClient.Update(ctx, updatedComponent)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("Wait for application to reconcile")
|
||||
time.Sleep(reconcileSleepTime)
|
||||
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "comptest", Namespace: namespace}, cm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
Expect(cm.Data["expectedVersion"]).To(BeEquivalentTo(updatedComponentVersion))
|
||||
|
||||
})
|
||||
|
||||
It("When speicified version is available for one component and unavailable for other, app should use autoupdate the latter", func() {
|
||||
By("Create configmap-component with 1.4.5 version")
|
||||
componentVersion := "1.4.5"
|
||||
componentType := "configmap-component"
|
||||
component := createComponent(componentVersion, namespace, componentType)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
time.Sleep(sleepTime)
|
||||
|
||||
By("Create application using configmap-component@1.4 version")
|
||||
app := updateAppComponent(appWithTwoComponentTemplate, "app1", namespace, componentType, "first-component", "1.4")
|
||||
|
||||
Expect(k8sClient.Create(ctx, app)).Should(Succeed())
|
||||
cm := new(corev1.ConfigMap)
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "comptest", Namespace: namespace}, cm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
Expect(cm.Data["expectedVersion"]).To(BeEquivalentTo(componentVersion))
|
||||
|
||||
pods := new(corev1.PodList)
|
||||
opts := []client.ListOption{
|
||||
client.InNamespace(namespace),
|
||||
client.MatchingLabels{
|
||||
oam.LabelAppName: "app1",
|
||||
},
|
||||
}
|
||||
Expect(k8sClient.List(ctx, pods, opts...)).To(BeNil())
|
||||
Expect(len(pods.Items)).To(BeEquivalentTo(1))
|
||||
|
||||
})
|
||||
|
||||
It("When specified exact trait version available, app should use exact version", func() {
|
||||
By("Create scaler-trait with 1.0.0 version and 1 replica")
|
||||
traitVersion := "1.0.0"
|
||||
traitType := "scaler-trait"
|
||||
trait := createTrait(traitVersion, namespace, traitType, "1")
|
||||
trait.SetNamespace(namespace)
|
||||
Expect(k8sClient.Create(ctx, trait)).Should(Succeed())
|
||||
|
||||
By("Create scaler-trait with 1.2.0 version and 2 replicas")
|
||||
updatedTrait := new(v1beta1.TraitDefinition)
|
||||
updatedTraitVersion := "1.2.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: traitType, Namespace: namespace}, updatedTrait)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedTrait.Spec.Version = updatedTraitVersion
|
||||
updatedTrait.Spec.Schematic.CUE.Template = createScalerTraitOutput("2")
|
||||
return k8sClient.Update(ctx, updatedTrait)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
time.Sleep(sleepTime)
|
||||
|
||||
app := updateAppTrait(traitApp, "app1", namespace, traitType, updatedTraitVersion)
|
||||
Expect(k8sClient.Create(ctx, app)).Should(Succeed())
|
||||
pods := new(corev1.PodList)
|
||||
opts := []client.ListOption{
|
||||
client.InNamespace(namespace),
|
||||
client.MatchingLabels{
|
||||
oam.LabelAppName: "app1",
|
||||
},
|
||||
}
|
||||
time.Sleep(sleepTime)
|
||||
Expect(k8sClient.List(ctx, pods, opts...)).To(BeNil())
|
||||
Expect(len(pods.Items)).To(BeEquivalentTo(2))
|
||||
|
||||
By("Create scaler-trait with 1.4.0 version")
|
||||
updatedTraitVersion = "1.4.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: traitType, Namespace: namespace}, updatedTrait)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedTrait.Spec.Version = updatedTraitVersion
|
||||
updatedTrait.Spec.Schematic.CUE.Template = createScalerTraitOutput("3")
|
||||
return k8sClient.Update(ctx, updatedTrait)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("Wait for application to reconcile")
|
||||
time.Sleep(reconcileSleepTime)
|
||||
pods = new(corev1.PodList)
|
||||
opts = []client.ListOption{
|
||||
client.InNamespace(namespace),
|
||||
client.MatchingLabels{
|
||||
oam.LabelAppName: "app1",
|
||||
},
|
||||
}
|
||||
time.Sleep(sleepTime)
|
||||
Expect(k8sClient.List(ctx, pods, opts...)).To(BeNil())
|
||||
Expect(len(pods.Items)).To(BeEquivalentTo(2))
|
||||
})
|
||||
|
||||
It("When specified trait version is unavailable, app should use latest version specified in range", func() {
|
||||
By("Create scaler-trait with 1.4.5 version and 4 replica")
|
||||
traitVersion := "1.4.5"
|
||||
traitType := "scaler-trait"
|
||||
|
||||
trait := createTrait(traitVersion, namespace, traitType, "4")
|
||||
Expect(k8sClient.Create(ctx, trait)).Should(Succeed())
|
||||
time.Sleep(sleepTime)
|
||||
|
||||
By("Create application using scaler-trait@v1.4")
|
||||
app := updateAppTrait(traitApp, "app1", namespace, traitType, "1.4")
|
||||
Expect(k8sClient.Create(ctx, app)).Should(Succeed())
|
||||
pods := new(corev1.PodList)
|
||||
opts := []client.ListOption{
|
||||
client.InNamespace(namespace),
|
||||
client.MatchingLabels{
|
||||
oam.LabelAppName: "app1",
|
||||
},
|
||||
}
|
||||
time.Sleep(sleepTime)
|
||||
Expect(k8sClient.List(ctx, pods, opts...)).To(BeNil())
|
||||
Expect(len(pods.Items)).To(BeEquivalentTo(4))
|
||||
})
|
||||
|
||||
It("When new trait version is created after app creation, app should use new version during reconciliation", func() {
|
||||
By("Create scaler-trait with 1.4.5 version and 4 replica")
|
||||
traitVersion := "1.4.5"
|
||||
traitType := "scaler-trait"
|
||||
|
||||
trait := createTrait(traitVersion, namespace, traitType, "4")
|
||||
Expect(k8sClient.Create(ctx, trait)).Should(Succeed())
|
||||
time.Sleep(sleepTime)
|
||||
|
||||
By("Create application using scaler-trait@v1.4")
|
||||
app := updateAppTrait(traitApp, "app1", namespace, traitType, "1.4")
|
||||
Expect(k8sClient.Create(ctx, app)).Should(Succeed())
|
||||
pods := new(corev1.PodList)
|
||||
opts := []client.ListOption{
|
||||
client.InNamespace(namespace),
|
||||
client.MatchingLabels{
|
||||
oam.LabelAppName: "app1",
|
||||
},
|
||||
}
|
||||
time.Sleep(sleepTime)
|
||||
Expect(k8sClient.List(ctx, pods, opts...)).To(BeNil())
|
||||
Expect(len(pods.Items)).To(BeEquivalentTo(4))
|
||||
|
||||
By("Create scaler-trait with 1.4.8 version and 2 replicas")
|
||||
updatedTrait := new(v1beta1.TraitDefinition)
|
||||
updatedTraitVersion := "1.4.8"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: traitType, Namespace: namespace}, updatedTrait)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedTrait.Spec.Version = updatedTraitVersion
|
||||
updatedTrait.Spec.Schematic.CUE.Template = createScalerTraitOutput("2")
|
||||
return k8sClient.Update(ctx, updatedTrait)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
|
||||
By("Wait for application to reconcile")
|
||||
time.Sleep(reconcileSleepTime)
|
||||
pods = new(corev1.PodList)
|
||||
opts = []client.ListOption{
|
||||
client.InNamespace(namespace),
|
||||
client.MatchingLabels{
|
||||
oam.LabelAppName: "app1",
|
||||
},
|
||||
}
|
||||
time.Sleep(sleepTime)
|
||||
Expect(k8sClient.List(ctx, pods, opts...)).To(BeNil())
|
||||
Expect(len(pods.Items)).To(BeEquivalentTo(2))
|
||||
|
||||
})
|
||||
|
||||
It("When Autoupdate and Publish version annotation are specified in application, app creation should fail", func() {
|
||||
By("Create configmap-component with 1.4.5 version")
|
||||
componentVersion := "1.4.5"
|
||||
componentType := "configmap-component"
|
||||
component := createComponent(componentVersion, namespace, componentType)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
time.Sleep(sleepTime)
|
||||
|
||||
By("Create application using configmap-component@1.4.5")
|
||||
app := updateAppComponent(appTemplate, "app1", namespace, componentType, "first-component", "1.4.5")
|
||||
app.ObjectMeta.Annotations[oam.AnnotationPublishVersion] = "alpha"
|
||||
err := k8sClient.Create(ctx, app)
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
Expect(err.Error()).Should(ContainSubstring("Application has both autoUpdate and publishVersion annotations. Only one can be present"))
|
||||
|
||||
})
|
||||
})
|
||||
|
||||
Context("Disabled", func() {
|
||||
It("When specified component version is available, app should use specified version", func() {
|
||||
By("Create configmap-component with 1.0.0 version")
|
||||
componentVersion := "1.0.0"
|
||||
componentType := "configmap-component"
|
||||
component := createComponent(componentVersion, namespace, componentType)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
|
||||
By("Create configmap-component with 1.2.0 version")
|
||||
updatedComponent := new(v1beta1.ComponentDefinition)
|
||||
updatedComponentVersion := "1.2.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: componentType, Namespace: namespace}, updatedComponent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedComponent.Spec.Version = updatedComponentVersion
|
||||
updatedComponent.Spec.Schematic.CUE.Template = createOutputConfigMap(componentVersion)
|
||||
return k8sClient.Update(ctx, updatedComponent)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
time.Sleep(sleepTime)
|
||||
|
||||
By("Create application using configmap-component@1.0.0 version")
|
||||
app := updateAppComponent(appTemplate, "app1", namespace, componentType, "first-component", componentVersion)
|
||||
app.ObjectMeta.Annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
Expect(k8sClient.Create(ctx, app)).Should(Succeed())
|
||||
cm := new(corev1.ConfigMap)
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: "comptest", Namespace: namespace}, cm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
Expect(cm.Data["expectedVersion"]).To(BeEquivalentTo(componentVersion))
|
||||
})
|
||||
|
||||
It("When specified component version is unavailable, app creation should fail", func() {
|
||||
By("Create configmap-component with 1.2.0 version")
|
||||
componentVersion := "1.2.0"
|
||||
componentType := "configmap-component"
|
||||
component := createComponent(componentVersion, namespace, componentType)
|
||||
Expect(k8sClient.Create(ctx, component)).Should(Succeed())
|
||||
time.Sleep(sleepTime)
|
||||
|
||||
By("Create application using configmap-component@1 version")
|
||||
app := updateAppComponent(appTemplate, "app1", namespace, componentType, "first-component", "1")
|
||||
app.ObjectMeta.Annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
Expect(k8sClient.Create(ctx, app)).ShouldNot(Succeed())
|
||||
cm := new(corev1.ConfigMap)
|
||||
time.Sleep(reconcileSleepTime)
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKey{Name: "comptest", Namespace: namespace}, cm)).ShouldNot(BeNil())
|
||||
|
||||
configmaps := new(corev1.ConfigMapList)
|
||||
opts := []client.ListOption{
|
||||
client.InNamespace(namespace),
|
||||
client.MatchingLabels{
|
||||
oam.LabelAppName: "app1",
|
||||
},
|
||||
}
|
||||
Expect(k8sClient.List(ctx, configmaps, opts...)).To(BeNil())
|
||||
Expect(len(configmaps.Items)).To(BeEquivalentTo(0))
|
||||
})
|
||||
|
||||
It("When specified trait version is available, app should specified trait version", func() {
|
||||
By("Create scaler-trait with 1.0.0 version and 1 replica")
|
||||
traitVersion := "1.0.0"
|
||||
traitType := "scaler-trait"
|
||||
trait := createTrait(traitVersion, namespace, traitType, "1")
|
||||
Expect(k8sClient.Create(ctx, trait)).Should(Succeed())
|
||||
|
||||
By("Create scaler-trait with 1.2.0 version and 2 replica")
|
||||
updatedTrait := new(v1beta1.TraitDefinition)
|
||||
updatedTraitVersion := "1.2.0"
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Get(ctx, client.ObjectKey{Name: traitType, Namespace: namespace}, updatedTrait)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updatedTrait.Spec.Version = updatedTraitVersion
|
||||
updatedTrait.Spec.Schematic.CUE.Template = createScalerTraitOutput("2")
|
||||
return k8sClient.Update(ctx, updatedTrait)
|
||||
}, 15*time.Second, time.Second).Should(BeNil())
|
||||
time.Sleep(sleepTime)
|
||||
|
||||
By("Create application using scaler-trait@1.0.0 version")
|
||||
app := updateAppTrait(traitApp, "app1", namespace, traitType, traitVersion)
|
||||
app.ObjectMeta.Annotations[oam.AnnotationAutoUpdate] = "false"
|
||||
Expect(k8sClient.Create(ctx, app)).Should(Succeed())
|
||||
|
||||
By("Wait for application to be created")
|
||||
time.Sleep(reconcileSleepTime)
|
||||
pods := new(corev1.PodList)
|
||||
opts := []client.ListOption{
|
||||
client.InNamespace(namespace),
|
||||
client.MatchingLabels{
|
||||
oam.LabelAppName: "app1",
|
||||
},
|
||||
}
|
||||
time.Sleep(5 * time.Second)
|
||||
Expect(k8sClient.List(ctx, pods, opts...)).To(BeNil())
|
||||
Expect(len(pods.Items)).To(BeEquivalentTo(1))
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
// TODO Add test cases for policydefinition and worflowstepdefinition
|
||||
|
||||
func updateAppComponent(appTemplate v1beta1.Application, appName, namespace, typeName, componentName, componentVersion string) *v1beta1.Application {
|
||||
app := appTemplate.DeepCopy()
|
||||
app.ObjectMeta.Name = appName
|
||||
app.SetNamespace(namespace)
|
||||
app.Spec.Components[0].Type = fmt.Sprintf("%s@v%s", typeName, componentVersion)
|
||||
|
||||
app.Spec.Components[0].Name = componentName
|
||||
return app
|
||||
}
|
||||
|
||||
func updateAppTrait(traitApp v1beta1.Application, appName, namespace, typeName, traitVersion string) *v1beta1.Application {
|
||||
app := traitApp.DeepCopy()
|
||||
app.ObjectMeta.Name = appName
|
||||
app.SetNamespace(namespace)
|
||||
app.Spec.Components[0].Traits[0].Type = fmt.Sprintf("%s@v%s", typeName, traitVersion)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
func createComponent(componentVersion, namespace, name string) *v1beta1.ComponentDefinition {
|
||||
component := configMapComponent.DeepCopy()
|
||||
component.ObjectMeta.Name = name
|
||||
component.Spec.Version = componentVersion
|
||||
component.Spec.Schematic.CUE.Template = createOutputConfigMap(componentVersion)
|
||||
component.SetNamespace(namespace)
|
||||
return component
|
||||
}
|
||||
|
||||
func createTrait(traitVersion, namespace, name, replicas string) *v1beta1.TraitDefinition {
|
||||
trait := scalerTrait.DeepCopy()
|
||||
trait.ObjectMeta.Name = name
|
||||
trait.Spec.Version = traitVersion
|
||||
trait.Spec.Schematic.CUE.Template = createScalerTraitOutput(replicas)
|
||||
trait.SetNamespace(namespace)
|
||||
return trait
|
||||
}
|
||||
|
||||
func createScalerTraitOutput(replicas string) string {
|
||||
return strings.Replace(scalerTraitOutputTemplate, "1", replicas, 1)
|
||||
}
|
||||
|
||||
func createOutputConfigMap(toVersion string) string {
|
||||
return strings.Replace(configMapOutputTemplate, "1.0.0", toVersion, 1)
|
||||
}
|
||||
|
||||
var configMapComponent = &v1beta1.ComponentDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ComponentDefinition",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "configmap-component",
|
||||
},
|
||||
Spec: v1beta1.ComponentDefinitionSpec{
|
||||
Version: "1.0.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
var configMapOutputTemplate = `output: {
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata: name: "comptest"
|
||||
data: {
|
||||
expectedVersion: "1.0.0"
|
||||
}
|
||||
}`
|
||||
|
||||
var appTemplate = v1beta1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "Name",
|
||||
Namespace: "Namespace",
|
||||
Annotations: map[string]string{
|
||||
oam.AnnotationAutoUpdate: "true",
|
||||
},
|
||||
},
|
||||
Spec: v1beta1.ApplicationSpec{
|
||||
Components: []common.ApplicationComponent{
|
||||
{
|
||||
Name: "comp1Name",
|
||||
Type: "type",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var appWithTwoComponentTemplate = v1beta1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "Name",
|
||||
Namespace: "Namespace",
|
||||
Annotations: map[string]string{
|
||||
oam.AnnotationAutoUpdate: "true",
|
||||
},
|
||||
},
|
||||
Spec: v1beta1.ApplicationSpec{
|
||||
Components: []common.ApplicationComponent{
|
||||
{
|
||||
Name: "first-component",
|
||||
Type: "configmap-component",
|
||||
},
|
||||
{
|
||||
Name: "second-component",
|
||||
Type: "webservice@v1",
|
||||
Properties: util.Object2RawExtension(map[string]interface{}{
|
||||
"image": "nginx",
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var scalerTraitOutputTemplate = `patch: spec: replicas: 1`
|
||||
|
||||
var scalerTrait = &v1beta1.TraitDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "TraitDefinition",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "scaler-trait",
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
Spec: v1beta1.TraitDefinitionSpec{
|
||||
Version: "1.0.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var traitApp = v1beta1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "app-with-trait",
|
||||
Namespace: "Namespace",
|
||||
Annotations: map[string]string{
|
||||
oam.AnnotationAutoUpdate: "true",
|
||||
},
|
||||
},
|
||||
Spec: v1beta1.ApplicationSpec{
|
||||
Components: []common.ApplicationComponent{
|
||||
{
|
||||
Name: "webservice-component",
|
||||
Type: "webservice",
|
||||
Properties: &runtime.RawExtension{Raw: []byte(`{"image": "busybox"}`)},
|
||||
Traits: []common.ApplicationTrait{
|
||||
{
|
||||
Type: "scaler-trait",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -122,79 +122,6 @@ var _ = Describe("Test application of the specified definition version", func()
|
||||
Expect(k8sClient.Delete(ctx, &ns, client.PropagationPolicy(metav1.DeletePropagationForeground))).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Test tries to deploy component which has both spec.version and revision name annotation", func() {
|
||||
workerV1 := workerWithNoTemplate.DeepCopy()
|
||||
workerV1.Spec.Workload = common.WorkloadTypeDescriptor{
|
||||
Definition: common.WorkloadGVK{
|
||||
APIVersion: "batch/v1",
|
||||
Kind: "Job",
|
||||
},
|
||||
}
|
||||
workerV1.ObjectMeta.Annotations[oam.AnnotationDefinitionRevisionName] = "1.0.0"
|
||||
workerV1.Spec.Version = "1.0.0"
|
||||
workerV1.Spec.Schematic.CUE.Template = workerV1Template
|
||||
workerV1.SetNamespace(namespace)
|
||||
|
||||
Expect(k8sClient.Create(ctx, workerV1)).ShouldNot(Succeed())
|
||||
})
|
||||
|
||||
It("Test tries to deploy component which has spec.version and but no revision name annotation", func() {
|
||||
workerV1 := workerWithNoTemplate.DeepCopy()
|
||||
workerV1.Spec.Workload = common.WorkloadTypeDescriptor{
|
||||
Definition: common.WorkloadGVK{
|
||||
APIVersion: "batch/v1",
|
||||
Kind: "Job",
|
||||
},
|
||||
}
|
||||
workerV1.Spec.Version = "1.0.0"
|
||||
workerV1.Spec.Schematic.CUE.Template = workerV1Template
|
||||
workerV1.SetNamespace(namespace)
|
||||
|
||||
Expect(k8sClient.Create(ctx, workerV1)).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Test tries to deploy trait which has both spec.version and revision name annotation", func() {
|
||||
traitV1 := scalerTrait.DeepCopy()
|
||||
|
||||
traitV1.Spec.Schematic.CUE.Template = scalerTraitOutputTemplate
|
||||
traitV1.ObjectMeta.Annotations[oam.AnnotationDefinitionRevisionName] = "1.0.0"
|
||||
// traitV1.Spec.Version = "1.0.0"
|
||||
traitV1.SetNamespace(namespace)
|
||||
|
||||
Expect(k8sClient.Create(ctx, traitV1)).ShouldNot(Succeed())
|
||||
})
|
||||
|
||||
It("Test tries to deploy trait which has spec.version and but no revision name annotation", func() {
|
||||
traitV1 := scalerTrait.DeepCopy()
|
||||
|
||||
traitV1.Spec.Schematic.CUE.Template = scalerTraitOutputTemplate
|
||||
traitV1.Spec.Version = "1.0.0"
|
||||
traitV1.SetNamespace(namespace)
|
||||
|
||||
Expect(k8sClient.Create(ctx, traitV1)).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Test tries to deploy policy which has both spec.version and revision name annotation", func() {
|
||||
policyV1 := policyDef.DeepCopy()
|
||||
|
||||
policyV1.ObjectMeta.Annotations[oam.AnnotationDefinitionRevisionName] = "1.0.0"
|
||||
policyV1.Spec.Version = "1.0.0"
|
||||
policyV1.Spec.Schematic.CUE.Template = workerV1Template
|
||||
policyV1.SetNamespace(namespace)
|
||||
|
||||
Expect(k8sClient.Create(ctx, policyV1)).ShouldNot(Succeed())
|
||||
})
|
||||
|
||||
It("Test tries to deploy policy which has spec.version and but no revision name annotation", func() {
|
||||
policyV1 := policyDef.DeepCopy()
|
||||
|
||||
policyV1.Spec.Version = "1.0.0"
|
||||
policyV1.Spec.Schematic.CUE.Template = workerV1Template
|
||||
policyV1.SetNamespace(namespace)
|
||||
|
||||
Expect(k8sClient.Create(ctx, policyV1)).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Test deploy application which containing cue rendering module", func() {
|
||||
var (
|
||||
appName = "test-website-app"
|
||||
@@ -538,8 +465,7 @@ var workerWithNoTemplate = &v1beta1.ComponentDefinition{
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "worker",
|
||||
Annotations: map[string]string{},
|
||||
Name: "worker",
|
||||
},
|
||||
Spec: v1beta1.ComponentDefinitionSpec{
|
||||
Schematic: &common.Schematic{
|
||||
@@ -576,27 +502,6 @@ var jobComponentDef = &v1beta1.ComponentDefinition{
|
||||
},
|
||||
}
|
||||
|
||||
var policyDefOutputTemplate = `properties: enable: true`
|
||||
|
||||
var policyDef = &v1beta1.PolicyDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "PolicyDefinition",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "policy-apply-once",
|
||||
Annotations: map[string]string{},
|
||||
},
|
||||
Spec: v1beta1.PolicyDefinitionSpec{
|
||||
Version: "1.0.0",
|
||||
Schematic: &common.Schematic{
|
||||
CUE: &common.CUE{
|
||||
Template: policyDefOutputTemplate,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var KUBEWorker = &v1beta1.ComponentDefinition{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "ComponentDefinition",
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
podsecuritycontext: {
|
||||
type: "trait"
|
||||
annotations: {}
|
||||
description: "Adds security context to the pod spec in path 'spec.template.spec.securityContext'."
|
||||
attributes: {
|
||||
podDisruptive: true
|
||||
appliesToWorkloads: ["deployments.apps", "statefulsets.apps", "daemonsets.apps", "jobs.batch"]
|
||||
}
|
||||
}
|
||||
|
||||
template: {
|
||||
patch: spec: template: spec: {
|
||||
securityContext: {
|
||||
if parameter.appArmorProfile != _|_ {
|
||||
appArmorProfile: parameter.appArmorProfile
|
||||
}
|
||||
if parameter.fsGroup != _|_ {
|
||||
fsGroup: parameter.fsGroup
|
||||
}
|
||||
if parameter.runAsGroup != _|_ {
|
||||
runAsGroup: parameter.runAsGroup
|
||||
}
|
||||
if parameter.runAsUser != _|_ {
|
||||
runAsUser: parameter.runAsUser
|
||||
}
|
||||
if parameter.seccompProfile != _|_ {
|
||||
seccompProfile: parameter.seccompProfile
|
||||
}
|
||||
runAsNonRoot: parameter.runAsNonRoot
|
||||
}
|
||||
}
|
||||
|
||||
parameter: {
|
||||
// +usage=Specify the AppArmor profile for the pod
|
||||
appArmorProfile?: {
|
||||
type: "RuntimeDefault" | "Unconfined" | "Localhost"
|
||||
localhostProfile: string
|
||||
}
|
||||
fsGroup?: int
|
||||
runAsGroup?: int
|
||||
// +usage=Specify the UID to run the entrypoint of the container process
|
||||
runAsUser?: int
|
||||
// +usage=Specify if the container runs as a non-root user
|
||||
runAsNonRoot: *true | bool
|
||||
// +usage=Specify the seccomp profile for the pod
|
||||
seccompProfile?: {
|
||||
type: "RuntimeDefault" | "Unconfined" | "Localhost"
|
||||
localhostProfile: string
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
securitycontext: {
|
||||
type: "trait"
|
||||
annotations: {}
|
||||
description: "Adds security context to the container spec in path 'spec.template.spec.containers.[].securityContext'."
|
||||
attributes: {
|
||||
podDisruptive: true
|
||||
appliesToWorkloads: ["deployments.apps", "statefulsets.apps", "daemonsets.apps", "jobs.batch"]
|
||||
}
|
||||
}
|
||||
|
||||
template: {
|
||||
#PatchParams: {
|
||||
// +usage=Specify the name of the target container, if not set, use the component name
|
||||
containerName: *"" | string
|
||||
addCapabilities?: [...string]
|
||||
allowPrivilegeEscalation: *false | bool
|
||||
dropCapabilities?: [...string]
|
||||
privileged: *false | bool
|
||||
readOnlyRootFilesystem: *false | bool
|
||||
runAsNonRoot: *true | bool
|
||||
runAsUser?: int
|
||||
runAsGroup?: int
|
||||
}
|
||||
|
||||
PatchContainer: {
|
||||
_params: #PatchParams
|
||||
name: _params.containerName
|
||||
_baseContainers: context.output.spec.template.spec.containers
|
||||
_matchContainers_: [for _container_ in _baseContainers if _container_.name == name {_container_}]
|
||||
_baseContainer: *_|_ | {...}
|
||||
if len(_matchContainers_) == 0 {
|
||||
err: "container \(name) not found"
|
||||
}
|
||||
if len(_matchContainers_) > 0 {
|
||||
securityContext: {
|
||||
capabilities: {
|
||||
if _params.addCapabilities != _|_ {
|
||||
add: _params.addCapabilities
|
||||
}
|
||||
if _params.dropCapabilities != _|_ {
|
||||
drop: _params.dropCapabilities
|
||||
}
|
||||
}
|
||||
if _params.runAsUser != _|_ {
|
||||
runAsUser: _params.runAsUser
|
||||
}
|
||||
if _params.runAsGroup != _|_ {
|
||||
runAsGroup: _params.runAsGroup
|
||||
}
|
||||
allowPrivilegeEscalation: _params.allowPrivilegeEscalation
|
||||
readOnlyRootFilesystem: _params.readOnlyRootFilesystem
|
||||
privileged: _params.privileged
|
||||
runAsNonRoot: _params.runAsNonRoot
|
||||
}
|
||||
}
|
||||
}
|
||||
patch: spec: template: spec: {
|
||||
if parameter.containers == _|_ {
|
||||
// +patchKey=name
|
||||
containers: [{
|
||||
PatchContainer & {_params: {
|
||||
if parameter.containerName == "" {
|
||||
containerName: context.name
|
||||
}
|
||||
if parameter.containerName != "" {
|
||||
containerName: parameter.containerName
|
||||
}
|
||||
allowPrivilegeEscalation: parameter.allowPrivilegeEscalation
|
||||
readOnlyRootFilesystem: parameter.readOnlyRootFilesystem
|
||||
privileged: parameter.privileged
|
||||
runAsNonRoot: parameter.runAsNonRoot
|
||||
runAsUser: parameter.runAsUser
|
||||
runAsGroup: parameter.runAsGroup
|
||||
addCapabilities: parameter.addCapabilities
|
||||
dropCapabilities: parameter.dropCapabilities
|
||||
}}
|
||||
}]
|
||||
}
|
||||
|
||||
if parameter.containers != _|_ {
|
||||
// +patchKey=name
|
||||
containers: [for c in parameter.containers {
|
||||
if c.containerName == "" {
|
||||
err: "containerName must be set for containers"
|
||||
}
|
||||
if c.containerName != "" {
|
||||
PatchContainer & {_params: c}
|
||||
}
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
parameter: #PatchParams | close({
|
||||
// +usage=Specify the container image for multiple containers
|
||||
containers: [...#PatchParams]
|
||||
})
|
||||
|
||||
errs: [for c in patch.spec.template.spec.containers if c.err != _|_ {c.err}]
|
||||
}
|
||||
Reference in New Issue
Block a user