Chore: remove schematic kube and helm (#6099)

* Chore: remove unused code

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

* Chore: remove schematic Kube & Helm

Signed-off-by: Somefive <yd219913@alibaba-inc.com>

---------

Signed-off-by: Somefive <yd219913@alibaba-inc.com>
This commit is contained in:
Somefive
2023-06-12 10:41:02 +08:00
committed by GitHub
parent c0cbe24dc4
commit f1bae16723
86 changed files with 136 additions and 6949 deletions

View File

@@ -32,16 +32,6 @@ import (
"github.com/oam-dev/kubevela/pkg/oam"
)
// Kube defines the encapsulation in raw Kubernetes resource format
type Kube struct {
// Template defines the raw Kubernetes resource
// +kubebuilder:pruning:PreserveUnknownFields
Template runtime.RawExtension `json:"template"`
// Parameters defines configurable parameters
Parameters []KubeParameter `json:"parameters,omitempty"`
}
// ParameterValueType refers to a data type of parameter
type ParameterValueType string
@@ -52,31 +42,6 @@ const (
BooleanType ParameterValueType = "boolean"
)
// A KubeParameter defines a configurable parameter of a component.
type KubeParameter struct {
// Name of this parameter
Name string `json:"name"`
// +kubebuilder:validation:Enum:=string;number;boolean
// ValueType indicates the type of the parameter value, and
// only supports basic data types: string, number, boolean.
ValueType ParameterValueType `json:"type"`
// FieldPaths specifies an array of fields within this workload that will be
// overwritten by the value of this parameter. All fields must be of the
// same type. Fields are specified as JSON field paths without a leading
// dot, for example 'spec.replicas'.
FieldPaths []string `json:"fieldPaths"`
// +kubebuilder:default:=false
// Required specifies whether or not a value for this parameter must be
// supplied when authoring an Application.
Required *bool `json:"required,omitempty"`
// Description of this parameter.
Description *string `json:"description,omitempty"`
}
// CUE defines the encapsulation in CUE format
type CUE struct {
// Template defines the abstraction template data of the capability, it will replace the old CUE template in extension field.
@@ -87,26 +52,11 @@ type CUE struct {
// Schematic defines the encapsulation of this capability(workload/trait/scope),
// the encapsulation can be defined in different ways, e.g. CUE/HCL(terraform)/KUBE(K8s Object)/HELM, etc...
type Schematic struct {
KUBE *Kube `json:"kube,omitempty"`
CUE *CUE `json:"cue,omitempty"`
HELM *Helm `json:"helm,omitempty"`
Terraform *Terraform `json:"terraform,omitempty"`
}
// A Helm represents resources used by a Helm module
type Helm struct {
// Release records a Helm release used by a Helm module workload.
// +kubebuilder:pruning:PreserveUnknownFields
Release runtime.RawExtension `json:"release"`
// HelmRelease records a Helm repository used by a Helm module workload.
// +kubebuilder:pruning:PreserveUnknownFields
Repository runtime.RawExtension `json:"repository"`
}
// Terraform is the struct to describe cloud resources managed by Hashicorp Terraform
type Terraform struct {
// Configuration is Terraform Configuration
@@ -213,26 +163,6 @@ const (
ApplicationDeleting ApplicationPhase = "deleting"
)
// WorkflowState is a string that mark the workflow state
type WorkflowState string
const (
// WorkflowStateInitializing means the workflow is in initial state
WorkflowStateInitializing WorkflowState = "Initializing"
// WorkflowStateTerminated means workflow is terminated manually, and it won't be started unless the spec changed.
WorkflowStateTerminated WorkflowState = "Terminated"
// WorkflowStateSuspended means workflow is suspended manually, and it can be resumed.
WorkflowStateSuspended WorkflowState = "Suspended"
// WorkflowStateSucceeded means workflow is running successfully, all steps finished.
WorkflowStateSucceeded WorkflowState = "Succeeded"
// WorkflowStateFinished means workflow is end.
WorkflowStateFinished WorkflowState = "Finished"
// WorkflowStateExecuting means workflow is still running or waiting some steps.
WorkflowStateExecuting WorkflowState = "Executing"
// WorkflowStateSkipping means it will skip this reconcile and let next reconcile to handle it.
WorkflowStateSkipping WorkflowState = "Skipping"
)
// ApplicationComponentStatus record the health status of App component
type ApplicationComponentStatus struct {
Name string `json:"name"`
@@ -269,13 +199,6 @@ type Revision struct {
RevisionHash string `json:"revisionHash,omitempty"`
}
// RawComponent record raw component
type RawComponent struct {
// +kubebuilder:validation:EmbeddedResource
// +kubebuilder:pruning:PreserveUnknownFields
Raw runtime.RawExtension `json:"raw"`
}
// AppStatus defines the observed state of Application
type AppStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster

View File

@@ -278,76 +278,6 @@ func (in *DefinitionReference) DeepCopy() *DefinitionReference {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Helm) DeepCopyInto(out *Helm) {
*out = *in
in.Release.DeepCopyInto(&out.Release)
in.Repository.DeepCopyInto(&out.Repository)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Helm.
func (in *Helm) DeepCopy() *Helm {
if in == nil {
return nil
}
out := new(Helm)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Kube) DeepCopyInto(out *Kube) {
*out = *in
in.Template.DeepCopyInto(&out.Template)
if in.Parameters != nil {
in, out := &in.Parameters, &out.Parameters
*out = make([]KubeParameter, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Kube.
func (in *Kube) DeepCopy() *Kube {
if in == nil {
return nil
}
out := new(Kube)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *KubeParameter) DeepCopyInto(out *KubeParameter) {
*out = *in
if in.FieldPaths != nil {
in, out := &in.FieldPaths, &out.FieldPaths
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Required != nil {
in, out := &in.Required, &out.Required
*out = new(bool)
**out = **in
}
if in.Description != nil {
in, out := &in.Description, &out.Description
*out = new(string)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new KubeParameter.
func (in *KubeParameter) DeepCopy() *KubeParameter {
if in == nil {
return nil
}
out := new(KubeParameter)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OAMObjectReference) DeepCopyInto(out *OAMObjectReference) {
*out = *in
@@ -383,22 +313,6 @@ func (in *PolicyStatus) DeepCopy() *PolicyStatus {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RawComponent) DeepCopyInto(out *RawComponent) {
*out = *in
in.Raw.DeepCopyInto(&out.Raw)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RawComponent.
func (in *RawComponent) DeepCopy() *RawComponent {
if in == nil {
return nil
}
out := new(RawComponent)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *RawExtensionPointer) DeepCopyInto(out *RawExtensionPointer) {
*out = *in
@@ -475,21 +389,11 @@ func (in *Revision) DeepCopy() *Revision {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Schematic) DeepCopyInto(out *Schematic) {
*out = *in
if in.KUBE != nil {
in, out := &in.KUBE, &out.KUBE
*out = new(Kube)
(*in).DeepCopyInto(*out)
}
if in.CUE != nil {
in, out := &in.CUE, &out.CUE
*out = new(CUE)
**out = **in
}
if in.HELM != nil {
in, out := &in.HELM, &out.HELM
*out = new(Helm)
(*in).DeepCopyInto(*out)
}
if in.Terraform != nil {
in, out := &in.Terraform, &out.Terraform
*out = new(Terraform)

View File

@@ -32,7 +32,6 @@ import (
"github.com/kubevela/pkg/util/compression"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/interfaces"
velatypes "github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/oam"
velaerr "github.com/oam-dev/kubevela/pkg/utils/errors"
@@ -53,8 +52,7 @@ type ResourceTracker struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec ResourceTrackerSpec `json:"spec,omitempty"`
Status ResourceTrackerStatus `json:"status,omitempty"`
Spec ResourceTrackerSpec `json:"spec,omitempty"`
}
// ResourceTrackerType defines the type of resourceTracker
@@ -140,7 +138,7 @@ type ManagedResource struct {
}
// Equal check if two managed resource equals
func (in ManagedResource) Equal(r ManagedResource) bool {
func (in *ManagedResource) Equal(r ManagedResource) bool {
if !in.ClusterObjectReference.Equal(r.ClusterObjectReference) {
return false
}
@@ -151,7 +149,7 @@ func (in ManagedResource) Equal(r ManagedResource) bool {
}
// DisplayName readable name for locating resource
func (in ManagedResource) DisplayName() string {
func (in *ManagedResource) DisplayName() string {
s := in.Kind + " " + in.Name
if in.Namespace != "" || in.Cluster != "" {
s += " ("
@@ -170,12 +168,12 @@ func (in ManagedResource) DisplayName() string {
}
// NamespacedName namespacedName
func (in ManagedResource) NamespacedName() types.NamespacedName {
func (in *ManagedResource) NamespacedName() types.NamespacedName {
return types.NamespacedName{Namespace: in.Namespace, Name: in.Name}
}
// ResourceKey computes the key for managed resource, resources with the same key points to the same resource
func (in ManagedResource) ResourceKey() string {
func (in *ManagedResource) ResourceKey() string {
group := in.GroupVersionKind().Group
kind := in.GroupVersionKind().Kind
cluster := in.Cluster
@@ -186,12 +184,12 @@ func (in ManagedResource) ResourceKey() string {
}
// ComponentKey computes the key for the component which managed resource belongs to
func (in ManagedResource) ComponentKey() string {
func (in *ManagedResource) ComponentKey() string {
return strings.Join([]string{in.Env, in.Component}, "/")
}
// UnmarshalTo unmarshal ManagedResource into target object
func (in ManagedResource) UnmarshalTo(obj interface{}) error {
func (in *ManagedResource) UnmarshalTo(obj interface{}) error {
if in.Data == nil || in.Data.Raw == nil {
return velaerr.ManagedResourceHasNoDataError{}
}
@@ -199,7 +197,7 @@ func (in ManagedResource) UnmarshalTo(obj interface{}) error {
}
// ToUnstructured converts managed resource into unstructured
func (in ManagedResource) ToUnstructured() *unstructured.Unstructured {
func (in *ManagedResource) ToUnstructured() *unstructured.Unstructured {
obj := &unstructured.Unstructured{}
obj.SetGroupVersionKind(in.GroupVersionKind())
obj.SetName(in.Name)
@@ -211,7 +209,7 @@ func (in ManagedResource) ToUnstructured() *unstructured.Unstructured {
}
// ToUnstructuredWithData converts managed resource into unstructured and unmarshal data
func (in ManagedResource) ToUnstructuredWithData() (*unstructured.Unstructured, error) {
func (in *ManagedResource) ToUnstructuredWithData() (*unstructured.Unstructured, error) {
obj := in.ToUnstructured()
if err := in.UnmarshalTo(obj); err != nil {
if errors.Is(err, velaerr.ManagedResourceHasNoDataError{}) {
@@ -221,13 +219,6 @@ func (in ManagedResource) ToUnstructuredWithData() (*unstructured.Unstructured,
return obj, nil
}
// ResourceTrackerStatus define the status of resourceTracker
// For backward-compatibility
type ResourceTrackerStatus struct {
// Deprecated
TrackedResources []common.ClusterObjectReference `json:"trackedResources,omitempty"`
}
// +kubebuilder:object:root=true
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
@@ -325,29 +316,3 @@ func (in *ResourceTracker) DeleteManagedResource(rsc client.Object, remove bool)
}
return true
}
// addClusterObjectReference
// Deprecated
func (in *ResourceTracker) addClusterObjectReference(ref common.ClusterObjectReference) bool {
for _, _rsc := range in.Status.TrackedResources {
if _rsc.Equal(ref) {
return true
}
}
in.Status.TrackedResources = append(in.Status.TrackedResources, ref)
return false
}
// AddTrackedResource add new object reference into tracked resources, return if already exists
// Deprecated
func (in *ResourceTracker) AddTrackedResource(rsc interfaces.TrackableResource) bool {
return in.addClusterObjectReference(common.ClusterObjectReference{
ObjectReference: corev1.ObjectReference{
APIVersion: rsc.GetAPIVersion(),
Kind: rsc.GetKind(),
Name: rsc.GetName(),
Namespace: rsc.GetNamespace(),
UID: rsc.GetUID(),
},
})
}

View File

@@ -679,7 +679,6 @@ func (in *ResourceTracker) DeepCopyInto(out *ResourceTracker) {
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceTracker.
@@ -771,26 +770,6 @@ func (in *ResourceTrackerSpec) DeepCopy() *ResourceTrackerSpec {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ResourceTrackerStatus) DeepCopyInto(out *ResourceTrackerStatus) {
*out = *in
if in.TrackedResources != nil {
in, out := &in.TrackedResources, &out.TrackedResources
*out = make([]common.ClusterObjectReference, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceTrackerStatus.
func (in *ResourceTrackerStatus) DeepCopy() *ResourceTrackerStatus {
if in == nil {
return nil
}
out := new(ResourceTrackerStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *TraitDefinition) DeepCopyInto(out *TraitDefinition) {
*out = *in

View File

@@ -1,35 +0,0 @@
/*
Copyright 2021 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 interfaces
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// ObjectOwner is the interface for get and set ownerReference
type ObjectOwner interface {
GetOwnerReferences() []metav1.OwnerReference
SetOwnerReferences([]metav1.OwnerReference)
}
// TrackableResource is the interface for resources to be tracked by resourcetracker
type TrackableResource interface {
client.Object
metav1.Type
ObjectOwner
}

View File

@@ -17,13 +17,7 @@ limitations under the License.
package types
import (
"encoding/json"
"cuelang.org/go/cue"
"github.com/spf13/pflag"
"k8s.io/apimachinery/pkg/runtime"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
)
// Source record the source of Capability
@@ -89,10 +83,6 @@ type CapabilityCategory string
const (
TerraformCategory CapabilityCategory = "terraform"
HelmCategory CapabilityCategory = "helm"
KubeCategory CapabilityCategory = "kube"
CUECategory CapabilityCategory = "cue"
)
@@ -109,49 +99,6 @@ type Parameter struct {
JSONType string `json:"jsonType,omitempty"`
}
// SetFlagBy set cli flag from Parameter
func SetFlagBy(flags *pflag.FlagSet, v Parameter) {
name := v.Name
if v.Alias != "" {
name = v.Alias
}
// nolint:exhaustive
switch v.Type {
case cue.IntKind:
var vv int64
switch val := v.Default.(type) {
case int64:
vv = val
case json.Number:
vv, _ = val.Int64()
case int:
vv = int64(val)
case float64:
vv = int64(val)
}
flags.Int64P(name, v.Short, vv, v.Usage)
case cue.StringKind:
flags.StringP(name, v.Short, v.Default.(string), v.Usage)
case cue.BoolKind:
flags.BoolP(name, v.Short, v.Default.(bool), v.Usage)
case cue.NumberKind, cue.FloatKind:
var vv float64
switch val := v.Default.(type) {
case int64:
vv = float64(val)
case json.Number:
vv, _ = val.Float64()
case int:
vv = float64(val)
case float64:
vv = val
}
flags.Float64P(name, v.Short, vv, v.Usage)
default:
// other types not supported yet
}
}
// Capability defines the content of a capability
type Capability struct {
Name string `json:"name"`
@@ -181,8 +128,4 @@ type Capability struct {
TerraformConfiguration string `json:"terraformConfiguration,omitempty"`
ConfigurationType string `json:"configurationType,omitempty"`
Path string `json:"path,omitempty"`
// KubeTemplate
KubeTemplate runtime.RawExtension `json:"kubetemplate,omitempty"`
KubeParameter []common.KubeParameter `json:"kubeparameter,omitempty"`
}

View File

@@ -1,29 +0,0 @@
/*
Copyright 2021 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 types
import (
corev1 "k8s.io/api/core/v1"
)
// WorkflowContext is the workflow context to pass into workflow objects.
type WorkflowContext struct {
AppName string `json:"appName,omitempty"`
AppRevision string `json:"appRevision,omitempty"`
WorkflowIndex int `json:"workflowIndex"`
ResourceConfigMap corev1.LocalObjectReference `json:"resourceConfigMap,omitempty"`
}

View File

@@ -968,79 +968,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm
module
properties:
release:
description: Release records a Helm release used
by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository
used by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable
parameter of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array
of fields within this workload that will
be overwritten by the value of this parameter.
\tAll fields must be of the same type. Fields
are specified as JSON field paths without
a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or
not a value for this parameter must be supplied
when authoring an Application.
type: boolean
type:
description: 'ValueType indicates the type
of the parameter value, and only supports
basic data types: string, number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes
resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud
resources managed by Hashicorp Terraform
@@ -1353,79 +1280,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm
module
properties:
release:
description: Release records a Helm release used
by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository
used by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable
parameter of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array
of fields within this workload that will
be overwritten by the value of this parameter.
\tAll fields must be of the same type. Fields
are specified as JSON field paths without
a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or
not a value for this parameter must be supplied
when authoring an Application.
type: boolean
type:
description: 'ValueType indicates the type
of the parameter value, and only supports
basic data types: string, number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes
resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud
resources managed by Hashicorp Terraform
@@ -1697,79 +1551,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm
module
properties:
release:
description: Release records a Helm release used
by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository
used by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable
parameter of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array
of fields within this workload that will
be overwritten by the value of this parameter.
\tAll fields must be of the same type. Fields
are specified as JSON field paths without
a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or
not a value for this parameter must be supplied
when authoring an Application.
type: boolean
type:
description: 'ValueType indicates the type
of the parameter value, and only supports
basic data types: string, number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes
resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud
resources managed by Hashicorp Terraform
@@ -2193,79 +1974,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm
module
properties:
release:
description: Release records a Helm release used
by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository
used by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable
parameter of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array
of fields within this workload that will
be overwritten by the value of this parameter.
\tAll fields must be of the same type. Fields
are specified as JSON field paths without
a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or
not a value for this parameter must be supplied
when authoring an Application.
type: boolean
type:
description: 'ValueType indicates the type
of the parameter value, and only supports
basic data types: string, number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes
resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud
resources managed by Hashicorp Terraform
@@ -2524,79 +2232,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm
module
properties:
release:
description: Release records a Helm release used
by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository
used by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable
parameter of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array
of fields within this workload that will
be overwritten by the value of this parameter.
\tAll fields must be of the same type. Fields
are specified as JSON field paths without
a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or
not a value for this parameter must be supplied
when authoring an Application.
type: boolean
type:
description: 'ValueType indicates the type
of the parameter value, and only supports
basic data types: string, number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes
resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud
resources managed by Hashicorp Terraform

View File

@@ -101,76 +101,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm module
properties:
release:
description: Release records a Helm release used by a Helm
module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository used by
a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable parameter
of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array of fields
within this workload that will be overwritten by the
value of this parameter. \tAll fields must be of the
same type. Fields are specified as JSON field paths
without a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or not a value
for this parameter must be supplied when authoring
an Application.
type: boolean
type:
description: 'ValueType indicates the type of the parameter
value, and only supports basic data types: string,
number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud resources
managed by Hashicorp Terraform

View File

@@ -142,78 +142,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm
module
properties:
release:
description: Release records a Helm release used by
a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository
used by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable
parameter of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array
of fields within this workload that will be
overwritten by the value of this parameter.
\tAll fields must be of the same type. Fields
are specified as JSON field paths without
a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or not
a value for this parameter must be supplied
when authoring an Application.
type: boolean
type:
description: 'ValueType indicates the type of
the parameter value, and only supports basic
data types: string, number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud
resources managed by Hashicorp Terraform
@@ -473,78 +401,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm
module
properties:
release:
description: Release records a Helm release used by
a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository
used by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable
parameter of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array
of fields within this workload that will be
overwritten by the value of this parameter.
\tAll fields must be of the same type. Fields
are specified as JSON field paths without
a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or not
a value for this parameter must be supplied
when authoring an Application.
type: boolean
type:
description: 'ValueType indicates the type of
the parameter value, and only supports basic
data types: string, number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud
resources managed by Hashicorp Terraform
@@ -805,78 +661,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm
module
properties:
release:
description: Release records a Helm release used by
a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository
used by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable
parameter of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array
of fields within this workload that will be
overwritten by the value of this parameter.
\tAll fields must be of the same type. Fields
are specified as JSON field paths without
a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or not
a value for this parameter must be supplied
when authoring an Application.
type: boolean
type:
description: 'ValueType indicates the type of
the parameter value, and only supports basic
data types: string, number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud
resources managed by Hashicorp Terraform
@@ -1112,78 +896,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm
module
properties:
release:
description: Release records a Helm release used by
a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository
used by a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable
parameter of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array
of fields within this workload that will be
overwritten by the value of this parameter.
\tAll fields must be of the same type. Fields
are specified as JSON field paths without
a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or not
a value for this parameter must be supplied
when authoring an Application.
type: boolean
type:
description: 'ValueType indicates the type of
the parameter value, and only supports basic
data types: string, number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud
resources managed by Hashicorp Terraform

View File

@@ -74,76 +74,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm module
properties:
release:
description: Release records a Helm release used by a Helm
module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository used by
a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable parameter
of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array of fields
within this workload that will be overwritten by the
value of this parameter. \tAll fields must be of the
same type. Fields are specified as JSON field paths
without a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or not a value
for this parameter must be supplied when authoring
an Application.
type: boolean
type:
description: 'ValueType indicates the type of the parameter
value, and only supports basic data types: string,
number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud resources
managed by Hashicorp Terraform

View File

@@ -130,56 +130,6 @@ spec:
required:
- applicationGeneration
type: object
status:
description: ResourceTrackerStatus define the status of resourceTracker
For backward-compatibility
properties:
trackedResources:
description: Deprecated
items:
description: ClusterObjectReference defines the object reference
with cluster.
properties:
apiVersion:
description: API version of the referent.
type: string
cluster:
type: string
creator:
type: string
fieldPath:
description: 'If referring to a piece of an object instead of
an entire object, this string should contain a valid JSON/Go
field access statement, such as desiredState.manifest.containers[2].
For example, if the object reference is to a container within
a pod, this would take on a value like: "spec.containers{name}"
(where "name" refers to the name of the container that triggered
the event) or if no container name is specified "spec.containers[2]"
(container with index 2 in this pod). This syntax is chosen
only to have some well-defined way of referencing a part of
an object. TODO: this design is not final and this field is
subject to change in the future.'
type: string
kind:
description: 'Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
name:
description: 'Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names'
type: string
namespace:
description: 'Namespace of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/'
type: string
resourceVersion:
description: 'Specific resourceVersion to which this reference
is made, if any. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency'
type: string
uid:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
x-kubernetes-map-type: atomic
type: array
type: object
type: object
served: true
storage: true

View File

@@ -119,76 +119,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm module
properties:
release:
description: Release records a Helm release used by a Helm
module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository used by
a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable parameter
of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array of fields
within this workload that will be overwritten by the
value of this parameter. \tAll fields must be of the
same type. Fields are specified as JSON field paths
without a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or not a value
for this parameter must be supplied when authoring
an Application.
type: boolean
type:
description: 'ValueType indicates the type of the parameter
value, and only supports basic data types: string,
number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud resources
managed by Hashicorp Terraform

View File

@@ -71,76 +71,6 @@ spec:
required:
- template
type: object
helm:
description: A Helm represents resources used by a Helm module
properties:
release:
description: Release records a Helm release used by a Helm
module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
repository:
description: HelmRelease records a Helm repository used by
a Helm module workload.
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- release
- repository
type: object
kube:
description: Kube defines the encapsulation in raw Kubernetes
resource format
properties:
parameters:
description: Parameters defines configurable parameters
items:
description: A KubeParameter defines a configurable parameter
of a component.
properties:
description:
description: Description of this parameter.
type: string
fieldPaths:
description: "FieldPaths specifies an array of fields
within this workload that will be overwritten by the
value of this parameter. \tAll fields must be of the
same type. Fields are specified as JSON field paths
without a leading dot, for example 'spec.replicas'."
items:
type: string
type: array
name:
description: Name of this parameter
type: string
required:
default: false
description: Required specifies whether or not a value
for this parameter must be supplied when authoring
an Application.
type: boolean
type:
description: 'ValueType indicates the type of the parameter
value, and only supports basic data types: string,
number, boolean.'
enum:
- string
- number
- boolean
type: string
required:
- fieldPaths
- name
- type
type: object
type: array
template:
description: Template defines the raw Kubernetes resource
type: object
x-kubernetes-preserve-unknown-fields: true
required:
- template
type: object
terraform:
description: Terraform is the struct to describe cloud resources
managed by Hashicorp Terraform

View File

@@ -25,6 +25,7 @@ import (
"github.com/kubevela/pkg/controller/sharding"
pkgmulticluster "github.com/kubevela/pkg/multicluster"
utillog "github.com/kubevela/pkg/util/log"
"github.com/kubevela/pkg/util/profiling"
wfTypes "github.com/kubevela/workflow/pkg/types"
utilfeature "k8s.io/apiserver/pkg/util/feature"
cliflag "k8s.io/component-base/cli/flag"
@@ -53,7 +54,6 @@ type CoreOptions struct {
InformerSyncPeriod time.Duration
QPS float64
Burst int
PprofAddr string
LeaderElectionResourceLock string
LeaseDuration time.Duration
RenewDeadLine time.Duration
@@ -90,7 +90,6 @@ func NewCoreOptions() *CoreOptions {
InformerSyncPeriod: 10 * time.Hour,
QPS: 50,
Burst: 100,
PprofAddr: "",
LeaderElectionResourceLock: "configmapsleases",
LeaseDuration: 15 * time.Second,
RenewDeadLine: 10 * time.Second,
@@ -123,7 +122,6 @@ func (s *CoreOptions) Flags() cliflag.NamedFlagSets {
"The re-sync period for informer in controller-runtime. This is a system-level configuration.")
gfs.Float64Var(&s.QPS, "kube-api-qps", s.QPS, "the qps for reconcile clients. Low qps may lead to low throughput. High qps may give stress to api-server. Raise this value if concurrent-reconciles is set to be high.")
gfs.IntVar(&s.Burst, "kube-api-burst", s.Burst, "the burst for reconcile clients. Recommend setting it qps*2.")
gfs.StringVar(&s.PprofAddr, "pprof-addr", s.PprofAddr, "The address for pprof to use while exporting profiling results. The default value is empty which means do not expose it. Set it to address like :6666 to expose it.")
gfs.StringVar(&s.LeaderElectionResourceLock, "leader-election-resource-lock", s.LeaderElectionResourceLock, "The resource lock to use for leader election")
gfs.DurationVar(&s.LeaseDuration, "leader-election-lease-duration", s.LeaseDuration,
"The duration that non-leader candidates will wait to force acquire leadership")
@@ -163,6 +161,7 @@ func (s *CoreOptions) Flags() cliflag.NamedFlagSets {
kfs := fss.FlagSet("klog")
pkgclient.AddTimeoutControllerClientFlags(fss.FlagSet("controllerclient"))
utillog.AddFlags(kfs)
profiling.AddFlags(fss.FlagSet("profiling"))
if s.LogDebug {
_ = kfs.Set("v", strconv.Itoa(int(commonconfig.LogDebug)))

View File

@@ -60,7 +60,6 @@ func TestCoreOptions_Flags(t *testing.T) {
"--max-workflow-wait-backoff-time=5",
"--metrics-addr=/metrics",
"--perf-enabled=true",
"--pprof-addr=/debug/pprof",
"--use-webhook=true",
"--webhook-cert-dir=/path/to/cert",
"--webhook-port=8080",
@@ -86,7 +85,6 @@ func TestCoreOptions_Flags(t *testing.T) {
InformerSyncPeriod: 3 * time.Second,
QPS: 200,
Burst: 500,
PprofAddr: "/debug/pprof",
LeaderElectionResourceLock: "/leases",
LeaseDuration: 3 * time.Second,
RenewDeadLine: 5 * time.Second,

View File

@@ -28,6 +28,7 @@ import (
velaclient "github.com/kubevela/pkg/controller/client"
"github.com/kubevela/pkg/controller/sharding"
"github.com/kubevela/pkg/meta"
"github.com/kubevela/pkg/util/profiling"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -52,7 +53,6 @@ import (
"github.com/oam-dev/kubevela/pkg/monitor/watcher"
"github.com/oam-dev/kubevela/pkg/multicluster"
"github.com/oam-dev/kubevela/pkg/oam"
pkgutil "github.com/oam-dev/kubevela/pkg/utils"
"github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/oam-dev/kubevela/pkg/utils/util"
oamwebhook "github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev"
@@ -101,10 +101,7 @@ func run(ctx context.Context, s *options.CoreOptions) error {
"QPS", restConfig.QPS,
"Burst", restConfig.Burst,
)
if s.PprofAddr != "" {
go pkgutil.EnablePprof(s.PprofAddr, nil)
}
go profiling.StartProfilingServer(nil)
// wrapper the round tripper by multi cluster rewriter
if s.EnableClusterGateway {

View File

@@ -43,8 +43,6 @@ var app v1beta1.Application
var testShowCdDef v1beta1.ComponentDefinition
var testShowTdDef v1beta1.TraitDefinition
var testCdDef v1beta1.ComponentDefinition
var testCdDefWithHelm v1beta1.ComponentDefinition
var testCdDefWithKube v1beta1.ComponentDefinition
var testCdWithDeepCue v1beta1.ComponentDefinition
var testTdDef v1beta1.TraitDefinition
var testTdDefWithKube v1beta1.TraitDefinition
@@ -80,14 +78,6 @@ var _ = BeforeSuite(func() {
err = k8sClient.Create(ctx, &testCdDef)
Expect(err).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
Expect(yaml.Unmarshal([]byte(componentDefWithHelm), &testCdDefWithHelm)).Should(BeNil())
err = k8sClient.Create(ctx, &testCdDefWithHelm)
Expect(err).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
Expect(yaml.Unmarshal([]byte(componentDefWithKube), &testCdDefWithKube)).Should(BeNil())
err = k8sClient.Create(ctx, &testCdDefWithKube)
Expect(err).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
Expect(yaml.Unmarshal([]byte(componentWithDeepCue), &testCdWithDeepCue)).Should(BeNil())
err = k8sClient.Create(ctx, &testCdWithDeepCue)
Expect(err).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
@@ -124,8 +114,6 @@ var _ = AfterSuite(func() {
Expect(k8sClient.Delete(ctx, &app)).Should(BeNil())
Expect(k8sClient.Delete(ctx, &testCdDef)).Should(BeNil())
Expect(k8sClient.Delete(ctx, &testCdDefWithHelm)).Should(BeNil())
Expect(k8sClient.Delete(ctx, &testCdDefWithKube)).Should(BeNil())
Expect(k8sClient.Delete(ctx, &testCdWithDeepCue)).Should(BeNil())
Expect(k8sClient.Delete(ctx, &testTdDef)).Should(BeNil())
Expect(k8sClient.Delete(ctx, &testTdDefWithKube)).Should(BeNil())

View File

@@ -131,29 +131,6 @@ var _ = Describe("Test Kubectl Plugin", func() {
Expect(err).NotTo(HaveOccurred())
Expect(output).Should(ContainSubstring(showTdResult))
})
It("Test show componentDefinition use Helm Charts as Workload", func() {
Eventually(func() string {
cdName := "test-webapp-chart"
output, _ := e2e.Exec(fmt.Sprintf("kubectl-vela show %s -n default", cdName))
return output
}, 20*time.Second, time.Second).Should(ContainSubstring("Specification"))
})
It("Test show componentDefinition def with raw Kube mode", func() {
cdName := "kube-worker"
output, err := e2e.Exec(fmt.Sprintf("kubectl-vela show %s -n default", cdName))
Expect(err).NotTo(HaveOccurred())
Expect(output).Should(ContainSubstring("image"))
Expect(output).Should(ContainSubstring("The value will be applied to fields: [spec.template.spec.containers[0].image]."))
Expect(output).Should(ContainSubstring("port"))
Expect(output).Should(ContainSubstring("the specific container port num which can accept external request."))
})
It("Test show traitDefinition def with raw Kube mode", func() {
tdName := "service-kube"
output, err := e2e.Exec(fmt.Sprintf("kubectl-vela show %s -n default", tdName))
Expect(err).NotTo(HaveOccurred())
Expect(output).Should(ContainSubstring("targetPort"))
Expect(output).Should(ContainSubstring("target port num for service provider."))
})
It("Test show traitDefinition def with cue single map parameter", func() {
tdName := "annotations"
output, err := e2e.Exec(fmt.Sprintf("kubectl-vela show %s -n default", tdName))
@@ -397,73 +374,6 @@ spec:
`
var componentDefWithHelm = `
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
name: test-webapp-chart
namespace: default
annotations:
definition.oam.dev/description: helm chart for webapp
spec:
workload:
definition:
apiVersion: apps/v1
kind: Deployment
schematic:
helm:
release:
chart:
spec:
chart: "podinfo"
version: "5.1.4"
repository:
url: "https://charts.kubevela.net/example/"
`
var componentDefWithKube = `
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
name: kube-worker
namespace: default
spec:
workload:
definition:
apiVersion: apps/v1
kind: Deployment
schematic:
kube:
template:
apiVersion: apps/v1
kind: Deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
ports:
- containerPort: 80
parameters:
- name: image
required: true
type: string
fieldPaths:
- "spec.template.spec.containers[0].image"
- name: port
required: true
type: string
fieldPaths:
- "spec.template.spec.containers[0].ports[0].containerPort"
description: "the specific container port num which can accept external request."
`
var traitDef = `
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition

View File

@@ -20,14 +20,14 @@ import (
"fmt"
"github.com/oam-dev/kubevela/e2e"
"github.com/oam-dev/kubevela/references/apis"
"github.com/oam-dev/kubevela/references/cli"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var (
registryConfigs = []apis.RegistryConfig{
registryConfigs = []cli.RegistryConfig{
{
Name: "e2e-oss-registry",
URL: "oss://registry.e2e.net",

1
go.mod
View File

@@ -13,7 +13,6 @@ require (
github.com/briandowns/spinner v1.23.0
github.com/chartmuseum/helm-push v0.10.4
github.com/containerd/containerd v1.7.1
github.com/coreos/prometheus-operator v0.41.1
github.com/crossplane/crossplane-runtime v0.19.2
github.com/cue-exp/kubevelafix v0.0.0-20220922150317-aead819d979d
github.com/dave/jennifer v1.6.1

733
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -23,9 +23,6 @@ import (
"reflect"
"strings"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/format"
json2cue "cuelang.org/go/encoding/json"
"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
"github.com/kubevela/pkg/util/slices"
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta2"
@@ -35,7 +32,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
velaclient "github.com/kubevela/pkg/controller/client"
@@ -47,7 +43,6 @@ import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/appfile/helm"
"github.com/oam-dev/kubevela/pkg/auth"
"github.com/oam-dev/kubevela/pkg/component"
"github.com/oam-dev/kubevela/pkg/cue/definition"
@@ -317,10 +312,6 @@ func (af *Appfile) GenerateComponentManifest(wl *Workload, mutate func(*velaproc
// generate context here to avoid nil pointer panic
wl.Ctx = NewBasicContext(ctxData, wl.Params)
switch wl.CapabilityCategory {
case types.HelmCategory:
return generateComponentFromHelmModule(wl, ctxData)
case types.KubeCategory:
return generateComponentFromKubeModule(wl, ctxData)
case types.TerraformCategory:
return generateComponentFromTerraformModule(wl, af.Name, af.Namespace)
default:
@@ -614,78 +605,6 @@ func evalWorkloadWithContext(pCtx process.Context, wl *Workload, ns, appName str
return compManifest, nil
}
// GenerateCUETemplate generate CUE Template from Kube module and Helm module
func GenerateCUETemplate(wl *Workload) (string, error) {
var templateStr string
switch wl.CapabilityCategory {
case types.KubeCategory:
kubeObj := &unstructured.Unstructured{}
err := json.Unmarshal(wl.FullTemplate.Kube.Template.Raw, kubeObj)
if err != nil {
return templateStr, errors.Wrap(err, "cannot decode Kube template into K8s object")
}
paramValues, err := resolveKubeParameters(wl.FullTemplate.Kube.Parameters, wl.Params)
if err != nil {
return templateStr, errors.WithMessage(err, "cannot resolve parameter settings")
}
if err := setParameterValuesToKubeObj(kubeObj, paramValues); err != nil {
return templateStr, errors.WithMessage(err, "cannot set parameters value")
}
// convert structured kube obj into CUE (go ==marshal==> json ==decoder==> cue)
objRaw, err := kubeObj.MarshalJSON()
if err != nil {
return templateStr, errors.Wrap(err, "cannot marshal kube object")
}
cuectx := cuecontext.New()
expr, err := json2cue.Extract("", objRaw)
if err != nil {
return templateStr, errors.Wrap(err, "cannot extract object into CUE")
}
v := cuectx.BuildExpr(expr)
cueRaw, err := format.Node(v.Syntax())
if err != nil {
return templateStr, errors.Wrap(err, "cannot format CUE")
}
// NOTE a hack way to enable using CUE capabilities on KUBE schematic workload
templateStr = fmt.Sprintf(`
output: %s`, string(cueRaw))
case types.HelmCategory:
gv, err := schema.ParseGroupVersion(wl.FullTemplate.Reference.Definition.APIVersion)
if err != nil {
return templateStr, err
}
targetWorkloadGVK := gv.WithKind(wl.FullTemplate.Reference.Definition.Kind)
// NOTE this is a hack way to enable using CUE module capabilities on Helm module workload
// construct an empty base workload according to its GVK
templateStr = fmt.Sprintf(`
output: {
apiVersion: "%s"
kind: "%s"
}`, targetWorkloadGVK.GroupVersion().String(), targetWorkloadGVK.Kind)
default:
}
return templateStr, nil
}
func generateComponentFromKubeModule(wl *Workload, ctxData velaprocess.ContextData) (*types.ComponentManifest, error) {
templateStr, err := GenerateCUETemplate(wl)
if err != nil {
return nil, err
}
wl.FullTemplate.TemplateStr = templateStr
// re-use the way CUE module generates comp & acComp
compManifest, err := generateComponentFromCUEModule(wl, ctxData)
if err != nil {
return nil, err
}
return compManifest, nil
}
func generateTerraformConfigurationWorkload(wl *Workload, ns string) (*unstructured.Unstructured, error) {
if wl.FullTemplate == nil || wl.FullTemplate.Terraform == nil || wl.FullTemplate.Terraform.Configuration == "" {
return nil, errors.New(errTerraformConfigurationIsNotSet)
@@ -772,37 +691,6 @@ type paramValueSetting struct {
FieldPaths []string
}
func resolveKubeParameters(params []common.KubeParameter, settings map[string]interface{}) (paramValueSettings, error) {
supported := map[string]*common.KubeParameter{}
for _, p := range params {
supported[p.Name] = p.DeepCopy()
}
values := make(paramValueSettings)
for name, v := range settings {
// check unsupported parameter setting
if supported[name] == nil {
return nil, errors.Errorf("unsupported parameter %q", name)
}
// construct helper map
values[name] = paramValueSetting{
Value: v,
ValueType: supported[name].ValueType,
FieldPaths: supported[name].FieldPaths,
}
}
// check required parameter
for _, p := range params {
if p.Required != nil && *p.Required {
if _, ok := values[p.Name]; !ok {
return nil, errors.Errorf("require parameter %q", p.Name)
}
}
}
return values, nil
}
func setParameterValuesToKubeObj(obj *unstructured.Unstructured, values paramValueSettings) error {
paved := fieldpath.Pave(obj.Object)
for paramName, v := range values {
@@ -839,35 +727,6 @@ func setParameterValuesToKubeObj(obj *unstructured.Unstructured, values paramVal
return nil
}
func generateComponentFromHelmModule(wl *Workload, ctxData velaprocess.ContextData) (*types.ComponentManifest, error) {
templateStr, err := GenerateCUETemplate(wl)
if err != nil {
return nil, err
}
wl.FullTemplate.TemplateStr = templateStr
// re-use the way CUE module generates comp & acComp
compManifest := &types.ComponentManifest{
Name: wl.Name,
Namespace: ctxData.Namespace,
StandardWorkload: &unstructured.Unstructured{},
}
if wl.FullTemplate.Reference.Type != types.AutoDetectWorkloadDefinition {
compManifest, err = generateComponentFromCUEModule(wl, ctxData)
if err != nil {
return nil, err
}
}
rls, repo, err := helm.RenderHelmReleaseAndHelmRepo(wl.FullTemplate.Helm, wl.Name, ctxData.AppName, ctxData.Namespace, wl.Params)
if err != nil {
return nil, err
}
compManifest.PackagedWorkloadResources = []*unstructured.Unstructured{rls, repo}
return compManifest, nil
}
// GenerateContextDataFromAppFile generates process context data from app file
func GenerateContextDataFromAppFile(appfile *Appfile, wlName string) velaprocess.ContextData {
data := velaprocess.ContextData{

View File

@@ -19,7 +19,6 @@ package appfile
import (
"context"
"encoding/json"
"fmt"
"testing"
"cuelang.org/go/cue/cuecontext"
@@ -35,7 +34,6 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/pointer"
"sigs.k8s.io/yaml"
"github.com/kubevela/workflow/pkg/cue/model"
@@ -49,259 +47,6 @@ import (
"github.com/oam-dev/kubevela/pkg/oam/util"
)
var _ = Describe("Test Helm schematic appfile", func() {
var (
appName = "test-app"
compName = "test-comp"
workloadName = "test-workload"
)
It("Test generate AppConfig resources from Helm schematic", func() {
appFile := &Appfile{
Name: appName,
Namespace: "default",
AppRevisionName: appName + "-v1",
RelatedTraitDefinitions: map[string]*v1beta1.TraitDefinition{
"scaler": {
Spec: v1beta1.TraitDefinitionSpec{},
},
},
Workloads: []*Workload{
{
Name: workloadName,
Type: "webapp-chart",
CapabilityCategory: oamtypes.HelmCategory,
Params: map[string]interface{}{
"image": map[string]interface{}{
"tag": "5.1.2",
},
},
engine: definition.NewWorkloadAbstractEngine(compName, pd),
Traits: []*Trait{
{
Name: "scaler",
Params: map[string]interface{}{
"replicas": float64(10),
},
engine: definition.NewTraitAbstractEngine("scaler", pd),
},
},
FullTemplate: &Template{
Reference: common.WorkloadTypeDescriptor{
Definition: common.WorkloadGVK{
APIVersion: "apps/v1",
Kind: "Deployment",
},
},
Helm: &common.Helm{
Release: *util.Object2RawExtension(map[string]interface{}{
"chart": map[string]interface{}{
"spec": map[string]interface{}{
"chart": "podinfo",
"version": "5.1.4",
},
},
}),
Repository: *util.Object2RawExtension(map[string]interface{}{
"url": "https://charts.kubevela.net/example/",
}),
},
},
},
},
}
By("Generate ApplicationConfiguration and Components")
components, err := appFile.GenerateComponentManifests()
Expect(err).To(BeNil())
expectCompManifest := &oamtypes.ComponentManifest{
Name: workloadName,
StandardWorkload: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"workload.oam.dev/type": "webapp-chart",
"app.oam.dev/component": compName,
"app.oam.dev/name": appName,
"app.oam.dev/appRevision": appName + "-v1",
}}}},
PackagedWorkloadResources: []*unstructured.Unstructured{
{
Object: map[string]interface{}{
"apiVersion": "helm.toolkit.fluxcd.io/v2beta1",
"kind": "HelmRelease",
"metadata": map[string]interface{}{
"name": fmt.Sprintf("%s-%s", appName, compName),
"namespace": "default",
},
"spec": map[string]interface{}{
"chart": map[string]interface{}{
"spec": map[string]interface{}{
"sourceRef": map[string]interface{}{
"kind": "HelmRepository",
"name": fmt.Sprintf("%s-%s", appName, compName),
"namespace": "default",
},
},
},
"interval": "5m0s",
"values": map[string]interface{}{
"image": map[string]interface{}{
"tag": "5.1.2",
},
},
},
},
},
{
Object: map[string]interface{}{
"apiVersion": "source.toolkit.fluxcd.io/v1beta1",
"kind": "HelmRepository",
"metadata": map[string]interface{}{
"name": fmt.Sprintf("%s-%s", appName, compName),
"namespace": "default",
},
"spec": map[string]interface{}{
"url": "https://charts.kubevela.net/example/",
},
},
},
},
}
By("Verify expected ComponentManifest")
diff := cmp.Diff(components[0], expectCompManifest)
Expect(diff).ShouldNot(BeEmpty())
})
})
var _ = Describe("Test Kube schematic appfile", func() {
var (
appName = "test-app"
compName = "test-comp"
)
var testTemplate = func() runtime.RawExtension {
yamlStr := `apiVersion: apps/v1
kind: Deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
ports:
- containerPort: 80 `
b, _ := yaml.YAMLToJSON([]byte(yamlStr))
return runtime.RawExtension{Raw: b}
}
var testAppfile = func() *Appfile {
return &Appfile{
AppRevisionName: appName + "-v1",
Name: appName,
Namespace: "default",
RelatedTraitDefinitions: map[string]*v1beta1.TraitDefinition{
"scaler": {
Spec: v1beta1.TraitDefinitionSpec{},
},
},
Workloads: []*Workload{
{
Type: "kube-worker",
CapabilityCategory: oamtypes.KubeCategory,
Params: map[string]interface{}{
"image": "nginx:1.14.0",
},
engine: definition.NewWorkloadAbstractEngine(compName, pd),
Traits: []*Trait{
{
Name: "scaler",
Params: map[string]interface{}{
"replicas": float64(10),
},
engine: definition.NewTraitAbstractEngine("scaler", pd),
},
},
FullTemplate: &Template{
Kube: &common.Kube{
Template: testTemplate(),
Parameters: []common.KubeParameter{
{
Name: "image",
ValueType: common.StringType,
Required: pointer.Bool(true),
FieldPaths: []string{"spec.template.spec.containers[0].image"},
},
},
},
Reference: common.WorkloadTypeDescriptor{
Definition: common.WorkloadGVK{
APIVersion: "apps/v1",
Kind: "Deployment",
},
},
},
},
},
}
}
It("Test generate AppConfig resources from Kube schematic", func() {
By("Generate ApplicationConfiguration and Components")
comps, err := testAppfile().GenerateComponentManifests()
Expect(err).To(BeNil())
expectWorkload := func() *unstructured.Unstructured {
yamlStr := `apiVersion: apps/v1
kind: Deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.0
ports:
- containerPort: 80 `
r := &unstructured.Unstructured{}
_ = yaml.Unmarshal([]byte(yamlStr), r)
return r
}()
expectCompManifest := &oamtypes.ComponentManifest{
Name: compName,
StandardWorkload: expectWorkload,
}
By("Verify expected Component")
diff := cmp.Diff(comps[0], expectCompManifest)
Expect(diff).ShouldNot(BeEmpty())
})
It("Test missing set required parameter", func() {
appfile := testAppfile()
// remove parameter settings
appfile.Workloads[0].Params = nil
_, err := appfile.GenerateComponentManifests()
expectError := errors.WithMessage(errors.New(`require parameter "image"`), "cannot resolve parameter settings")
diff := cmp.Diff(expectError, err, test.EquateErrors())
Expect(diff).Should(BeEmpty())
})
})
var _ = Describe("Test Workflow", func() {
It("generate workflow task runners", func() {
workflowStepDef := v1beta1.WorkflowStepDefinition{
@@ -462,77 +207,6 @@ variable "password" {
})
})
func TestResolveKubeParameters(t *testing.T) {
stringParam := &common.KubeParameter{
Name: "strParam",
ValueType: common.StringType,
FieldPaths: []string{"spec"},
}
requiredParam := &common.KubeParameter{
Name: "reqParam",
Required: pointer.Bool(true),
ValueType: common.StringType,
FieldPaths: []string{"spec"},
}
tests := map[string]struct {
reason string
params []common.KubeParameter
settings map[string]interface{}
want paramValueSettings
wantErr error
}{
"EmptyParam": {
reason: "Empty value settings and no error should be returned",
want: make(paramValueSettings),
},
"UnsupportedParam": {
reason: "An error shoulde be returned because of unsupported param",
params: []common.KubeParameter{*stringParam},
settings: map[string]interface{}{"unsupported": "invalid parameter"},
want: nil,
wantErr: errors.Errorf("unsupported parameter %q", "unsupported"),
},
"MissingRequiredParam": {
reason: "An error should be returned because of missing required param",
params: []common.KubeParameter{*stringParam, *requiredParam},
settings: map[string]interface{}{"strParam": "string"},
want: nil,
wantErr: errors.Errorf("require parameter %q", "reqParam"),
},
"Succeed": {
reason: "No error should be returned",
params: []common.KubeParameter{*stringParam, *requiredParam},
settings: map[string]interface{}{"strParam": "test", "reqParam": "test"},
want: paramValueSettings{
"strParam": paramValueSetting{
Value: "test",
ValueType: common.StringType,
FieldPaths: stringParam.FieldPaths,
},
"reqParam": paramValueSetting{
Value: "test",
ValueType: common.StringType,
FieldPaths: requiredParam.FieldPaths,
},
},
wantErr: nil,
},
}
for tcName, tc := range tests {
t.Run(tcName, func(t *testing.T) {
result, err := resolveKubeParameters(tc.params, tc.settings)
if diff := cmp.Diff(tc.want, result); diff != "" {
t.Fatalf("\nresolveKubeParameters(...)(...) -want +get \nreason:%s\n%s\n", tc.reason, diff)
}
if diff := cmp.Diff(tc.wantErr, err, test.EquateErrors()); diff != "" {
t.Fatalf("\nresolveKubeParameters(...)(...) -want +get \nreason:%s\n%s\n", tc.reason, diff)
}
})
}
}
func TestSetParameterValuesToKubeObj(t *testing.T) {
tests := map[string]struct {
reason string
@@ -949,202 +623,6 @@ func TestGenerateTerraformConfigurationWorkload(t *testing.T) {
}
}
func TestGenerateCUETemplate(t *testing.T) {
var testCorrectTemplate = func() runtime.RawExtension {
yamlStr := `apiVersion: apps/v1
kind: Deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
ports:
- containerPort: 80 `
b, _ := yaml.YAMLToJSON([]byte(yamlStr))
return runtime.RawExtension{Raw: b}
}
var testErrorTemplate = func() runtime.RawExtension {
yamlStr := `apiVersion: apps/v1
kind: Deployment
spec:
template:
selector:
matchLabels:
app: nginx
`
b, _ := yaml.YAMLToJSON([]byte(yamlStr))
return runtime.RawExtension{Raw: b}
}
testcases := map[string]struct {
workload *Workload
expectData string
hasError bool
errInfo string
}{"Kube workload with Correct template": {
workload: &Workload{
FullTemplate: &Template{
Kube: &common.Kube{
Template: testCorrectTemplate(),
Parameters: []common.KubeParameter{
{
Name: "image",
ValueType: common.StringType,
Required: pointer.Bool(true),
FieldPaths: []string{"spec.template.spec.containers[0].image"},
},
},
},
Reference: common.WorkloadTypeDescriptor{
Definition: common.WorkloadGVK{
APIVersion: "apps/v1",
Kind: "Deployment",
},
},
},
Params: map[string]interface{}{
"image": "nginx:1.14.0",
},
CapabilityCategory: oamtypes.KubeCategory,
},
expectData: `
output: {
apiVersion: "apps/v1"
kind: "Deployment"
spec: {
selector: {
matchLabels: {
app: "nginx"
}
}
template: {
metadata: {
labels: {
app: "nginx"
}
}
spec: {
containers: [{
image: "nginx:1.14.0"
name: "nginx"
}]
ports: [{
containerPort: 80
}]
}
}
}
}`,
hasError: false,
}, "Kube workload with wrong template": {
workload: &Workload{
FullTemplate: &Template{
Kube: &common.Kube{
Template: testErrorTemplate(),
Parameters: []common.KubeParameter{
{
Name: "image",
ValueType: common.StringType,
Required: pointer.Bool(true),
FieldPaths: []string{"spec.template.spec.containers[0].image"},
},
},
},
Reference: common.WorkloadTypeDescriptor{
Definition: common.WorkloadGVK{
APIVersion: "apps/v1",
Kind: "Deployment",
},
},
},
Params: map[string]interface{}{
"image": "nginx:1.14.0",
},
CapabilityCategory: oamtypes.KubeCategory,
},
hasError: true,
errInfo: "cannot decode Kube template into K8s object: unexpected end of JSON input",
}, "Kube workload with wrong parameter": {
workload: &Workload{
FullTemplate: &Template{
Kube: &common.Kube{
Template: testCorrectTemplate(),
Parameters: []common.KubeParameter{
{
Name: "image",
ValueType: common.StringType,
Required: pointer.Bool(true),
FieldPaths: []string{"spec.template.spec.containers[0].image"},
},
},
},
Reference: common.WorkloadTypeDescriptor{
Definition: common.WorkloadGVK{
APIVersion: "apps/v1",
Kind: "Deployment",
},
},
},
Params: map[string]interface{}{
"unsupported": "invalid parameter",
},
CapabilityCategory: oamtypes.KubeCategory,
},
hasError: true,
errInfo: "cannot resolve parameter settings: unsupported parameter \"unsupported\"",
}, "Helm workload with correct reference": {
workload: &Workload{
FullTemplate: &Template{
Reference: common.WorkloadTypeDescriptor{
Definition: common.WorkloadGVK{
APIVersion: "app/v1",
Kind: "deployment",
},
},
},
CapabilityCategory: oamtypes.HelmCategory,
},
hasError: false,
expectData: `
output: {
apiVersion: "app/v1"
kind: "deployment"
}`,
}, "Helm workload with wrong reference": {
workload: &Workload{
FullTemplate: &Template{
Reference: common.WorkloadTypeDescriptor{
Definition: common.WorkloadGVK{
APIVersion: "app@//v1",
Kind: "deployment",
},
},
},
CapabilityCategory: oamtypes.HelmCategory,
},
hasError: true,
errInfo: "unexpected GroupVersion string: app@//v1",
}}
for i, tc := range testcases {
template, err := GenerateCUETemplate(tc.workload)
assert.Equal(t, err != nil, tc.hasError)
if tc.hasError {
assert.Equal(t, tc.errInfo, err.Error())
continue
}
assert.Equal(t, tc.expectData, template, i)
}
}
func TestPrepareArtifactsData(t *testing.T) {
compManifests := []*oamtypes.ComponentManifest{
{

View File

@@ -1,111 +0,0 @@
/*
Copyright 2021 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 helm
import (
"encoding/json"
"fmt"
"time"
"github.com/pkg/errors"
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
helmapi "github.com/oam-dev/kubevela/pkg/appfile/helm/flux2apis"
commonutil "github.com/oam-dev/kubevela/pkg/utils/common"
)
var (
// DefaultIntervalDuration is the interval that flux controller reconcile HelmRelease and HelmRepository
DefaultIntervalDuration = &metav1.Duration{Duration: 5 * time.Minute}
)
// ConstructHelmReleaseName will format helm release name in a fixed way
func ConstructHelmReleaseName(appName, compName string) string {
return appName + "-" + compName
}
// RenderHelmReleaseAndHelmRepo constructs HelmRelease and HelmRepository in unstructured format
func RenderHelmReleaseAndHelmRepo(helmSpec *common.Helm, compName, appName, ns string, values map[string]interface{}) (*unstructured.Unstructured, *unstructured.Unstructured, error) {
releaseSpec, repoSpec, err := decodeHelmSpec(helmSpec)
if err != nil {
return nil, nil, errors.WithMessage(err, "Helm spec is invalid")
}
if releaseSpec.Interval == nil {
releaseSpec.Interval = DefaultIntervalDuration
}
if repoSpec.Interval == nil {
repoSpec.Interval = DefaultIntervalDuration
}
// construct unstructured HelmRepository object
repoName := fmt.Sprintf("%s-%s", appName, compName)
helmRepo := commonutil.GenerateUnstructuredObj(repoName, ns, helmapi.HelmRepositoryGVK)
if err := commonutil.SetSpecObjIntoUnstructuredObj(repoSpec, helmRepo); err != nil {
return nil, nil, errors.Wrap(err, "cannot set spec to HelmRepository")
}
// construct unstructured HelmRelease object
rlsName := ConstructHelmReleaseName(appName, compName)
helmRelease := commonutil.GenerateUnstructuredObj(rlsName, ns, helmapi.HelmReleaseGVK)
// construct HelmRelease chart values
chartValues := map[string]interface{}{}
if releaseSpec.Values != nil {
if err := json.Unmarshal(releaseSpec.Values.Raw, &chartValues); err != nil {
return nil, nil, errors.Wrap(err, "cannot get chart values")
}
}
for k, v := range values {
// override values with settings from application
chartValues[k] = v
}
if len(chartValues) > 0 {
// avoid an empty map
vJSON, err := json.Marshal(chartValues)
if err != nil {
return nil, nil, errors.Wrap(err, "cannot get chart values")
}
releaseSpec.Values = &apiextensionsv1.JSON{Raw: vJSON}
}
// reference HelmRepository by HelmRelease
releaseSpec.Chart.Spec.SourceRef = helmapi.CrossNamespaceObjectReference{
Kind: helmapi.HelmRepositoryKind,
Namespace: ns,
Name: repoName,
}
if err := commonutil.SetSpecObjIntoUnstructuredObj(releaseSpec, helmRelease); err != nil {
return nil, nil, errors.Wrap(err, "cannot set spec to HelmRelease")
}
return helmRelease, helmRepo, nil
}
func decodeHelmSpec(h *common.Helm) (*helmapi.HelmReleaseSpec, *helmapi.HelmRepositorySpec, error) {
releaseSpec := &helmapi.HelmReleaseSpec{}
if err := json.Unmarshal(h.Release.Raw, releaseSpec); err != nil {
return nil, nil, errors.Wrap(err, "Helm release spec is invalid")
}
repoSpec := &helmapi.HelmRepositorySpec{}
if err := json.Unmarshal(h.Repository.Raw, repoSpec); err != nil {
return nil, nil, errors.Wrap(err, "Helm repository spec is invalid")
}
return releaseSpec, repoSpec, nil
}

View File

@@ -1,101 +0,0 @@
/*
Copyright 2021 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 helm
import (
"fmt"
"testing"
"github.com/google/go-cmp/cmp"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/yaml"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
helmapi "github.com/oam-dev/kubevela/pkg/appfile/helm/flux2apis"
)
func TestRenderHelmReleaseAndHelmRepo(t *testing.T) {
h := testData("podinfo", "1.0.0", "test.com", "testSecret")
chartValues := map[string]interface{}{
"image": map[string]interface{}{
"tag": "1.0.1",
},
}
rls, repo, err := RenderHelmReleaseAndHelmRepo(h, "test-comp", "test-app", "test-ns", chartValues)
if err != nil {
t.Fatalf("want: nil, got: %v", err)
}
expectRls := &unstructured.Unstructured{}
expectRls.SetGroupVersionKind(helmapi.HelmReleaseGVK)
expectRls.SetName("test-app-test-comp")
expectRls.SetNamespace("test-ns")
unstructured.SetNestedMap(expectRls.Object, map[string]interface{}{
"chart": map[string]interface{}{
"spec": map[string]interface{}{
"chart": "podinfo",
"version": "1.0.0",
"sourceRef": map[string]interface{}{
"kind": "HelmRepository",
"name": "test-app-test-comp",
"namespace": "test-ns",
},
},
},
"interval": "5m0s",
"values": map[string]interface{}{"image": map[string]interface{}{"tag": "1.0.1"}},
}, "spec")
if diff := cmp.Diff(expectRls, rls); diff != "" {
t.Errorf("\n%s\nApply(...): -want , +got \n%s\n", "render HelmRelease", diff)
}
expectRepo := &unstructured.Unstructured{}
expectRepo.SetGroupVersionKind(helmapi.HelmRepositoryGVK)
expectRepo.SetName("test-app-test-comp")
expectRepo.SetNamespace("test-ns")
unstructured.SetNestedMap(expectRepo.Object, map[string]interface{}{
"url": "test.com",
"secretRef": map[string]interface{}{
"name": "testSecret",
},
"interval": "5m0s",
}, "spec")
if diff := cmp.Diff(expectRepo, repo); diff != "" {
t.Errorf("\n%s\nApply(...): -want , +got \n%s\n", "render HelmRepository", diff)
}
}
func testData(chart, version, repoURL, secretName string) *common.Helm {
rlsStr := fmt.Sprintf(
`chart:
spec:
chart: "%s"
version: "%s"`, chart, version)
repoStr := fmt.Sprintf(
`url: "%s"
secretRef:
name: "%s"`, repoURL, secretName)
rlsJson, _ := yaml.YAMLToJSON([]byte(rlsStr))
repoJson, _ := yaml.YAMLToJSON([]byte(repoStr))
h := &common.Helm{}
h.Release.Raw = rlsJson
h.Repository.Raw = repoJson
return h
}

View File

@@ -1,218 +0,0 @@
/*
Copyright 2021 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 helm
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/format"
"cuelang.org/go/encoding/openapi"
"cuelang.org/go/encoding/yaml"
"github.com/getkin/kin-openapi/openapi3"
"github.com/pkg/errors"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/getter"
"helm.sh/helm/v3/pkg/repo"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
)
var (
getters = getter.Providers{
getter.Provider{
Schemes: []string{"http", "https"},
New: getter.NewHTTPGetter,
},
}
)
// GetChartValuesJSONSchema fetched the Chart bundle and get JSON schema of Values
// file. If the Chart provides a 'values.json.schema' file, use it directly.
// Otherwise, try to generate a JSON schema based on the Values file.
func GetChartValuesJSONSchema(ctx context.Context, h *common.Helm) ([]byte, error) {
releaseSpec, repoSpec, err := decodeHelmSpec(h)
if err != nil {
return nil, errors.WithMessage(err, "Helm spec is invalid")
}
chartSpec := releaseSpec.Chart.Spec
files, err := loadChartFiles(ctx, repoSpec.URL, chartSpec.Chart, chartSpec.Version)
if err != nil {
return nil, errors.WithMessage(err, "cannot load Chart files")
}
var values *loader.BufferedFile
for _, f := range files {
switch f.Name {
case "values.yaml", "values.yml":
values = f
case "values.schema.json":
// use the JSON schema file if exists
return f.Data, nil
default:
continue
}
}
if values == nil {
return nil, errors.New("cannot find 'values.schema.json' or 'values.yaml' file in the Chart")
}
// try to generate a schema based on Values file
generatedSchema, err := generateSchemaFromValues(values.Data)
if err != nil {
return nil, errors.WithMessage(err, "cannot generate schema from Values file")
}
return generatedSchema, nil
}
// generateSchemaFromValues generate OpenAPIv3 schema based on Chart Values
// file.
func generateSchemaFromValues(values []byte) ([]byte, error) {
valuesIdentifier := "values"
cuectx := cuecontext.New()
// convert Values yaml to CUE
file, err := yaml.Extract("", string(values))
if err != nil {
return nil, errors.Wrap(err, "cannot extract Values.yaml to CUE")
}
ins := cuectx.BuildFile(file)
// get the streamed CUE including the comments which will be used as
// 'description' in the schema
c, err := format.Node(ins.Value().Syntax(cue.Docs(true)), format.Simplify())
if err != nil {
return nil, errors.Wrap(err, "cannot format CUE generated from Values.yaml")
}
// cue openapi encoder only works on top-level identifier, we have to add
// an identifier manually
valuesStr := fmt.Sprintf("#%s:{\n%s\n}", valuesIdentifier, string(c))
val := cuecontext.New().CompileString(valuesStr)
if val.Err() != nil {
return nil, errors.Wrap(val.Err(), "cannot compile CUE generated from Values.yaml")
}
// generate OpenAPIv3 schema through cue openapi encoder
rawSchema, err := openapi.Gen(val, &openapi.Config{})
if err != nil {
return nil, errors.Wrap(err, "cannot generate OpenAPIv3 schema")
}
rawSchema, err = makeSwaggerCompatible(rawSchema)
if err != nil {
return nil, errors.WithMessage(err, "cannot make CUE-generated schema compatible with Swagger")
}
var out = &bytes.Buffer{}
_ = json.Indent(out, rawSchema, "", " ")
// load schema into Swagger to validate it compatible with Swagger OpenAPIv3
fullSchemaBySwagger, err := openapi3.NewLoader().LoadFromData(out.Bytes())
if err != nil {
return nil, errors.Wrap(err, "cannot load schema by SwaggerLoader")
}
valuesSchema := fullSchemaBySwagger.Components.Schemas[valuesIdentifier].Value
changeEnumToDefault(valuesSchema)
b, err := valuesSchema.MarshalJSON()
if err != nil {
return nil, errors.Wrap(err, "cannot marshall Values schema")
}
return b, nil
}
func loadChartFiles(ctx context.Context, repoURL, chart, version string) ([]*loader.BufferedFile, error) {
url, err := repo.FindChartInRepoURL(repoURL, chart, version, "", "", "", getters)
if err != nil {
return nil, errors.Wrap(err, "cannot find Chart URL")
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, errors.Wrapf(err, "cannot fetch Chart from remote URL:%s", url)
}
//nolint:errcheck
defer resp.Body.Close()
files, err := loader.LoadArchiveFiles(resp.Body)
if err != nil {
return nil, errors.Wrap(err, "cannot load Chart files")
}
return files, nil
}
// cue openapi encoder converts default in Chart Values as enum in schema
// changing enum to default makes the schema consistent with Chart Values
func changeEnumToDefault(schema *openapi3.Schema) {
t := schema.Type
switch t {
case "object":
for _, v := range schema.Properties {
s := v.Value
changeEnumToDefault(s)
}
case "array":
if schema.Items != nil {
changeEnumToDefault(schema.Items.Value)
}
}
// change enum to default
if len(schema.Enum) > 0 {
schema.Default = schema.Enum[0]
schema.Enum = nil
}
// remove all required fields, because fields in Values.yml are all optional
schema.Required = nil
}
// cue openapi encoder converts 'items' field in an array type field into array,
// that's not compatible with OpenAPIv3. 'items' field should be an object.
func makeSwaggerCompatible(d []byte) ([]byte, error) {
m := map[string]interface{}{}
err := json.Unmarshal(d, &m)
if err != nil {
return nil, errors.Wrap(err, "cannot unmarshall schema")
}
handleItemsOfArrayType(m)
b, err := json.Marshal(m)
if err != nil {
return nil, errors.Wrap(err, "cannot marshall schema")
}
return b, nil
}
// handleItemsOfArrayType will convert all 'items' of array type from array to object
// and remove enum in the items
func handleItemsOfArrayType(t map[string]interface{}) {
for _, v := range t {
if next, ok := v.(map[string]interface{}); ok {
handleItemsOfArrayType(next)
}
}
if t["type"] == "array" {
if i, ok := t["items"].([]interface{}); ok {
if len(i) > 0 {
if itemSpec, ok := i[0].(map[string]interface{}); ok {
handleItemsOfArrayType(itemSpec)
itemSpec["enum"] = nil
t["items"] = itemSpec
}
}
}
}
}

View File

@@ -1,295 +0,0 @@
/*
Copyright 2021 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 helm
import (
"context"
"encoding/json"
"fmt"
"os"
"testing"
"github.com/getkin/kin-openapi/openapi3"
"github.com/google/go-cmp/cmp"
)
func TestGenerateSchemaFromValues(t *testing.T) {
testValues, err := os.ReadFile("./testdata/values.yaml")
if err != nil {
t.Error(err, "cannot load test data")
}
wantSchema, err := os.ReadFile("./testdata/values.schema.json")
if err != nil {
t.Error(err, "cannot load expected data")
}
wantSchemaMap := map[string]interface{}{}
// convert bytes to map for diff converience
_ = json.Unmarshal(wantSchema, &wantSchemaMap)
result, err := generateSchemaFromValues(testValues)
if err != nil {
t.Error(err, "failed generate schema from values")
}
resultMap := map[string]interface{}{}
if err := json.Unmarshal(result, &resultMap); err != nil {
t.Error(err, "cannot unmarshal result bytes")
}
if diff := cmp.Diff(resultMap, wantSchemaMap); diff != "" {
t.Fatalf("\ngenerateSchemaFromValues(...)(...) -want +get \n%s", diff)
}
}
func TestGetChartValuesJSONSchema(t *testing.T) {
testHelm := testData("podinfo", "5.1.4", "https://charts.kubevela.net/example", "testSecret")
wantSchema, err := os.ReadFile("./testdata/podinfo.values.schema.json")
if err != nil {
t.Error(err, "cannot load expected data")
}
wantSchemaMap := map[string]interface{}{}
// convert bytes to map for diff converience
_ = json.Unmarshal(wantSchema, &wantSchemaMap)
result, err := GetChartValuesJSONSchema(context.Background(), testHelm)
if err != nil {
t.Error(err, "failed get schema")
}
resultMap := map[string]interface{}{}
if err := json.Unmarshal(result, &resultMap); err != nil {
t.Error(err, "cannot unmarshal result bytes")
}
if diff := cmp.Diff(resultMap, wantSchemaMap); diff != "" {
t.Fatalf("\nGetChartValuesJSONSchema(...)(...) -want +get \n%s", diff)
}
}
func TestChangeEnumToDefault(t *testing.T) {
// testData contains object, string, integer, bool, and array type fields
// with enum and required values
testData := `{"properties":{"array":{"enum":[["a","b","c"]],"items":{"type":"string"},"type":"array"},"bool":{"enum":[false],"type":"boolean"},"integer":{"enum":[1],"type":"integer"},"obj":{"properties":{"f0":{"enum":["v0"],"type":"string"},"f1":{"enum":["v1"],"type":"string"},"f2":{"enum":["v2"],"type":"string"}},"required":["f0","f1","f2"],"type":"object"},"string":{"enum":["a"],"type":"string"}},"required":["bool","string","obj","array","integer"],"type":"object"}`
s := fmt.Sprintf(`{"components":{"schemas":{"values":%s}}}`, testData)
testSwagger, err := openapi3.NewLoader().LoadFromData([]byte(s))
if err != nil {
t.Error(err)
}
testSchema := testSwagger.Components.Schemas["values"].Value
changeEnumToDefault(testSchema)
result, err := testSchema.MarshalJSON()
if err != nil {
t.Error(err)
}
resultMap := map[string]interface{}{}
err = json.Unmarshal(result, &resultMap)
if err != nil {
t.Error(err)
}
want := `{"properties":{"array":{"default":["a","b","c"],"items":{"type":"string"},"type":"array"},"bool":{"default":false,"type":"boolean"},"integer":{"default":1,"type":"integer"},"obj":{"properties":{"f0":{"default":"v0","type":"string"},"f1":{"default":"v1","type":"string"},"f2":{"default":"v2","type":"string"}},"type":"object"},"string":{"default":"a","type":"string"}},"type":"object"}`
wantMap := map[string]interface{}{}
_ = json.Unmarshal([]byte(want), &wantMap)
if diff := cmp.Diff(resultMap, wantMap); diff != "" {
t.Fatalf("\nchangeEnumToDefault(...) -want +get %s\n", diff)
}
}
func TestMakeSwaggerCompatible(t *testing.T) {
tests := []struct {
caseName string
testdata string
want string
}{
{
caseName: "integer type array",
testdata: `{"integerArray": {
"type": "array",
"items": [
{
"type": "integer",
"enum": [
0
]
},
{
"type": "integer",
"enum": [
1
]
},
{
"type": "integer",
"enum": [
2
]
}
],
"enum": [
[
0,
1,
2
]
]
}}`,
want: `{"integerArray":{"enum":[[0,1,2]],"items":{"enum":null,"type":"integer"},"type":"array"}}`,
},
{
caseName: "string type array",
testdata: `{"stringArray": {
"type": "array",
"items": [
{
"type": "string",
"enum": [
"a"
]
},
{
"type": "string",
"enum": [
"b"
]
},
{
"type": "string",
"enum": [
"c"
]
}
],
"enum": [
[
"a",
"b",
"c"
]
]
}}`,
want: `{"stringArray":{"enum":[["a","b","c"]],"items":{"enum":null,"type":"string"},"type":"array"}}`,
},
{
caseName: "bool type array",
testdata: `{"boolArray": {
"type": "array",
"items": [
{
"type": "boolean",
"enum": [
true
]
},
{
"type": "boolean",
"enum": [
false
]
}
],
"enum": [
[
true,
false
]
]
}}`,
want: `{"boolArray":{"enum":[[true,false]],"items":{"enum":null,"type":"boolean"},"type":"array"}}`,
},
{
caseName: "object type array",
testdata: `{"objectArray": {
"type": "array",
"items": [
{
"type": "object",
"required": [
"f0",
"f1",
"f2"
],
"properties": {
"f0": {
"type": "string",
"enum": [
"v0"
]
},
"f1": {
"type": "string",
"enum": [
"v1"
]
},
"f2": {
"type": "string",
"enum": [
"v2"
]
}
}
}
]
}}`,
want: `{"objectArray":{"items":{"enum":null,"properties":{"f0":{"enum":["v0"],"type":"string"},"f1":{"enum":["v1"],"type":"string"},"f2":{"enum":["v2"],"type":"string"}},"required":["f0","f1","f2"],"type":"object"},"type":"array"}}`,
},
{
caseName: "object type array embeds object type array",
testdata: `{
"objectArray": {
"type": "array",
"items": [
{
"type": "array",
"items": [
{
"type": "object",
"required": [
"f0"
],
"properties": {
"f0": {
"type": "string",
"enum": [
"v0"
]
}
}
}
]
}
]
}
}
`,
want: `{"objectArray":{"items":{"enum":null,"items":{"enum":null,"properties":{"f0":{"enum":["v0"],"type":"string"}},"required":["f0"],"type":"object"},"type":"array"},"type":"array"}}`,
},
}
for _, tc := range tests {
t.Run(tc.caseName, func(t *testing.T) {
result, err := makeSwaggerCompatible([]byte(tc.testdata))
if err != nil {
t.Error(err)
}
resultMap := map[string]interface{}{}
err = json.Unmarshal(result, &resultMap)
if err != nil {
t.Error(err)
}
wantMap := map[string]interface{}{}
_ = json.Unmarshal([]byte(tc.want), &wantMap)
if diff := cmp.Diff(resultMap, wantMap); diff != "" {
t.Fatalf("\nmakeSwaggerCompatible(...) -want +get %s\n", diff)
}
})
}
}

View File

@@ -54,8 +54,6 @@ type Template struct {
CustomStatus string
CapabilityCategory types.CapabilityCategory
Reference common.WorkloadTypeDescriptor
Helm *common.Helm
Kube *common.Kube
Terraform *common.Terraform
ComponentDefinition *v1beta1.ComponentDefinition
@@ -362,16 +360,6 @@ func loadSchematicToTemplate(tmpl *Template, status *common.Status, schematic *c
tmpl.CapabilityCategory = types.CUECategory
tmpl.TemplateStr = schematic.CUE.Template
}
if schematic.HELM != nil {
tmpl.CapabilityCategory = types.HelmCategory
tmpl.Helm = schematic.HELM
return nil
}
if schematic.KUBE != nil {
tmpl.CapabilityCategory = types.KubeCategory
tmpl.Kube = schematic.KUBE
return nil
}
if schematic.Terraform != nil {
tmpl.CapabilityCategory = types.TerraformCategory
tmpl.Terraform = schematic.Terraform

View File

@@ -293,20 +293,6 @@ func TestLoadSchematicToTemplate(t *testing.T) {
Terraform: &common.Terraform{},
},
},
"helm schematic": {
schematic: &common.Schematic{HELM: &common.Helm{}},
want: &Template{
CapabilityCategory: types.HelmCategory,
Helm: &common.Helm{},
},
},
"kube schematic": {
schematic: &common.Schematic{KUBE: &common.Kube{}},
want: &Template{
CapabilityCategory: types.KubeCategory,
Kube: &common.Kube{},
},
},
}
for reason, casei := range testCases {
gtmp := &Template{}
@@ -365,8 +351,6 @@ spec:
Kind: "Deployment",
},
},
Helm: nil,
Kube: nil,
ComponentDefinition: compDef,
}
@@ -375,8 +359,6 @@ spec:
Health: "testHealthPolicy",
CustomStatus: "testCustomStatus",
CapabilityCategory: types.CUECategory,
Helm: nil,
Kube: nil,
TraitDefinition: traitDef,
}

View File

@@ -21,12 +21,11 @@ package auth
import (
"net/http"
"github.com/kubevela/pkg/util/net"
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/client-go/transport"
"k8s.io/klog/v2"
"github.com/oam-dev/kubevela/pkg/utils"
)
const (
@@ -67,7 +66,7 @@ func (rt *impersonatingRoundTripper) RoundTrip(req *http.Request) (*http.Respons
}
func (rt *impersonatingRoundTripper) CancelRequest(req *http.Request) {
utils.TryCancelRequest(rt.WrappedRoundTripper(), req)
net.TryCancelRequest(rt.WrappedRoundTripper(), req)
}
func (rt *impersonatingRoundTripper) WrappedRoundTripper() http.RoundTripper {

View File

@@ -22,23 +22,18 @@ import (
"strings"
"time"
pkgmulticluster "github.com/kubevela/pkg/multicluster"
utilfeature "k8s.io/apiserver/pkg/util/feature"
configprovider "github.com/oam-dev/kubevela/pkg/config/provider"
ctrlutil "github.com/oam-dev/kubevela/pkg/controller/utils"
"github.com/oam-dev/kubevela/pkg/features"
"github.com/oam-dev/kubevela/pkg/utils/apply"
"github.com/crossplane/crossplane-runtime/pkg/meta"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/klog/v2"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
monitorContext "github.com/kubevela/pkg/monitor/context"
pkgmulticluster "github.com/kubevela/pkg/multicluster"
"github.com/kubevela/pkg/util/slices"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/kubevela/workflow/pkg/cue/model/value"
"github.com/kubevela/workflow/pkg/executor"
@@ -53,15 +48,17 @@ import (
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/auth"
configprovider "github.com/oam-dev/kubevela/pkg/config/provider"
"github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1beta1/application/assemble"
ctrlutil "github.com/oam-dev/kubevela/pkg/controller/utils"
velaprocess "github.com/oam-dev/kubevela/pkg/cue/process"
"github.com/oam-dev/kubevela/pkg/features"
"github.com/oam-dev/kubevela/pkg/monitor/metrics"
"github.com/oam-dev/kubevela/pkg/multicluster"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/util"
"github.com/oam-dev/kubevela/pkg/policy/envbinding"
"github.com/oam-dev/kubevela/pkg/stdlib"
"github.com/oam-dev/kubevela/pkg/utils"
"github.com/oam-dev/kubevela/pkg/utils/apply"
"github.com/oam-dev/kubevela/pkg/velaql/providers/query"
multiclusterProvider "github.com/oam-dev/kubevela/pkg/workflow/providers/multicluster"
oamProvider "github.com/oam-dev/kubevela/pkg/workflow/providers/oam"
@@ -308,7 +305,7 @@ func checkDependsOnValidComponent(dependsOnComponentNames, allComponentNames []s
return "", true
}
for _, dc := range dependsOnComponentNames {
if !utils.StringsContain(allComponentNames, dc) {
if !slices.Contains(allComponentNames, dc) {
return dc, false
}
}
@@ -370,7 +367,6 @@ func (h *AppHandler) applyComponentFunc(appParser *appfile.Parser, appRev *v1bet
ctx := multicluster.ContextWithClusterName(baseCtx, clusterName)
ctx = contextWithComponentNamespace(ctx, overrideNamespace)
ctx = contextWithReplicaKey(ctx, comp.ReplicaKey)
ctx = envbinding.ContextWithEnvName(ctx, env)
wl, manifest, err := h.prepareWorkloadAndManifests(ctx, appParser, comp, appRev, patcher, af)
if err != nil {

View File

@@ -22,8 +22,6 @@ import (
"fmt"
"time"
"k8s.io/klog/v2"
"github.com/oam-dev/kubevela/pkg/oam/testutil"
. "github.com/onsi/ginkgo/v2"
@@ -31,13 +29,11 @@ import (
corev1 "k8s.io/api/core/v1"
crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/yaml"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/oam/util"
@@ -319,100 +315,6 @@ spec:
})
})
Context("When the ComponentDefinition contains Helm Module, should create a ConfigMap", func() {
var componentDefinitionName = "cd-with-helm-module"
var namespace = "default"
req := reconcile.Request{NamespacedName: client.ObjectKey{Name: componentDefinitionName, Namespace: namespace}}
It("Applying ComponentDefinition with Helm module", func() {
cd := v1beta1.ComponentDefinition{}
cd.SetName(componentDefinitionName)
cd.SetNamespace(namespace)
cd.Spec.Workload.Definition = common.WorkloadGVK{APIVersion: "apps/v1", Kind: "Deployment"}
cd.Spec.Schematic = &common.Schematic{
HELM: &common.Helm{
Release: *util.Object2RawExtension(map[string]interface{}{
"chart": map[string]interface{}{
"spec": map[string]interface{}{
"chart": "podinfo",
"version": "5.1.4",
},
},
}),
Repository: *util.Object2RawExtension(map[string]interface{}{
"url": "https://charts.kubevela.net/example/",
}),
},
}
By("Create ComponentDefinition")
Expect(k8sClient.Create(ctx, &cd)).Should(Succeed())
testutil.ReconcileRetry(&r, req)
By("Check whether ConfigMap is created")
var cm corev1.ConfigMap
name := fmt.Sprintf("component-%s%s", types.CapabilityConfigMapNamePrefix, componentDefinitionName)
Eventually(func() bool {
err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: name}, &cm)
if err != nil {
klog.ErrorS(err, "failed to get configmap")
}
return err == nil
}, 10*time.Second, time.Second).Should(BeTrue())
Expect(cm.Data[types.OpenapiV3JSONSchema]).Should(Not(Equal("")))
By("Check whether ConfigMapRef refer to right ConfigMap")
Eventually(func() string {
_ = k8sClient.Get(ctx, client.ObjectKey{Namespace: cd.Namespace, Name: cd.Name}, &cd)
return cd.Status.ConfigMapRef
}, 10*time.Second, time.Second).Should(Equal(name))
})
})
Context("When the ComponentDefinition contains Kube Module, should create a ConfigMap", func() {
var componentDefinitionName = "cd-with-kube-module"
var namespace = "default"
req := reconcile.Request{NamespacedName: client.ObjectKey{Name: componentDefinitionName, Namespace: namespace}}
It("Applying ComponentDefinition with kube Module", func() {
cd := v1beta1.ComponentDefinition{}
cd.SetName(componentDefinitionName)
cd.SetNamespace(namespace)
cd.Spec.Workload.Definition = common.WorkloadGVK{APIVersion: "apps/v1", Kind: "Deployment"}
cd.Spec.Schematic = &common.Schematic{
KUBE: &common.Kube{
Template: generateTemplate(KUBEWorkerTemplate),
Parameters: []common.KubeParameter{
{
Name: "image",
ValueType: common.StringType,
FieldPaths: []string{"spec.template.spec.containers[0].image"},
Required: pointer.Bool(true),
Description: pointer.String("test description"),
},
},
},
}
By("Create ComponentDefinition")
Expect(k8sClient.Create(ctx, &cd)).Should(Succeed())
testutil.ReconcileRetry(&r, req)
By("Check whether ConfigMap is created")
var cm corev1.ConfigMap
name := fmt.Sprintf("component-%s%s", types.CapabilityConfigMapNamePrefix, componentDefinitionName)
Eventually(func() bool {
err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: name}, &cm)
return err == nil
}, 10*time.Second, time.Second).Should(BeTrue())
Expect(cm.Data[types.OpenapiV3JSONSchema]).Should(Not(Equal("")))
By("Check whether ConfigMapRef refer to right ConfigMap")
Eventually(func() string {
_ = k8sClient.Get(ctx, client.ObjectKey{Namespace: cd.Namespace, Name: cd.Name}, &cd)
return cd.Status.ConfigMapRef
}, 10*time.Second, time.Second).Should(Equal(name))
})
})
Context("When the ComponentDefinition contains Terraform Module, should create a ConfigMap", func() {
var componentDefinitionName = "alibaba-rds-test"
var namespace = "default"
@@ -740,25 +642,3 @@ spec:
})
})
})
func generateTemplate(template string) runtime.RawExtension {
b, _ := yaml.YAMLToJSON([]byte(template))
return runtime.RawExtension{Raw: b}
}
var KUBEWorkerTemplate = `apiVersion: apps/v1
kind: Deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
ports:
- containerPort: 80
`

View File

@@ -1,51 +0,0 @@
/*
Copyright 2021 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 utils
import (
"context"
"k8s.io/client-go/util/retry"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/oam"
)
// FreezeApplication freeze application to disable the reconciling process for it
func FreezeApplication(ctx context.Context, cli client.Client, app *v1beta1.Application, mutate func()) (string, error) {
return oam.GetControllerRequirement(app), _updateApplicationWithControllerRequirement(ctx, cli, app, mutate, "Disabled")
}
// UnfreezeApplication unfreeze application to enable the reconciling process for it
func UnfreezeApplication(ctx context.Context, cli client.Client, app *v1beta1.Application, mutate func(), originalControllerRequirement string) error {
return _updateApplicationWithControllerRequirement(ctx, cli, app, mutate, originalControllerRequirement)
}
func _updateApplicationWithControllerRequirement(ctx context.Context, cli client.Client, app *v1beta1.Application, mutate func(), controllerRequirement string) error {
appKey := client.ObjectKeyFromObject(app)
return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
if err := cli.Get(ctx, appKey, app); err != nil {
return err
}
oam.SetControllerRequirement(app, controllerRequirement)
if mutate != nil {
mutate()
}
return cli.Update(ctx, app)
})
}

View File

@@ -40,7 +40,6 @@ import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/appfile/helm"
"github.com/oam-dev/kubevela/pkg/cue/script"
"github.com/oam-dev/kubevela/pkg/oam/util"
"github.com/oam-dev/kubevela/pkg/utils/common"
@@ -99,8 +98,6 @@ type CapabilityComponentDefinition struct {
WorkloadType util.WorkloadType `json:"workloadType"`
WorkloadDefName string `json:"workloadDefName"`
Helm *commontypes.Helm `json:"helm"`
Kube *commontypes.Kube `json:"kube"`
Terraform *commontypes.Terraform `json:"terraform"`
CapabilityBaseDefinition
}
@@ -114,14 +111,6 @@ func NewCapabilityComponentDef(componentDefinition *v1beta1.ComponentDefinition)
def.WorkloadDefName = componentDefinition.Spec.Workload.Type
}
if componentDefinition.Spec.Schematic != nil {
if componentDefinition.Spec.Schematic.HELM != nil {
def.WorkloadType = util.HELMDef
def.Helm = componentDefinition.Spec.Schematic.HELM
}
if componentDefinition.Spec.Schematic.KUBE != nil {
def.WorkloadType = util.KubeDef
def.Kube = componentDefinition.Spec.Schematic.KUBE
}
if componentDefinition.Spec.Schematic.Terraform != nil {
def.WorkloadType = util.TerraformDef
def.Terraform = componentDefinition.Spec.Schematic.Terraform
@@ -329,37 +318,6 @@ func generateJSONSchemaWithRequiredProperty(schemas map[string]*openapi3.Schema,
return b, nil
}
// GetKubeSchematicOpenAPISchema gets OpenAPI v3 schema based on kube schematic parameters for component and trait definition
func GetKubeSchematicOpenAPISchema(params []commontypes.KubeParameter) ([]byte, error) {
required := []string{}
properties := map[string]*openapi3.Schema{}
for _, p := range params {
var tmp *openapi3.Schema
switch p.ValueType {
case commontypes.StringType:
tmp = openapi3.NewStringSchema()
case commontypes.NumberType:
tmp = openapi3.NewFloat64Schema()
case commontypes.BooleanType:
tmp = openapi3.NewBoolSchema()
default:
tmp = openapi3.NewStringSchema()
}
if p.Required != nil && *p.Required {
required = append(required, p.Name)
}
if p.Description != nil {
tmp.Description = fmt.Sprintf("%s %s", tmp.Description, *p.Description)
} else {
// save FieldPaths into description
tmp.Description = fmt.Sprintf("The value will be applied to fields: [%s].", strings.Join(p.FieldPaths, ","))
}
properties[p.Name] = tmp
}
return generateJSONSchemaWithRequiredProperty(properties, required)
}
// GetGitSSHPublicKey gets a kubernetes secret containing the SSH private key based on gitCredentialsSecretReference parameters for component and trait definition
func GetGitSSHPublicKey(ctx context.Context, k8sClient client.Client, gitCredentialsSecretReference *v1.SecretReference) (*gitssh.PublicKeys, error) {
gitCredentialsSecretName := gitCredentialsSecretReference.Name
@@ -403,10 +361,6 @@ func (def *CapabilityComponentDefinition) StoreOpenAPISchema(ctx context.Context
var jsonSchema []byte
var err error
switch def.WorkloadType {
case util.HELMDef:
jsonSchema, err = helm.GetChartValuesJSONSchema(ctx, def.Helm)
case util.KubeDef:
jsonSchema, err = GetKubeSchematicOpenAPISchema(def.Kube.Parameters)
case util.TerraformDef:
if def.Terraform == nil {
return "", fmt.Errorf("no Configuration is set in Terraform specification: %s", def.Name)
@@ -475,8 +429,6 @@ type CapabilityTraitDefinition struct {
DefCategoryType util.WorkloadType `json:"defCategoryType"`
Kube *commontypes.Kube `json:"kube"`
CapabilityBaseDefinition
}
@@ -484,10 +436,6 @@ type CapabilityTraitDefinition struct {
func NewCapabilityTraitDef(traitdefinition *v1beta1.TraitDefinition) CapabilityTraitDefinition {
var def CapabilityTraitDefinition
def.Name = traitdefinition.Name // or def.Name = req.NamespacedName.Name
if traitdefinition.Spec.Schematic != nil && traitdefinition.Spec.Schematic.KUBE != nil {
def.DefCategoryType = util.KubeDef
def.Kube = traitdefinition.Spec.Schematic.KUBE
}
def.TraitDefinition = *traitdefinition.DeepCopy()
return def
}
@@ -503,14 +451,7 @@ func (def *CapabilityTraitDefinition) GetOpenAPISchema(name string) ([]byte, err
// StoreOpenAPISchema stores OpenAPI v3 schema from TraitDefinition in ConfigMap
func (def *CapabilityTraitDefinition) StoreOpenAPISchema(ctx context.Context, k8sClient client.Client, namespace, name string, revName string) (string, error) {
var jsonSchema []byte
var err error
switch def.DefCategoryType {
case util.KubeDef: // Kube template
jsonSchema, err = GetKubeSchematicOpenAPISchema(def.Kube.Parameters)
default: // CUE template
jsonSchema, err = def.GetOpenAPISchema(name)
}
jsonSchema, err := def.GetOpenAPISchema(name)
if err != nil {
return "", fmt.Errorf("failed to generate OpenAPI v3 JSON schema for capability %s: %w", def.Name, err)
}

View File

@@ -20,23 +20,13 @@ import (
"fmt"
"strconv"
"strings"
"time"
"github.com/mitchellh/hashstructure/v2"
"k8s.io/apimachinery/pkg/util/wait"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/oam/util"
)
// DefaultBackoff is the backoff we use in controller
var DefaultBackoff = wait.Backoff{
Duration: 1 * time.Second,
Factor: 2,
Steps: 5,
Jitter: 0.1,
}
// GetAppNextRevision will generate the next revision name and revision number for application
func GetAppNextRevision(app *v1beta1.Application) (string, int64) {
if app == nil {

View File

@@ -41,10 +41,7 @@ import (
ocmclusterv1 "open-cluster-management.io/api/cluster/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/policy/envbinding"
"github.com/oam-dev/kubevela/pkg/utils"
velaerrors "github.com/oam-dev/kubevela/pkg/utils/errors"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
)
@@ -597,25 +594,5 @@ func getMutableClusterSecret(ctx context.Context, c client.Client, clusterName s
if labels == nil || labels[clustercommon.LabelKeyClusterCredentialType] == "" {
return nil, fmt.Errorf("invalid cluster secret %s: cluster credential type label %s is not set", clusterName, clustercommon.LabelKeyClusterCredentialType)
}
apps := &v1beta1.ApplicationList{}
if err := c.List(ctx, apps); err != nil {
return nil, errors.Wrap(err, "failed to find applications to check clusters")
}
errs := velaerrors.ErrorList{}
for _, app := range apps.Items {
status, err := envbinding.GetEnvBindingPolicyStatus(app.DeepCopy(), "")
if err == nil && status != nil {
for _, env := range status.Envs {
for _, placement := range env.Placements {
if placement.Cluster == clusterName {
errs = append(errs, fmt.Errorf("application %s/%s (env: %s) is currently using cluster %s", app.Namespace, app.Name, env.Env, clusterName))
}
}
}
}
}
if errs.HasError() {
return nil, errors.Wrapf(errs, "cluster %s is in use now", clusterName)
}
return clusterSecret, nil
}

View File

@@ -35,16 +35,6 @@ func ReconcileRetry(r reconcile.Reconciler, req reconcile.Request) {
}, 15*time.Second, time.Second).Should(gomega.BeNil())
}
// ReconcileRetryAndExpectErr will reconcile and get error
func ReconcileRetryAndExpectErr(r reconcile.Reconciler, req reconcile.Request) {
gomega.Eventually(func() error {
if _, err := r.Reconcile(context.TODO(), req); err != nil {
return err
}
return nil
}, 3*time.Second, time.Second).ShouldNot(gomega.BeNil())
}
// ReconcileOnce will just reconcile once
func ReconcileOnce(r reconcile.Reconciler, req reconcile.Request) {
if _, err := r.Reconcile(context.TODO(), req); err != nil {

View File

@@ -18,7 +18,6 @@ package envbinding
import (
"encoding/json"
"fmt"
"regexp"
"strings"
@@ -200,19 +199,3 @@ func PatchComponents(baseComponents []common.ApplicationComponent, patchComponen
}
return newComponents, nil
}
// PatchApplicationByEnvBindingEnv get patched application directly through policyName and envName
func PatchApplicationByEnvBindingEnv(app *v1beta1.Application, policyName string, envName string) (*v1beta1.Application, error) {
policy, err := GetEnvBindingPolicy(app, policyName)
if err != nil {
return nil, err
}
if policy != nil {
for _, env := range policy.Envs {
if env.Name == envName {
return PatchApplication(app, &env.Patch, env.Selector)
}
}
}
return nil, fmt.Errorf("target env %s in policy %s not found", envName, policyName)
}

View File

@@ -26,21 +26,6 @@ import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
)
// ReadPlacementDecisions read placement decisions from application status, return (decisions, if decision is made, error)
// Deprecated As it is only used in EnvBinding policy
func ReadPlacementDecisions(app *v1beta1.Application, policyName string, envName string) ([]v1alpha1.PlacementDecision, bool, error) {
envBindingStatus, err := GetEnvBindingPolicyStatus(app, policyName)
if err != nil || envBindingStatus == nil {
return nil, false, err
}
for _, envStatus := range envBindingStatus.Envs {
if envStatus.Env == envName {
return envStatus.Placements, true, nil
}
}
return nil, false, nil
}
// updateClusterConnections update cluster connection in envbinding status with decisions
func updateClusterConnections(status *v1alpha1.EnvBindingStatus, decisions []v1alpha1.PlacementDecision, app *v1beta1.Application) {
var currentRev string

View File

@@ -17,83 +17,15 @@ limitations under the License.
package envbinding
import (
"encoding/json"
"testing"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/runtime"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
)
func TestReadPlacementDecisions(t *testing.T) {
pld := []v1alpha1.PlacementDecision{{
Cluster: "example-cluster",
Namespace: "example-namespace",
}}
testCases := []struct {
Status *v1alpha1.EnvBindingStatus
StatusRaw []byte
ExpectedExists bool
ExpectedHasError bool
}{{
Status: nil,
StatusRaw: []byte(`bad value`),
ExpectedExists: false,
ExpectedHasError: true,
}, {
Status: &v1alpha1.EnvBindingStatus{
Envs: []v1alpha1.EnvStatus{{
Env: "example-env",
Placements: pld,
}},
},
ExpectedExists: true,
ExpectedHasError: false,
}, {
Status: &v1alpha1.EnvBindingStatus{
Envs: []v1alpha1.EnvStatus{{
Env: "bad-env",
Placements: pld,
}},
},
ExpectedExists: false,
ExpectedHasError: false,
}}
r := require.New(t)
for _, testCase := range testCases {
app := &v1beta1.Application{}
_status := common.PolicyStatus{
Name: "example-policy",
Type: v1alpha1.EnvBindingPolicyType,
}
if testCase.Status == nil {
_status.Status = &runtime.RawExtension{Raw: testCase.StatusRaw}
} else {
bs, err := json.Marshal(testCase.Status)
r.NoError(err)
_status.Status = &runtime.RawExtension{Raw: bs}
}
app.Status.PolicyStatus = []common.PolicyStatus{_status}
pds, exists, err := ReadPlacementDecisions(app, "", "example-env")
r.Equal(testCase.ExpectedExists, exists)
if testCase.ExpectedHasError {
r.Error(err)
continue
}
r.NoError(err)
if exists {
r.Equal(len(pld), len(pds))
for idx := range pld {
r.Equal(pld[idx].Cluster, pds[idx].Cluster)
r.Equal(pld[idx].Namespace, pds[idx].Namespace)
}
}
}
}
func TestUpdateClusterConnections(t *testing.T) {
app := &v1beta1.Application{}
app.Status.LatestRevision = &common.Revision{Name: "v1"}

View File

@@ -1,78 +0,0 @@
/*
Copyright 2021 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 envbinding
import (
"context"
"encoding/json"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
)
type contextKey string
const (
// EnvNameContextKey is the name of env
// Deprecated
EnvNameContextKey = contextKey("EnvName")
)
// GetEnvBindingPolicy extract env-binding policy with given policy name, if policy name is empty, the first env-binding policy will be used
// Deprecated
func GetEnvBindingPolicy(app *v1beta1.Application, policyName string) (*v1alpha1.EnvBindingSpec, error) {
for _, policy := range app.Spec.Policies {
if (policy.Name == policyName || policyName == "") && policy.Type == v1alpha1.EnvBindingPolicyType && policy.Properties != nil {
envBindingSpec := &v1alpha1.EnvBindingSpec{}
err := json.Unmarshal(policy.Properties.Raw, envBindingSpec)
return envBindingSpec, err
}
}
return nil, nil
}
// GetEnvBindingPolicyStatus extract env-binding policy status with given policy name, if policy name is empty, the first env-binding policy will be used
// Deprecated
func GetEnvBindingPolicyStatus(app *v1beta1.Application, policyName string) (*v1alpha1.EnvBindingStatus, error) {
for _, policyStatus := range app.Status.PolicyStatus {
if (policyStatus.Name == policyName || policyName == "") && policyStatus.Type == v1alpha1.EnvBindingPolicyType {
envBindingStatus := &v1alpha1.EnvBindingStatus{}
if policyStatus.Status != nil {
err := json.Unmarshal(policyStatus.Status.Raw, envBindingStatus)
return envBindingStatus, err
}
return nil, nil
}
}
return nil, nil
}
// EnvNameInContext extract env name from context
// Deprecated
func EnvNameInContext(ctx context.Context) string {
envName := ctx.Value(EnvNameContextKey)
if envName != nil {
return envName.(string)
}
return ""
}
// ContextWithEnvName wraps context with envName
// Deprecated
func ContextWithEnvName(ctx context.Context, envName string) context.Context {
return context.WithValue(ctx, EnvNameContextKey, envName)
}

View File

@@ -1,32 +0,0 @@
/*
Copyright 2021 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 envbinding
import (
"context"
"testing"
"github.com/stretchr/testify/require"
)
func TestEnvContext(t *testing.T) {
r := require.New(t)
envName := "env"
extracted := EnvNameInContext(ContextWithEnvName(context.Background(), envName))
r.Equal(envName, extracted)
r.Equal("", EnvNameInContext(context.Background()))
}

View File

@@ -84,7 +84,8 @@ func TestResourceCache(t *testing.T) {
}
rts := []*v1beta1.ResourceTracker{nil, rt1, rt2, rt3}
cache.registerResourceTrackers(rts...)
o, ok := cache.m.Get(createMR("resource-1").ResourceKey())
mr := createMR("resource-1")
o, ok := cache.m.Get(mr.ResourceKey())
r.True(ok)
r.False(o.loaded)
for _, check := range []struct {

View File

@@ -331,7 +331,7 @@ func (h *gcHandler) deleteIndependentComponent(ctx context.Context, mr v1beta1.M
} else {
dependentClear := true
for _, mr := range rt.Spec.ManagedResources {
if utils.StringsContain(dependent, mr.Component) {
if slices.Contains(dependent, mr.Component) {
entry := h.cache.get(ctx, mr)
if entry.gcExecutorRT != rt {
continue
@@ -435,7 +435,7 @@ func (h *gcHandler) checkDependentComponent(mr v1beta1.ManagedResource) []string
}
for _, comp := range h.app.Spec.Components {
for _, input := range comp.Inputs {
if utils.StringsContain(outputs, input.From) {
if slices.Contains(outputs, input.From) {
dependent = append(dependent, comp.Name)
}
}

View File

@@ -30,21 +30,6 @@
dependsOn?: [...string]
}
// deprecated
#ReadPlacementDecisions: {
#provider: "multicluster"
#do: "read-placement-decisions"
inputs: {
policyName: string
envName: string
}
outputs: {
decisions?: [...#PlacementDecision]
}
}
// deprecated
#MakePlacementDecisions: {
#provider: "multicluster"

View File

@@ -84,7 +84,7 @@ func RollbackApplicationWithRevision(ctx context.Context, cli client.Client, app
// freeze the application
appKey := client.ObjectKeyFromObject(app)
controllerRequirement, err := utils.FreezeApplication(ctx, cli, app, func() {
controllerRequirement, err := FreezeApplication(ctx, cli, app, func() {
app.Spec = matchedRev.Spec.Application.Spec
oam.SetPublishVersion(app, publishVersion)
})
@@ -94,7 +94,7 @@ func RollbackApplicationWithRevision(ctx context.Context, cli client.Client, app
defer func() {
// unfreeze application
if err = utils.UnfreezeApplication(ctx, cli, app, nil, controllerRequirement); err != nil {
if err = UnfreezeApplication(ctx, cli, app, nil, controllerRequirement); err != nil {
klog.Errorf("failed to unfreeze application %s after update:%s", appKey, err.Error())
}
}()
@@ -130,3 +130,27 @@ func RollbackApplicationWithRevision(ctx context.Context, cli client.Client, app
}
return matchedRev, app, nil
}
// FreezeApplication freeze application to disable the reconciling process for it
func FreezeApplication(ctx context.Context, cli client.Client, app *v1beta1.Application, mutate func()) (string, error) {
return oam.GetControllerRequirement(app), _updateApplicationWithControllerRequirement(ctx, cli, app, mutate, "Disabled")
}
// UnfreezeApplication unfreeze application to enable the reconciling process for it
func UnfreezeApplication(ctx context.Context, cli client.Client, app *v1beta1.Application, mutate func(), originalControllerRequirement string) error {
return _updateApplicationWithControllerRequirement(ctx, cli, app, mutate, originalControllerRequirement)
}
func _updateApplicationWithControllerRequirement(ctx context.Context, cli client.Client, app *v1beta1.Application, mutate func(), controllerRequirement string) error {
appKey := client.ObjectKeyFromObject(app)
return retry.RetryOnConflict(retry.DefaultBackoff, func() error {
if err := cli.Get(ctx, appKey, app); err != nil {
return err
}
oam.SetControllerRequirement(app, controllerRequirement)
if mutate != nil {
mutate()
}
return cli.Update(ctx, app)
})
}

View File

@@ -16,20 +16,6 @@ limitations under the License.
package errors
import (
"fmt"
)
// ResourceTrackerNotExistError identifies error caused by resourcetracker not exist
type ResourceTrackerNotExistError struct {
Name string
}
// Error implement error interface
func (err ResourceTrackerNotExistError) Error() string {
return fmt.Sprintf("given resource tracker %q doesn't exist", err.Name)
}
// ManagedResourceHasNoDataError identifies error caused by no data in maanged resource
type ManagedResourceHasNoDataError struct{}

View File

@@ -19,32 +19,21 @@ package helm
import (
"context"
"fmt"
"io"
"log"
"os"
"strings"
v1 "k8s.io/api/core/v1"
types2 "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/pkg/errors"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/cli"
"helm.sh/helm/v3/pkg/getter"
"helm.sh/helm/v3/pkg/release"
"helm.sh/helm/v3/pkg/repo"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/utils/common"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
)
// VelaDebugLog defines an ENV to set vela helm install log to be debug
const (
VelaDebugLog = "VELA_DEBUG"
userNameSecKey = "username"
userPasswordSecKey = "password"
caFileSecKey = "caFile"
@@ -56,138 +45,6 @@ var (
settings = cli.New()
)
// Install will install helm chart
func Install(ioStreams cmdutil.IOStreams, repoName, repoURL, chartName, version, namespace, releaseName string,
vals map[string]interface{}) error {
if len(namespace) > 0 {
args, err := common.InitBaseRestConfig()
if err != nil {
return err
}
kubeClient, err := args.GetClient()
if err != nil {
return err
}
exist, err := cmdutil.DoesNamespaceExist(kubeClient, namespace)
if err != nil {
return err
}
if !exist {
if err = cmdutil.NewNamespace(kubeClient, namespace); err != nil {
return fmt.Errorf("create namespace (%s) failed for chart %s: %w", namespace, chartName, err)
}
}
}
// check release running first before add repo and install chart
if IsHelmReleaseRunning(releaseName, chartName, namespace, ioStreams) {
return nil
}
if !IsHelmRepositoryExist(repoName, repoURL) {
err := AddHelmRepository(repoName, repoURL,
"", "", "", "", "", false, ioStreams.Out)
if err != nil {
return err
}
}
chartClient, err := NewHelmInstall(version, namespace, releaseName)
if err != nil {
return err
}
chartRequested, err := GetChart(chartClient, repoName+"/"+chartName)
if err != nil {
return err
}
rel, err := chartClient.Run(chartRequested, vals)
if err != nil {
return err
}
ioStreams.Infof("Successfully installed chart (%s) with release name (%s)\n", chartName, rel.Name)
return nil
}
// Uninstall will uninstall helm chart
func Uninstall(ioStreams cmdutil.IOStreams, chartName, namespace, releaseName string) error {
if !IsHelmReleaseRunning(releaseName, chartName, namespace, ioStreams) {
return nil
}
uninstall, err := NewHelmUninstall(namespace)
if err != nil {
return err
}
_, err = uninstall.Run(releaseName)
if err != nil {
return err
}
ioStreams.Infof("Successfully removed chart (%s) with release name (%s)\n", chartName, releaseName)
return nil
}
// NewHelmInstall will create a install client for helm install
func NewHelmInstall(version, namespace, releaseName string) (*action.Install, error) {
actionConfig := new(action.Configuration)
if len(namespace) == 0 {
namespace = types.DefaultKubeVelaNS
}
if err := actionConfig.Init(
cmdutil.NewRestConfigGetter(namespace),
namespace,
os.Getenv("HELM_DRIVER"),
debug,
); err != nil {
return nil, err
}
client := action.NewInstall(actionConfig)
client.ReleaseName = releaseName
// MUST set here, client didn't use namespace from configuration
client.Namespace = namespace
if len(version) > 0 {
client.Version = version
} else {
client.Version = types.DefaultKubeVelaVersion
}
return client, nil
}
// NewHelmUninstall will create a helm uninstall client
func NewHelmUninstall(namespace string) (*action.Uninstall, error) {
actionConfig := new(action.Configuration)
if err := actionConfig.Init(
cmdutil.NewRestConfigGetter(namespace),
namespace,
os.Getenv("HELM_DRIVER"),
debug,
); err != nil {
return nil, err
}
return action.NewUninstall(actionConfig), nil
}
// IsHelmRepositoryExist will check help repo exists
func IsHelmRepositoryExist(name, url string) bool {
repos := GetHelmRepositoryList()
for _, repo := range repos {
if repo.Name == name && repo.URL == url {
return true
}
}
return false
}
// GetHelmRepositoryList get the helm repo list from default setting
func GetHelmRepositoryList() []*repo.Entry {
f, err := repo.LoadFile(settings.RepositoryConfig)
if err == nil && len(f.Repositories) > 0 {
return f.Repositories
}
return nil
}
func debug(format string, v ...interface{}) {
if settings.Debug {
format = fmt.Sprintf("[debug] %s\n", format)
@@ -195,53 +52,6 @@ func debug(format string, v ...interface{}) {
}
}
// AddHelmRepository add helm repo
func AddHelmRepository(name, url, username, password, certFile, keyFile, caFile string, insecureSkipTLSverify bool, out io.Writer) error {
var f repo.File
c := repo.Entry{
Name: name,
URL: url,
Username: username,
Password: password,
CertFile: certFile,
KeyFile: keyFile,
CAFile: caFile,
InsecureSkipTLSverify: insecureSkipTLSverify,
}
r, err := repo.NewChartRepository(&c, getter.All(settings))
if err != nil {
return err
}
if _, err := r.DownloadIndexFile(); err != nil {
return errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", url)
}
f.Update(&c)
if err := f.WriteFile(settings.RepositoryConfig, 0644); err != nil {
return err
}
fmt.Fprintf(out, "%q has been added to your repositories\n", name)
return nil
}
// IsHelmReleaseRunning check helm release running
func IsHelmReleaseRunning(releaseName, chartName, ns string, streams cmdutil.IOStreams) bool {
releases, err := GetHelmRelease(ns)
if err != nil {
streams.Error("get helm release err", err)
return false
}
for _, r := range releases {
if strings.Contains(r.Chart.ChartFullPath(), chartName) && r.Name == releaseName {
return true
}
}
return false
}
// GetHelmRelease will get helm release
func GetHelmRelease(ns string) ([]*release.Release, error) {
actionConfig := new(action.Configuration)
@@ -258,29 +68,6 @@ func GetHelmRelease(ns string) ([]*release.Release, error) {
return results, nil
}
// GetChart will locate chart
func GetChart(client *action.Install, name string) (*chart.Chart, error) {
if os.Getenv(VelaDebugLog) != "" {
settings.Debug = true
}
chartPath, err := client.ChartPathOptions.LocateChart(name, settings)
if err != nil {
return nil, err
}
chartRequested, err := loader.Load(chartPath)
if err != nil {
return nil, err
}
return chartRequested, nil
}
// InstallHelmChart will install helm chart from types.Chart
func InstallHelmChart(ioStreams cmdutil.IOStreams, c types.Chart) error {
return Install(ioStreams, c.Repo, c.URL, c.Name, c.Version, c.Namespace, c.Name, c.Values)
}
// SetHTTPOption will read username and password from secret return a httpOption that contain these info.
func SetHTTPOption(ctx context.Context, k8sClient client.Client, secretRef types2.NamespacedName) (*common.HTTPOption, error) {
sec := v1.Secret{}

View File

@@ -21,12 +21,6 @@ import (
"encoding/json"
)
// DumpJSON returns the JSON encoding
func DumpJSON(o interface{}) string {
j, _ := json.Marshal(o)
return string(j)
}
// StrictUnmarshal unmarshal target structure and disallow unknown fields
func StrictUnmarshal(bs []byte, dest interface{}) error {
d := json.NewDecoder(bytes.NewReader(bs))

View File

@@ -185,14 +185,6 @@ func GetUserInfoFromConfig(cfg *rest.Config) *authv1.UserInfo {
return nil
}
// AutoSetSelfImpersonationInConfig set impersonate username and group to the identity in the original rest config
func AutoSetSelfImpersonationInConfig(cfg *rest.Config) {
if userInfo := GetUserInfoFromConfig(cfg); userInfo != nil {
cfg.Impersonate.UserName = userInfo.Username
cfg.Impersonate.Groups = append(cfg.Impersonate.Groups, userInfo.Groups...)
}
}
// CreateOrUpdate create or update a kubernetes object
func CreateOrUpdate(ctx context.Context, cli client.Client, obj client.Object) (controllerutil.OperationResult, error) {
bs, err := json.Marshal(obj)

View File

@@ -1,64 +0,0 @@
/*
Copyright 2022 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package utils
import (
"encoding/json"
"net/http"
"net/http/pprof"
"runtime"
"time"
"k8s.io/klog/v2"
)
// EnablePprof listen to the pprofAddr and export the profiling results
// If the errChan is nil, this function will panic when the listening error occurred.
func EnablePprof(pprofAddr string, errChan chan error) {
// Start pprof server if enabled
mux := http.NewServeMux()
mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
mux.HandleFunc("/mem/stat", func(writer http.ResponseWriter, request *http.Request) {
var ms runtime.MemStats
runtime.ReadMemStats(&ms)
bs, _ := json.Marshal(ms)
_, _ = writer.Write(bs)
})
mux.HandleFunc("/gc", func(writer http.ResponseWriter, request *http.Request) {
runtime.GC()
})
pprofServer := http.Server{
Addr: pprofAddr,
Handler: mux,
ReadHeaderTimeout: 2 * time.Second,
}
klog.InfoS("Starting debug HTTP server", "addr", pprofServer.Addr)
if err := pprofServer.ListenAndServe(); err != nil {
klog.Error(err, "Failed to start debug HTTP server")
if errChan != nil {
errChan <- err
} else {
panic(err)
}
}
}

View File

@@ -1,41 +0,0 @@
/*
Copyright 2021 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 utils
import (
"net/http"
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/klog/v2"
)
// TryCancelRequest tries to cancel the request by traversing round trippers
func TryCancelRequest(rt http.RoundTripper, req *http.Request) {
type canceler interface {
CancelRequest(*http.Request)
}
switch rt := rt.(type) {
case canceler:
rt.CancelRequest(req)
case utilnet.RoundTripperWrapper:
TryCancelRequest(rt.WrappedRoundTripper(), req)
default:
klog.Warningf("Unable to cancel request for %T", rt)
}
}

View File

@@ -1,26 +0,0 @@
/*
Copyright 2021 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 utils
import "strings"
// Sanitize the inputs by removing line endings
func Sanitize(s string) string {
s = strings.ReplaceAll(s, "\n", "")
s = strings.ReplaceAll(s, "\r", "")
return s
}

View File

@@ -1,28 +0,0 @@
/*
Copyright 2021 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 utils
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestSanitize(t *testing.T) {
s := "abc\ndef\rgh"
require.Equal(t, "abcdefgh", Sanitize(s))
}

View File

@@ -18,9 +18,8 @@ package schema
import (
"fmt"
"strings"
"github.com/oam-dev/kubevela/pkg/utils"
"github.com/kubevela/pkg/util/slices"
)
// UISchema ui schema
@@ -87,7 +86,7 @@ func (c Condition) Validate() error {
if c.Action != "enable" && c.Action != "disable" && c.Action != "" {
return fmt.Errorf("the action of the condition only supports enable, disable or leave it empty")
}
if c.Op != "" && !utils.StringsContain([]string{"==", "!=", "in"}, c.Op) {
if c.Op != "" && !slices.Contains([]string{"==", "!=", "in"}, c.Op) {
return fmt.Errorf("the op of the condition must be `==` 、`!=` and `in`")
}
return nil
@@ -125,22 +124,6 @@ type Option struct {
Value interface{} `json:"value"`
}
// FirstUpper Sets the first letter of the string to upper.
func FirstUpper(s string) string {
if s == "" {
return ""
}
return strings.ToUpper(s[:1]) + s[1:]
}
// FirstLower Sets the first letter of the string to lowercase.
func FirstLower(s string) string {
if s == "" {
return ""
}
return strings.ToLower(s[:1]) + s[1:]
}
// GetDefaultUIType Set the default mapping for API Schema Type
func GetDefaultUIType(apiType string, haveOptions bool, subType string, haveSub bool) string {
switch apiType {
@@ -170,15 +153,3 @@ func GetDefaultUIType(apiType string, haveOptions bool, subType string, haveSub
return "Input"
}
}
// RenderLabel render option label
func RenderLabel(source interface{}) string {
switch v := source.(type) {
case int:
return fmt.Sprintf("%d", v)
case string:
return FirstUpper(v)
default:
return FirstUpper(fmt.Sprintf("%v", v))
}
}

View File

@@ -17,128 +17,9 @@ limitations under the License.
package utils
import (
"net/url"
"path"
"reflect"
"sort"
"strconv"
"strings"
)
// StringsContain strings contain
func StringsContain(items []string, source string) bool {
for _, item := range items {
if item == source {
return true
}
}
return false
}
// ThreeWaySliceCompare will compare two string slice, with the three return values: [both in A and B], [only in A], [only in B]
func ThreeWaySliceCompare(a []string, b []string) ([]string, []string, []string) {
m := make(map[string]struct{})
for _, k := range b {
m[k] = struct{}{}
}
var AB, AO, BO []string
for _, k := range a {
_, ok := m[k]
if !ok {
AO = append(AO, k)
continue
}
AB = append(AB, k)
delete(m, k)
}
for k := range m {
BO = append(BO, k)
}
sort.Strings(AB)
sort.Strings(AO)
sort.Strings(BO)
return AB, AO, BO
}
// EqualSlice checks if two slice are equal
func EqualSlice(a, b []string) bool {
sort.Strings(a)
sort.Strings(b)
return reflect.DeepEqual(a, b)
}
// SliceIncludeSlice the slice include the b slice
func SliceIncludeSlice(a, b []string) bool {
if EqualSlice(a, b) {
return true
}
for _, item := range b {
if !StringsContain(a, item) {
return false
}
}
return true
}
// ToString convery an interface to a string type.
func ToString(i interface{}) string {
if i == nil {
return ""
}
v := reflect.ValueOf(i)
if v.Kind() == reflect.Ptr && !v.IsNil() {
v = v.Elem()
}
i = v.Interface()
switch s := i.(type) {
case string:
return s
case bool:
return strconv.FormatBool(s)
case float64:
return strconv.FormatFloat(s, 'f', -1, 64)
case float32:
return strconv.FormatFloat(float64(s), 'f', -1, 32)
case int:
return strconv.Itoa(s)
case int64:
return strconv.FormatInt(s, 10)
case int32:
return strconv.Itoa(int(s))
case int16:
return strconv.FormatInt(int64(s), 10)
case int8:
return strconv.FormatInt(int64(s), 10)
case uint:
return strconv.FormatUint(uint64(s), 10)
case uint64:
// nolint
return strconv.FormatUint(uint64(s), 10)
case uint32:
return strconv.FormatUint(uint64(s), 10)
case uint16:
return strconv.FormatUint(uint64(s), 10)
case uint8:
return strconv.FormatUint(uint64(s), 10)
case []byte:
return string(s)
case nil:
return ""
default:
return ""
}
}
// MapKey2Array convery map keys to array
func MapKey2Array(source map[string]string) []string {
var list []string
for k := range source {
list = append(list, k)
}
return list
}
// GetBoxDrawingString get line drawing string, see https://en.wikipedia.org/wiki/Box-drawing_character
// nolint:gocyclo
func GetBoxDrawingString(up bool, down bool, left bool, right bool, padLeft int, padRight int) string {
@@ -193,14 +74,9 @@ func GetBoxDrawingString(up bool, down bool, left bool, right bool, padLeft int,
return sb.String()
}
// JoinURL join baseURL and subPath to be new URL
func JoinURL(baseURL, subPath string) (string, error) {
parsedURL, err := url.Parse(baseURL)
if err != nil {
return "", err
}
parsedURL.RawPath = path.Join(parsedURL.RawPath, subPath)
parsedURL.Path = path.Join(parsedURL.Path, subPath)
URL := parsedURL.String()
return URL, nil
// Sanitize the inputs by removing line endings
func Sanitize(s string) string {
s = strings.ReplaceAll(s, "\n", "")
s = strings.ReplaceAll(s, "\r", "")
return s
}

View File

@@ -17,202 +17,12 @@
package utils
import (
"errors"
"net/url"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestCompareSlice(t *testing.T) {
caseA := []string{"c", "b", "a"}
caseB := []string{"c", "b", "a"}
gotab, gotao, gotbo := ThreeWaySliceCompare(caseA, caseB)
assert.Equal(t, gotab, []string{"a", "b", "c"})
assert.Equal(t, gotao, []string(nil))
assert.Equal(t, gotbo, []string(nil))
caseA = []string{"c", "b"}
caseB = []string{"c", "a"}
gotab, gotao, gotbo = ThreeWaySliceCompare(caseA, caseB)
assert.Equal(t, gotab, []string{"c"})
assert.Equal(t, gotao, []string{"b"})
assert.Equal(t, gotbo, []string{"a"})
caseA = []string{"c", "b"}
caseB = nil
gotab, gotao, gotbo = ThreeWaySliceCompare(caseA, caseB)
assert.Equal(t, gotab, []string(nil))
assert.Equal(t, gotao, []string{"b", "c"})
assert.Equal(t, gotbo, []string(nil))
caseA = nil
caseB = []string{"c", "b"}
gotab, gotao, gotbo = ThreeWaySliceCompare(caseA, caseB)
assert.Equal(t, gotab, []string(nil))
assert.Equal(t, gotao, []string(nil))
assert.Equal(t, gotbo, []string{"b", "c"})
}
func TestEqual(t *testing.T) {
caseA := []string{"c", "b", "a"}
caseB := []string{"c", "b", "a"}
assert.Equal(t, EqualSlice(caseA, caseB), true)
caseA = []string{"c", "a", "b"}
caseB = []string{"c", "b", "a"}
assert.Equal(t, EqualSlice(caseA, caseB), true)
caseA = []string{"c", "a", "b"}
caseB = []string{"b", "a", "c"}
assert.Equal(t, EqualSlice(caseA, caseB), true)
caseA = []string{"c", "a", "b"}
caseB = []string{"b", "a", "c", "d"}
assert.Equal(t, EqualSlice(caseA, caseB), false)
caseA = []string{}
caseB = []string{}
assert.Equal(t, EqualSlice(caseA, caseB), true)
caseA = []string{}
caseB = []string{"b", "a", "c"}
assert.Equal(t, EqualSlice(caseA, caseB), false)
}
func TestSliceIncludeSlice(t *testing.T) {
caseA := []string{"b", "a", "c"}
caseB := []string{}
assert.Equal(t, SliceIncludeSlice(caseA, caseB), true)
caseA = []string{"b", "a", "c"}
caseB = []string{"b"}
assert.Equal(t, SliceIncludeSlice(caseA, caseB), true)
caseA = []string{"b", "a", "c"}
caseB = []string{"b", "c"}
assert.Equal(t, SliceIncludeSlice(caseA, caseB), true)
caseA = []string{"b", "a", "c"}
caseB = []string{"b", "c", "d"}
assert.Equal(t, SliceIncludeSlice(caseA, caseB), false)
caseA = []string{"b", "a", "c"}
caseB = []string{"b", "c", "a"}
assert.Equal(t, SliceIncludeSlice(caseA, caseB), true)
}
func TestJoinURL(t *testing.T) {
testcase := []struct {
baseURL string
subPath string
expectedUrl string
err error
}{
{
baseURL: "https://www.kubevela.com",
subPath: "index.yaml",
expectedUrl: "https://www.kubevela.com/index.yaml",
err: nil,
},
{
baseURL: "http://www.kubevela.com",
subPath: "index.yaml",
expectedUrl: "http://www.kubevela.com/index.yaml",
err: nil,
},
{
baseURL: "0x7f:",
subPath: "index.yaml",
expectedUrl: "",
err: &url.Error{Op: "parse", URL: "0x7f:", Err: errors.New("first path segment in URL cannot contain colon")},
},
}
for _, tc := range testcase {
url, err := JoinURL(tc.baseURL, tc.subPath)
assert.Equal(t, tc.expectedUrl, url)
assert.Equal(t, tc.err, err)
}
}
func TestToString(t *testing.T) {
type Obj struct {
k string
}
obj := &Obj{"foo"}
boolPtr := true
caseA := []struct {
input interface{}
expect string
}{
{int(666), "666"},
{int8(6), "6"},
{int16(6), "6"},
{int32(6), "6"},
{int64(6), "6"},
{uint(6), "6"},
{uint8(6), "6"},
{uint16(6), "6"},
{uint32(6), "6"},
{uint64(6), "6"},
{float32(3.14), "3.14"},
{float64(3.14), "3.14"},
{true, "true"},
{false, "false"},
{&boolPtr, "true"},
{nil, ""},
{[]byte("one time"), "one time"},
{"one more time", "one more time"},
{obj, ""},
}
for _, test := range caseA {
v := ToString(test.input)
assert.Equal(t, test.expect, v)
}
}
func TestStringsContain(t *testing.T) {
type args struct {
items []string
source string
}
tests := []struct {
name string
args args
want bool
}{
{
name: "test empty items should not contain any string",
args: args{
items: []string{},
source: "foo",
},
want: false,
},
{
name: "test items should contain source",
args: args{
items: []string{"foo", "bar"},
source: "foo",
},
want: true,
},
{
name: "test items should not contain source",
args: args{
items: []string{"foo", "bar"},
source: "baz",
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equalf(t, tt.want, StringsContain(tt.args.items, tt.args.source), "StringsContain(%v, %v)", tt.args.items, tt.args.source)
})
}
func TestSanitize(t *testing.T) {
s := "abc\ndef\rgh"
require.Equal(t, "abcdefgh", Sanitize(s))
}

View File

@@ -54,15 +54,6 @@ func GetVelaHomeDir() (string, error) {
return velaHome, nil
}
// GetDefaultFrontendDir return default vela frontend dir
func GetDefaultFrontendDir() (string, error) {
home, err := GetVelaHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, "frontend"), nil
}
// GetCapCenterDir return cap center dir
func GetCapCenterDir() (string, error) {
home, err := GetVelaHomeDir()

View File

@@ -19,6 +19,7 @@ package utils
import (
"fmt"
"net/url"
"path"
"regexp"
)
@@ -70,3 +71,15 @@ func IsValidURL(strURL string) bool {
}
return true
}
// JoinURL join baseURL and subPath to be new URL
func JoinURL(baseURL, subPath string) (string, error) {
parsedURL, err := url.Parse(baseURL)
if err != nil {
return "", err
}
parsedURL.RawPath = path.Join(parsedURL.RawPath, subPath)
parsedURL.Path = path.Join(parsedURL.Path, subPath)
URL := parsedURL.String()
return URL, nil
}

View File

@@ -17,6 +17,8 @@ limitations under the License.
package utils
import (
"fmt"
"net/url"
"testing"
"github.com/stretchr/testify/assert"
@@ -113,3 +115,37 @@ func TestIsValidURL(t *testing.T) {
})
}
}
func TestJoinURL(t *testing.T) {
testcase := []struct {
baseURL string
subPath string
expectedUrl string
err error
}{
{
baseURL: "https://www.kubevela.com",
subPath: "index.yaml",
expectedUrl: "https://www.kubevela.com/index.yaml",
err: nil,
},
{
baseURL: "http://www.kubevela.com",
subPath: "index.yaml",
expectedUrl: "http://www.kubevela.com/index.yaml",
err: nil,
},
{
baseURL: "0x7f:",
subPath: "index.yaml",
expectedUrl: "",
err: &url.Error{Op: "parse", URL: "0x7f:", Err: fmt.Errorf("first path segment in URL cannot contain colon")},
},
}
for _, tc := range testcase {
url, err := JoinURL(tc.baseURL, tc.subPath)
assert.Equal(t, tc.expectedUrl, url)
assert.Equal(t, tc.err, err)
}
}

View File

@@ -23,6 +23,7 @@ import (
"strings"
"time"
"github.com/kubevela/pkg/util/slices"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/api/networking/v1"
networkv1beta1 "k8s.io/api/networking/v1beta1"
@@ -41,7 +42,6 @@ import (
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
apis "github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/multicluster"
"github.com/oam-dev/kubevela/pkg/utils"
querytypes "github.com/oam-dev/kubevela/pkg/velaql/providers/query/types"
)
@@ -236,7 +236,7 @@ func generatorFromIngress(ingress v1.Ingress, cluster, component string) (servic
getAppProtocol := func(host string) string {
if len(ingress.Spec.TLS) > 0 {
for _, tls := range ingress.Spec.TLS {
if len(tls.Hosts) > 0 && utils.StringsContain(tls.Hosts, host) {
if len(tls.Hosts) > 0 && slices.Contains(tls.Hosts, host) {
return querytypes.HTTPS
}
if len(tls.Hosts) == 0 {

View File

@@ -169,25 +169,5 @@ var _ = Describe("Test ComponentDefinition validating handler", func() {
Expect(resp.Allowed).Should(BeFalse())
Expect(resp.Result.Reason).Should(Equal(metav1.StatusReason("the type and the definition of the workload field in ComponentDefinition wrongCd should represent the same workload")))
})
It("Test HELM type componentDefinition without definition", func() {
helmCd := v1beta1.ComponentDefinition{}
helmCd.SetGroupVersionKind(v1beta1.ComponentDefinitionGroupVersionKind)
helmCd.SetName("helmCd")
helmCd.Spec.Workload.Type = "deployments.apps"
helmCd.Spec.Schematic = &common.Schematic{
HELM: &common.Helm{},
}
helmCdRaw, _ := json.Marshal(helmCd)
req := admission.Request{
AdmissionRequest: admissionv1.AdmissionRequest{
Operation: admissionv1.Create,
Resource: reqResource,
Object: runtime.RawExtension{Raw: helmCdRaw},
},
}
resp := handler.Handle(context.TODO(), req)
Expect(resp.Allowed).Should(BeTrue())
})
})
})

View File

@@ -40,6 +40,7 @@ import (
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/resourcetracker"
"github.com/oam-dev/kubevela/pkg/rollout"
kubevelaapp "github.com/oam-dev/kubevela/pkg/utils/app"
errors3 "github.com/oam-dev/kubevela/pkg/utils/errors"
)
@@ -320,7 +321,7 @@ func (wo appWorkflowOperator) Rollback(ctx context.Context) error {
}
appKey := client.ObjectKeyFromObject(app)
// rollback application spec and freeze
controllerRequirement, err := utils.FreezeApplication(ctx, wo.cli, app, func() {
controllerRequirement, err := kubevelaapp.FreezeApplication(ctx, wo.cli, app, func() {
app.Spec = rev.Spec.Application.Spec
oam.SetPublishVersion(app, publishVersion)
})
@@ -369,7 +370,7 @@ func (wo appWorkflowOperator) Rollback(ctx context.Context) error {
}
// unfreeze application
if err = utils.UnfreezeApplication(ctx, wo.cli, app, nil, controllerRequirement); err != nil {
if err = kubevelaapp.UnfreezeApplication(ctx, wo.cli, app, nil, controllerRequirement); err != nil {
return errors.Wrapf(err, "failed to resume application to restart")
}

View File

@@ -48,27 +48,6 @@ type provider struct {
renderer oamProvider.WorkloadRenderer
}
// ReadPlacementDecisions
// Deprecated
func (p *provider) ReadPlacementDecisions(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act wfTypes.Action) error {
policy, err := v.GetString("inputs", "policyName")
if err != nil {
return err
}
env, err := v.GetString("inputs", "envName")
if err != nil {
return err
}
decisions, exists, err := envbinding.ReadPlacementDecisions(p.app, policy, env)
if err != nil {
return err
}
if exists {
return v.FillObject(map[string]interface{}{"decisions": decisions}, "outputs")
}
return v.FillObject(map[string]interface{}{}, "outputs")
}
// MakePlacementDecisions
// Deprecated
func (p *provider) MakePlacementDecisions(ctx monitorContext.Context, wfCtx wfContext.Context, v *value.Value, act wfTypes.Action) error {
@@ -210,7 +189,6 @@ func (p *provider) GetPlacementsFromTopologyPolicies(ctx monitorContext.Context,
func Install(p wfTypes.Providers, c client.Client, app *v1beta1.Application, af *appfile.Appfile, apply oamProvider.ComponentApply, healthCheck oamProvider.ComponentHealthCheck, renderer oamProvider.WorkloadRenderer) {
prd := &provider{Client: c, app: app, af: af, apply: apply, healthCheck: healthCheck, renderer: renderer}
p.Register(ProviderName, map[string]wfTypes.Handler{
"read-placement-decisions": prd.ReadPlacementDecisions,
"make-placement-decisions": prd.MakePlacementDecisions,
"patch-application": prd.PatchApplication,
"list-clusters": prd.ListClusters,

View File

@@ -40,93 +40,6 @@ import (
"github.com/oam-dev/kubevela/pkg/utils/common"
)
func TestReadPlacementDecisions(t *testing.T) {
testCases := []struct {
InputVal map[string]interface{}
OldCluster string
OldNamespace string
ExpectError string
ExpectDecisionExists bool
ExpectCluster string
ExpectNamespace string
}{{
InputVal: map[string]interface{}{},
ExpectError: "var(path=inputs.policyName) not exist",
}, {
InputVal: map[string]interface{}{
"policyName": "example-policy",
},
ExpectError: "var(path=inputs.envName) not exist",
}, {
InputVal: map[string]interface{}{
"policyName": "example-policy",
"envName": "example-env",
},
ExpectError: "",
ExpectDecisionExists: false,
}, {
InputVal: map[string]interface{}{
"policyName": "example-policy",
"envName": "example-env",
},
OldCluster: "example-cluster",
OldNamespace: "example-namespace",
ExpectError: "",
ExpectDecisionExists: true,
ExpectCluster: "example-cluster",
ExpectNamespace: "example-namespace",
}}
r := require.New(t)
for _, testCase := range testCases {
cli := fake.NewClientBuilder().WithScheme(common.Scheme).Build()
app := &v1beta1.Application{}
p := &provider{
Client: cli,
app: app,
}
act := &mock.Action{}
v, err := value.NewValue("", nil, "")
r.NoError(err)
r.NoError(v.FillObject(testCase.InputVal, "inputs"))
if testCase.ExpectCluster != "" || testCase.ExpectNamespace != "" {
pd := v1alpha1.PlacementDecision{
Cluster: testCase.OldCluster,
Namespace: testCase.OldNamespace,
}
bs, err := json.Marshal(&v1alpha1.EnvBindingStatus{
Envs: []v1alpha1.EnvStatus{{
Env: "example-env",
Placements: []v1alpha1.PlacementDecision{pd},
}},
})
r.NoError(err)
app.Status.PolicyStatus = []apicommon.PolicyStatus{{
Name: "example-policy",
Type: v1alpha1.EnvBindingPolicyType,
Status: &runtime.RawExtension{Raw: bs},
}}
}
err = p.ReadPlacementDecisions(nil, nil, v, act)
if testCase.ExpectError == "" {
r.NoError(err)
} else {
r.Contains(err.Error(), testCase.ExpectError)
continue
}
outputs, err := v.LookupValue("outputs")
r.NoError(err)
md := map[string][]v1alpha1.PlacementDecision{}
r.NoError(outputs.UnmarshalTo(&md))
if !testCase.ExpectDecisionExists {
r.Equal(0, len(md))
} else {
r.Equal(1, len(md["decisions"]))
r.Equal(testCase.ExpectCluster, md["decisions"][0].Cluster)
r.Equal(testCase.ExpectNamespace, md["decisions"][0].Namespace)
}
}
}
func TestMakePlacementDecisions(t *testing.T) {
multicluster.ClusterGatewaySecretNamespace = types.DefaultKubeVelaNS
testCases := []struct {

View File

@@ -1,100 +0,0 @@
/*
Copyright 2021 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 apis
import (
"k8s.io/apimachinery/pkg/runtime"
"github.com/oam-dev/kubevela/apis/types"
)
// Environment contains all info needed in `vela env` command
type Environment struct {
EnvName string `json:"envName" binding:"required,min=1,max=32"`
Namespace string `json:"namespace" binding:"required,min=1,max=32"`
Email string `json:"email"`
Domain string `json:"domain"`
Current string `json:"current,omitempty"`
}
// EnvironmentBody used for restful API in dashboard server
type EnvironmentBody struct {
Namespace string `json:"namespace" binding:"required,min=1,max=32"`
}
// Response used for restful API response in dashboard server
type Response struct {
Code int `json:"code"`
Data interface{} `json:"data" swaggerignore:"true"`
}
// CommonFlag used for restful API flags in dashboard server
type CommonFlag struct {
Name string `json:"name"`
Value string `json:"value"`
}
// WorkloadMeta store workload metadata for dashboard restful API server
type WorkloadMeta struct {
Name string `json:"name"`
Parameters []types.Parameter `json:"parameters,omitempty"`
Description string `json:"description,omitempty"`
}
// TraitBody used to present trait which is to be attached and, of which parameters are set
type TraitBody struct {
EnvName string `json:"envName"`
Name string `json:"name"`
Flags []CommonFlag `json:"flags"`
ComponentName string `json:"componentName"`
AppName string `json:"appName,omitempty"`
Staging string `json:"staging,omitempty"`
}
// ComponentMeta store component info for dashboard restful API server
type ComponentMeta struct {
Name string `json:"name"`
Status string `json:"status,omitempty"`
Workload runtime.RawExtension `json:"workload,omitempty"`
// WorkloadName for `vela comp ls`
WorkloadName string `json:"workloadName,omitempty"`
// TraitNames for `vela comp ls`
TraitNames []string `json:"traitsNames,omitempty"`
App string `json:"app"`
CreatedTime string `json:"createdTime,omitempty"`
}
// ApplicationMeta used for dashboard restful API server
type ApplicationMeta struct {
Name string `json:"name"`
Status string `json:"status,omitempty"`
Components []ComponentMeta `json:"components,omitempty"`
CreatedTime string `json:"createdTime,omitempty"`
}
// CapabilityMeta used for dashboard restful API server
type CapabilityMeta struct {
CapabilityName string `json:"capabilityName"`
CapabilityCenterName string `json:"capabilityCenterName,omitempty"`
}
// RegistryConfig is used to store registry config in file
type RegistryConfig struct {
Name string `json:"name"`
URL string `json:"url"`
Token string `json:"token"`
}

View File

@@ -17,14 +17,8 @@ limitations under the License.
package appfile
import (
"encoding/json"
"errors"
"fmt"
"k8s.io/apimachinery/pkg/runtime"
"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/references/appfile/api"
)
@@ -47,73 +41,3 @@ func SetWorkload(app *api.Application, componentName, workloadType string, workl
app.Services[componentName] = s
return Validate(app)
}
// SetTrait will set user trait for Appfile
func SetTrait(app *v1beta1.Application, componentName, traitType string, traitData map[string]interface{}) error {
if app == nil {
return errorAppNilPointer
}
if traitData == nil {
traitData = make(map[string]interface{})
}
data, err := json.Marshal(traitData)
if err != nil {
return fmt.Errorf("fail to marshal trait data %w", err)
}
var foundComp bool
for idx, comp := range app.Spec.Components {
if comp.Name != componentName {
continue
}
foundComp = true
var added bool
for j, tr := range app.Spec.Components[idx].Traits {
if tr.Type != traitType {
continue
}
added = true
if app.Spec.Components[idx].Traits[j].Properties == nil && data != nil {
app.Spec.Components[idx].Traits[j].Properties = &runtime.RawExtension{Raw: data}
} else {
app.Spec.Components[idx].Traits[j].Properties.Raw = data
}
}
if !added {
app.Spec.Components[idx].Traits = append(app.Spec.Components[idx].Traits, common.ApplicationTrait{Type: traitType, Properties: &runtime.RawExtension{Raw: data}})
}
}
if !foundComp {
return errors.New(componentName + " not found in app " + app.Name)
}
return nil
}
// RemoveTrait will remove a trait from Appfile
func RemoveTrait(app *api.Application, componentName, traitType string) error {
if app == nil {
return errorAppNilPointer
}
s, ok := app.Services[componentName]
if !ok {
return nil
}
delete(s, traitType)
return nil
}
// RemoveComponent will remove component from Application
func RemoveComponent(app *v1beta1.Application, componentName string) error {
if app == nil {
return errorAppNilPointer
}
var newComps []common.ApplicationComponent
for _, comp := range app.Spec.Components {
if comp.Name == componentName {
continue
}
newComps = append(newComps, comp)
}
app.Spec.Components = newComps
return nil
}

View File

@@ -41,10 +41,16 @@ import (
"github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/oam-dev/kubevela/pkg/utils/system"
cmdutil "github.com/oam-dev/kubevela/pkg/utils/util"
"github.com/oam-dev/kubevela/references/apis"
"github.com/oam-dev/kubevela/references/docgen"
)
// RegistryConfig is used to store registry config in file
type RegistryConfig struct {
Name string `json:"name"`
URL string `json:"url"`
Token string `json:"token"`
}
// NewRegistryCommand Manage Capability Center
func NewRegistryCommand(ioStream cmdutil.IOStreams, order string) *cobra.Command {
cmd := &cobra.Command{
@@ -150,7 +156,7 @@ func listCapRegistrys(ioStreams cmdutil.IOStreams) error {
// addRegistry will add a registry
func addRegistry(regName, regURL, regToken string) error {
regConfig := apis.RegistryConfig{
regConfig := RegistryConfig{
Name: regName, URL: regURL, Token: regToken,
}
repos, err := ListRegistryConfig()
@@ -222,7 +228,7 @@ type GithubRegistry struct {
}
// NewRegistryFromConfig return Registry interface to get capabilities
func NewRegistryFromConfig(config apis.RegistryConfig) (Registry, error) {
func NewRegistryFromConfig(config RegistryConfig) (Registry, error) {
return NewRegistry(context.TODO(), config.Token, config.Name, config.URL)
}
@@ -273,9 +279,8 @@ func NewRegistry(ctx context.Context, token, registryName string, regURL string)
// ListRegistryConfig will get all registry config stored in local
// this will return at least one config, which is DefaultRegistry
func ListRegistryConfig() ([]apis.RegistryConfig, error) {
defaultRegistryConfig := apis.RegistryConfig{Name: DefaultRegistry, URL: "oss://registry.kubevela.net/"}
func ListRegistryConfig() ([]RegistryConfig, error) {
defaultRegistryConfig := RegistryConfig{Name: DefaultRegistry, URL: "oss://registry.kubevela.net/"}
config, err := system.GetRepoConfig()
if err != nil {
return nil, err
@@ -283,7 +288,7 @@ func ListRegistryConfig() ([]apis.RegistryConfig, error) {
data, err := os.ReadFile(filepath.Clean(config))
if err != nil {
if os.IsNotExist(err) {
err := StoreRepos([]apis.RegistryConfig{defaultRegistryConfig})
err := StoreRepos([]RegistryConfig{defaultRegistryConfig})
if err != nil {
return nil, errors.Wrap(err, "error initialize default registry")
}
@@ -291,7 +296,7 @@ func ListRegistryConfig() ([]apis.RegistryConfig, error) {
}
return nil, err
}
var regConfigs []apis.RegistryConfig
var regConfigs []RegistryConfig
if err = yaml.Unmarshal(data, &regConfigs); err != nil {
return nil, err
}
@@ -722,7 +727,7 @@ func Parse(addr string) (string, *Content, error) {
}
// StoreRepos will store registry repo locally
func StoreRepos(registries []apis.RegistryConfig) error {
func StoreRepos(registries []RegistryConfig) error {
config, err := system.GetRepoConfig()
if err != nil {
return err

View File

@@ -1,21 +0,0 @@
/*
Copyright 2021 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 fake
// FrontendSource is a base64-encoded, gzipped tarball of the default Frontend Static files.
// This whole file will be rewrite at build time.
var FrontendSource string

View File

@@ -1,17 +0,0 @@
/*
Copyright 2021 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 common

View File

@@ -1,59 +0,0 @@
/*
Copyright 2021 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 common
import (
"context"
"github.com/oam-dev/kubevela/pkg/utils/util"
monitoring "github.com/coreos/prometheus-operator/pkg/apis/monitoring/v1"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
)
// InstallPrometheusInstance will install prometheus instance when the Capability is 'metrics'
func InstallPrometheusInstance(kubecli client.Client) error {
var promIns = monitoring.Prometheus{}
err := kubecli.Get(context.Background(), types.NamespacedName{Namespace: "monitoring", Name: "oam"}, &promIns)
if err == nil {
return nil
}
promIns.Name = "oam"
promIns.Namespace = "monitoring"
promIns.SetLabels(map[string]string{"prometheus": "kubevela"})
promIns.Spec = monitoring.PrometheusSpec{
Image: pointer.String("quay.io/prometheus/prometheus:v2.19.2"),
NodeSelector: map[string]string{"kubernetes.io/os": "linux"},
Replicas: pointer.Int32(1),
ServiceAccountName: "kube-prometheus-stack-prometheus",
SecurityContext: &corev1.PodSecurityContext{
RunAsUser: pointer.Int64(1000),
RunAsNonRoot: pointer.Bool(true),
FSGroup: pointer.Int64(2000),
},
ServiceMonitorSelector: &v1.LabelSelector{MatchLabels: map[string]string{"k8s-app": "oam", "controller": "metricsTrait"}},
ServiceMonitorNamespaceSelector: &v1.LabelSelector{
MatchLabels: util.OAMLabel,
},
Version: "v2.19.2",
}
return kubecli.Create(context.Background(), &promIns)
}

View File

@@ -378,12 +378,6 @@ func HandleTemplate(in *runtime.RawExtension, schematic *commontypes.Schematic,
tmp.Path = schematic.Terraform.Path
return tmp, nil
}
if schematic.KUBE != nil {
tmp.Category = types.KubeCategory
tmp.KubeTemplate = schematic.KUBE.Template
tmp.KubeParameter = schematic.KUBE.Parameters
return tmp, nil
}
}
if tmp.CueTemplateURI != "" {
b, err := common.HTTPGetWithOption(context.Background(), tmp.CueTemplateURI, nil)
@@ -393,10 +387,6 @@ func HandleTemplate(in *runtime.RawExtension, schematic *commontypes.Schematic,
tmp.CueTemplate = string(b)
}
if tmp.CueTemplate == "" {
if schematic != nil && schematic.HELM != nil {
tmp.Category = types.HelmCategory
return tmp, nil
}
return types.Capability{}, errors.New("template not exist in definition")
}
tmp.Parameters, err = cue.GetParameters(tmp.CueTemplate, pd)

View File

@@ -18,7 +18,6 @@ package docgen
import (
"context"
"encoding/json"
"os"
"path/filepath"
"strings"
@@ -155,18 +154,8 @@ var _ = Describe("test GetCapabilityByName", func() {
defaultNS string
cd1 corev1beta1.ComponentDefinition
cd2 corev1beta1.ComponentDefinition
cd3 corev1beta1.ComponentDefinition
cd4 corev1beta1.ComponentDefinition
td1 corev1beta1.TraitDefinition
td2 corev1beta1.TraitDefinition
td3 corev1beta1.TraitDefinition
component1 string
component2 string
component3 string
component4 string
trait1 string
trait2 string
trait3 string
)
BeforeEach(func() {
c = common.Args{}
@@ -176,12 +165,6 @@ var _ = Describe("test GetCapabilityByName", func() {
defaultNS = types.DefaultKubeVelaNS
component1 = "cd1"
component2 = "cd2"
component3 = "cd3"
component4 = "cd4"
trait1 = "td1"
trait2 = "td2"
trait3 = "td3"
By("create namespace")
Expect(k8sClient.Create(ctx, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}})).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
@@ -191,11 +174,6 @@ var _ = Describe("test GetCapabilityByName", func() {
data, _ := os.ReadFile("testdata/componentDef.yaml")
yaml.Unmarshal(data, &cd1)
yaml.Unmarshal(data, &cd2)
data2, _ := os.ReadFile("testdata/kube-worker.yaml")
yaml.Unmarshal(data2, &cd3)
helmYaml, _ := os.ReadFile("testdata/helm.yaml")
yaml.Unmarshal(helmYaml, &cd4)
cd1.Namespace = ns
cd1.Name = component1
@@ -204,38 +182,10 @@ var _ = Describe("test GetCapabilityByName", func() {
cd2.Namespace = defaultNS
cd2.Name = component2
Expect(k8sClient.Create(ctx, &cd2)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
cd3.Namespace = ns
cd3.Name = component3
Expect(k8sClient.Create(ctx, &cd3)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
cd4.Namespace = ns
cd4.Name = component4
Expect(k8sClient.Create(ctx, &cd4)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
By("create TraitDefinition")
data3, _ := os.ReadFile("testdata/svcTraitDef.yaml")
yaml.Unmarshal(data3, &td3)
td3.DeepCopyInto(&td1)
td3.DeepCopyInto(&td2)
td3.Namespace = ns
td3.Name = trait3
Expect(k8sClient.Create(ctx, &td3)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
td1.Name = trait1
td2.Name = trait2
td1.Namespace = ns
td1.Name = trait1
td1.SetResourceVersion("")
Expect(k8sClient.Create(ctx, &td1)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
td2.Namespace = defaultNS
td2.Name = trait2
td2.SetResourceVersion("")
Expect(k8sClient.Create(ctx, &td2)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
})
AfterEach(func() {
for _, obj := range []client.Object{&cd1, &cd2, &cd3, &cd4, &td1, &td2, &td3} {
for _, obj := range []client.Object{&cd1, &cd2} {
key := client.ObjectKeyFromObject(obj)
Expect(k8sClient.Delete(ctx, obj)).Should(Succeed())
Eventually(func(g Gomega) {
@@ -253,36 +203,6 @@ var _ = Describe("test GetCapabilityByName", func() {
_, err = GetCapabilityByName(ctx, c, component2, ns, nil)
Expect(err).Should(BeNil())
By("ComponentDefinition is in the default namespace")
cap, err := GetCapabilityByName(ctx, c, component3, ns, nil)
Expect(err).Should(BeNil())
jsontmp, err := json.Marshal(cap.KubeParameter)
Expect(err).Should(BeNil())
Expect(string(jsontmp)).Should(ContainSubstring("image"))
Expect(string(jsontmp)).Should(ContainSubstring("spec.template.spec.containers[0].image"))
Expect(string(jsontmp)).Should(ContainSubstring("port"))
Expect(string(jsontmp)).Should(ContainSubstring("the specific container port num which can accept external request."))
By("ComponentDefinition's workload type is AutoDetectWorkloadDefinition")
_, err = GetCapabilityByName(ctx, c, component4, ns, nil)
Expect(err).Should(BeNil())
By("TraitDefinition is in the current namespace")
_, err = GetCapabilityByName(ctx, c, trait1, ns, nil)
Expect(err).Should(BeNil())
By("TraitDefinition is in the default namespace")
_, err = GetCapabilityByName(ctx, c, trait2, ns, nil)
Expect(err).Should(BeNil())
By("TraitDefinition is in the default namespace")
cap, err = GetCapabilityByName(ctx, c, trait3, ns, nil)
Expect(err).Should(BeNil())
jsontmp, err = json.Marshal(cap.KubeParameter)
Expect(err).Should(BeNil())
Expect(string(jsontmp)).Should(ContainSubstring("targetPort"))
Expect(string(jsontmp)).Should(ContainSubstring("target port num for service provider."))
By("capability cloud not be found")
_, err = GetCapabilityByName(ctx, c, "a-component-definition-not-existed", ns, nil)
Expect(err).Should(HaveOccurred())

View File

@@ -150,11 +150,6 @@ func (ref *ConsoleReference) Show(ctx context.Context, c common.Args, ioStreams
if err != nil {
return err
}
case types.HelmCategory, types.KubeCategory:
_, propertyConsole, err = ref.GenerateHelmAndKubeProperties(ctx, capability)
if err != nil {
return err
}
default:
return fmt.Errorf("unsupport capability category %s", capability.Category)
}

View File

@@ -176,14 +176,6 @@ func (ref *MarkdownReference) GenerateMarkdownForCap(ctx context.Context, c type
klog.Warningf("failed to get base resource kinds for %s: %v", c.Name, warnErr)
}
}
case types.HelmCategory, types.KubeCategory:
properties, _, err := ref.GenerateHelmAndKubeProperties(ctx, &c)
if err != nil {
return "", fmt.Errorf("failed to retrieve `parameters` value from %s with err: %w", c.Name, err)
}
for _, property := range properties {
generatedDoc += ref.getParameterString("###"+property.Name, property.Parameters, types.HelmCategory)
}
case types.TerraformCategory:
generatedDoc, err = ref.GenerateTerraformCapabilityPropertiesAndOutputs(c)
if err != nil {
@@ -319,16 +311,6 @@ func (ref *MarkdownReference) getParameterString(tableName string, parameterList
tab += fmt.Sprintf(" %s | %s | %s | %t | %s \n", p.Name, ref.prettySentence(p.Usage), ref.formatTableString(p.PrintableType), p.Required, printableDefaultValue)
}
}
case types.HelmCategory:
for _, p := range parameterList {
printableDefaultValue := ref.getJSONPrintableDefaultValue(p.JSONType, p.Default)
tab += fmt.Sprintf(" %s | %s | %s | %t | %s \n", p.Name, ref.prettySentence(p.Usage), ref.formatTableString(p.PrintableType), p.Required, printableDefaultValue)
}
case types.KubeCategory:
for _, p := range parameterList {
// Kube parameter doesn't have default value
tab += fmt.Sprintf(" %s | %s | %s | %t | %s \n", p.Name, ref.prettySentence(p.Usage), ref.formatTableString(p.PrintableType), p.Required, "")
}
case types.TerraformCategory:
// Terraform doesn't have default value
for _, p := range parameterList {

View File

@@ -33,7 +33,6 @@ import (
"github.com/olekukonko/tablewriter"
"github.com/pkg/errors"
"github.com/rogpeppe/go-internal/modfile"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -49,7 +48,6 @@ import (
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/controller/utils"
velacue "github.com/oam-dev/kubevela/pkg/cue"
velaprocess "github.com/oam-dev/kubevela/pkg/cue/process"
pkgdef "github.com/oam-dev/kubevela/pkg/definition"
pkgUtils "github.com/oam-dev/kubevela/pkg/utils"
"github.com/oam-dev/kubevela/pkg/utils/common"
@@ -148,11 +146,6 @@ func (ref *ParseReference) prepareConsoleParameter(tableName string, parameterLi
table.Append([]string{ref.I18N.Get(p.Name), ref.prettySentence(p.Usage), ref.I18N.Get(p.PrintableType), ref.I18N.Get(strconv.FormatBool(p.Required)), ref.I18N.Get(printableDefaultValue)})
}
}
case types.HelmCategory, types.KubeCategory:
for _, p := range parameterList {
printableDefaultValue := ref.getJSONPrintableDefaultValue(p.JSONType, p.Default)
table.Append([]string{ref.I18N.Get(p.Name), ref.prettySentence(p.Usage), ref.I18N.Get(p.PrintableType), ref.I18N.Get(strconv.FormatBool(p.Required)), ref.I18N.Get(printableDefaultValue)})
}
case types.TerraformCategory:
// Terraform doesn't have default value
for _, p := range parameterList {
@@ -432,20 +425,6 @@ func (ref *ParseReference) getCUEPrintableDefaultValue(v interface{}) string {
return ""
}
func (ref *ParseReference) getJSONPrintableDefaultValue(dataType string, value interface{}) string {
if value != nil {
return strings.TrimSpace(fmt.Sprintf("%v", value))
}
defaultValueMap := map[string]string{
"number": "0",
"boolean": "false",
"string": "\"\"",
"object": "{}",
"array": "[]",
}
return defaultValueMap[dataType]
}
// CommonReference contains parameters info of HelmCategory and KubuCategory type capability at present
type CommonReference struct {
Name string
@@ -459,40 +438,6 @@ type CommonSchema struct {
Schemas *openapi3.Schema
}
// GenerateHelmAndKubeProperties get all properties of a Helm/Kube Category type capability
func (ref *ParseReference) GenerateHelmAndKubeProperties(ctx context.Context, capability *types.Capability) ([]CommonReference, []ConsoleReference, error) {
cmName := fmt.Sprintf("%s%s", types.CapabilityConfigMapNamePrefix, capability.Name)
switch capability.Type {
case types.TypeComponentDefinition:
cmName = fmt.Sprintf("component-%s", cmName)
case types.TypeTrait:
cmName = fmt.Sprintf("trait-%s", cmName)
default:
}
var cm v1.ConfigMap
commonRefs = make([]CommonReference, 0)
if err := ref.Client.Get(ctx, client.ObjectKey{Namespace: capability.Namespace, Name: cmName}, &cm); err != nil {
return nil, nil, err
}
data, ok := cm.Data[types.OpenapiV3JSONSchema]
if !ok {
return nil, nil, errors.Errorf("configMap doesn't have openapi-v3-json-schema data")
}
parameterJSON := fmt.Sprintf(BaseOpenAPIV3Template, data)
swagger, err := openapi3.NewLoader().LoadFromData(json.RawMessage(parameterJSON))
if err != nil {
return nil, nil, err
}
parameters := swagger.Components.Schemas[velaprocess.ParameterFieldName].Value
WalkParameterSchema(parameters, Specification, 0)
var consoleRefs []ConsoleReference
for _, item := range commonRefs {
consoleRefs = append(consoleRefs, ref.prepareConsoleParameter(item.Name, item.Parameters, types.HelmCategory))
}
return commonRefs, consoleRefs, err
}
// GenerateTerraformCapabilityProperties generates Capability properties for Terraform ComponentDefinition
func (ref *ParseReference) parseTerraformCapabilityParameters(capability types.Capability) ([]ReferenceParameterTable, []ReferenceParameterTable, error) {
var (

View File

@@ -1,40 +0,0 @@
apiVersion: core.oam.dev/v1beta1
kind: ComponentDefinition
metadata:
name: kube-worker
namespace: default
spec:
workload:
definition:
apiVersion: apps/v1
kind: Deployment
schematic:
kube:
template:
apiVersion: apps/v1
kind: Deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
ports:
- containerPort: 80
parameters:
- name: image
required: true
type: string
fieldPaths:
- "spec.template.spec.containers[0].image"
- name: port
required: true
type: string
fieldPaths:
- "spec.template.spec.containers[0].ports[0].containerPort"
description: "the specific container port num which can accept external request."

View File

@@ -1,30 +0,0 @@
apiVersion: core.oam.dev/v1beta1
kind: TraitDefinition
metadata:
name: service-kube
namespace: default
spec:
appliesToWorkloads:
- webservice
- worker
- backend
podDisruptive: true
schematic:
kube:
template:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
parameters:
- name: targetPort
required: true
type: number
fieldPaths:
- "spec.template.spec.ports[0].targetPort"
description: "target port num for service provider."

View File

@@ -125,35 +125,6 @@ var _ = Describe("Test multicluster scenario", func() {
Expect(out).Should(ContainSubstring("alias-worker"))
})
It("Test detach cluster with application use", func() {
const testClusterName = "test-cluster"
_, err := execCommand("cluster", "join", "/tmp/worker.kubeconfig", "--name", testClusterName)
Expect(err).Should(Succeed())
app := &v1beta1.Application{}
bs, err := os.ReadFile("./testdata/app/example-lite-envbinding-app.yaml")
Expect(err).Should(Succeed())
appYaml := strings.ReplaceAll(string(bs), "TEST_CLUSTER_NAME", testClusterName)
Expect(yaml.Unmarshal([]byte(appYaml), app)).Should(Succeed())
ctx := context.Background()
err = k8sClient.Create(ctx, app)
Expect(err).Should(Succeed())
namespacedName := client.ObjectKeyFromObject(app)
Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(ctx, namespacedName, app)).Should(Succeed())
g.Expect(len(app.Status.PolicyStatus)).ShouldNot(Equal(0))
}, 30*time.Second).Should(Succeed())
_, err = execCommand("cluster", "detach", testClusterName)
Expect(err).ShouldNot(Succeed())
err = k8sClient.Delete(ctx, app)
Expect(err).Should(Succeed())
Eventually(func(g Gomega) {
err := k8sClient.Get(ctx, namespacedName, app)
g.Expect(kerrors.IsNotFound(err)).Should(BeTrue())
}, 30*time.Second).Should(Succeed())
_, err = execCommand("cluster", "detach", testClusterName)
Expect(err).Should(Succeed())
})
It("Test generate service account kubeconfig", func() {
_, workerCtx := initializeContext()
By("create service account kubeconfig in worker cluster")
@@ -234,145 +205,6 @@ var _ = Describe("Test multicluster scenario", func() {
cleanUpNamespace(hubCtx, workerCtx, prodNamespace)
})
It("Test create EnvBinding Application", func() {
// This test is going to cover multiple functions, including
// 1. Multiple stage deployment for three environment
// 2. Namespace selector.
// 3. A special cluster: local cluster
// 4. Component selector.
By("apply application")
app := &v1beta1.Application{}
bs, err := os.ReadFile("./testdata/app/example-envbinding-app.yaml")
Expect(err).Should(Succeed())
appYaml := strings.ReplaceAll(strings.ReplaceAll(string(bs), "TEST_NAMESPACE", testNamespace), "PROD_NAMESPACE", prodNamespace)
Expect(yaml.Unmarshal([]byte(appYaml), app)).Should(Succeed())
app.SetNamespace(namespace)
err = k8sClient.Create(hubCtx, app)
Expect(err).Should(Succeed())
var hubDeployName string
By("wait application resource ready")
Eventually(func(g Gomega) {
// check deployments in clusters
deploys := &appsv1.DeploymentList{}
g.Expect(k8sClient.List(hubCtx, deploys, client.InNamespace(testNamespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(1))
hubDeployName = deploys.Items[0].Name
deploys = &appsv1.DeploymentList{}
g.Expect(k8sClient.List(workerCtx, deploys, client.InNamespace(namespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(2))
deploys = &appsv1.DeploymentList{}
g.Expect(k8sClient.List(workerCtx, deploys, client.InNamespace(prodNamespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(2))
}, time.Minute).Should(Succeed())
Expect(hubDeployName).Should(Equal("data-worker"))
// delete application
By("delete application")
Expect(k8sClient.Delete(hubCtx, app)).Should(Succeed())
By("wait application resource delete")
Eventually(func(g Gomega) {
// check deployments in clusters
deploys := &appsv1.DeploymentList{}
g.Expect(k8sClient.List(hubCtx, deploys, client.InNamespace(namespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(0))
deploys = &appsv1.DeploymentList{}
g.Expect(k8sClient.List(workerCtx, deploys, client.InNamespace(namespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(0))
}, time.Minute).Should(Succeed())
})
It("Test create EnvBinding Application with trait disable and without workflow, delete env, change env and add env", func() {
// This test is going to cover multiple functions, including
// 1. disable trait
// 2. auto deploy2env workflow
// 3. delete env
// 4. change cluster in env
// 5. add env
By("apply application")
app := &v1beta1.Application{}
bs, err := os.ReadFile("./testdata/app/example-envbinding-app-wo-workflow.yaml")
Expect(err).Should(Succeed())
appYaml := strings.ReplaceAll(string(bs), "TEST_NAMESPACE", testNamespace)
Expect(yaml.Unmarshal([]byte(appYaml), app)).Should(Succeed())
app.SetNamespace(testNamespace)
namespacedName := client.ObjectKeyFromObject(app)
err = k8sClient.Create(hubCtx, app)
Expect(err).Should(Succeed())
By("wait application resource ready")
Eventually(func(g Gomega) {
// check deployments in clusters
deploys := &appsv1.DeploymentList{}
g.Expect(k8sClient.List(hubCtx, deploys, client.InNamespace(testNamespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(1))
g.Expect(int(*deploys.Items[0].Spec.Replicas)).Should(Equal(2))
g.Expect(k8sClient.List(workerCtx, deploys, client.InNamespace(testNamespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(1))
g.Expect(int(*deploys.Items[0].Spec.Replicas)).Should(Equal(1))
}, time.Minute).Should(Succeed())
By("test delete env")
spec := &v1alpha1.EnvBindingSpec{}
Expect(json.Unmarshal(app.Spec.Policies[0].Properties.Raw, spec)).Should(Succeed())
envs := spec.Envs
bs, err = json.Marshal(&v1alpha1.EnvBindingSpec{Envs: []v1alpha1.EnvConfig{envs[0]}})
Expect(err).Should(Succeed())
Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(hubCtx, namespacedName, app)).Should(Succeed())
app.Spec.Policies[0].Properties.Raw = bs
g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed())
}, 15*time.Second).Should(Succeed())
Eventually(func(g Gomega) {
deploys := &appsv1.DeploymentList{}
g.Expect(k8sClient.List(workerCtx, deploys, client.InNamespace(testNamespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(0))
}, time.Minute).Should(Succeed())
By("test change env cluster name")
envs[0].Placement.ClusterSelector.Name = WorkerClusterName
bs, err = json.Marshal(&v1alpha1.EnvBindingSpec{Envs: []v1alpha1.EnvConfig{envs[0]}})
Expect(err).Should(Succeed())
Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(hubCtx, namespacedName, app)).Should(Succeed())
app.Spec.Policies[0].Properties.Raw = bs
g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed())
}, 15*time.Second).Should(Succeed())
Eventually(func(g Gomega) {
deploys := &appsv1.DeploymentList{}
g.Expect(k8sClient.List(hubCtx, deploys, client.InNamespace(testNamespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(0))
g.Expect(k8sClient.List(workerCtx, deploys, client.InNamespace(testNamespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(1))
}, time.Minute).Should(Succeed())
By("test add env")
envs[1].Placement.ClusterSelector.Name = multicluster.ClusterLocalName
bs, err = json.Marshal(&v1alpha1.EnvBindingSpec{Envs: envs})
Expect(err).Should(Succeed())
Eventually(func(g Gomega) {
g.Expect(k8sClient.Get(hubCtx, namespacedName, app)).Should(Succeed())
app.Spec.Policies[0].Properties.Raw = bs
g.Expect(k8sClient.Update(hubCtx, app)).Should(Succeed())
}, 15*time.Second).Should(Succeed())
Eventually(func(g Gomega) {
deploys := &appsv1.DeploymentList{}
g.Expect(k8sClient.List(hubCtx, deploys, client.InNamespace(testNamespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(1))
g.Expect(int(*deploys.Items[0].Spec.Replicas)).Should(Equal(1))
g.Expect(k8sClient.List(workerCtx, deploys, client.InNamespace(testNamespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(1))
g.Expect(int(*deploys.Items[0].Spec.Replicas)).Should(Equal(2))
}, time.Minute).Should(Succeed())
// delete application
By("delete application")
Expect(k8sClient.Delete(hubCtx, app)).Should(Succeed())
By("wait application resource delete")
Eventually(func(g Gomega) {
// check deployments in clusters
deploys := &appsv1.DeploymentList{}
g.Expect(k8sClient.List(hubCtx, deploys, client.InNamespace(testNamespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(0))
deploys = &appsv1.DeploymentList{}
g.Expect(k8sClient.List(workerCtx, deploys, client.InNamespace(testNamespace))).Should(Succeed())
g.Expect(len(deploys.Items)).Should(Equal(0))
}, time.Minute).Should(Succeed())
})
It("Test deploy multi-cluster application with target", func() {
By("apply application")
app := &v1beta1.Application{

View File

@@ -1,40 +0,0 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: example-app
namespace: TEST_NAMESPACE # to be replaced
spec:
components:
- name: hello-world-server
type: webservice
properties:
image: crccheck/hello-world
ports:
- port: 8000
expose: true
traits:
- type: scaler
properties:
replicas: 2
policies:
- name: example-multi-env-policy
type: env-binding
properties:
envs:
- name: test
placement: # selecting the cluster to deploy to
clusterSelector:
name: local
- name: staging
placement: # selecting the cluster to deploy to
clusterSelector:
name: cluster-worker
patch:
components:
- name: hello-world-server
type: webservice
traits:
- type: scaler
disable: true

View File

@@ -1,80 +0,0 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: example-app
namespace: default
spec:
components:
- name: hello-world-server
type: webservice
properties:
image: crccheck/hello-world
ports:
- port: 8000
expose: true
traits:
- type: scaler
properties:
replicas: 1
- name: data-worker
type: worker
properties:
image: busybox
cmd:
- sleep
- '1000000'
policies:
- name: example-multi-env-policy
type: env-binding
properties:
envs:
- name: test
placement: # selecting the namespace (in local cluster) to deploy to
namespaceSelector:
name: TEST_NAMESPACE
selector:
components:
- data-worker
- name: staging
placement: # selecting the cluster to deploy to
clusterSelector:
name: cluster-worker
- name: prod
placement: # selecting both namespace and cluster to deploy to
clusterSelector:
name: cluster-worker
namespaceSelector:
name: PROD_NAMESPACE
patch: # overlay patch on above components
components:
- name: hello-world-server
type: webservice
traits:
- type: scaler
properties:
replicas: 3
workflow:
steps:
# deploy to test env
- name: deploy-test
type: deploy2env
properties:
policy: example-multi-env-policy
env: test
# deploy to staging env
- name: deploy-staging
type: deploy2env
properties:
policy: example-multi-env-policy
env: staging
# deploy to prod env
- name: deploy-prod
type: deploy2env
properties:
policy: example-multi-env-policy
env: prod

View File

@@ -1,32 +0,0 @@
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: example-lite-app
namespace: default
spec:
components:
- name: data-worker
type: worker
properties:
image: busybox
cmd:
- sleep
- '1000000'
policies:
- name: example-multi-env-policy
type: env-binding
properties:
envs:
- name: test
placement:
clusterSelector:
name: TEST_CLUSTER_NAME
workflow:
steps:
# deploy to test env
- name: deploy-test
type: deploy2env
properties:
policy: example-multi-env-policy
env: test

View File

@@ -28,10 +28,7 @@ import (
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
@@ -352,339 +349,6 @@ var _ = Describe("Test application of the specified definition version", func()
}, 30*time.Second, 3*time.Second).Should(Succeed())
})
PIt("Test deploy application which containing helm module", func() {
var (
appName = "test-helm"
compName = "worker"
)
helmworkerV1 := HELMWorker.DeepCopy()
helmworkerV1.SetNamespace(namespace)
helmworkerV1.Spec.Workload.Definition = common.WorkloadGVK{
APIVersion: "batch/v1beta1",
Kind: "CronJob",
}
helmworkerV1.Spec.Schematic = &common.Schematic{
HELM: &common.Helm{
Release: *util.Object2RawExtension(map[string]interface{}{
"chart": map[string]interface{}{
"spec": map[string]interface{}{
"chart": "podinfo",
"version": "5.1.4",
},
},
}),
Repository: *util.Object2RawExtension(map[string]interface{}{
"url": "https://stefanprodan.github.io/podinfo",
}),
},
}
Expect(k8sClient.Create(ctx, helmworkerV1)).Should(Succeed())
helmworkerV1DefRev := new(v1beta1.DefinitionRevision)
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: "helm-worker-v1", Namespace: namespace}, helmworkerV1DefRev)
}, 15*time.Second, time.Second).Should(BeNil())
helmworkerV2 := new(v1beta1.ComponentDefinition)
Eventually(func() error {
err := k8sClient.Get(ctx, client.ObjectKey{Name: "helm-worker", Namespace: namespace}, helmworkerV2)
if err != nil {
return err
}
helmworkerV2.Spec.Workload.Definition = common.WorkloadGVK{
APIVersion: "apps/v1",
Kind: "Deployment",
}
helmworkerV2.Spec.Workload.Type = "deployments.apps"
helmworkerV2.Spec.Schematic = &common.Schematic{
HELM: &common.Helm{
Release: *util.Object2RawExtension(map[string]interface{}{
"chart": map[string]interface{}{
"spec": map[string]interface{}{
"chart": "podinfo",
"version": "5.2.0",
},
},
}),
Repository: *util.Object2RawExtension(map[string]interface{}{
"url": "https://stefanprodan.github.io/podinfo",
}),
},
}
return k8sClient.Update(ctx, helmworkerV2)
}, 15*time.Second, time.Second).Should(BeNil())
helmworkerV2DefRev := new(v1beta1.DefinitionRevision)
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: "helm-worker-v2", Namespace: namespace}, helmworkerV2DefRev)
}, 15*time.Second, time.Second).Should(BeNil())
app := v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: "helm-worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": map[string]interface{}{
"tag": "5.1.2",
},
}),
Traits: []common.ApplicationTrait{
{
Type: "label",
Properties: util.Object2RawExtension(map[string]interface{}{
"labels": map[string]string{
"hello": "world",
},
}),
},
},
},
},
},
}
By("Create application")
Eventually(func() error {
return k8sClient.Create(ctx, app.DeepCopy())
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
By("Verify the workload(deployment) is created successfully by Helm")
deploy := &appsv1.Deployment{}
deployName := fmt.Sprintf("%s-%s-podinfo", appName, compName)
Eventually(func() bool {
err := k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy)
if err != nil {
return false
}
DeployLabels := deploy.GetLabels()
return DeployLabels["helm.sh/chart"] == "podinfo-5.2.0"
}, 120*time.Second, 5*time.Second).Should(BeTrue())
By("Verify trait is applied to the workload")
Eventually(func() bool {
deploy := &appsv1.Deployment{}
if err := k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy); err != nil {
return false
}
By("Verify patch trait is applied")
templateLabels := deploy.GetLabels()
return templateLabels["hello"] == "world"
}, 200*time.Second, 10*time.Second).Should(BeTrue())
app = v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: "helm-worker@v1",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": map[string]interface{}{
"tag": "5.1.2",
},
}),
},
},
},
}
By("Create application")
Expect(k8sClient.Patch(ctx, &app, client.Merge)).Should(Succeed())
By("Verify the workload(deployment) is update successfully by Helm")
deploy = &appsv1.Deployment{}
Eventually(func() bool {
err := k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy)
if err != nil {
return false
}
DeployLabels := deploy.GetLabels()
return DeployLabels["helm.sh/chart"] != "podinfo-5.1.4"
}, 120*time.Second, 5*time.Second).Should(BeTrue())
})
It("Test deploy application which containing kube module", func() {
var (
appName = "test-kube-app"
compName = "worker"
)
kubeworkerV1 := KUBEWorker.DeepCopy()
kubeworkerV1.Spec.Workload.Definition = common.WorkloadGVK{
APIVersion: "apps/v1",
Kind: "Deployment",
}
kubeworkerV1.Spec.Schematic = &common.Schematic{
KUBE: &common.Kube{
Template: generateTemplate(KUBEWorkerV1Template),
Parameters: []common.KubeParameter{
{
Name: "image",
ValueType: common.StringType,
FieldPaths: []string{"spec.template.spec.containers[0].image"},
Required: pointer.Bool(true),
Description: pointer.String("test description"),
},
},
},
}
kubeworkerV1.SetNamespace(namespace)
Expect(k8sClient.Create(ctx, kubeworkerV1)).Should(Succeed())
kubeworkerV1DefRev := new(v1beta1.DefinitionRevision)
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: "kube-worker-v1", Namespace: namespace}, kubeworkerV1DefRev)
}, 15*time.Second, time.Second).Should(BeNil())
kubeworkerV2 := new(v1beta1.ComponentDefinition)
Eventually(func() error {
err := k8sClient.Get(ctx, client.ObjectKey{Name: "kube-worker", Namespace: namespace}, kubeworkerV2)
if err != nil {
return err
}
kubeworkerV2.Spec.Workload.Definition = common.WorkloadGVK{
APIVersion: "batch/v1",
Kind: "Job",
}
kubeworkerV2.Spec.Workload.Type = "jobs.batch"
kubeworkerV2.Spec.Schematic = &common.Schematic{
KUBE: &common.Kube{
Template: generateTemplate(KUBEWorkerV2Template),
Parameters: []common.KubeParameter{
{
Name: "image",
ValueType: common.StringType,
FieldPaths: []string{"spec.template.spec.containers[0].image"},
Required: pointer.Bool(true),
Description: pointer.String("test description"),
},
},
},
}
return k8sClient.Update(ctx, kubeworkerV2)
}, 15*time.Second, time.Second).Should(BeNil())
kubeworkerV2DefRev := new(v1beta1.DefinitionRevision)
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: "kube-worker-v2", Namespace: namespace}, kubeworkerV2DefRev)
}, 15*time.Second, time.Second).Should(BeNil())
app := v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: "kube-worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
Traits: []common.ApplicationTrait{
{
Type: "label",
Properties: util.Object2RawExtension(map[string]interface{}{
"labels": map[string]string{
"hello": "world",
},
}),
},
},
},
},
},
}
By("Create application")
Eventually(func() error {
return k8sClient.Create(ctx, app.DeepCopy())
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
By("Verify the workload(job) is created successfully")
job := &batchv1.Job{}
jobName := compName
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: jobName, Namespace: namespace}, job)
}, 30*time.Second, 3*time.Second).Should(Succeed())
By("Verify trait is applied to the workload")
Labels := job.GetLabels()
Expect(Labels["hello"]).Should(Equal("world"))
By("Update Application and Specify the Definition version in Application")
app = v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: "kube-worker@v1",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "nginx",
}),
Traits: []common.ApplicationTrait{
{
Type: "label",
Properties: util.Object2RawExtension(map[string]interface{}{
"labels": map[string]string{
"hello": "kubevela",
},
}),
},
},
},
},
},
}
Expect(k8sClient.Patch(ctx, &app, client.Merge)).Should(Succeed())
By("Verify the workload(deployment) is created successfully")
deploy := &appsv1.Deployment{}
deployName := compName
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy)
}, 30*time.Second, 3*time.Second).Should(Succeed())
By("Verify trait is applied to the workload")
webserviceV1Labels := deploy.GetLabels()
Expect(webserviceV1Labels["hello"]).Should(Equal("kubevela"))
By("Application specifies the wrong version of the Definition, it will raise an error")
app = v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: "kube-worker@a1",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "nginx",
}),
},
},
},
}
Expect(k8sClient.Patch(ctx, &app, client.Merge)).Should(HaveOccurred())
})
// refer to https://github.com/oam-dev/kubevela/discussions/1810#discussioncomment-914295
It("Test k8s resources created by application whether with correct label", func() {
var (
@@ -892,11 +556,6 @@ var exposeWithNoTemplate = &v1beta1.TraitDefinition{
},
}
func generateTemplate(template string) runtime.RawExtension {
b, _ := yaml.YAMLToJSON([]byte(template))
return runtime.RawExtension{Raw: b}
}
var webServiceV1Template = `output: {
apiVersion: "apps/v1"
kind: "Deployment"

View File

@@ -1,387 +0,0 @@
/*
Copyright 2021 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"
"errors"
"fmt"
"strings"
"time"
"github.com/oam-dev/kubevela/apis/types"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"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/util"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("Test application containing helm module", func() {
ctx := context.Background()
var (
appName = "test-app"
compName = "test-comp"
cdName = "webapp-chart"
wdName = "webapp-chart-wd"
tdName = "virtualgroup"
)
var namespace string
var app v1beta1.Application
var ns corev1.Namespace
BeforeEach(func() {
namespace = randomNamespaceName("helm-e2e-test")
ns = corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
Eventually(
func() error {
return k8sClient.Create(ctx, &ns)
},
time.Second*3, time.Millisecond*300).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
cd := v1beta1.ComponentDefinition{}
cd.SetName(cdName)
cd.SetNamespace(namespace)
cd.Spec.Workload.Definition = common.WorkloadGVK{APIVersion: "apps/v1", Kind: "Deployment"}
cd.Spec.Schematic = &common.Schematic{
HELM: &common.Helm{
Release: *util.Object2RawExtension(map[string]interface{}{
"chart": map[string]interface{}{
"spec": map[string]interface{}{
"chart": "podinfo",
"version": "5.1.4",
},
},
}),
Repository: *util.Object2RawExtension(map[string]interface{}{
"url": "https://charts.kubevela.net/example/",
}),
},
}
Expect(k8sClient.Create(ctx, &cd)).Should(Succeed())
By("Install a patch trait used to test CUE module")
td := v1beta1.TraitDefinition{}
td.SetName(tdName)
td.SetNamespace(namespace)
td.Spec.AppliesToWorkloads = []string{"deployments.apps"}
td.Spec.Schematic = &common.Schematic{
CUE: &common.CUE{
Template: `patch: {
spec: template: {
metadata: labels: {
if parameter.type == "namespace" {
"app.namespace.virtual.group": parameter.group
}
if parameter.type == "cluster" {
"app.cluster.virtual.group": parameter.group
}
}
}
}
parameter: {
group: *"default" | string
type: *"namespace" | string
}`,
},
}
Expect(k8sClient.Create(ctx, &td)).Should(Succeed())
By("Add 'deployments.apps' to scaler's appliesToWorkloads")
scalerTd := v1beta1.TraitDefinition{}
Expect(k8sClient.Get(ctx, client.ObjectKey{Name: "scaler", Namespace: "vela-system"}, &scalerTd)).Should(Succeed())
scalerTd.Spec.AppliesToWorkloads = []string{"deployments.apps", "webservice", "worker"}
scalerTd.SetResourceVersion("")
Expect(k8sClient.Patch(ctx, &scalerTd, client.Merge)).Should(Succeed())
})
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.WorkloadDefinition{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(ctx, &v1beta1.TraitDefinition{}, client.InNamespace(namespace))
By(fmt.Sprintf("Delete the entire namespaceName %s", ns.Name))
Expect(k8sClient.Delete(ctx, &ns, client.PropagationPolicy(metav1.DeletePropagationForeground))).Should(Succeed())
By("Remove 'deployments.apps' from scaler's appliesToWorkloads")
scalerTd := v1beta1.TraitDefinition{}
Expect(k8sClient.Get(ctx, client.ObjectKey{Name: "scaler", Namespace: "vela-system"}, &scalerTd)).Should(Succeed())
scalerTd.Spec.AppliesToWorkloads = []string{"webservice", "worker"}
scalerTd.SetResourceVersion("")
Expect(k8sClient.Patch(ctx, &scalerTd, client.Merge)).Should(Succeed())
})
PIt("Test deploy an application containing helm module", func() {
app = v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: cdName,
Properties: util.Object2RawExtension(map[string]interface{}{
"image": map[string]interface{}{
"tag": "5.1.2",
},
}),
Traits: []common.ApplicationTrait{
{
Type: "scaler",
Properties: util.Object2RawExtension(map[string]interface{}{
"replicas": 0,
}),
},
{
Type: tdName,
Properties: util.Object2RawExtension(map[string]interface{}{
"group": "my-group",
"type": "cluster",
}),
},
},
},
},
},
}
By("Create application")
Eventually(func() error {
return k8sClient.Create(ctx, app.DeepCopy())
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
By("Verify the workload(deployment) is created successfully by Helm")
deploy := &appsv1.Deployment{}
deployName := fmt.Sprintf("%s-%s-podinfo", appName, compName)
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy)
}, 120*time.Second, 5*time.Second).Should(Succeed())
By("Verify two traits are applied to the workload")
Eventually(func() bool {
deploy := &appsv1.Deployment{}
if err := k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy); err != nil {
return false
}
By("Verify patch trait is applied")
templateLabels := deploy.Spec.Template.Labels
if templateLabels["app.cluster.virtual.group"] != "my-group" {
return false
}
By("Verify scaler trait is applied")
if *deploy.Spec.Replicas != 0 {
return false
}
By("Verify application's settings override chart default values")
// the default value of 'image.tag' is 5.1.4 in the chart, but settings reset it to 5.1.2
return strings.HasSuffix(deploy.Spec.Template.Spec.Containers[0].Image, "5.1.2")
// it takes pretty long time to fetch chart and install the Helm release
}, 120*time.Second, 10*time.Second).Should(BeTrue())
By("Update the application")
app = v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: cdName,
Properties: util.Object2RawExtension(map[string]interface{}{
"image": map[string]interface{}{
"tag": "5.1.3", // change 5.1.2 => 5.1.3
},
}),
Traits: []common.ApplicationTrait{
{
Type: "scaler",
Properties: util.Object2RawExtension(map[string]interface{}{
"replicas": 1, // change 0 => 1
}),
},
{
Type: tdName,
Properties: util.Object2RawExtension(map[string]interface{}{
"group": "my-group-0", // change my-group => my-group-0
"type": "cluster",
}),
},
},
},
},
},
}
Expect(k8sClient.Patch(ctx, &app, client.Merge)).Should(Succeed())
By("Verify the changes are applied to the workload")
Eventually(func() bool {
deploy := &appsv1.Deployment{}
if err := k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy); err != nil {
return false
}
By("Verify new patch trait is applied")
templateLabels := deploy.Spec.Template.Labels
if templateLabels["app.cluster.virtual.group"] != "my-group-0" {
return false
}
By("Verify new scaler trait is applied")
if *deploy.Spec.Replicas != 1 {
return false
}
By("Verify new application's settings override chart default values")
return strings.HasSuffix(deploy.Spec.Template.Spec.Containers[0].Image, "5.1.3")
}, 120*time.Second, 10*time.Second).Should(BeTrue())
})
It("Test deploy an application containing helm module defined by workloadDefinition", func() {
workloaddef := v1beta1.WorkloadDefinition{}
workloaddef.SetName(wdName)
workloaddef.SetNamespace(namespace)
workloaddef.Spec.Reference = common.DefinitionReference{Name: "deployments.apps", Version: "v1"}
workloaddef.Spec.Schematic = &common.Schematic{
HELM: &common.Helm{
Release: *util.Object2RawExtension(map[string]interface{}{
"chart": map[string]interface{}{
"spec": map[string]interface{}{
"chart": "podinfo",
"version": "5.1.4",
},
},
}),
Repository: *util.Object2RawExtension(map[string]interface{}{
"url": "https://charts.kubevela.net/example/",
}),
},
}
By("register workloadDefinition")
Expect(k8sClient.Create(ctx, &workloaddef)).Should(Succeed())
appTestName := "test-app-refer-to-workloaddef"
appTest := v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appTestName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: wdName,
Properties: util.Object2RawExtension(map[string]interface{}{
"image": map[string]interface{}{
"tag": "5.1.2",
},
}),
},
},
},
}
By("Create application")
Eventually(func() error {
return k8sClient.Create(ctx, appTest.DeepCopy())
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
By("Verify the workload(deployment) is created successfully by Helm")
deploy := &appsv1.Deployment{}
deployName := fmt.Sprintf("%s-%s-podinfo", appTestName, compName)
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy)
}, 240*time.Second, 5*time.Second).Should(Succeed())
})
It("Test deploy an application containing helm module and the component refer to autodetect type workload", func() {
cd := v1beta1.ComponentDefinition{}
cd.SetName("podinfo")
cd.SetNamespace(namespace)
cd.Spec.Schematic = &common.Schematic{
HELM: &common.Helm{
Release: *util.Object2RawExtension(map[string]interface{}{
"chart": map[string]interface{}{
"spec": map[string]interface{}{
"chart": "podinfo",
"version": "5.1.4",
},
},
}),
Repository: *util.Object2RawExtension(map[string]interface{}{
"url": "https://charts.kubevela.net/example/",
}),
},
}
cd.Spec.Workload.Type = types.AutoDetectWorkloadDefinition
Expect(k8sClient.Create(ctx, &cd)).Should(Succeed())
newAppName := "test-autodetect"
newApp := v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: newAppName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: "podinfo",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": map[string]interface{}{
"tag": "5.1.2",
},
}),
},
},
},
}
By("Create application")
Eventually(func() error {
return k8sClient.Create(ctx, newApp.DeepCopy())
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
By("Verify the workload(deployment) is created successfully by Helm")
deploy := &appsv1.Deployment{}
deployName := fmt.Sprintf("%s-%s-podinfo", newAppName, compName)
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy)
}, 120*time.Second, 5*time.Second).Should(Succeed())
})
It("Test store JSON schema of Helm Chart in ConfigMap", func() {
By("Get the ConfigMap")
cmName := fmt.Sprintf("component-schema-%s", cdName)
Eventually(func() error {
cm := &corev1.ConfigMap{}
if err := k8sClient.Get(ctx, client.ObjectKey{Name: cmName, Namespace: namespace}, cm); err != nil {
return err
}
if cm.Data[types.OpenapiV3JSONSchema] == "" {
return errors.New("json schema is not found in the ConfigMap")
}
return nil
}, 60*time.Second, 500*time.Millisecond).Should(Succeed())
})
})

View File

@@ -1,357 +0,0 @@
/*
Copyright 2021 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"
"errors"
"fmt"
"time"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/oam/util"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("Test application containing kube module", func() {
ctx := context.Background()
var (
appName = "test-app"
compName = "test-comp"
cdName = "test-kube-worker"
wdName = "test-kube-worker-wd"
tdName = "test-virtualgroup"
)
var namespace string
var app v1beta1.Application
var ns corev1.Namespace
var testTemplate = func() runtime.RawExtension {
yamlStr := `apiVersion: apps/v1
kind: Deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
ports:
- containerPort: 80 `
b, _ := yaml.YAMLToJSON([]byte(yamlStr))
return runtime.RawExtension{Raw: b}
}
BeforeEach(func() {
namespace = randomNamespaceName("kube-e2e-test")
ns = corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
Eventually(
func() error {
return k8sClient.Create(ctx, &ns)
},
time.Second*3, time.Millisecond*300).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
cd := v1beta1.ComponentDefinition{}
cd.SetName(cdName)
cd.SetNamespace(namespace)
cd.Spec.Workload.Definition = common.WorkloadGVK{APIVersion: "apps/v1", Kind: "Deployment"}
cd.Spec.Schematic = &common.Schematic{
KUBE: &common.Kube{
Template: testTemplate(),
Parameters: []common.KubeParameter{
{
Name: "image",
ValueType: common.StringType,
FieldPaths: []string{"spec.template.spec.containers[0].image"},
Required: pointer.Bool(true),
Description: pointer.String("test description"),
},
},
},
}
Expect(k8sClient.Create(ctx, &cd)).Should(Succeed())
By("Install a patch trait used to test CUE module")
td := v1beta1.TraitDefinition{}
td.SetName(tdName)
td.SetNamespace(namespace)
td.Spec.AppliesToWorkloads = []string{"deployments.apps"}
td.Spec.Schematic = &common.Schematic{
CUE: &common.CUE{
Template: `patch: {
spec: template: {
metadata: labels: {
if parameter.type == "namespace" {
"app.namespace.virtual.group": parameter.group
}
if parameter.type == "cluster" {
"app.cluster.virtual.group": parameter.group
}
}
}
}
parameter: {
group: *"default" | string
type: *"namespace" | string
}`,
},
}
Expect(k8sClient.Create(ctx, &td)).Should(Succeed())
By("Verify ComponentDefinition and TraitDefinition are created successfully")
Eventually(func() error {
if err := k8sClient.Get(ctx, client.ObjectKey{Name: cdName, Namespace: namespace}, &v1beta1.ComponentDefinition{}); err != nil {
return err
}
if err := k8sClient.Get(ctx, client.ObjectKey{Name: tdName, Namespace: namespace}, &v1beta1.TraitDefinition{}); err != nil {
return err
}
return nil
}, 20*time.Second, 500*time.Millisecond).Should(Succeed())
By("Add 'deployments.apps' to scaler's appliesToWorkloads")
scalerTd := v1beta1.TraitDefinition{}
Expect(k8sClient.Get(ctx, client.ObjectKey{Name: "scaler", Namespace: "vela-system"}, &scalerTd)).Should(Succeed())
scalerTd.Spec.AppliesToWorkloads = []string{"deployments.apps", "webservice", "worker"}
scalerTd.SetResourceVersion("")
Expect(k8sClient.Patch(ctx, &scalerTd, client.Merge)).Should(Succeed())
})
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.WorkloadDefinition{}, client.InNamespace(namespace))
k8sClient.DeleteAllOf(ctx, &v1beta1.TraitDefinition{}, client.InNamespace(namespace))
By(fmt.Sprintf("Delete the entire namespaceName %s", ns.Name))
Expect(k8sClient.Delete(ctx, &ns, client.PropagationPolicy(metav1.DeletePropagationForeground))).Should(Succeed())
By("Remove 'deployments.apps' from scaler's appliesToWorkloads")
scalerTd := v1beta1.TraitDefinition{}
Expect(k8sClient.Get(ctx, client.ObjectKey{Name: "scaler", Namespace: "vela-system"}, &scalerTd)).Should(Succeed())
scalerTd.Spec.AppliesToWorkloads = []string{"webservice", "worker"}
scalerTd.SetResourceVersion("")
Expect(k8sClient.Patch(ctx, &scalerTd, client.Merge)).Should(Succeed())
})
It("Test deploy an application containing kube module", func() {
app = v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: cdName,
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "nginx:1.14.0",
}),
Traits: []common.ApplicationTrait{
{
Type: "scaler",
Properties: util.Object2RawExtension(map[string]interface{}{
"replicas": 2,
}),
},
{
Type: tdName,
Properties: util.Object2RawExtension(map[string]interface{}{
"group": "my-group",
"type": "cluster",
}),
},
},
},
},
},
}
By("Create application")
Eventually(func() error {
return k8sClient.Create(ctx, app.DeepCopy())
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
By("Verify the workload(deployment) is created successfully")
deploy := &appsv1.Deployment{}
deployName := compName
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy)
}, 30*time.Second, 3*time.Second).Should(Succeed())
By("Verify two traits are applied to the workload")
Eventually(func() bool {
deploy := &appsv1.Deployment{}
if err := k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy); err != nil {
return false
}
By("Verify patch trait is applied")
templateLabels := deploy.Spec.Template.Labels
if templateLabels["app.cluster.virtual.group"] != "my-group" {
return false
}
By("Verify scaler trait is applied")
if *deploy.Spec.Replicas != 2 {
return false
}
By("Verify parameter is applied")
return deploy.Spec.Template.Spec.Containers[0].Image == "nginx:1.14.0"
}, 15*time.Second, 3*time.Second).Should(BeTrue())
By("Update the application")
app = v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: cdName,
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "nginx:1.14.1", // nginx:1.14.0 => nginx:1.14.1
}),
Traits: []common.ApplicationTrait{
{
Type: "scaler",
Properties: util.Object2RawExtension(map[string]interface{}{
"replicas": 3, // change 2 => 3
}),
},
{
Type: tdName,
Properties: util.Object2RawExtension(map[string]interface{}{
"group": "my-group-0", // change my-group => my-group-0
"type": "cluster",
}),
},
},
},
},
},
}
Expect(k8sClient.Patch(ctx, &app, client.Merge)).Should(Succeed())
By("Verify the workload(deployment) is created successfully")
deploy = &appsv1.Deployment{}
deployName = compName
By("Verify the changes are applied to the workload")
Eventually(func() bool {
deploy := &appsv1.Deployment{}
if err := k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy); err != nil {
return false
}
By("Verify new patch trait is applied")
templateLabels := deploy.Spec.Template.Labels
if templateLabels["app.cluster.virtual.group"] != "my-group-0" {
return false
}
By("Verify new scaler trait is applied")
if *deploy.Spec.Replicas != 3 {
return false
}
By("Verify new parameter is applied")
return deploy.Spec.Template.Spec.Containers[0].Image == "nginx:1.14.1"
}, 60*time.Second, 10*time.Second).Should(BeTrue())
})
It("Test deploy an application containing kube module defined by workloadDefinition", func() {
workloaddef := v1beta1.WorkloadDefinition{}
workloaddef.SetName(wdName)
workloaddef.SetNamespace(namespace)
workloaddef.Spec.Reference = common.DefinitionReference{Name: "deployments.apps", Version: "v1"}
workloaddef.Spec.Schematic = &common.Schematic{
KUBE: &common.Kube{
Template: testTemplate(),
Parameters: []common.KubeParameter{
{
Name: "image",
ValueType: common.StringType,
FieldPaths: []string{"spec.template.spec.containers[0].image"},
Required: pointer.Bool(true),
Description: pointer.String("test description"),
},
},
},
}
By("register workloadDefinition")
Expect(k8sClient.Create(ctx, &workloaddef)).Should(Succeed())
appTestName := "test-app-refer-to-workloaddef"
appTest := v1beta1.Application{
ObjectMeta: metav1.ObjectMeta{
Name: appTestName,
Namespace: namespace,
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{
{
Name: compName,
Type: cdName,
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "nginx:1.14.0",
}),
},
},
},
}
By("Create application")
Eventually(func() error {
return k8sClient.Create(ctx, appTest.DeepCopy())
}, 10*time.Second, 500*time.Millisecond).Should(Succeed())
By("Verify the workload(deployment) is created successfully")
deploy := &appsv1.Deployment{}
deployName := compName
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Name: deployName, Namespace: namespace}, deploy)
}, 15*time.Second, 3*time.Second).Should(Succeed())
})
It("Test store JSON schema of Kube parameter in ConfigMap", func() {
By("Get the ConfigMap")
cmName := fmt.Sprintf("component-schema-%s", cdName)
Eventually(func() error {
cm := &corev1.ConfigMap{}
if err := k8sClient.Get(ctx, client.ObjectKey{Name: cmName, Namespace: namespace}, cm); err != nil {
return err
}
if cm.Data[types.OpenapiV3JSONSchema] == "" {
return errors.New("json schema is not found in the ConfigMap")
}
return nil
}, 60*time.Second, 5*time.Second).Should(Succeed())
})
})