Chore: refactor workflow from workflow engine (#4631)

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>

Signed-off-by: FogDong <dongtianxin.tx@alibaba-inc.com>
This commit is contained in:
Tianxin Dong 2022-09-02 12:55:03 +08:00 committed by GitHub
parent a3e1c4d5ce
commit 239c5474dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
201 changed files with 2292 additions and 18416 deletions

1
.gitignore vendored
View File

@ -33,6 +33,7 @@ vendor/
# Vscode files
.vscode
.history
pkg/test/vela
config/crd/bases

View File

@ -26,6 +26,8 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
"github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/pkg/oam"
@ -268,33 +270,6 @@ type RawComponent struct {
Raw runtime.RawExtension `json:"raw"`
}
// StepStatus record the base status of workflow step, which could be workflow step or subStep
type StepStatus struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Phase WorkflowStepPhase `json:"phase,omitempty"`
// A human readable message indicating details about why the workflowStep is in this state.
Message string `json:"message,omitempty"`
// A brief CamelCase message indicating details about why the workflowStep is in this state.
Reason string `json:"reason,omitempty"`
// FirstExecuteTime is the first time this step execution.
FirstExecuteTime metav1.Time `json:"firstExecuteTime,omitempty"`
// LastExecuteTime is the last time this step execution.
LastExecuteTime metav1.Time `json:"lastExecuteTime,omitempty"`
}
// WorkflowStepStatus record the status of a workflow step, include step status and subStep status
type WorkflowStepStatus struct {
StepStatus `json:",inline"`
SubStepsStatus []WorkflowSubStepStatus `json:"subSteps,omitempty"`
}
// WorkflowSubStepStatus record the status of a workflow subStep
type WorkflowSubStepStatus struct {
StepStatus `json:",inline"`
}
// AppStatus defines the observed state of Application
type AppStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
@ -337,95 +312,26 @@ type PolicyStatus struct {
Status *runtime.RawExtension `json:"status,omitempty"`
}
// WorkflowStep defines how to execute a workflow step.
type WorkflowStep struct {
// Name is the unique name of the workflow step.
Name string `json:"name"`
Type string `json:"type"`
Meta *WorkflowStepMeta `json:"meta,omitempty"`
// +kubebuilder:pruning:PreserveUnknownFields
Properties *runtime.RawExtension `json:"properties,omitempty"`
SubSteps []WorkflowSubStep `json:"subSteps,omitempty"`
If string `json:"if,omitempty"`
Timeout string `json:"timeout,omitempty"`
DependsOn []string `json:"dependsOn,omitempty"`
Inputs StepInputs `json:"inputs,omitempty"`
Outputs StepOutputs `json:"outputs,omitempty"`
}
// WorkflowStepMeta contains the meta data of a workflow step
type WorkflowStepMeta struct {
Alias string `json:"alias,omitempty"`
}
// WorkflowSubStep defines how to execute a workflow subStep.
type WorkflowSubStep struct {
// Name is the unique name of the workflow step.
Name string `json:"name"`
Type string `json:"type"`
Meta *WorkflowStepMeta `json:"meta,omitempty"`
// +kubebuilder:pruning:PreserveUnknownFields
Properties *runtime.RawExtension `json:"properties,omitempty"`
If string `json:"if,omitempty"`
Timeout string `json:"timeout,omitempty"`
DependsOn []string `json:"dependsOn,omitempty"`
Inputs StepInputs `json:"inputs,omitempty"`
Outputs StepOutputs `json:"outputs,omitempty"`
}
// WorkflowStatus record the status of workflow
type WorkflowStatus struct {
AppRevision string `json:"appRevision,omitempty"`
Mode WorkflowMode `json:"mode"`
Message string `json:"message,omitempty"`
AppRevision string `json:"appRevision,omitempty"`
Mode string `json:"mode"`
Phase workflowv1alpha1.WorkflowRunPhase `json:"status,omitempty"`
Message string `json:"message,omitempty"`
Suspend bool `json:"suspend"`
SuspendState string `json:"suspendState,omitempty"`
Suspend bool `json:"suspend"`
Terminated bool `json:"terminated"`
Finished bool `json:"finished"`
ContextBackend *corev1.ObjectReference `json:"contextBackend,omitempty"`
Steps []WorkflowStepStatus `json:"steps,omitempty"`
ContextBackend *corev1.ObjectReference `json:"contextBackend,omitempty"`
Steps []workflowv1alpha1.WorkflowStepStatus `json:"steps,omitempty"`
StartTime metav1.Time `json:"startTime,omitempty"`
EndTime metav1.Time `json:"endTime,omitempty"`
}
// WorkflowStepPhase describes the phase of a workflow step.
type WorkflowStepPhase string
const (
// WorkflowStepPhaseSucceeded will make the controller run the next step.
WorkflowStepPhaseSucceeded WorkflowStepPhase = "succeeded"
// WorkflowStepPhaseFailed will report error in `message`.
WorkflowStepPhaseFailed WorkflowStepPhase = "failed"
// WorkflowStepPhaseSkipped will make the controller skip the step.
WorkflowStepPhaseSkipped WorkflowStepPhase = "skipped"
// WorkflowStepPhaseStopped will make the controller stop the workflow.
WorkflowStepPhaseStopped WorkflowStepPhase = "stopped"
// WorkflowStepPhaseRunning will make the controller continue the workflow.
WorkflowStepPhaseRunning WorkflowStepPhase = "running"
// WorkflowStepPhasePending will make the controller wait for the step to run.
WorkflowStepPhasePending WorkflowStepPhase = "pending"
)
// DefinitionType describes the type of DefinitionRevision.
// +kubebuilder:validation:Enum=Component;Trait;Policy;WorkflowStep
type DefinitionType string
@ -444,16 +350,6 @@ const (
WorkflowStepType DefinitionType = "WorkflowStep"
)
// WorkflowMode describes the mode of workflow
type WorkflowMode string
const (
// WorkflowModeDAG describes the DAG mode of workflow
WorkflowModeDAG WorkflowMode = "DAG"
// WorkflowModeStep describes the step by step mode of workflow
WorkflowModeStep WorkflowMode = "StepByStep"
)
// AppRolloutStatus defines the observed state of AppRollout
type AppRolloutStatus struct {
v1alpha1.RolloutStatus `json:",inline"`
@ -483,9 +379,9 @@ type ApplicationComponent struct {
// +kubebuilder:pruning:PreserveUnknownFields
Properties *runtime.RawExtension `json:"properties,omitempty"`
DependsOn []string `json:"dependsOn,omitempty"`
Inputs StepInputs `json:"inputs,omitempty"`
Outputs StepOutputs `json:"outputs,omitempty"`
DependsOn []string `json:"dependsOn,omitempty"`
Inputs workflowv1alpha1.StepInputs `json:"inputs,omitempty"`
Outputs workflowv1alpha1.StepOutputs `json:"outputs,omitempty"`
// Traits define the trait of one component, the type must be array to keep the order.
Traits []ApplicationTrait `json:"traits,omitempty"`
@ -500,22 +396,6 @@ type ApplicationComponent struct {
ReplicaKey string `json:"-"`
}
// StepOutputs defines output variable of WorkflowStep
type StepOutputs []outputItem
// StepInputs defines variable input of WorkflowStep
type StepInputs []inputItem
type inputItem struct {
ParameterKey string `json:"parameterKey"`
From string `json:"from"`
}
type outputItem struct {
ValueFrom string `json:"valueFrom"`
Name string `json:"name"`
}
// ClusterSelector defines the rules to select a Cluster resource.
// Either name or labels is needed.
type ClusterSelector struct {
@ -542,16 +422,13 @@ type ClusterPlacement struct {
Distribution Distribution `json:"distribution,omitempty"`
}
// ResourceCreatorRole defines the resource creator.
type ResourceCreatorRole string
const (
// PolicyResourceCreator create the policy resource.
PolicyResourceCreator ResourceCreatorRole = "policy"
PolicyResourceCreator string = "policy"
// WorkflowResourceCreator create the resource in workflow.
WorkflowResourceCreator ResourceCreatorRole = "workflow"
WorkflowResourceCreator string = "workflow"
// DebugResourceCreator create the debug resource.
DebugResourceCreator ResourceCreatorRole = "debug"
DebugResourceCreator string = "debug"
)
// OAMObjectReference defines the object reference for an oam resource
@ -598,8 +475,8 @@ func NewOAMObjectReferenceFromObject(obj client.Object) OAMObjectReference {
// ClusterObjectReference defines the object reference with cluster.
type ClusterObjectReference struct {
Cluster string `json:"cluster,omitempty"`
Creator ResourceCreatorRole `json:"creator,omitempty"`
Cluster string `json:"cluster,omitempty"`
Creator string `json:"creator,omitempty"`
corev1.ObjectReference `json:",inline"`
}

View File

@ -22,6 +22,7 @@ limitations under the License.
package common
import (
"github.com/kubevela/workflow/api/v1alpha1"
crossplane_runtime "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -108,12 +109,12 @@ func (in *ApplicationComponent) DeepCopyInto(out *ApplicationComponent) {
}
if in.Inputs != nil {
in, out := &in.Inputs, &out.Inputs
*out = make(StepInputs, len(*in))
*out = make(v1alpha1.StepInputs, len(*in))
copy(*out, *in)
}
if in.Outputs != nil {
in, out := &in.Outputs, &out.Outputs
*out = make(StepOutputs, len(*in))
*out = make(v1alpha1.StepOutputs, len(*in))
copy(*out, *in)
}
if in.Traits != nil {
@ -573,61 +574,6 @@ func (in *Status) DeepCopy() *Status {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in StepInputs) DeepCopyInto(out *StepInputs) {
{
in := &in
*out = make(StepInputs, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepInputs.
func (in StepInputs) DeepCopy() StepInputs {
if in == nil {
return nil
}
out := new(StepInputs)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in StepOutputs) DeepCopyInto(out *StepOutputs) {
{
in := &in
*out = make(StepOutputs, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepOutputs.
func (in StepOutputs) DeepCopy() StepOutputs {
if in == nil {
return nil
}
out := new(StepOutputs)
in.DeepCopyInto(out)
return *out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *StepStatus) DeepCopyInto(out *StepStatus) {
*out = *in
in.FirstExecuteTime.DeepCopyInto(&out.FirstExecuteTime)
in.LastExecuteTime.DeepCopyInto(&out.LastExecuteTime)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepStatus.
func (in *StepStatus) DeepCopy() *StepStatus {
if in == nil {
return nil
}
out := new(StepStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Terraform) DeepCopyInto(out *Terraform) {
*out = *in
@ -663,12 +609,13 @@ func (in *WorkflowStatus) DeepCopyInto(out *WorkflowStatus) {
}
if in.Steps != nil {
in, out := &in.Steps, &out.Steps
*out = make([]WorkflowStepStatus, len(*in))
*out = make([]v1alpha1.WorkflowStepStatus, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.StartTime.DeepCopyInto(&out.StartTime)
in.EndTime.DeepCopyInto(&out.EndTime)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStatus.
@ -681,147 +628,6 @@ func (in *WorkflowStatus) DeepCopy() *WorkflowStatus {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkflowStep) DeepCopyInto(out *WorkflowStep) {
*out = *in
if in.Meta != nil {
in, out := &in.Meta, &out.Meta
*out = new(WorkflowStepMeta)
**out = **in
}
if in.Properties != nil {
in, out := &in.Properties, &out.Properties
*out = new(runtime.RawExtension)
(*in).DeepCopyInto(*out)
}
if in.SubSteps != nil {
in, out := &in.SubSteps, &out.SubSteps
*out = make([]WorkflowSubStep, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.DependsOn != nil {
in, out := &in.DependsOn, &out.DependsOn
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Inputs != nil {
in, out := &in.Inputs, &out.Inputs
*out = make(StepInputs, len(*in))
copy(*out, *in)
}
if in.Outputs != nil {
in, out := &in.Outputs, &out.Outputs
*out = make(StepOutputs, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStep.
func (in *WorkflowStep) DeepCopy() *WorkflowStep {
if in == nil {
return nil
}
out := new(WorkflowStep)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkflowStepMeta) DeepCopyInto(out *WorkflowStepMeta) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStepMeta.
func (in *WorkflowStepMeta) DeepCopy() *WorkflowStepMeta {
if in == nil {
return nil
}
out := new(WorkflowStepMeta)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkflowStepStatus) DeepCopyInto(out *WorkflowStepStatus) {
*out = *in
in.StepStatus.DeepCopyInto(&out.StepStatus)
if in.SubStepsStatus != nil {
in, out := &in.SubStepsStatus, &out.SubStepsStatus
*out = make([]WorkflowSubStepStatus, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStepStatus.
func (in *WorkflowStepStatus) DeepCopy() *WorkflowStepStatus {
if in == nil {
return nil
}
out := new(WorkflowStepStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkflowSubStep) DeepCopyInto(out *WorkflowSubStep) {
*out = *in
if in.Meta != nil {
in, out := &in.Meta, &out.Meta
*out = new(WorkflowStepMeta)
**out = **in
}
if in.Properties != nil {
in, out := &in.Properties, &out.Properties
*out = new(runtime.RawExtension)
(*in).DeepCopyInto(*out)
}
if in.DependsOn != nil {
in, out := &in.DependsOn, &out.DependsOn
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Inputs != nil {
in, out := &in.Inputs, &out.Inputs
*out = make(StepInputs, len(*in))
copy(*out, *in)
}
if in.Outputs != nil {
in, out := &in.Outputs, &out.Outputs
*out = make(StepOutputs, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowSubStep.
func (in *WorkflowSubStep) DeepCopy() *WorkflowSubStep {
if in == nil {
return nil
}
out := new(WorkflowSubStep)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkflowSubStepStatus) DeepCopyInto(out *WorkflowSubStepStatus) {
*out = *in
in.StepStatus.DeepCopyInto(&out.StepStatus)
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowSubStepStatus.
func (in *WorkflowSubStepStatus) DeepCopy() *WorkflowSubStepStatus {
if in == nil {
return nil
}
out := new(WorkflowSubStepStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkloadGVK) DeepCopyInto(out *WorkloadGVK) {
*out = *in

View File

@ -19,8 +19,6 @@ package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
)
// +kubebuilder:object:root=true
@ -49,27 +47,3 @@ type PolicyList struct {
metav1.ListMeta `json:"metadata,omitempty"`
Items []Policy `json:"items"`
}
// +kubebuilder:object:root=true
// Workflow is the Schema for the policy API
// +kubebuilder:storageversion
// +kubebuilder:resource:categories={oam}
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type Workflow struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Steps []common.WorkflowStep `json:"steps,omitempty"`
}
// +kubebuilder:object:root=true
// WorkflowList contains a list of Workflow
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
type WorkflowList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Workflow `json:"items"`
}

View File

@ -20,6 +20,8 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
)
@ -54,5 +56,5 @@ var (
func init() {
SchemeBuilder.Register(&Policy{}, &PolicyList{})
SchemeBuilder.Register(&Workflow{}, &WorkflowList{})
SchemeBuilder.Register(&workflowv1alpha1.Workflow{}, &workflowv1alpha1.WorkflowList{})
}

View File

@ -735,67 +735,3 @@ func (in *TopologyPolicySpec) DeepCopy() *TopologyPolicySpec {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Workflow) DeepCopyInto(out *Workflow) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
if in.Steps != nil {
in, out := &in.Steps, &out.Steps
*out = make([]common.WorkflowStep, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Workflow.
func (in *Workflow) DeepCopy() *Workflow {
if in == nil {
return nil
}
out := new(Workflow)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Workflow) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkflowList) DeepCopyInto(out *WorkflowList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Workflow, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowList.
func (in *WorkflowList) DeepCopy() *WorkflowList {
if in == nil {
return nil
}
out := new(WorkflowList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *WorkflowList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}

View File

@ -23,6 +23,8 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
)
@ -49,20 +51,11 @@ type AppPolicy struct {
Properties *runtime.RawExtension `json:"properties,omitempty"`
}
// WorkflowStep defines how to execute a workflow step.
type WorkflowStep common.WorkflowStep
// Workflow defines workflow steps and other attributes
type Workflow struct {
Ref string `json:"ref,omitempty"`
Mode *WorkflowExecuteMode `json:"mode,omitempty"`
Steps []WorkflowStep `json:"steps,omitempty"`
}
// WorkflowExecuteMode defines the mode of workflow execution
type WorkflowExecuteMode struct {
Steps common.WorkflowMode `json:"steps,omitempty"`
SubSteps common.WorkflowMode `json:"subSteps,omitempty"`
Ref string `json:"ref,omitempty"`
Mode *workflowv1alpha1.WorkflowExecuteMode `json:"mode,omitempty"`
Steps []workflowv1alpha1.WorkflowStep `json:"steps,omitempty"`
}
// ApplicationSpec is the spec of Application

View File

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

View File

@ -290,7 +290,7 @@ func (in *ResourceTracker) ContainsManagedResource(rsc client.Object) bool {
}
// AddManagedResource add object to managed resources, if exists, update
func (in *ResourceTracker) AddManagedResource(rsc client.Object, metaOnly bool, skipGC bool, creator common.ResourceCreatorRole) (updated bool) {
func (in *ResourceTracker) AddManagedResource(rsc client.Object, metaOnly bool, skipGC bool, creator string) (updated bool) {
mr := newManagedResourceFromResource(rsc)
mr.SkipGC = skipGC
if !metaOnly {

View File

@ -22,11 +22,12 @@ limitations under the License.
package v1beta1
import (
"github.com/kubevela/workflow/api/v1alpha1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"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"
core_oam_devv1alpha1 "github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
@ -222,7 +223,7 @@ func (in *ApplicationRevisionSpec) DeepCopyInto(out *ApplicationRevisionSpec) {
}
if in.Policies != nil {
in, out := &in.Policies, &out.Policies
*out = make(map[string]v1alpha1.Policy, len(*in))
*out = make(map[string]core_oam_devv1alpha1.Policy, len(*in))
for key, val := range *in {
(*out)[key] = *val.DeepCopy()
}
@ -945,12 +946,12 @@ func (in *Workflow) DeepCopyInto(out *Workflow) {
*out = *in
if in.Mode != nil {
in, out := &in.Mode, &out.Mode
*out = new(WorkflowExecuteMode)
*out = new(v1alpha1.WorkflowExecuteMode)
**out = **in
}
if in.Steps != nil {
in, out := &in.Steps, &out.Steps
*out = make([]WorkflowStep, len(*in))
*out = make([]v1alpha1.WorkflowStep, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
@ -967,68 +968,6 @@ func (in *Workflow) DeepCopy() *Workflow {
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkflowExecuteMode) DeepCopyInto(out *WorkflowExecuteMode) {
*out = *in
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowExecuteMode.
func (in *WorkflowExecuteMode) DeepCopy() *WorkflowExecuteMode {
if in == nil {
return nil
}
out := new(WorkflowExecuteMode)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkflowStep) DeepCopyInto(out *WorkflowStep) {
*out = *in
if in.Meta != nil {
in, out := &in.Meta, &out.Meta
*out = new(common.WorkflowStepMeta)
**out = **in
}
if in.Properties != nil {
in, out := &in.Properties, &out.Properties
*out = new(runtime.RawExtension)
(*in).DeepCopyInto(*out)
}
if in.SubSteps != nil {
in, out := &in.SubSteps, &out.SubSteps
*out = make([]common.WorkflowSubStep, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
if in.DependsOn != nil {
in, out := &in.DependsOn, &out.DependsOn
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Inputs != nil {
in, out := &in.Inputs, &out.Inputs
*out = make(common.StepInputs, len(*in))
copy(*out, *in)
}
if in.Outputs != nil {
in, out := &in.Outputs, &out.Outputs
*out = make(common.StepOutputs, len(*in))
copy(*out, *in)
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStep.
func (in *WorkflowStep) DeepCopy() *WorkflowStep {
if in == nil {
return nil
}
out := new(WorkflowStep)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *WorkflowStepDefinition) DeepCopyInto(out *WorkflowStepDefinition) {
*out = *in

View File

@ -461,8 +461,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource
creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead
@ -844,16 +842,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition
of a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of
@ -889,8 +893,9 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the
status of a workflow subStep
description: StepStatus record the base status
of workflow step, which could be workflow step
or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first
@ -2218,14 +2223,16 @@ spec:
step.
properties:
dependsOn:
description: DependsOn is the dependency of the
step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of
WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -2238,8 +2245,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta
data of a workflow step
description: Meta is the meta data of the workflow
step.
properties:
alias:
type: string
@ -2249,8 +2256,7 @@ spec:
step.
type: string
outputs:
description: StepOutputs defines output variable
of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -2263,22 +2269,27 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the
step
type: object
x-kubernetes-preserve-unknown-fields: true
subSteps:
items:
description: WorkflowSubStep defines how to execute
a workflow subStep.
description: WorkflowStepBase defines the workflow
step base
properties:
dependsOn:
description: DependsOn is the dependency of
the step
items:
type: string
type: array
if:
description: If is the if condition of the
step
type: string
inputs:
description: StepInputs defines variable input
of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -2291,8 +2302,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the
meta data of a workflow step
description: Meta is the meta data of the
workflow step.
properties:
alias:
type: string
@ -2302,8 +2313,8 @@ spec:
workflow step.
type: string
outputs:
description: StepOutputs defines output variable
of WorkflowStep
description: Outputs is the outputs of the
step
items:
properties:
name:
@ -2316,11 +2327,17 @@ spec:
type: object
type: array
properties:
description: Properties is the properties
of the step
type: object
x-kubernetes-preserve-unknown-fields: true
timeout:
description: Timeout is the timeout of the
step
type: string
type:
description: Type is the type of the workflow
step.
type: string
required:
- name
@ -2328,8 +2345,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -2356,8 +2375,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource
creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead
@ -2739,16 +2756,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition
of a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of
@ -2784,8 +2807,9 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the
status of a workflow subStep
description: StepStatus record the base status
of workflow step, which could be workflow step
or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first
@ -3986,13 +4010,15 @@ spec:
step.
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -4005,8 +4031,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of
a workflow step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -4015,7 +4040,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -4028,22 +4053,24 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
subSteps:
items:
description: WorkflowSubStep defines how to execute a
workflow subStep.
description: WorkflowStepBase defines the workflow step
base
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of
WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -4056,8 +4083,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data
of a workflow step
description: Meta is the meta data of the workflow
step.
properties:
alias:
type: string
@ -4067,8 +4094,7 @@ spec:
step.
type: string
outputs:
description: StepOutputs defines output variable of
WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -4081,11 +4107,14 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -4093,8 +4122,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -4763,16 +4794,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition of
a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of a workflow
@ -4806,8 +4843,8 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the status of
a workflow subStep
description: StepStatus record the base status of workflow
step, which could be workflow step or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first time this

View File

@ -414,7 +414,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead of
@ -767,16 +766,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition of
a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of a workflow
@ -810,8 +815,8 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the status of
a workflow subStep
description: StepStatus record the base status of workflow
step, which could be workflow step or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first time this
@ -1029,13 +1034,15 @@ spec:
step.
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -1048,8 +1055,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of
a workflow step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -1058,7 +1064,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -1071,22 +1077,24 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
subSteps:
items:
description: WorkflowSubStep defines how to execute a
workflow subStep.
description: WorkflowStepBase defines the workflow step
base
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of
WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -1099,8 +1107,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data
of a workflow step
description: Meta is the meta data of the workflow
step.
properties:
alias:
type: string
@ -1110,8 +1118,7 @@ spec:
step.
type: string
outputs:
description: StepOutputs defines output variable of
WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -1124,11 +1131,14 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -1136,8 +1146,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -1164,7 +1176,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead of
@ -1517,16 +1528,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition of
a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of a workflow
@ -1560,8 +1577,8 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the status of
a workflow subStep
description: StepStatus record the base status of workflow
step, which could be workflow step or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first time this

View File

@ -79,7 +79,6 @@ spec:
component:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
deleted:
description: Deleted marks the resource to be deleted
@ -147,7 +146,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead of

View File

@ -20,7 +20,7 @@ spec:
- name: v1alpha1
schema:
openAPIV3Schema:
description: Workflow is the Schema for the policy API
description: Workflow is the Schema for the workflow API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
@ -39,13 +39,15 @@ spec:
description: WorkflowStep defines how to execute a workflow step.
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -58,8 +60,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of a workflow
step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -68,7 +69,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -81,21 +82,23 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
subSteps:
items:
description: WorkflowSubStep defines how to execute a workflow
subStep.
description: WorkflowStepBase defines the workflow step base
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -108,8 +111,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of a
workflow step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -118,7 +120,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -131,11 +133,14 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -143,8 +148,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -176,13 +183,15 @@ spec:
description: WorkflowStep defines how to execute a workflow step.
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -195,8 +204,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of a workflow
step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -205,7 +213,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -218,21 +226,23 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
subSteps:
items:
description: WorkflowSubStep defines how to execute a workflow
subStep.
description: WorkflowStepBase defines the workflow step base
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -245,8 +255,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of a
workflow step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -255,7 +264,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -268,11 +277,14 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -280,8 +292,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name

View File

@ -117,7 +117,7 @@ spec:
text: string
blocks?: *null | close([...block])
attachments?: *null | close({
blocks?: *null | [...block]
blocks?: *null | close([...block])
color?: string
})
thread_ts?: string

View File

@ -461,8 +461,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource
creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead
@ -844,16 +842,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition
of a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of
@ -889,8 +893,9 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the
status of a workflow subStep
description: StepStatus record the base status
of workflow step, which could be workflow step
or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first
@ -2218,14 +2223,16 @@ spec:
step.
properties:
dependsOn:
description: DependsOn is the dependency of the
step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of
WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -2238,8 +2245,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta
data of a workflow step
description: Meta is the meta data of the workflow
step.
properties:
alias:
type: string
@ -2249,8 +2256,7 @@ spec:
step.
type: string
outputs:
description: StepOutputs defines output variable
of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -2263,22 +2269,27 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the
step
type: object
x-kubernetes-preserve-unknown-fields: true
subSteps:
items:
description: WorkflowSubStep defines how to execute
a workflow subStep.
description: WorkflowStepBase defines the workflow
step base
properties:
dependsOn:
description: DependsOn is the dependency of
the step
items:
type: string
type: array
if:
description: If is the if condition of the
step
type: string
inputs:
description: StepInputs defines variable input
of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -2291,8 +2302,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the
meta data of a workflow step
description: Meta is the meta data of the
workflow step.
properties:
alias:
type: string
@ -2302,8 +2313,8 @@ spec:
workflow step.
type: string
outputs:
description: StepOutputs defines output variable
of WorkflowStep
description: Outputs is the outputs of the
step
items:
properties:
name:
@ -2316,11 +2327,17 @@ spec:
type: object
type: array
properties:
description: Properties is the properties
of the step
type: object
x-kubernetes-preserve-unknown-fields: true
timeout:
description: Timeout is the timeout of the
step
type: string
type:
description: Type is the type of the workflow
step.
type: string
required:
- name
@ -2328,8 +2345,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -2356,8 +2375,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource
creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead
@ -2739,16 +2756,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition
of a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of
@ -2784,8 +2807,9 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the
status of a workflow subStep
description: StepStatus record the base status
of workflow step, which could be workflow step
or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first
@ -3986,13 +4010,15 @@ spec:
step.
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -4005,8 +4031,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of
a workflow step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -4015,7 +4040,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -4028,22 +4053,24 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
subSteps:
items:
description: WorkflowSubStep defines how to execute a
workflow subStep.
description: WorkflowStepBase defines the workflow step
base
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of
WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -4056,8 +4083,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data
of a workflow step
description: Meta is the meta data of the workflow
step.
properties:
alias:
type: string
@ -4067,8 +4094,7 @@ spec:
step.
type: string
outputs:
description: StepOutputs defines output variable of
WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -4081,11 +4107,14 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -4093,8 +4122,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -4763,16 +4794,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition of
a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of a workflow
@ -4806,8 +4843,8 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the status of
a workflow subStep
description: StepStatus record the base status of workflow
step, which could be workflow step or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first time this

View File

@ -414,7 +414,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead of
@ -767,16 +766,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition of
a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of a workflow
@ -810,8 +815,8 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the status of
a workflow subStep
description: StepStatus record the base status of workflow
step, which could be workflow step or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first time this
@ -1029,13 +1034,15 @@ spec:
step.
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -1048,8 +1055,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of
a workflow step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -1058,7 +1064,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -1071,22 +1077,24 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
subSteps:
items:
description: WorkflowSubStep defines how to execute a
workflow subStep.
description: WorkflowStepBase defines the workflow step
base
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of
WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -1099,8 +1107,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data
of a workflow step
description: Meta is the meta data of the workflow
step.
properties:
alias:
type: string
@ -1110,8 +1118,7 @@ spec:
step.
type: string
outputs:
description: StepOutputs defines output variable of
WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -1124,11 +1131,14 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
x-kubernetes-preserve-unknown-fields: true
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -1136,8 +1146,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -1164,7 +1176,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead of
@ -1517,16 +1528,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition of
a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of a workflow
@ -1560,8 +1577,8 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the status of
a workflow subStep
description: StepStatus record the base status of workflow
step, which could be workflow step or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first time this

View File

@ -79,7 +79,6 @@ spec:
component:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
deleted:
description: Deleted marks the resource to be deleted
@ -147,7 +146,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead of

View File

@ -117,7 +117,7 @@ spec:
text: string
blocks?: *null | close([...block])
attachments?: *null | close({
blocks?: *null | [...block]
blocks?: *null | close([...block])
color?: string
})
thread_ts?: string

View File

@ -36,6 +36,9 @@ import (
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"github.com/kubevela/workflow/pkg/cue/packages"
wfTypes "github.com/kubevela/workflow/pkg/types"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/auth"
@ -45,7 +48,6 @@ import (
oamcontroller "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
oamv1alpha2 "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2"
"github.com/oam-dev/kubevela/pkg/controller/utils"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/features"
_ "github.com/oam-dev/kubevela/pkg/monitor/metrics"
"github.com/oam-dev/kubevela/pkg/monitor/watcher"
@ -57,7 +59,6 @@ import (
"github.com/oam-dev/kubevela/pkg/utils/system"
"github.com/oam-dev/kubevela/pkg/utils/util"
oamwebhook "github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev"
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
"github.com/oam-dev/kubevela/version"
)

51
go.mod
View File

@ -32,8 +32,10 @@ require (
github.com/fluxcd/helm-controller/api v0.21.0
github.com/fluxcd/source-controller/api v0.24.4
github.com/form3tech-oss/jwt-go v3.2.3+incompatible
github.com/gdamore/tcell/v2 v2.5.2
github.com/gertd/go-pluralize v0.1.7
github.com/getkin/kin-openapi v0.94.0
github.com/ghodss/yaml v1.0.0
github.com/go-logr/logr v1.2.2
github.com/go-openapi/spec v0.19.8
github.com/go-playground/validator/v10 v10.9.0
@ -42,6 +44,7 @@ require (
github.com/google/go-containerregistry v0.9.0
github.com/google/go-github/v32 v32.1.0
github.com/google/uuid v1.3.0
github.com/gorilla/websocket v1.4.2
github.com/gosuri/uilive v0.0.4
github.com/gosuri/uitable v0.0.4
github.com/hashicorp/go-version v1.3.0
@ -51,6 +54,7 @@ require (
github.com/klauspost/compress v1.15.9
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c
github.com/kubevela/prism v1.4.1-0.20220613123457-94f1190f87c2
github.com/kubevela/workflow v0.0.0-20220902034653-f90574237d75
github.com/kyokomi/emoji v2.2.4+incompatible
github.com/mitchellh/hashstructure/v2 v2.0.1
github.com/oam-dev/cluster-gateway v1.4.0
@ -60,10 +64,10 @@ require (
github.com/olekukonko/tablewriter v0.0.5
github.com/onsi/ginkgo v1.16.5
github.com/onsi/gomega v1.19.0
github.com/opencontainers/runc v1.1.3 // indirect
github.com/openkruise/kruise-api v1.1.0
github.com/pkg/errors v0.9.1
github.com/prometheus/client_golang v1.11.0
github.com/rivo/tview v0.0.0-20220709181631-73bf2902b59a
github.com/robfig/cron/v3 v3.0.1
github.com/rogpeppe/go-internal v1.8.1
github.com/sirupsen/logrus v1.8.1
@ -80,10 +84,7 @@ require (
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a // indirect
gomodules.xyz/jsonpatch/v2 v2.2.0
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
gopkg.in/src-d/go-git.v4 v4.13.1
gopkg.in/yaml.v3 v3.0.1
gotest.tools v2.2.0+incompatible
@ -107,30 +108,11 @@ require (
open-cluster-management.io/api v0.7.0
sigs.k8s.io/controller-runtime v0.11.2
sigs.k8s.io/controller-tools v0.6.2
sigs.k8s.io/gateway-api v0.4.3
sigs.k8s.io/kind v0.9.0
sigs.k8s.io/yaml v1.3.0
)
require (
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/ghodss/yaml v1.0.0
github.com/gorilla/websocket v1.4.2
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/openkruise/rollouts v0.1.1-0.20220622054609-149e5a48da5e
github.com/xanzy/ssh-agent v0.3.0 // indirect
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
google.golang.org/protobuf v1.28.0 // indirect
sigs.k8s.io/gateway-api v0.4.3
)
require (
github.com/gdamore/tcell/v2 v2.5.2
github.com/rivo/tview v0.0.0-20220709181631-73bf2902b59a
)
require (
cloud.google.com/go/compute v1.7.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
@ -164,7 +146,7 @@ require (
github.com/aws/aws-sdk-go v1.36.30 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver v3.5.1+incompatible // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
github.com/cockroachdb/apd/v2 v2.0.1 // indirect
github.com/containerd/continuity v0.1.0 // indirect
@ -174,6 +156,7 @@ require (
github.com/creack/pty v1.1.11 // indirect
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
github.com/docker/cli v20.10.16+incompatible // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/docker v20.10.16+incompatible // indirect
github.com/docker/docker-credential-helpers v0.6.4 // indirect
github.com/docker/go-connections v0.4.0 // indirect
@ -216,6 +199,8 @@ require (
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
@ -225,6 +210,7 @@ require (
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
github.com/kr/pretty v0.3.0 // indirect
github.com/kr/pty v1.1.8 // indirect
github.com/kr/text v0.2.0 // indirect
@ -257,14 +243,16 @@ require (
github.com/nxadm/tail v1.4.8 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20220114050600-8b9d41f48198 // indirect
github.com/opencontainers/runc v1.1.3 // indirect
github.com/openkruise/rollouts v0.1.1-0.20220622054609-149e5a48da5e
github.com/openshift/library-go v0.0.0-20220112153822-ac82336bd076 // indirect
github.com/pelletier/go-toml v1.9.4 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.28.0 // indirect
github.com/prometheus/procfs v0.6.0 // indirect
github.com/prometheus/common v0.32.1 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/protocolbuffers/txtpbfmt v0.0.0-20220428173112-74888fd59c2b // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rubenv/sql-migrate v0.0.0-20210614095031-55d5740dbbcc // indirect
@ -278,6 +266,7 @@ require (
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tjfoc/gmsm v1.3.2 // indirect
github.com/xanzy/ssh-agent v0.3.0 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.0.2 // indirect
github.com/xdg-go/stringprep v1.0.2 // indirect
@ -301,16 +290,22 @@ require (
go.opentelemetry.io/otel/trace v0.20.0 // indirect
go.opentelemetry.io/proto/otlp v0.7.0 // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a // indirect
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03 // indirect
google.golang.org/grpc v1.47.0 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/gorp.v1 v1.7.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.63.2 // indirect

14
go.sum
View File

@ -367,8 +367,9 @@ github.com/cespare/xxhash v0.0.0-20181017004759-096ff4a8a059/go.mod h1:XrSqR1Vqq
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8=
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
github.com/charithe/durationcheck v0.0.8/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg=
@ -1378,6 +1379,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kubevela/prism v1.4.1-0.20220613123457-94f1190f87c2 h1:TaHlO4raKI3ehVSYY8QixYMHdI0VwKHY1KPNWcUre3I=
github.com/kubevela/prism v1.4.1-0.20220613123457-94f1190f87c2/go.mod h1:RP69+bRb57Occer6BeeF5zK3hrD1IhnYf2RNRsIdh9E=
github.com/kubevela/workflow v0.0.0-20220902034653-f90574237d75 h1:cFaaF3N38HGt04GmfmqA/IxwyB2COTgpP/lJM249fV8=
github.com/kubevela/workflow v0.0.0-20220902034653-f90574237d75/go.mod h1:zp/JKGCy6T0vEvIpWOrmJ9owB+BIIUwsfEIFOm+4/FE=
github.com/kulti/thelper v0.4.0/go.mod h1:vMu2Cizjy/grP+jmsvOFDx1kYP6+PD1lqg4Yu5exl2U=
github.com/kunwardeep/paralleltest v1.0.2/go.mod h1:ZPqNm1fVHPllh5LPVujzbVz1JN2GhLxSfY+oqUsvG30=
github.com/kunwardeep/paralleltest v1.0.3/go.mod h1:vLydzomDFpk7yu5UX02RmP0H8QfRPOV/oFhWN85Mjb4=
@ -1808,8 +1811,9 @@ github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt2
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
github.com/prometheus/common v0.28.0 h1:vGVfV9KrDTvWt5boZO0I19g2E3CsWfpPPKZM9dt3mEw=
github.com/prometheus/common v0.28.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4=
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
github.com/prometheus/procfs v0.0.0-20180125133057-cb4147076ac7/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@ -1825,8 +1829,9 @@ github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+Gx
github.com/prometheus/procfs v0.0.11/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
github.com/prometheus/prometheus v0.0.0-20180315085919-58e2a31db8de/go.mod h1:oAIUtOny2rjMX0OWN5vPR5/q/twIROJvdqnQKDdil/s=
github.com/prometheus/prometheus v1.8.2-0.20200110114423-1e64d757f711/go.mod h1:7U90zPoLkWjEIQcy/rweQla82OCTUzxVHE51G3OhJbI=
github.com/prometheus/prometheus v1.8.2-0.20200507164740-ecee9c8abfd1/go.mod h1:S5n0C6tSgdnwWshBUceRx5G1OsjLv/EeZ9t3wIfEtsY=
@ -2220,8 +2225,9 @@ go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADbpZtnU=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=

View File

@ -461,8 +461,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource
creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead
@ -844,16 +842,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition
of a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of
@ -889,8 +893,9 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the
status of a workflow subStep
description: StepStatus record the base status
of workflow step, which could be workflow step
or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first
@ -2218,14 +2223,16 @@ spec:
step.
properties:
dependsOn:
description: DependsOn is the dependency of the
step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of
WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -2238,8 +2245,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta
data of a workflow step
description: Meta is the meta data of the workflow
step.
properties:
alias:
type: string
@ -2249,8 +2256,7 @@ spec:
step.
type: string
outputs:
description: StepOutputs defines output variable
of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -2263,22 +2269,27 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the
step
type: object
subSteps:
items:
description: WorkflowSubStep defines how to execute
a workflow subStep.
description: WorkflowStepBase defines the workflow
step base
properties:
dependsOn:
description: DependsOn is the dependency of
the step
items:
type: string
type: array
if:
description: If is the if condition of the
step
type: string
inputs:
description: StepInputs defines variable input
of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -2291,8 +2302,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the
meta data of a workflow step
description: Meta is the meta data of the
workflow step.
properties:
alias:
type: string
@ -2302,8 +2313,8 @@ spec:
workflow step.
type: string
outputs:
description: StepOutputs defines output variable
of WorkflowStep
description: Outputs is the outputs of the
step
items:
properties:
name:
@ -2316,11 +2327,17 @@ spec:
type: object
type: array
properties:
description: Properties is the properties
of the step
type: object
timeout:
description: Timeout is the timeout of the
step
type: string
type:
description: Type is the type of the workflow
step.
type: string
required:
- name
@ -2328,8 +2345,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -2356,8 +2375,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource
creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead
@ -2739,16 +2756,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition
of a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of
@ -2784,8 +2807,9 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the
status of a workflow subStep
description: StepStatus record the base status
of workflow step, which could be workflow step
or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first
@ -3986,13 +4010,15 @@ spec:
step.
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -4005,8 +4031,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of
a workflow step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -4015,7 +4040,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -4028,22 +4053,24 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
subSteps:
items:
description: WorkflowSubStep defines how to execute a
workflow subStep.
description: WorkflowStepBase defines the workflow step
base
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of
WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -4056,8 +4083,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data
of a workflow step
description: Meta is the meta data of the workflow
step.
properties:
alias:
type: string
@ -4067,8 +4094,7 @@ spec:
step.
type: string
outputs:
description: StepOutputs defines output variable of
WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -4081,11 +4107,14 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -4093,8 +4122,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -4763,16 +4794,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition of
a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of a workflow
@ -4806,8 +4843,8 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the status of
a workflow subStep
description: StepStatus record the base status of workflow
step, which could be workflow step or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first time this

View File

@ -415,7 +415,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead of
@ -768,16 +767,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition of
a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of a workflow
@ -811,8 +816,8 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the status of
a workflow subStep
description: StepStatus record the base status of workflow
step, which could be workflow step or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first time this
@ -1030,13 +1035,15 @@ spec:
step.
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -1049,8 +1056,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of
a workflow step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -1059,7 +1065,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -1072,22 +1078,24 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
subSteps:
items:
description: WorkflowSubStep defines how to execute a
workflow subStep.
description: WorkflowStepBase defines the workflow step
base
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of
WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -1100,8 +1108,8 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data
of a workflow step
description: Meta is the meta data of the workflow
step.
properties:
alias:
type: string
@ -1111,8 +1119,7 @@ spec:
step.
type: string
outputs:
description: StepOutputs defines output variable of
WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -1125,11 +1132,14 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -1137,8 +1147,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -1165,7 +1177,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead of
@ -1518,16 +1529,22 @@ spec:
description: 'UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#uids'
type: string
type: object
endTime:
format: date-time
type: string
finished:
type: boolean
message:
type: string
mode:
description: WorkflowMode describes the mode of workflow
type: string
startTime:
format: date-time
type: string
status:
description: WorkflowRunPhase is a label for the condition of
a WorkflowRun at the current time
type: string
steps:
items:
description: WorkflowStepStatus record the status of a workflow
@ -1561,8 +1578,8 @@ spec:
type: string
subSteps:
items:
description: WorkflowSubStepStatus record the status of
a workflow subStep
description: StepStatus record the base status of workflow
step, which could be workflow step or subStep
properties:
firstExecuteTime:
description: FirstExecuteTime is the first time this

View File

@ -79,7 +79,6 @@ spec:
component:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
deleted:
description: Deleted marks the resource to be deleted
@ -147,7 +146,6 @@ spec:
cluster:
type: string
creator:
description: ResourceCreatorRole defines the resource creator.
type: string
fieldPath:
description: 'If referring to a piece of an object instead of

View File

@ -20,7 +20,7 @@ spec:
- name: v1alpha1
schema:
openAPIV3Schema:
description: Workflow is the Schema for the policy API
description: Workflow is the Schema for the workflow API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
@ -39,13 +39,15 @@ spec:
description: WorkflowStep defines how to execute a workflow step.
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -58,8 +60,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of a workflow
step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -68,7 +69,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -81,21 +82,23 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
subSteps:
items:
description: WorkflowSubStep defines how to execute a workflow
subStep.
description: WorkflowStepBase defines the workflow step base
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -108,8 +111,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of a
workflow step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -118,7 +120,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -131,11 +133,14 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -143,8 +148,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -154,6 +161,150 @@ spec:
type: object
served: true
storage: true
- name: v1alpha1
schema:
openAPIV3Schema:
description: Workflow is the Schema for the workflow API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
steps:
items:
description: WorkflowStep defines how to execute a workflow step.
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: Inputs is the inputs of the step
items:
properties:
from:
type: string
parameterKey:
type: string
required:
- from
- parameterKey
type: object
type: array
meta:
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
type: object
name:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: Outputs is the outputs of the step
items:
properties:
name:
type: string
valueFrom:
type: string
required:
- name
- valueFrom
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
subSteps:
items:
description: WorkflowStepBase defines the workflow step base
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: Inputs is the inputs of the step
items:
properties:
from:
type: string
parameterKey:
type: string
required:
- from
- parameterKey
type: object
type: array
meta:
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
type: object
name:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: Outputs is the outputs of the step
items:
properties:
name:
type: string
valueFrom:
type: string
required:
- name
- valueFrom
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
- type
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
- type
type: object
type: array
type: object
served: true
storage: false
- name: v1beta1
schema:
openAPIV3Schema:
@ -176,13 +327,15 @@ spec:
description: WorkflowStep defines how to execute a workflow step.
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -195,8 +348,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of a workflow
step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -205,7 +357,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -218,21 +370,23 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
subSteps:
items:
description: WorkflowSubStep defines how to execute a workflow
subStep.
description: WorkflowStepBase defines the workflow step base
properties:
dependsOn:
description: DependsOn is the dependency of the step
items:
type: string
type: array
if:
description: If is the if condition of the step
type: string
inputs:
description: StepInputs defines variable input of WorkflowStep
description: Inputs is the inputs of the step
items:
properties:
from:
@ -245,8 +399,7 @@ spec:
type: object
type: array
meta:
description: WorkflowStepMeta contains the meta data of a
workflow step
description: Meta is the meta data of the workflow step.
properties:
alias:
type: string
@ -255,7 +408,7 @@ spec:
description: Name is the unique name of the workflow step.
type: string
outputs:
description: StepOutputs defines output variable of WorkflowStep
description: Outputs is the outputs of the step
items:
properties:
name:
@ -268,11 +421,14 @@ spec:
type: object
type: array
properties:
description: Properties is the properties of the step
type: object
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name
@ -280,8 +436,10 @@ spec:
type: object
type: array
timeout:
description: Timeout is the timeout of the step
type: string
type:
description: Type is the type of the workflow step.
type: string
required:
- name

View File

@ -64,7 +64,9 @@ var _ = Describe("Addon test", func() {
return err
}
appPatch := client.MergeFrom(checkApp.DeepCopy())
checkApp.Status.Workflow = &common.WorkflowStatus{Suspend: true}
checkApp.Status.Workflow = &common.WorkflowStatus{
Suspend: true,
}
if err := k8sClient.Status().Patch(ctx, checkApp, appPatch); err != nil {
return err
}
@ -111,7 +113,10 @@ var _ = Describe("Addon test", func() {
return err
}
appPatch := client.MergeFrom(checkApp.DeepCopy())
checkApp.Status.Workflow = &common.WorkflowStatus{Message: "someMessage", AppRevision: "test-revision"}
checkApp.Status.Workflow = &common.WorkflowStatus{
Message: "someMessage",
AppRevision: "test-revision",
}
checkApp.Status.Phase = common.ApplicationRunning
if err := k8sClient.Status().Patch(ctx, checkApp, appPatch); err != nil {
return err

View File

@ -383,7 +383,9 @@ func TestGetAddonStatus(t *testing.T) {
case "addon-suspend":
o := obj.(*v1beta1.Application)
app := &v1beta1.Application{}
app.Status.Workflow = &common.WorkflowStatus{Suspend: true}
app.Status.Workflow = &common.WorkflowStatus{
Suspend: true,
}
*o = *app
case "addon-enabled":
o := obj.(*v1beta1.Application)

View File

@ -31,12 +31,13 @@ import (
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/kubevela/workflow/pkg/cue/model/value"
common2 "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"
"github.com/oam-dev/kubevela/apis/types"
cuemodel "github.com/oam-dev/kubevela/pkg/cue/model"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/cue/process"
"github.com/oam-dev/kubevela/pkg/multicluster"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/util"
@ -65,7 +66,7 @@ func (a addonCueTemplateRender) formatContext() (string, error) {
if err != nil {
return "", err
}
paramFile := fmt.Sprintf("%s: %s", cuemodel.ParameterFieldName, string(bt))
paramFile := fmt.Sprintf("%s: %s", process.ParameterFieldName, string(bt))
var contextFile = strings.Builder{}
// user custom parameter but be the first data and generated data should be appended at last

View File

@ -41,7 +41,8 @@ import (
coreoam "github.com/oam-dev/kubevela/apis/core.oam.dev"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
// +kubebuilder:scaffold:imports
)

View File

@ -20,6 +20,8 @@ import (
"fmt"
"time"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
)
@ -123,11 +125,11 @@ type ApplicationComponent struct {
Type string `json:"type"`
Main bool `json:"main"`
// ExternalRevision specified the component revisionName
ExternalRevision string `json:"externalRevision,omitempty"`
Properties *JSONStruct `json:"properties,omitempty"`
DependsOn []string `json:"dependsOn,omitempty"`
Inputs common.StepInputs `json:"inputs,omitempty"`
Outputs common.StepOutputs `json:"outputs,omitempty"`
ExternalRevision string `json:"externalRevision,omitempty"`
Properties *JSONStruct `json:"properties,omitempty"`
DependsOn []string `json:"dependsOn,omitempty"`
Inputs workflowv1alpha1.StepInputs `json:"inputs,omitempty"`
Outputs workflowv1alpha1.StepOutputs `json:"outputs,omitempty"`
// Traits define the trait of one component, the type must be array to keep the order.
Traits []ApplicationTrait `json:"traits,omitempty"`
// scopes in ApplicationComponent defines the component-level scopes

View File

@ -21,7 +21,7 @@ import (
"strconv"
"time"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
)
func init() {
@ -51,15 +51,15 @@ type Workflow struct {
// WorkflowStep defines how to execute a workflow step.
type WorkflowStep struct {
// Name is the unique name of the workflow step.
Name string `json:"name"`
Alias string `json:"alias"`
Type string `json:"type"`
Description string `json:"description"`
OrderIndex int `json:"orderIndex"`
Inputs common.StepInputs `json:"inputs,omitempty"`
Outputs common.StepOutputs `json:"outputs,omitempty"`
DependsOn []string `json:"dependsOn"`
Properties *JSONStruct `json:"properties,omitempty"`
Name string `json:"name"`
Alias string `json:"alias"`
Type string `json:"type"`
Description string `json:"description"`
OrderIndex int `json:"orderIndex"`
Inputs workflowv1alpha1.StepInputs `json:"inputs,omitempty"`
Outputs workflowv1alpha1.StepOutputs `json:"outputs,omitempty"`
DependsOn []string `json:"dependsOn"`
Properties *JSONStruct `json:"properties,omitempty"`
}
// TableName return custom table name
@ -114,15 +114,15 @@ type WorkflowRecord struct {
// WorkflowStepStatus is the workflow step status database model
type WorkflowStepStatus struct {
ID string `json:"id"`
Name string `json:"name"`
Alias string `json:"alias"`
Type string `json:"type,omitempty"`
Phase common.WorkflowStepPhase `json:"phase,omitempty"`
Message string `json:"message,omitempty"`
Reason string `json:"reason,omitempty"`
FirstExecuteTime time.Time `json:"firstExecuteTime,omitempty"`
LastExecuteTime time.Time `json:"lastExecuteTime,omitempty"`
ID string `json:"id"`
Name string `json:"name"`
Alias string `json:"alias"`
Type string `json:"type,omitempty"`
Phase workflowv1alpha1.WorkflowStepPhase `json:"phase,omitempty"`
Message string `json:"message,omitempty"`
Reason string `json:"reason,omitempty"`
FirstExecuteTime time.Time `json:"firstExecuteTime,omitempty"`
LastExecuteTime time.Time `json:"lastExecuteTime,omitempty"`
}
// TableName return custom table name

View File

@ -23,6 +23,7 @@ import (
"fmt"
"strings"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
k8stypes "k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
@ -502,7 +503,7 @@ func createOverrideConfigForTerraformComponent(env *model.Env, target *model.Tar
// GenEnvWorkflowStepsAndPolicies will generate workflow steps and policies for an env and application
func GenEnvWorkflowStepsAndPolicies(ctx context.Context, kubeClient client.Client, ds datastore.DataStore, env *model.Env, app *model.Application) ([]model.WorkflowStep, []datastore.Entity) {
var workflowSteps []v1beta1.WorkflowStep
var workflowSteps []workflowv1alpha1.WorkflowStep
var policies []datastore.Entity
components, err := ds.List(ctx, &model.ApplicationComponent{AppPrimaryKey: app.PrimaryKey()}, nil)
if err != nil {
@ -534,13 +535,15 @@ func GenEnvWorkflowStepsAndPolicies(ctx context.Context, kubeClient client.Clien
// gen workflow step and policies for all targets
for i := range targets {
target := targets[i].(*model.Target)
step := v1beta1.WorkflowStep{
Name: target.Name + "-cloud-resource",
Type: DeployCloudResource,
Properties: util.Object2RawExtension(map[string]string{
"policy": genPolicyName(env.Name),
"env": genPolicyEnvName(target.Name),
}),
step := workflowv1alpha1.WorkflowStep{
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: target.Name + "-cloud-resource",
Type: DeployCloudResource,
Properties: util.Object2RawExtension(map[string]string{
"policy": genPolicyName(env.Name),
"env": genPolicyEnvName(target.Name),
}),
},
}
workflowSteps = append(workflowSteps, step)
envs = append(envs, createOverrideConfigForTerraformComponent(env, target, terraformComponents))
@ -562,12 +565,14 @@ func GenEnvWorkflowStepsAndPolicies(ctx context.Context, kubeClient client.Clien
if target.Cluster == nil {
continue
}
step := v1beta1.WorkflowStep{
Name: target.Name,
Type: step.DeployWorkflowStep,
Properties: util.Object2RawExtension(map[string]interface{}{
"policies": []string{target.Name},
}),
step := workflowv1alpha1.WorkflowStep{
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: target.Name,
Type: step.DeployWorkflowStep,
Properties: util.Object2RawExtension(map[string]interface{}{
"policies": []string{target.Name},
}),
},
}
workflowSteps = append(workflowSteps, step)
appPolicy := &model.ApplicationPolicy{

View File

@ -27,6 +27,7 @@ import (
"strings"
"time"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -938,13 +939,15 @@ func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appMo
}
if workflow != nil {
app.Annotations[oam.AnnotationWorkflowName] = workflow.Name
var steps []v1beta1.WorkflowStep
var steps []workflowv1alpha1.WorkflowStep
for _, step := range workflow.Steps {
var workflowStep = v1beta1.WorkflowStep{
Name: step.Name,
Type: step.Type,
Inputs: step.Inputs,
Outputs: step.Outputs,
var workflowStep = workflowv1alpha1.WorkflowStep{
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: step.Name,
Type: step.Type,
Inputs: step.Inputs,
Outputs: step.Outputs,
},
}
if step.Properties != nil {
workflowStep.Properties = step.Properties.RawExtension()

View File

@ -1004,8 +1004,8 @@ func createTestSuspendApp(ctx context.Context, appName, envName, revisionVersion
},
Status: common.AppStatus{
Workflow: &common.WorkflowStatus{
Suspend: true,
AppRevision: recordName,
Suspend: true,
},
},
}

View File

@ -24,11 +24,12 @@ import (
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/clients"
apis "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/dto/v1"
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
"github.com/oam-dev/kubevela/pkg/velaql"
)

View File

@ -23,6 +23,7 @@ import (
"strconv"
"strings"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"helm.sh/helm/v3/pkg/time"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
@ -30,7 +31,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
wfTypes "github.com/kubevela/workflow/pkg/types"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
"github.com/oam-dev/kubevela/pkg/apiserver/domain/repository"
@ -43,7 +45,6 @@ import (
"github.com/oam-dev/kubevela/pkg/oam"
pkgUtils "github.com/oam-dev/kubevela/pkg/utils"
"github.com/oam-dev/kubevela/pkg/utils/apply"
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
)
// WorkflowService workflow manage api
@ -368,6 +369,10 @@ func (w *workflowServiceImpl) SyncWorkflowRecord(ctx context.Context) error {
continue
}
if app.Status.Workflow == nil {
continue
}
// there is a ":" in the default app revision
recordName := strings.Replace(app.Status.Workflow.AppRevision, ":", "-", 1)
@ -379,7 +384,7 @@ func (w *workflowServiceImpl) SyncWorkflowRecord(ctx context.Context) error {
continue
}
// try to sync the status from the controller revision
// try to sync the status from the application revision
var revision = &model.ApplicationRevision{AppPrimaryKey: record.AppPrimaryKey, Version: record.RevisionPrimaryKey}
if err := w.Store.Get(ctx, revision); err != nil {
if errors.Is(err, datastore.ErrRecordNotExist) {
@ -414,10 +419,12 @@ func (w *workflowServiceImpl) SyncWorkflowRecord(ctx context.Context) error {
continue
}
appRevision.Spec.Application.Status.Workflow = appRevision.Status.Workflow
if !appRevision.Spec.Application.Status.Workflow.Finished {
appRevision.Spec.Application.Status.Workflow.Finished = true
appRevision.Spec.Application.Status.Workflow.Terminated = true
if appRevision.Status.Workflow != nil {
appRevision.Spec.Application.Status.Workflow = appRevision.Status.Workflow
if !appRevision.Spec.Application.Status.Workflow.Finished {
appRevision.Spec.Application.Status.Workflow.Finished = true
appRevision.Spec.Application.Status.Workflow.Terminated = true
}
}
if err := w.syncWorkflowStatus(ctx, record.AppPrimaryKey, &appRevision.Spec.Application, record.Name, revision.RevisionCRName); err != nil {
klog.ErrorS(err, "failed to sync workflow status", "oam app name", appName, "workflow name", record.WorkflowName, "record name", record.Name)
@ -491,7 +498,7 @@ func (w *workflowServiceImpl) syncWorkflowStatus(ctx context.Context, appPrimary
}
record.Status = summaryStatus
stepStatus := make(map[string]*common.WorkflowStepStatus, len(status.Steps))
stepStatus := make(map[string]*workflowv1alpha1.WorkflowStepStatus, len(status.Steps))
for i, step := range status.Steps {
stepStatus[step.Name] = &status.Steps[i]
}
@ -608,8 +615,8 @@ func resetRevisionsAndRecords(ctx context.Context, ds datastore.DataStore, appNa
record.Status = model.RevisionStatusTerminated
record.Finished = "true"
for i, step := range record.Steps {
if step.Phase == common.WorkflowStepPhaseRunning {
record.Steps[i].Phase = common.WorkflowStepPhaseStopped
if step.Phase == workflowv1alpha1.WorkflowStepPhaseRunning {
record.Steps[i].Phase = workflowv1alpha1.WorkflowStepPhaseStopped
}
}
if err := ds.Put(ctx, record); err != nil {
@ -666,12 +673,12 @@ func ResumeWorkflow(ctx context.Context, kubecli client.Client, app *v1beta1.App
app.Status.Workflow.Suspend = false
steps := app.Status.Workflow.Steps
for i, step := range steps {
if step.Type == wfTypes.WorkflowStepTypeSuspend && step.Phase == common.WorkflowStepPhaseRunning {
steps[i].Phase = common.WorkflowStepPhaseSucceeded
if step.Type == wfTypes.WorkflowStepTypeSuspend && step.Phase == workflowv1alpha1.WorkflowStepPhaseRunning {
steps[i].Phase = workflowv1alpha1.WorkflowStepPhaseSucceeded
}
for j, sub := range step.SubStepsStatus {
if sub.Type == wfTypes.WorkflowStepTypeSuspend && sub.Phase == common.WorkflowStepPhaseRunning {
steps[i].SubStepsStatus[j].Phase = common.WorkflowStepPhaseSucceeded
if sub.Type == wfTypes.WorkflowStepTypeSuspend && sub.Phase == workflowv1alpha1.WorkflowStepPhaseRunning {
steps[i].SubStepsStatus[j].Phase = workflowv1alpha1.WorkflowStepPhaseSucceeded
}
}
}
@ -690,23 +697,23 @@ func TerminateWorkflow(ctx context.Context, kubecli client.Client, app *v1beta1.
steps := app.Status.Workflow.Steps
for i, step := range steps {
switch step.Phase {
case common.WorkflowStepPhaseFailed:
case workflowv1alpha1.WorkflowStepPhaseFailed:
if step.Reason != wfTypes.StatusReasonFailedAfterRetries && step.Reason != wfTypes.StatusReasonTimeout {
steps[i].Reason = wfTypes.StatusReasonTerminate
}
case common.WorkflowStepPhaseRunning:
steps[i].Phase = common.WorkflowStepPhaseFailed
case workflowv1alpha1.WorkflowStepPhaseRunning:
steps[i].Phase = workflowv1alpha1.WorkflowStepPhaseFailed
steps[i].Reason = wfTypes.StatusReasonTerminate
default:
}
for j, sub := range step.SubStepsStatus {
switch sub.Phase {
case common.WorkflowStepPhaseFailed:
case workflowv1alpha1.WorkflowStepPhaseFailed:
if sub.Reason != wfTypes.StatusReasonFailedAfterRetries && sub.Reason != wfTypes.StatusReasonTimeout {
steps[i].SubStepsStatus[j].Phase = wfTypes.StatusReasonTerminate
}
case common.WorkflowStepPhaseRunning:
steps[i].SubStepsStatus[j].Phase = common.WorkflowStepPhaseFailed
case workflowv1alpha1.WorkflowStepPhaseRunning:
steps[i].SubStepsStatus[j].Phase = workflowv1alpha1.WorkflowStepPhaseFailed
steps[i].SubStepsStatus[j].Reason = wfTypes.StatusReasonTerminate
default:
}

View File

@ -24,13 +24,13 @@ import (
"time"
"github.com/google/go-cmp/cmp"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"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/pkg/apiserver/domain/model"
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
@ -256,9 +256,9 @@ var _ = Describe("Test workflow service functions", func() {
Expect(err).Should(BeNil())
Expect(record.Status).Should(Equal(model.RevisionStatusComplete))
Expect(record.Steps[0].Alias).Should(Equal("step-alias-1"))
Expect(record.Steps[0].Phase).Should(Equal(common.WorkflowStepPhaseSucceeded))
Expect(record.Steps[0].Phase).Should(Equal(workflowv1alpha1.WorkflowStepPhaseSucceeded))
Expect(record.Steps[1].Alias).Should(Equal("step-alias-2"))
Expect(record.Steps[1].Phase).Should(Equal(common.WorkflowStepPhaseSucceeded))
Expect(record.Steps[1].Phase).Should(Equal(workflowv1alpha1.WorkflowStepPhaseSucceeded))
By("check the application revision")
err = workflowService.Store.Get(ctx, revision)
@ -540,10 +540,10 @@ var _ = Describe("Test workflow service functions", func() {
Finished: "false",
Steps: []model.WorkflowStepStatus{
{
Phase: common.WorkflowStepPhaseSucceeded,
Phase: workflowv1alpha1.WorkflowStepPhaseSucceeded,
},
{
Phase: common.WorkflowStepPhaseRunning,
Phase: workflowv1alpha1.WorkflowStepPhaseRunning,
},
},
})
@ -561,7 +561,7 @@ var _ = Describe("Test workflow service functions", func() {
Expect(err).Should(BeNil())
Expect(record.Status).Should(Equal(model.RevisionStatusTerminated))
Expect(record.Finished).Should(Equal("true"))
Expect(record.Steps[1].Phase).Should(Equal(common.WorkflowStepPhaseStopped))
Expect(record.Steps[1].Phase).Should(Equal(workflowv1alpha1.WorkflowStepPhaseStopped))
})
})

View File

@ -22,19 +22,18 @@ import (
"strings"
"time"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"k8s.io/apimachinery/pkg/types"
"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/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
"github.com/oam-dev/kubevela/pkg/multicluster"
"github.com/oam-dev/kubevela/pkg/policy"
"github.com/oam-dev/kubevela/pkg/workflow/step"
)
// FromCRComponent concerts Application CR Component object into velaux data store component
@ -86,7 +85,7 @@ func FromCRPolicy(appPrimaryKey string, policyCR v1beta1.AppPolicy, creator stri
}
// FromCRWorkflow converts Application CR Workflow section into velaux data store workflow
func FromCRWorkflow(ctx context.Context, cli client.Client, appPrimaryKey string, app *v1beta1.Application) (model.Workflow, []v1beta1.WorkflowStep, error) {
func FromCRWorkflow(ctx context.Context, cli client.Client, appPrimaryKey string, app *v1beta1.Application) (model.Workflow, []workflowv1alpha1.WorkflowStep, error) {
var defaultWorkflow = true
dataWf := model.Workflow{
AppPrimaryKey: appPrimaryKey,
@ -101,14 +100,14 @@ func FromCRWorkflow(ctx context.Context, cli client.Client, appPrimaryKey string
if app.Spec.Workflow == nil {
return dataWf, nil, nil
}
var steps []v1beta1.WorkflowStep
var steps []workflowv1alpha1.WorkflowStep
if app.Spec.Workflow.Ref != "" {
dataWf.Name = app.Spec.Workflow.Ref
wf := &v1alpha1.Workflow{}
wf := &workflowv1alpha1.Workflow{}
if err := cli.Get(ctx, types.NamespacedName{Namespace: app.GetNamespace(), Name: app.Spec.Workflow.Ref}, wf); err != nil {
return dataWf, nil, err
}
steps = step.ConvertSteps(wf.Steps)
steps = wf.Steps
} else {
steps = app.Spec.Workflow.Steps
}

View File

@ -25,9 +25,10 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"github.com/kubevela/workflow/pkg/cue/packages"
apiConfig "github.com/oam-dev/kubevela/pkg/apiserver/config"
"github.com/oam-dev/kubevela/pkg/auth"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/multicluster"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
"github.com/oam-dev/kubevela/pkg/utils/common"

View File

@ -19,10 +19,10 @@ package v1
import (
"time"
"helm.sh/helm/v3/pkg/repo"
"github.com/getkin/kin-openapi/openapi3"
registryv1 "github.com/google/go-containerregistry/pkg/v1"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"helm.sh/helm/v3/pkg/repo"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
@ -669,8 +669,8 @@ type ComponentBase struct {
Creator string `json:"creator,omitempty"`
CreateTime time.Time `json:"createTime"`
UpdateTime time.Time `json:"updateTime"`
Inputs common.StepInputs `json:"inputs,omitempty"`
Outputs common.StepOutputs `json:"outputs,omitempty"`
Inputs workflowv1alpha1.StepInputs `json:"inputs,omitempty"`
Outputs workflowv1alpha1.StepOutputs `json:"outputs,omitempty"`
Traits []*ApplicationTrait `json:"traits"`
WorkloadType common.WorkloadTypeDescriptor `json:"workloadType,omitempty"`
}
@ -690,8 +690,8 @@ type CreateComponentRequest struct {
ComponentType string `json:"componentType" validate:"checkname"`
Properties string `json:"properties,omitempty"`
DependsOn []string `json:"dependsOn" optional:"true"`
Inputs common.StepInputs `json:"inputs,omitempty" optional:"true"`
Outputs common.StepOutputs `json:"outputs,omitempty" optional:"true"`
Inputs workflowv1alpha1.StepInputs `json:"inputs,omitempty" optional:"true"`
Outputs workflowv1alpha1.StepOutputs `json:"outputs,omitempty" optional:"true"`
Traits []*CreateApplicationTraitRequest `json:"traits,omitempty" optional:"true"`
}
@ -967,14 +967,14 @@ type UpdateWorkflowRequest struct {
// WorkflowStep workflow step config
type WorkflowStep struct {
// Name is the unique name of the workflow step.
Name string `json:"name" validate:"checkname"`
Alias string `json:"alias" validate:"checkalias" optional:"true"`
Type string `json:"type" validate:"checkname"`
Description string `json:"description" optional:"true"`
DependsOn []string `json:"dependsOn" optional:"true"`
Properties string `json:"properties,omitempty"`
Inputs common.StepInputs `json:"inputs,omitempty" optional:"true"`
Outputs common.StepOutputs `json:"outputs,omitempty" optional:"true"`
Name string `json:"name" validate:"checkname"`
Alias string `json:"alias" validate:"checkalias" optional:"true"`
Type string `json:"type" validate:"checkname"`
Description string `json:"description" optional:"true"`
DependsOn []string `json:"dependsOn" optional:"true"`
Properties string `json:"properties,omitempty"`
Inputs workflowv1alpha1.StepInputs `json:"inputs,omitempty" optional:"true"`
Outputs workflowv1alpha1.StepOutputs `json:"outputs,omitempty" optional:"true"`
}
// DetailWorkflowResponse detail workflow response

View File

@ -37,6 +37,10 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/kubevela/workflow/pkg/cue/model/value"
"github.com/kubevela/workflow/pkg/cue/process"
"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"
@ -46,9 +50,7 @@ import (
velaclient "github.com/oam-dev/kubevela/pkg/client"
"github.com/oam-dev/kubevela/pkg/component"
"github.com/oam-dev/kubevela/pkg/cue/definition"
"github.com/oam-dev/kubevela/pkg/cue/model"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/cue/process"
velaprocess "github.com/oam-dev/kubevela/pkg/cue/process"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/util"
utilscommon "github.com/oam-dev/kubevela/pkg/utils/common"
@ -175,13 +177,13 @@ type Appfile struct {
Policies []v1beta1.AppPolicy
PolicyWorkloads []*Workload
WorkflowSteps []v1beta1.WorkflowStep
Components []common.ApplicationComponent
Artifacts []*types.ComponentManifest
WorkflowMode common.WorkflowMode
WorkflowSteps []workflowv1alpha1.WorkflowStep
WorkflowMode *workflowv1alpha1.WorkflowExecuteMode
ExternalPolicies map[string]*v1alpha1.Policy
ExternalWorkflow *v1alpha1.Workflow
ExternalWorkflow *workflowv1alpha1.Workflow
ReferredObjects []*unstructured.Unstructured
parser *Parser
@ -217,9 +219,9 @@ func (af *Appfile) generateUnstructured(workload *Workload) (*unstructured.Unstr
return un, nil
}
func generateUnstructuredFromCUEModule(wl *Workload, artifacts []*types.ComponentManifest, ctxData process.ContextData) (*unstructured.Unstructured, error) {
pCtx := process.NewContext(ctxData)
pCtx.PushData(model.ContextDataArtifacts, prepareArtifactsData(artifacts))
func generateUnstructuredFromCUEModule(wl *Workload, artifacts []*types.ComponentManifest, ctxData velaprocess.ContextData) (*unstructured.Unstructured, error) {
pCtx := velaprocess.NewContext(ctxData)
pCtx.PushData(velaprocess.ContextDataArtifacts, prepareArtifactsData(artifacts))
if err := wl.EvalContext(pCtx); err != nil {
return nil, errors.Wrapf(err, "evaluate base template app=%s in namespace=%s", ctxData.AppName, ctxData.Namespace)
}
@ -270,7 +272,7 @@ func (af *Appfile) GenerateComponentManifests() ([]*types.ComponentManifest, err
}
// GenerateComponentManifest generate only one ComponentManifest
func (af *Appfile) GenerateComponentManifest(wl *Workload, mutate func(*process.ContextData)) (*types.ComponentManifest, error) {
func (af *Appfile) GenerateComponentManifest(wl *Workload, mutate func(*velaprocess.ContextData)) (*types.ComponentManifest, error) {
if af.Namespace == "" {
af.Namespace = corev1.NamespaceDefault
}
@ -457,7 +459,7 @@ func (af *Appfile) setWorkloadRefToTrait(wlRef corev1.ObjectReference, trait *un
}
// PrepareProcessContext prepares a DSL process Context
func PrepareProcessContext(wl *Workload, ctxData process.ContextData) (process.Context, error) {
func PrepareProcessContext(wl *Workload, ctxData velaprocess.ContextData) (process.Context, error) {
if wl.Ctx == nil {
wl.Ctx = NewBasicContext(ctxData, wl.Params)
}
@ -468,15 +470,15 @@ func PrepareProcessContext(wl *Workload, ctxData process.ContextData) (process.C
}
// NewBasicContext prepares a basic DSL process Context
func NewBasicContext(contextData process.ContextData, params map[string]interface{}) process.Context {
pCtx := process.NewContext(contextData)
func NewBasicContext(contextData velaprocess.ContextData, params map[string]interface{}) process.Context {
pCtx := velaprocess.NewContext(contextData)
if params != nil {
pCtx.SetParameters(params)
}
return pCtx
}
func generateComponentFromCUEModule(wl *Workload, ctxData process.ContextData) (*types.ComponentManifest, error) {
func generateComponentFromCUEModule(wl *Workload, ctxData velaprocess.ContextData) (*types.ComponentManifest, error) {
pCtx, err := PrepareProcessContext(wl, ctxData)
if err != nil {
return nil, err
@ -490,7 +492,7 @@ func generateComponentFromTerraformModule(wl *Workload, appName, ns string) (*ty
func baseGenerateComponent(pCtx process.Context, wl *Workload, appName, ns string) (*types.ComponentManifest, error) {
var err error
pCtx.PushData(model.ContextComponentType, wl.Type)
pCtx.PushData(velaprocess.ContextComponentType, wl.Type)
for _, tr := range wl.Traits {
if err := tr.EvalContext(pCtx); err != nil {
return nil, errors.Wrapf(err, "evaluate template trait=%s app=%s", tr.Name, wl.Name)
@ -553,7 +555,7 @@ func makeWorkloadWithContext(pCtx process.Context, wl *Workload, ns, appName str
return nil, errors.Wrapf(err, "evaluate base template component=%s app=%s", wl.Name, appName)
}
}
commonLabels := definition.GetCommonLabels(pCtx.BaseContextLabels())
commonLabels := definition.GetCommonLabels(definition.GetBaseContextLabels(pCtx))
util.AddLabels(workload, util.MergeMapOverrideWithDst(commonLabels, map[string]string{oam.WorkloadTypeLabel: wl.Type}))
return workload, nil
}
@ -569,7 +571,7 @@ func evalWorkloadWithContext(pCtx process.Context, wl *Workload, ns, appName str
_, assists := pCtx.Output()
compManifest.Traits = make([]*unstructured.Unstructured, len(assists))
commonLabels := definition.GetCommonLabels(pCtx.BaseContextLabels())
commonLabels := definition.GetCommonLabels(definition.GetBaseContextLabels(pCtx))
for i, assist := range assists {
tr, err := assist.Ins.Unstructured()
if err != nil {
@ -642,7 +644,7 @@ output: {
return templateStr, nil
}
func generateComponentFromKubeModule(wl *Workload, ctxData process.ContextData) (*types.ComponentManifest, error) {
func generateComponentFromKubeModule(wl *Workload, ctxData velaprocess.ContextData) (*types.ComponentManifest, error) {
templateStr, err := GenerateCUETemplate(wl)
if err != nil {
return nil, err
@ -805,7 +807,7 @@ func setParameterValuesToKubeObj(obj *unstructured.Unstructured, values paramVal
return nil
}
func generateComponentFromHelmModule(wl *Workload, ctxData process.ContextData) (*types.ComponentManifest, error) {
func generateComponentFromHelmModule(wl *Workload, ctxData velaprocess.ContextData) (*types.ComponentManifest, error) {
templateStr, err := GenerateCUETemplate(wl)
if err != nil {
return nil, err
@ -836,8 +838,8 @@ func generateComponentFromHelmModule(wl *Workload, ctxData process.ContextData)
}
// GenerateContextDataFromAppFile generates process context data from app file
func GenerateContextDataFromAppFile(appfile *Appfile, wlName string) process.ContextData {
data := process.ContextData{
func GenerateContextDataFromAppFile(appfile *Appfile, wlName string) velaprocess.ContextData {
data := velaprocess.ContextData{
Namespace: appfile.Namespace,
AppName: appfile.Name,
CompName: wlName,
@ -861,7 +863,7 @@ func (af *Appfile) WorkflowClient(cli client.Client) client.Client {
return velaclient.DelegatingHandlerClient{
Client: cli,
Getter: func(ctx context.Context, key client.ObjectKey, obj client.Object) error {
if wf, ok := obj.(*v1alpha1.Workflow); ok {
if wf, ok := obj.(*workflowv1alpha1.Workflow); ok {
if af.AppRevision != nil {
if af.ExternalWorkflow != nil && af.ExternalWorkflow.Name == key.Name && af.ExternalWorkflow.Namespace == key.Namespace {
af.ExternalWorkflow.DeepCopyInto(wf)
@ -872,7 +874,7 @@ func (af *Appfile) WorkflowClient(cli client.Client) client.Client {
if err := cli.Get(ctx, key, obj); err != nil {
return err
}
af.ExternalWorkflow = obj.(*v1alpha1.Workflow)
af.ExternalWorkflow = obj.(*workflowv1alpha1.Workflow)
return nil
}
return cli.Get(ctx, key, obj)

View File

@ -38,11 +38,13 @@ import (
"k8s.io/utils/pointer"
"sigs.k8s.io/yaml"
"github.com/kubevela/workflow/pkg/cue/model"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
oamtypes "github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/cue/definition"
"github.com/oam-dev/kubevela/pkg/cue/model"
"github.com/oam-dev/kubevela/pkg/cue/process"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/util"
)
@ -573,7 +575,7 @@ variable "password" {
"writeConnectionSecretToRef": map[string]interface{}{
"name": "db",
},
model.OutputSecretName: "db-conn",
process.OutputSecretName: "db-conn",
},
}

View File

@ -28,12 +28,14 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/kubevela/workflow/pkg/cue/packages"
"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"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
)
@ -567,7 +569,7 @@ func marshalObject(o client.Object) ([]byte, error) {
obj.Status = common.AppStatus{}
case *v1alpha1.Policy:
obj.SetGroupVersionKind(v1alpha1.PolicyGroupVersionKind)
case *v1alpha1.Workflow:
case *workflowv1alpha1.Workflow:
obj.SetGroupVersionKind(v1alpha1.WorkflowGroupVersionKind)
}
o.SetLabels(clearedLabels(o.GetLabels()))

View File

@ -35,11 +35,12 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
"github.com/kubevela/workflow/pkg/cue/packages"
"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/cue/definition"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
oamutil "github.com/oam-dev/kubevela/pkg/oam/util"

View File

@ -35,9 +35,10 @@ import (
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"github.com/kubevela/workflow/pkg/cue/packages"
coreoam "github.com/oam-dev/kubevela/apis/core.oam.dev"
"github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
oamutil "github.com/oam-dev/kubevela/pkg/oam/util"

View File

@ -31,6 +31,9 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature"
"sigs.k8s.io/controller-runtime/pkg/client"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/kubevela/workflow/pkg/cue/packages"
"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"
@ -38,7 +41,6 @@ import (
"github.com/oam-dev/kubevela/pkg/auth"
"github.com/oam-dev/kubevela/pkg/component"
"github.com/oam-dev/kubevela/pkg/cue/definition"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/features"
monitorContext "github.com/oam-dev/kubevela/pkg/monitor/context"
"github.com/oam-dev/kubevela/pkg/monitor/metrics"
@ -49,7 +51,6 @@ import (
"github.com/oam-dev/kubevela/pkg/utils"
utilscommon "github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/oam-dev/kubevela/pkg/workflow/step"
wftypes "github.com/oam-dev/kubevela/pkg/workflow/types"
)
// TemplateLoaderFn load template of a capability definition
@ -297,7 +298,7 @@ func (p *Parser) GenerateAppFileFromRevision(appRev *v1beta1.ApplicationRevision
if len(appfile.RelatedWorkflowStepDefinitions) == 0 && len(appfile.WorkflowSteps) > 0 {
ctx := context.Background()
for _, workflowStep := range appfile.WorkflowSteps {
if wftypes.IsBuiltinWorkflowStepType(workflowStep.Type) {
if step.IsBuiltinWorkflowStepType(workflowStep.Type) {
continue
}
if _, found := appfile.RelatedWorkflowStepDefinitions[workflowStep.Type]; found {
@ -447,13 +448,20 @@ func (p *Parser) parsePolicies(ctx context.Context, af *Appfile) (err error) {
func (p *Parser) loadWorkflowToAppfile(ctx context.Context, af *Appfile) error {
var err error
// parse workflow steps
af.WorkflowMode = common.WorkflowModeDAG
af.WorkflowMode = &workflowv1alpha1.WorkflowExecuteMode{
Steps: workflowv1alpha1.WorkflowModeDAG,
SubSteps: workflowv1alpha1.WorkflowModeDAG,
}
if wfSpec := af.app.Spec.Workflow; wfSpec != nil && len(wfSpec.Steps) > 0 {
af.WorkflowSteps = wfSpec.Steps
if wfSpec.Mode != nil && wfSpec.Mode.Steps == common.WorkflowModeDAG {
af.WorkflowMode = common.WorkflowModeDAG
} else {
af.WorkflowMode = common.WorkflowModeStep
af.WorkflowMode.Steps = workflowv1alpha1.WorkflowModeStep
if wfSpec.Mode != nil {
if wfSpec.Mode.Steps != "" {
af.WorkflowMode.Steps = wfSpec.Mode.Steps
}
if wfSpec.Mode.SubSteps != "" {
af.WorkflowMode.SubSteps = wfSpec.Mode.SubSteps
}
}
}
af.WorkflowSteps, err = step.NewChainWorkflowStepGenerator(
@ -493,7 +501,7 @@ func (p *Parser) parseWorkflowSteps(ctx context.Context, af *Appfile) error {
}
func (p *Parser) parseWorkflowStep(ctx context.Context, af *Appfile, workflowStepType string) error {
if wftypes.IsBuiltinWorkflowStepType(workflowStepType) {
if step.IsBuiltinWorkflowStepType(workflowStepType) {
return nil
}
if _, found := af.RelatedWorkflowStepDefinitions[workflowStepType]; found {
@ -506,6 +514,7 @@ func (p *Parser) parseWorkflowStep(ctx context.Context, af *Appfile, workflowSte
af.RelatedWorkflowStepDefinitions[workflowStepType] = def
return nil
}
func (p *Parser) makeWorkload(ctx context.Context, name, typ string, capType types.CapType, props *runtime.RawExtension) (*Workload, error) {
templ, err := p.tmplLoader.LoadTemplate(ctx, p.dm, p.client, typ, capType)
if err != nil {

View File

@ -22,11 +22,8 @@ import (
"reflect"
"strings"
common2 "github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/google/go-cmp/cmp"
"github.com/crossplane/crossplane-runtime/pkg/test"
"github.com/google/go-cmp/cmp"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
@ -36,10 +33,13 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/yaml"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/cue/definition"
"github.com/oam-dev/kubevela/pkg/oam/util"
common2 "github.com/oam-dev/kubevela/pkg/utils/common"
)
var expectedExceptApp = &Appfile{
@ -116,10 +116,12 @@ var expectedExceptApp = &Appfile{
},
},
},
WorkflowSteps: []v1beta1.WorkflowStep{
WorkflowSteps: []workflowv1alpha1.WorkflowStep{
{
Name: "suspend",
Type: "suspend",
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "suspend",
Type: "suspend",
},
},
},
}
@ -644,10 +646,12 @@ patch: spec: replicas: parameter.replicas
},
},
},
WorkflowSteps: []v1beta1.WorkflowStep{
WorkflowSteps: []workflowv1alpha1.WorkflowStep{
{
Name: "apply",
Type: "apply-application",
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "apply",
Type: "apply-application",
},
},
},
}

View File

@ -33,8 +33,9 @@ import (
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"github.com/kubevela/workflow/pkg/cue/packages"
coreoam "github.com/oam-dev/kubevela/apis/core.oam.dev"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
// +kubebuilder:scaffold:imports
)

View File

@ -21,8 +21,10 @@ import (
"github.com/pkg/errors"
"github.com/kubevela/workflow/pkg/cue/process"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/cue/process"
velaprocess "github.com/oam-dev/kubevela/pkg/cue/process"
)
// ValidateCUESchematicAppfile validates CUE schematic workloads in an Appfile
@ -50,7 +52,7 @@ func (p *Parser) ValidateCUESchematicAppfile(a *Appfile) error {
return nil
}
func newValidationProcessContext(wl *Workload, ctxData process.ContextData) (process.Context, error) {
func newValidationProcessContext(wl *Workload, ctxData velaprocess.ContextData) (process.Context, error) {
baseHooks := []process.BaseHook{
// add more hook funcs here to validate CUE base
}
@ -61,7 +63,7 @@ func newValidationProcessContext(wl *Workload, ctxData process.ContextData) (pro
ctxData.BaseHooks = baseHooks
ctxData.AuxiliaryHooks = auxiliaryHooks
pCtx := process.NewContext(ctxData)
pCtx := velaprocess.NewContext(ctxData)
if err := wl.EvalContext(pCtx); err != nil {
return nil, errors.Wrapf(err, "evaluate base template app=%s in namespace=%s", ctxData.AppName, ctxData.Namespace)
}

View File

@ -29,6 +29,8 @@ import (
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/utils/strings/slices"
monitorContext "github.com/kubevela/workflow/pkg/monitor/context"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/features"
"github.com/oam-dev/kubevela/pkg/oam"
@ -47,6 +49,14 @@ func ContextWithUserInfo(ctx context.Context, app *v1beta1.Application) context.
return request.WithUser(ctx, GetUserInfoInAnnotation(&app.ObjectMeta))
}
// MonitorContextWithUserInfo inject username & group from app annotations into monitor context
func MonitorContextWithUserInfo(ctx monitorContext.Context, app *v1beta1.Application) monitorContext.Context {
_ctx := ctx.GetContext()
authCtx := ContextWithUserInfo(_ctx, app)
ctx.SetContext(authCtx)
return ctx
}
// ContextClearUserInfo clear user info in context
func ContextClearUserInfo(ctx context.Context) context.Context {
return request.WithUser(ctx, nil)

View File

@ -27,8 +27,9 @@ import (
"cuelang.org/go/cue"
"github.com/pkg/errors"
"github.com/kubevela/workflow/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/builtin/registry"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
)
func init() {

View File

@ -31,9 +31,10 @@ import (
"cuelang.org/go/cue/cuecontext"
"github.com/bmizerany/assert"
"github.com/kubevela/workflow/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/builtin/http/testdata"
"github.com/oam-dev/kubevela/pkg/builtin/registry"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
)
const (

View File

@ -25,7 +25,7 @@ import (
"cuelang.org/go/cue"
"cuelang.org/go/cue/errors"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/kubevela/workflow/pkg/cue/model/value"
)
// Meta provides context for running a task.

View File

@ -19,7 +19,8 @@ package core_oam_dev
import (
"time"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
)

View File

@ -40,16 +40,21 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
wfContext "github.com/kubevela/workflow/pkg/context"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/kubevela/workflow/pkg/executor"
monitorContext "github.com/kubevela/workflow/pkg/monitor/context"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
velatypes "github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/auth"
common2 "github.com/oam-dev/kubevela/pkg/controller/common"
core "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/features"
monitorContext "github.com/oam-dev/kubevela/pkg/monitor/context"
"github.com/oam-dev/kubevela/pkg/monitor/metrics"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
@ -57,7 +62,6 @@ import (
"github.com/oam-dev/kubevela/pkg/resourcekeeper"
"github.com/oam-dev/kubevela/pkg/resourcetracker"
"github.com/oam-dev/kubevela/pkg/workflow"
wfContext "github.com/oam-dev/kubevela/pkg/workflow/context"
"github.com/oam-dev/kubevela/version"
)
@ -107,7 +111,6 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
ctx, cancel := context.WithTimeout(ctx, common2.ReconcileTimeout)
defer cancel()
logCtx := monitorContext.NewTraceContext(ctx, "").AddTag("application", req.String(), "controller", "application")
logCtx.Info("Start reconcile application")
defer logCtx.Commit("End reconcile application")
@ -191,7 +194,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
app.Status.SetConditions(condition.ReadyCondition(common.PolicyCondition.String()))
r.Recorder.Event(app, event.Normal(velatypes.ReasonPolicyGenerated, velatypes.MessagePolicyGenerated))
steps, err := handler.GenerateApplicationSteps(logCtx, app, appParser, appFile, handler.currentAppRev)
workflowInstance, runners, err := handler.GenerateApplicationSteps(logCtx, app, appParser, appFile, handler.currentAppRev)
if err != nil {
logCtx.Error(err, "[handle workflow]")
r.Recorder.Event(app, event.Warning(velatypes.ReasonFailedWorkflow, err))
@ -199,8 +202,12 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
}
app.Status.SetConditions(condition.ReadyCondition(common.RenderCondition.String()))
r.Recorder.Event(app, event.Normal(velatypes.ReasonRendered, velatypes.MessageRendered))
wf := workflow.NewWorkflow(app, r.Client, appFile.WorkflowMode, appFile.Debug, handler.resourceKeeper)
workflowState, err := wf.ExecuteSteps(logCtx.Fork("workflow"), handler.currentAppRev, steps)
executor := executor.New(workflowInstance, r.Client)
authCtx := logCtx.Fork("execute application workflow")
defer authCtx.Commit("finish execute application workflow")
authCtx = auth.MonitorContextWithUserInfo(authCtx, app)
workflowState, err := executor.ExecuteRunners(authCtx, runners)
if err != nil {
logCtx.Error(err, "[handle workflow]")
r.Recorder.Event(app, event.Warning(velatypes.ReasonFailedWorkflow, err))
@ -211,53 +218,45 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
handler.addAppliedResource(true, app.Status.AppliedResources...)
app.Status.AppliedResources = handler.appliedResources
app.Status.Services = handler.services
isUpdate := app.Status.Workflow.Message != "" && workflowInstance.Status.Message == ""
workflowInstance.Status.Phase = workflowState
app.Status.Workflow = workflow.ConvertWorkflowStatus(workflowInstance.Status, app.Status.Workflow.AppRevision)
switch workflowState {
case common.WorkflowStateInitializing:
metrics.WorkflowInitializedCounter.WithLabelValues().Inc()
logCtx.Info("Workflow return state=Initializing")
handler.UpdateApplicationRevisionStatus(logCtx, handler.currentAppRev, false, app.Status.Workflow)
return r.gcResourceTrackers(logCtx, handler, common.ApplicationRendering, false, false)
case common.WorkflowStateSuspended:
case workflowv1alpha1.WorkflowStateSuspending:
logCtx.Info("Workflow return state=Suspend")
if duration := wf.GetSuspendBackoffWaitTime(); duration > 0 {
_, err = r.gcResourceTrackers(logCtx, handler, common.ApplicationWorkflowSuspending, false, true)
if duration := executor.GetSuspendBackoffWaitTime(); duration > 0 {
_, err = r.gcResourceTrackers(logCtx, handler, common.ApplicationWorkflowSuspending, false, isUpdate)
return r.result(err).requeue(duration).ret()
}
if !workflow.IsFailedAfterRetry(app) || !feature.DefaultMutableFeatureGate.Enabled(features.EnableSuspendOnFailure) {
r.stateKeep(logCtx, handler, app)
}
return r.gcResourceTrackers(logCtx, handler, common.ApplicationWorkflowSuspending, false, true)
case common.WorkflowStateTerminated:
return r.gcResourceTrackers(logCtx, handler, common.ApplicationWorkflowSuspending, false, isUpdate)
case workflowv1alpha1.WorkflowStateTerminated:
logCtx.Info("Workflow return state=Terminated")
handler.UpdateApplicationRevisionStatus(logCtx, handler.latestAppRev, false, app.Status.Workflow)
if err := r.doWorkflowFinish(app, wf, workflowState); err != nil {
return r.endWithNegativeCondition(ctx, app, condition.ErrorCondition(common.WorkflowCondition.String(), errors.WithMessage(err, "DoWorkflowFinish")), common.ApplicationRunningWorkflow)
}
return r.gcResourceTrackers(logCtx, handler, common.ApplicationWorkflowTerminated, false, true)
case common.WorkflowStateExecuting:
r.doWorkflowFinish(app, workflowState)
return r.gcResourceTrackers(logCtx, handler, common.ApplicationWorkflowTerminated, false, isUpdate)
case workflowv1alpha1.WorkflowStateExecuting:
logCtx.Info("Workflow return state=Executing")
_, err = r.gcResourceTrackers(logCtx, handler, common.ApplicationRunningWorkflow, false, true)
return r.result(err).requeue(wf.GetBackoffWaitTime()).ret()
case common.WorkflowStateSucceeded:
_, err = r.gcResourceTrackers(logCtx, handler, common.ApplicationRunningWorkflow, false, isUpdate)
return r.result(err).requeue(executor.GetBackoffWaitTime()).ret()
case workflowv1alpha1.WorkflowStateSucceeded:
logCtx.Info("Workflow return state=Succeeded")
handler.UpdateApplicationRevisionStatus(logCtx, handler.currentAppRev, true, app.Status.Workflow)
if err := r.doWorkflowFinish(app, wf, workflowState); err != nil {
return r.endWithNegativeCondition(logCtx, app, condition.ErrorCondition(common.WorkflowCondition.String(), errors.WithMessage(err, "DoWorkflowFinish")), common.ApplicationRunningWorkflow)
}
r.doWorkflowFinish(app, workflowState)
app.Status.SetConditions(condition.ReadyCondition(common.WorkflowCondition.String()))
r.Recorder.Event(app, event.Normal(velatypes.ReasonApplied, velatypes.MessageWorkflowFinished))
logCtx.Info("Application manifests has applied by workflow successfully")
if !EnableReconcileLoopReduction {
return r.gcResourceTrackers(logCtx, handler, common.ApplicationWorkflowFinished, false, true)
if result, err := r.gcResourceTrackers(logCtx, handler, common.ApplicationRunning, false, isUpdate); err != nil {
return result, err
}
}
case common.WorkflowStateFinished:
logCtx.Info("Workflow state=Finished")
if status := app.Status.Workflow; status != nil && status.Terminated {
return r.result(nil).ret()
}
case common.WorkflowStateSkipping:
case workflowv1alpha1.WorkflowStateSkipped:
logCtx.Info("Skip this reconcile")
return ctrl.Result{}, nil
default:
}
var phase = common.ApplicationRunning
@ -282,7 +281,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu
Reason: condition.ReasonReconcileSuccess,
})
r.Recorder.Event(app, event.Normal(velatypes.ReasonDeployed, velatypes.MessageDeployed))
return r.gcResourceTrackers(logCtx, handler, phase, true, true)
return r.gcResourceTrackers(logCtx, handler, phase, true, false)
}
func (r *Reconciler) stateKeep(logCtx monitorContext.Context, handler *AppHandler, app *v1beta1.Application) {
@ -296,7 +295,7 @@ func (r *Reconciler) stateKeep(logCtx monitorContext.Context, handler *AppHandle
}
}
func (r *Reconciler) gcResourceTrackers(logCtx monitorContext.Context, handler *AppHandler, phase common.ApplicationPhase, gcOutdated bool, isPatch bool) (ctrl.Result, error) {
func (r *Reconciler) gcResourceTrackers(logCtx monitorContext.Context, handler *AppHandler, phase common.ApplicationPhase, gcOutdated bool, isUpdate bool) (ctrl.Result, error) {
subCtx := logCtx.Fork("gc_resourceTrackers", monitorContext.DurationMetric(func(v float64) {
metrics.GCResourceTrackersDurationHistogram.WithLabelValues("-").Observe(v)
}))
@ -322,8 +321,8 @@ func (r *Reconciler) gcResourceTrackers(logCtx monitorContext.Context, handler *
return r.result(r.patchStatus(logCtx, handler.app, phase)).requeue(baseGCBackoffWaitTime).ret()
}
logCtx.Info("GarbageCollected resourcetrackers")
if !isPatch {
return r.result(r.updateStatus(logCtx, handler.app, common.ApplicationRunningWorkflow)).ret()
if isUpdate {
return r.result(r.updateStatus(logCtx, handler.app, phase)).ret()
}
return r.result(r.patchStatus(logCtx, handler.app, phase)).ret()
}
@ -411,7 +410,7 @@ func (r *Reconciler) patchStatus(ctx context.Context, app *v1beta1.Application,
updateObservedGeneration(app)
if err := r.Status().Patch(ctx, app, client.Merge); err != nil {
// set to -1 to re-run workflow if status is failed to patch
workflow.StepStatusCache.Store(fmt.Sprintf("%s-%s", app.Name, app.Namespace), -1)
executor.StepStatusCache.Store(fmt.Sprintf("%s-%s", app.Name, app.Namespace), -1)
return err
}
return nil
@ -430,20 +429,19 @@ func (r *Reconciler) updateStatus(ctx context.Context, app *v1beta1.Application,
}
if err := r.Status().Update(ctx, obj); err != nil {
// set to -1 to re-run workflow if status is failed to update
workflow.StepStatusCache.Store(fmt.Sprintf("%s-%s", app.Name, app.Namespace), -1)
executor.StepStatusCache.Store(fmt.Sprintf("%s-%s", app.Name, app.Namespace), -1)
return err
}
return nil
}
func (r *Reconciler) doWorkflowFinish(app *v1beta1.Application, wf workflow.Workflow, state common.WorkflowState) error {
func (r *Reconciler) doWorkflowFinish(app *v1beta1.Application, state workflowv1alpha1.WorkflowRunPhase) {
app.Status.Workflow.Finished = true
if err := wf.Trace(); err != nil {
return errors.WithMessage(err, "record workflow state")
}
app.Status.Workflow.EndTime = metav1.Now()
executor.StepStatusCache.Delete(fmt.Sprintf("%s-%s", app.Name, app.Namespace))
wfContext.CleanupMemoryStore(app.Name, app.Namespace)
t := time.Since(app.Status.Workflow.StartTime.Time).Seconds()
metrics.WorkflowFinishedTimeHistogram.WithLabelValues(string(state)).Observe(t)
return nil
}
func hasHealthCheckPolicy(policies []*appfile.Workload) bool {
@ -509,13 +507,19 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
}
// filter managedFields changes
new.ManagedFields = old.ManagedFields
old.ManagedFields = nil
new.ManagedFields = nil
// if the generation is changed, return true to let the controller handle it
if old.Generation != new.Generation {
return true
}
// filter the events triggered by initial application status
if new.Status.Phase == common.ApplicationRendering || (old.Status.Phase == common.ApplicationRendering && new.Status.Phase == common.ApplicationRunningWorkflow) {
return false
}
// ignore the changes in workflow status
if old.Status.Workflow != nil && new.Status.Workflow != nil {
// only workflow execution will change the status.workflow
@ -523,15 +527,16 @@ func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
new.Status.Workflow.Steps = old.Status.Workflow.Steps
new.Status.Workflow.ContextBackend = old.Status.Workflow.ContextBackend
new.Status.Workflow.Message = old.Status.Workflow.Message
// appliedResources and Services will be changed during the execution of workflow
// once the resources is added, the managed fields will also be changed
new.Status.AppliedResources = old.Status.AppliedResources
new.Status.Services = old.Status.Services
// the resource version will be changed if the object is changed
// ignore this change and let reflect.DeepEqual to compare the rest of the object
new.ResourceVersion = old.ResourceVersion
new.Status.Workflow.EndTime = old.Status.Workflow.EndTime
}
// appliedResources and Services will be changed during the execution of workflow
// once the resources is added, the managed fields will also be changed
new.Status.AppliedResources = old.Status.AppliedResources
new.Status.Services = old.Status.Services
// the resource version will be changed if the object is changed
// ignore this change and let reflect.DeepEqual to compare the rest of the object
new.ResourceVersion = old.ResourceVersion
return !reflect.DeepEqual(old, new)
},
CreateFunc: func(e ctrlEvent.CreateEvent) bool {

View File

@ -189,6 +189,7 @@ var _ = Describe("Test application controller finalizer logic", func() {
By("delete app will delete resourceTracker")
// reconcile will delete resourceTracker and unset app's finalizer
testutil.ReconcileOnceAfterFinalizer(reconciler, ctrl.Request{NamespacedName: appKey})
testutil.ReconcileOnce(reconciler, ctrl.Request{NamespacedName: appKey})
checkApp = new(v1beta1.Application)
Expect(k8sClient.Get(ctx, appKey, checkApp)).Should(util.NotFoundMatcher{})
checkRt := new(v1beta1.ResourceTracker)

View File

@ -82,7 +82,7 @@ func NewAppHandler(ctx context.Context, r *Reconciler, app *v1beta1.Application,
}
// Dispatch apply manifests into k8s.
func (h *AppHandler) Dispatch(ctx context.Context, cluster string, owner common.ResourceCreatorRole, manifests ...*unstructured.Unstructured) error {
func (h *AppHandler) Dispatch(ctx context.Context, cluster string, owner string, manifests ...*unstructured.Unstructured) error {
manifests = multicluster.ResourcesWithClusterName(cluster, manifests...)
if err := h.resourceKeeper.Dispatch(ctx, manifests, nil); err != nil {
return err
@ -110,7 +110,7 @@ func (h *AppHandler) Dispatch(ctx context.Context, cluster string, owner common.
}
// Delete delete manifests from k8s.
func (h *AppHandler) Delete(ctx context.Context, cluster string, owner common.ResourceCreatorRole, manifest *unstructured.Unstructured) error {
func (h *AppHandler) Delete(ctx context.Context, cluster string, owner string, manifest *unstructured.Unstructured) error {
manifests := multicluster.ResourcesWithClusterName(cluster, manifest)
if err := h.resourceKeeper.Delete(ctx, manifests); err != nil {
return err

View File

@ -36,11 +36,12 @@ import (
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
// +kubebuilder:scaffold:imports
)

View File

@ -39,6 +39,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/yaml"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/oam"
@ -249,7 +251,7 @@ var _ = Describe("Test Application with GC options", func() {
return errors.New("app is not in running status")
}
return nil
}, 3*time.Second, 300*time.Second).Should(BeNil())
}, 3*time.Second, 300*time.Microsecond).Should(BeNil())
Expect(newApp.Status.LatestRevision.Revision).Should(Equal(int64(7)))
By("check the resourceTrackers number")
@ -498,7 +500,7 @@ var _ = Describe("Test Application with GC options", func() {
Name: "worker2",
Type: "worker",
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)},
Inputs: common.StepInputs{
Inputs: workflowv1alpha1.StepInputs{
{
From: "worker3-output",
ParameterKey: "test",
@ -509,7 +511,7 @@ var _ = Describe("Test Application with GC options", func() {
Name: "worker3",
Type: "worker",
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)},
Outputs: common.StepOutputs{
Outputs: workflowv1alpha1.StepOutputs{
{
Name: "worker3-output",
ValueFrom: "output.metadata.name",

View File

@ -18,41 +18,57 @@ package application
import (
"context"
"encoding/json"
"os"
"strings"
"time"
"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"
"k8s.io/klog/v2"
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/kubevela/workflow/pkg/cue/model/value"
"github.com/kubevela/workflow/pkg/executor"
"github.com/kubevela/workflow/pkg/generator"
monitorContext "github.com/kubevela/workflow/pkg/monitor/context"
"github.com/kubevela/workflow/pkg/providers"
"github.com/kubevela/workflow/pkg/providers/kube"
wfTypes "github.com/kubevela/workflow/pkg/types"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/auth"
"github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2/application/assemble"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/cue/process"
monitorContext "github.com/oam-dev/kubevela/pkg/monitor/context"
velaprocess "github.com/oam-dev/kubevela/pkg/cue/process"
"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/velaql/providers/query"
"github.com/oam-dev/kubevela/pkg/workflow/providers"
"github.com/oam-dev/kubevela/pkg/workflow/providers/http"
"github.com/oam-dev/kubevela/pkg/workflow/providers/kube"
"github.com/oam-dev/kubevela/pkg/workflow"
multiclusterProvider "github.com/oam-dev/kubevela/pkg/workflow/providers/multicluster"
oamProvider "github.com/oam-dev/kubevela/pkg/workflow/providers/oam"
terraformProvider "github.com/oam-dev/kubevela/pkg/workflow/providers/terraform"
"github.com/oam-dev/kubevela/pkg/workflow/tasks"
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
"github.com/oam-dev/kubevela/pkg/workflow/template"
)
func init() {
if err := stdlib.SetupBuiltinImports(); err != nil {
klog.ErrorS(err, "Unable to set up builtin imports on package initialization")
os.Exit(1)
}
}
var (
// DisableResourceApplyDoubleCheck optimize applyComponentFunc by disable post resource existing check after dispatch
DisableResourceApplyDoubleCheck = false
@ -64,15 +80,20 @@ func (h *AppHandler) GenerateApplicationSteps(ctx monitorContext.Context,
app *v1beta1.Application,
appParser *appfile.Parser,
af *appfile.Appfile,
appRev *v1beta1.ApplicationRevision) ([]wfTypes.TaskRunner, error) {
appRev *v1beta1.ApplicationRevision) (*wfTypes.WorkflowInstance, []wfTypes.TaskRunner, error) {
handlerProviders := providers.NewProviders()
kube.Install(handlerProviders, app, h.r.Client, h.Dispatch, h.Delete)
kube.Install(handlerProviders, h.r.Client,
map[string]string{
oam.LabelAppName: app.Name,
oam.LabelAppNamespace: app.Namespace,
}, &kube.Handlers{
Apply: h.Dispatch,
Delete: h.Delete,
})
oamProvider.Install(handlerProviders, app, af, h.r.Client, h.applyComponentFunc(
appParser, appRev, af), h.renderComponentFunc(appParser, appRev, af))
http.Install(handlerProviders, h.r.Client, app.Namespace)
pCtx := process.NewContext(generateContextDataFromApp(app, appRev.Name))
taskDiscover := tasks.NewTaskDiscoverFromRevision(ctx, handlerProviders, h.r.pd, appRev, h.r.dm, pCtx)
pCtx := velaprocess.NewContext(generateContextDataFromApp(app, appRev.Name))
multiclusterProvider.Install(handlerProviders, h.r.Client, app, af,
h.applyComponentFunc(appParser, appRev, af),
h.checkComponentHealth(appParser, appRev, af),
@ -83,84 +104,114 @@ func (h *AppHandler) GenerateApplicationSteps(ctx monitorContext.Context,
terraformProvider.Install(handlerProviders, app, func(comp common.ApplicationComponent) (*appfile.Workload, error) {
return appParser.ParseWorkloadFromRevision(comp, appRev)
})
query.Install(handlerProviders, h.r.Client, nil, func() context.Context {
return auth.ContextWithUserInfo(ctx, h.app)
query.Install(handlerProviders, h.r.Client, nil)
instance, err := generateWorkflowInstance(af, app, appRev.Name)
if err != nil {
return nil, nil, err
}
executor.InitializeWorkflowInstance(instance)
runners, err := generator.GenerateRunners(ctx, instance, wfTypes.StepGeneratorOptions{
Providers: handlerProviders,
PackageDiscover: h.r.pd,
ProcessCtx: pCtx,
TemplateLoader: template.NewWorkflowStepTemplateRevisionLoader(appRev, h.r.dm),
Client: h.r.Client,
StepConvertor: map[string]func(step workflowv1alpha1.WorkflowStep) (workflowv1alpha1.WorkflowStep, error){
wfTypes.WorkflowStepTypeApplyComponent: func(lstep workflowv1alpha1.WorkflowStep) (workflowv1alpha1.WorkflowStep, error) {
copierStep := lstep.DeepCopy()
if err := convertStepProperties(copierStep, app); err != nil {
return lstep, errors.WithMessage(err, "convert [apply-component]")
}
copierStep.Type = wfTypes.WorkflowStepTypeBuiltinApplyComponent
return *copierStep, nil
},
},
})
var tasks []wfTypes.TaskRunner
for _, step := range af.WorkflowSteps {
task, err := generateStep(ctx, app, step, taskDiscover, h.r.pd, pCtx, "")
if err != nil {
return nil, err
}
tasks = append(tasks, task)
if err != nil {
return nil, nil, err
}
return tasks, nil
return instance, runners, nil
}
func generateStep(ctx context.Context,
app *v1beta1.Application,
step v1beta1.WorkflowStep,
taskDiscover wfTypes.TaskDiscover,
pd *packages.PackageDiscover,
pCtx process.Context,
parentStepName string) (wfTypes.TaskRunner, error) {
options := &wfTypes.GeneratorOptions{
ID: generateStepID(step.Name, app.Status.Workflow, parentStepName),
PackageDiscover: pd,
ProcessContext: pCtx,
}
generatorName := step.Type
switch {
case generatorName == wfTypes.WorkflowStepTypeApplyComponent:
generatorName = wfTypes.WorkflowStepTypeBuiltinApplyComponent
options.StepConvertor = func(lstep v1beta1.WorkflowStep) (v1beta1.WorkflowStep, error) {
copierStep := lstep.DeepCopy()
if err := convertStepProperties(copierStep, app); err != nil {
return lstep, errors.WithMessage(err, "convert [apply-component]")
}
return *copierStep, nil
}
case generatorName == wfTypes.WorkflowStepTypeStepGroup:
var subTaskRunners []wfTypes.TaskRunner
for _, subStep := range step.SubSteps {
workflowStep := v1beta1.WorkflowStep{
Name: subStep.Name,
Type: subStep.Type,
Properties: subStep.Properties,
DependsOn: subStep.DependsOn,
Inputs: subStep.Inputs,
Outputs: subStep.Outputs,
If: subStep.If,
Timeout: subStep.Timeout,
Meta: subStep.Meta,
}
subTask, err := generateStep(ctx, app, workflowStep, taskDiscover, pd, pCtx, step.Name)
if err != nil {
return nil, err
}
subTaskRunners = append(subTaskRunners, subTask)
}
options.SubTaskRunners = subTaskRunners
options.ExecuteMode = common.WorkflowModeDAG
if app.Spec.Workflow != nil && app.Spec.Workflow.Mode != nil {
options.ExecuteMode = app.Spec.Workflow.Mode.SubSteps
}
}
genTask, err := taskDiscover.GetTaskGenerator(ctx, generatorName)
func generateWorkflowInstance(af *appfile.Appfile, app *v1beta1.Application, appRev string) (*wfTypes.WorkflowInstance, error) {
revAndSpecHash, err := workflow.ComputeWorkflowRevisionHash(appRev, app)
if err != nil {
return nil, err
}
task, err := genTask(step, options)
if err != nil {
return nil, err
anno := make(map[string]string)
if af.Debug {
anno[wfTypes.AnnotationWorkflowRunDebug] = "true"
}
return task, nil
instance := &wfTypes.WorkflowInstance{
WorkflowMeta: wfTypes.WorkflowMeta{
Name: af.Name,
Namespace: af.Namespace,
Annotations: app.Annotations,
Labels: app.Labels,
ChildOwnerReferences: []metav1.OwnerReference{
{
APIVersion: v1beta1.SchemeGroupVersion.String(),
Kind: v1beta1.ApplicationKind,
Name: app.Name,
UID: app.GetUID(),
Controller: pointer.BoolPtr(true),
},
},
},
Debug: af.Debug,
Steps: af.WorkflowSteps,
Mode: af.WorkflowMode,
}
if app.Status.Workflow == nil || app.Status.Workflow.AppRevision != revAndSpecHash {
// clean recorded resources info.
app.Status.Services = nil
app.Status.AppliedResources = nil
// clean conditions after render
var reservedConditions []condition.Condition
for i, cond := range app.Status.Conditions {
condTpy, err := common.ParseApplicationConditionType(string(cond.Type))
if err == nil {
if condTpy <= common.RenderCondition {
reservedConditions = append(reservedConditions, app.Status.Conditions[i])
}
}
}
app.Status.Conditions = reservedConditions
app.Status.Workflow = &common.WorkflowStatus{
AppRevision: revAndSpecHash,
}
return instance, nil
}
status := app.Status.Workflow
instance.Status = workflowv1alpha1.WorkflowRunStatus{
Mode: *af.WorkflowMode,
Phase: status.Phase,
Message: status.Message,
Suspend: status.Suspend,
SuspendState: status.SuspendState,
Terminated: status.Terminated,
Finished: status.Finished,
ContextBackend: status.ContextBackend,
Steps: status.Steps,
StartTime: status.StartTime,
EndTime: status.EndTime,
}
switch app.Status.Phase {
case common.ApplicationRunning:
instance.Status.Phase = workflowv1alpha1.WorkflowStateSucceeded
case common.ApplicationWorkflowSuspending:
instance.Status.Phase = workflowv1alpha1.WorkflowStateSuspending
case common.ApplicationWorkflowTerminated:
instance.Status.Phase = workflowv1alpha1.WorkflowStateTerminated
default:
instance.Status.Phase = workflowv1alpha1.WorkflowStateExecuting
}
return instance, nil
}
func convertStepProperties(step *v1beta1.WorkflowStep, app *v1beta1.Application) error {
func convertStepProperties(step *workflowv1alpha1.WorkflowStep, app *v1beta1.Application) error {
o := struct {
Component string `json:"component"`
}{}
@ -333,7 +384,7 @@ func (h *AppHandler) prepareWorkloadAndManifests(ctx context.Context,
return nil, nil, errors.WithMessage(err, "ParseWorkload")
}
wl.Patch = patcher
manifest, err := af.GenerateComponentManifest(wl, func(ctxData *process.ContextData) {
manifest, err := af.GenerateComponentManifest(wl, func(ctxData *velaprocess.ContextData) {
if ns := componentNamespaceFromContext(ctx); ns != "" {
ctxData.Namespace = ns
}
@ -414,46 +465,8 @@ func getComponentResources(ctx context.Context, manifest *types.ComponentManifes
return workload, traits, nil
}
func getStepID(stepName string, stepsStatus []common.StepStatus) string {
for _, status := range stepsStatus {
if status.Name == stepName {
return status.ID
}
}
return ""
}
func generateStepID(stepName string, workflowStatus *common.WorkflowStatus, parentStepName string) string {
var id string
if workflowStatus != nil {
workflowStepsStatus := workflowStatus.Steps
if parentStepName != "" {
for _, status := range workflowStepsStatus {
if status.Name == parentStepName {
var stepsStatus []common.StepStatus
for _, status := range status.SubStepsStatus {
stepsStatus = append(stepsStatus, status.StepStatus)
}
id = getStepID(stepName, stepsStatus)
}
}
} else {
var stepsStatus []common.StepStatus
for _, status := range workflowStepsStatus {
stepsStatus = append(stepsStatus, status.StepStatus)
}
id = getStepID(stepName, stepsStatus)
}
}
if id == "" {
id = utils.RandomString(10)
}
return id
}
func generateContextDataFromApp(app *v1beta1.Application, appRev string) process.ContextData {
data := process.ContextData{
func generateContextDataFromApp(app *v1beta1.Application, appRev string) velaprocess.ContextData {
data := velaprocess.ContextData{
Namespace: app.Namespace,
AppName: app.Name,
CompName: app.Name,

View File

@ -28,9 +28,11 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/yaml"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
monitorContext "github.com/kubevela/workflow/pkg/monitor/context"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
oamcore "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
monitorContext "github.com/oam-dev/kubevela/pkg/monitor/context"
"github.com/oam-dev/kubevela/pkg/oam/util"
)
@ -81,7 +83,7 @@ var _ = Describe("Test Application workflow generator", func() {
Name: "myweb1",
Type: "worker-with-health",
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)},
Inputs: common.StepInputs{
Inputs: workflowv1alpha1.StepInputs{
{
From: "message",
ParameterKey: "properties.enemies",
@ -96,7 +98,7 @@ var _ = Describe("Test Application workflow generator", func() {
Name: "myweb2",
Type: "worker-with-health",
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)},
Outputs: common.StepOutputs{
Outputs: workflowv1alpha1.StepOutputs{
{
Name: "message",
ValueFrom: "output.status.conditions[0].message+\",\"+outputs.gameconfig.data.lives",
@ -116,7 +118,7 @@ var _ = Describe("Test Application workflow generator", func() {
Expect(err).Should(Succeed())
logCtx := monitorContext.NewTraceContext(ctx, "")
taskRunner, err := handler.GenerateApplicationSteps(logCtx, app, appParser, af, appRev)
_, taskRunner, err := handler.GenerateApplicationSteps(logCtx, app, appParser, af, appRev)
Expect(err).To(BeNil())
Expect(len(taskRunner)).Should(BeEquivalentTo(2))
Expect(taskRunner[0].Name()).Should(BeEquivalentTo("myweb1"))
@ -158,7 +160,7 @@ var _ = Describe("Test Application workflow generator", func() {
Expect(err).Should(Succeed())
logCtx := monitorContext.NewTraceContext(ctx, "")
taskRunner, err := handler.GenerateApplicationSteps(logCtx, app, appParser, af, appRev)
_, taskRunner, err := handler.GenerateApplicationSteps(logCtx, app, appParser, af, appRev)
Expect(err).To(BeNil())
Expect(len(taskRunner)).Should(BeEquivalentTo(2))
Expect(taskRunner[0].Name()).Should(BeEquivalentTo("myweb1"))
@ -278,7 +280,7 @@ var _ = Describe("Test Application workflow generator", func() {
Expect(err).Should(Succeed())
logCtx := monitorContext.NewTraceContext(ctx, "")
taskRunner, err := handler.GenerateApplicationSteps(logCtx, app, appParser, af, appRev)
_, taskRunner, err := handler.GenerateApplicationSteps(logCtx, app, appParser, af, appRev)
Expect(err).To(BeNil())
Expect(len(taskRunner)).Should(BeEquivalentTo(2))
Expect(taskRunner[0].Name()).Should(BeEquivalentTo("myweb1"))
@ -319,7 +321,7 @@ var _ = Describe("Test Application workflow generator", func() {
Expect(err).Should(Succeed())
logCtx := monitorContext.NewTraceContext(ctx, "")
_, err = handler.GenerateApplicationSteps(logCtx, app, appParser, af, appRev)
_, _, err = handler.GenerateApplicationSteps(logCtx, app, appParser, af, appRev)
Expect(err).NotTo(BeNil())
})
@ -357,7 +359,7 @@ var _ = Describe("Test Application workflow generator", func() {
Expect(err).Should(Succeed())
logCtx := monitorContext.NewTraceContext(ctx, "")
_, err = handler.GenerateApplicationSteps(logCtx, app, appParser, af, appRev)
_, _, err = handler.GenerateApplicationSteps(logCtx, app, appParser, af, appRev)
Expect(err).NotTo(BeNil())
})
})

View File

@ -36,6 +36,8 @@ import (
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
@ -46,7 +48,7 @@ import (
"github.com/oam-dev/kubevela/pkg/auth"
"github.com/oam-dev/kubevela/pkg/component"
"github.com/oam-dev/kubevela/pkg/controller/utils"
"github.com/oam-dev/kubevela/pkg/cue/model"
"github.com/oam-dev/kubevela/pkg/cue/process"
"github.com/oam-dev/kubevela/pkg/features"
monitorContext "github.com/oam-dev/kubevela/pkg/monitor/context"
"github.com/oam-dev/kubevela/pkg/monitor/metrics"
@ -532,7 +534,7 @@ func deepEqualPolicy(old, new v1alpha1.Policy) bool {
return old.Type == new.Type && apiequality.Semantic.DeepEqual(old.Properties, new.Properties)
}
func deepEqualWorkflow(old, new v1alpha1.Workflow) bool {
func deepEqualWorkflow(old, new workflowv1alpha1.Workflow) bool {
return apiequality.Semantic.DeepEqual(old.Steps, new.Steps)
}
@ -904,8 +906,8 @@ func gatherUsingAppRevision(h *AppHandler) map[string]bool {
func replaceComponentRevisionContext(u *unstructured.Unstructured, compRevName string) error {
str := string(util.JSONMarshal(u))
if strings.Contains(str, model.ComponentRevisionPlaceHolder) {
newStr := strings.ReplaceAll(str, model.ComponentRevisionPlaceHolder, compRevName)
if strings.Contains(str, process.ComponentRevisionPlaceHolder) {
newStr := strings.ReplaceAll(str, process.ComponentRevisionPlaceHolder, compRevName)
if err := json.Unmarshal([]byte(newStr), u); err != nil {
return err
}

View File

@ -43,7 +43,7 @@ import (
"github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
oamtypes "github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/cue/model"
"github.com/oam-dev/kubevela/pkg/cue/process"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/util"
)
@ -753,7 +753,7 @@ var _ = Describe("Test ReplaceComponentRevisionContext func", func() {
Kind: "Rollout",
},
Spec: v1alpha1.RolloutSpec{
TargetRevisionName: model.ComponentRevisionPlaceHolder,
TargetRevisionName: process.ComponentRevisionPlaceHolder,
},
}
u, err := util.Object2Unstructured(rollout)
@ -774,7 +774,7 @@ var _ = Describe("Test ReplaceComponentRevisionContext func", func() {
Kind: "Rollout",
},
Spec: v1alpha1.RolloutSpec{
TargetRevisionName: model.ComponentRevisionPlaceHolder,
TargetRevisionName: process.ComponentRevisionPlaceHolder,
},
}
u, err := util.Object2Unstructured(rollout)

View File

@ -48,11 +48,12 @@ import (
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
"github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/features"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
// +kubebuilder:scaffold:imports

View File

@ -36,11 +36,13 @@ import (
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/yaml"
workflowv1alpha1 "github.com/kubevela/workflow/api/v1alpha1"
wfTypes "github.com/kubevela/workflow/pkg/types"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
oamcore "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/oam/testutil"
"github.com/oam-dev/kubevela/pkg/oam/util"
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
)
var _ = Describe("Test Workflow", func() {
@ -59,10 +61,12 @@ var _ = Describe("Test Workflow", func() {
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)},
}},
Workflow: &oamcore.Workflow{
Steps: []oamcore.WorkflowStep{{
Name: "test-wf1",
Type: "foowf",
Properties: &runtime.RawExtension{Raw: []byte(`{"namespace":"test-ns"}`)},
Steps: []workflowv1alpha1.WorkflowStep{{
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "test-wf1",
Type: "foowf",
Properties: &runtime.RawExtension{Raw: []byte(`{"namespace":"test-ns"}`)},
},
}},
},
},
@ -107,33 +111,12 @@ var _ = Describe("Test Workflow", func() {
Expect(k8sClient.DeleteAllOf(ctx, &appsv1.ControllerRevision{}, client.InNamespace(namespace))).Should(Succeed())
})
It("should create ConfigMap with final resources for app with workflow", func() {
Expect(k8sClient.Create(ctx, appWithWorkflowAndPolicy)).Should(BeNil())
// first try to add finalizer
tryReconcile(reconciler, appWithWorkflowAndPolicy.Name, appWithWorkflowAndPolicy.Namespace)
tryReconcile(reconciler, appWithWorkflowAndPolicy.Name, appWithWorkflowAndPolicy.Namespace)
appRev := &oamcore.ApplicationRevision{}
Expect(k8sClient.Get(ctx, client.ObjectKey{
Name: appWithWorkflowAndPolicy.Name + "-v1",
Namespace: namespace,
}, appRev)).Should(BeNil())
cm := &corev1.ConfigMap{}
Expect(k8sClient.Get(ctx, client.ObjectKey{
Name: appRev.Name,
Namespace: namespace,
}, cm)).Should(util.NotFoundMatcher{})
})
It("should create workload in application when policy is specified", func() {
Expect(k8sClient.Create(ctx, appWithPolicy)).Should(BeNil())
// first try to add finalizer
tryReconcile(reconciler, appWithPolicy.Name, appWithPolicy.Namespace)
tryReconcile(reconciler, appWithPolicy.Name, appWithPolicy.Namespace)
tryReconcile(reconciler, appWithPolicy.Name, appWithPolicy.Namespace)
deploy := &appsv1.Deployment{}
Expect(k8sClient.Get(ctx, client.ObjectKey{
@ -154,9 +137,8 @@ var _ = Describe("Test Workflow", func() {
}, policyObj)).Should(BeNil())
})
It("should create workload in policy before workflow start", func() {
It("should create workload in policy", func() {
appWithPolicyAndWorkflow := appWithWorkflow.DeepCopy()
appWithPolicyAndWorkflow.SetName("test-app-with-policy")
appWithPolicyAndWorkflow.Spec.Policies = []oamcore.AppPolicy{{
Name: "test-foo-policy",
Type: "foopolicy",
@ -169,6 +151,12 @@ var _ = Describe("Test Workflow", func() {
tryReconcile(reconciler, appWithPolicyAndWorkflow.Name, appWithPolicyAndWorkflow.Namespace)
tryReconcile(reconciler, appWithPolicyAndWorkflow.Name, appWithPolicyAndWorkflow.Namespace)
appRev := &oamcore.ApplicationRevision{}
Expect(k8sClient.Get(ctx, client.ObjectKey{
Name: appWithWorkflow.Name + "-v1",
Namespace: namespace,
}, appRev)).Should(BeNil())
policyObj := &unstructured.Unstructured{}
policyObj.SetGroupVersionKind(schema.GroupVersionKind{
Group: "example.com",
@ -180,15 +168,6 @@ var _ = Describe("Test Workflow", func() {
Name: "test-foo-policy",
Namespace: appWithPolicyAndWorkflow.Namespace,
}, policyObj)).Should(BeNil())
})
It("should execute workflow step to apply and wait", func() {
Expect(k8sClient.Create(ctx, appWithWorkflow.DeepCopy())).Should(BeNil())
// first try to add finalizer
tryReconcile(reconciler, appWithWorkflow.Name, appWithWorkflow.Namespace)
tryReconcile(reconciler, appWithWorkflow.Name, appWithWorkflow.Namespace)
tryReconcile(reconciler, appWithWorkflow.Name, appWithWorkflow.Namespace)
// check resource created
stepObj := &unstructured.Unstructured{}
@ -212,14 +191,13 @@ var _ = Describe("Test Workflow", func() {
Expect(appObj.Status.Workflow.Steps[0].Name).Should(Equal("test-wf1"))
Expect(appObj.Status.Workflow.Steps[0].Type).Should(Equal("foowf"))
Expect(appObj.Status.Workflow.Steps[0].Phase).Should(Equal(common.WorkflowStepPhaseRunning))
Expect(appObj.Status.Workflow.Steps[0].Phase).Should(Equal(workflowv1alpha1.WorkflowStepPhaseRunning))
Expect(appObj.Status.Workflow.Steps[0].Reason).Should(Equal("Wait"))
// update spec to trigger spec
triggerWorkflowStepToSucceed(stepObj)
Expect(k8sClient.Update(ctx, stepObj)).Should(BeNil())
tryReconcile(reconciler, appWithWorkflow.Name, appWithWorkflow.Namespace)
tryReconcile(reconciler, appWithWorkflow.Name, appWithWorkflow.Namespace)
tryReconcile(reconciler, appWithWorkflow.Name, appWithWorkflow.Namespace)
@ -229,24 +207,25 @@ var _ = Describe("Test Workflow", func() {
Namespace: appWithWorkflow.Namespace,
}, appObj)).Should(BeNil())
Expect(appObj.Status.Workflow.Steps[0].Phase).Should(Equal(common.WorkflowStepPhaseSucceeded))
Expect(appObj.Status.Workflow.Steps[0].Phase).Should(Equal(workflowv1alpha1.WorkflowStepPhaseSucceeded))
Expect(appObj.Status.Phase).Should(BeEquivalentTo(common.ApplicationRunning))
})
It("test workflow suspend", func() {
suspendApp := appWithWorkflow.DeepCopy()
suspendApp.Name = "test-app-suspend"
suspendApp.Spec.Workflow.Steps = []oamcore.WorkflowStep{{
Name: "suspend",
Type: "suspend",
Properties: &runtime.RawExtension{Raw: []byte(`{}`)},
suspendApp.Spec.Workflow.Steps = []workflowv1alpha1.WorkflowStep{{
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "suspend",
Type: "suspend",
Properties: &runtime.RawExtension{Raw: []byte(`{}`)},
},
}}
Expect(k8sClient.Create(ctx, suspendApp)).Should(BeNil())
// first try to add finalizer
tryReconcile(reconciler, suspendApp.Name, suspendApp.Namespace)
tryReconcile(reconciler, suspendApp.Name, suspendApp.Namespace)
tryReconcile(reconciler, suspendApp.Name, suspendApp.Namespace)
appObj := &oamcore.Application{}
Expect(k8sClient.Get(ctx, client.ObjectKey{
@ -256,11 +235,11 @@ var _ = Describe("Test Workflow", func() {
Expect(appObj.Status.Workflow.Suspend).Should(BeTrue())
Expect(appObj.Status.Phase).Should(BeEquivalentTo(common.ApplicationWorkflowSuspending))
Expect(appObj.Status.Workflow.Steps[0].Phase).Should(BeEquivalentTo(common.WorkflowStepPhaseRunning))
Expect(appObj.Status.Workflow.Steps[0].Phase).Should(BeEquivalentTo(workflowv1alpha1.WorkflowStepPhaseRunning))
Expect(appObj.Status.Workflow.Steps[0].ID).ShouldNot(BeEquivalentTo(""))
// resume
appObj.Status.Workflow.Suspend = false
appObj.Status.Workflow.Steps[0].Phase = common.WorkflowStepPhaseSucceeded
appObj.Status.Workflow.Steps[0].Phase = workflowv1alpha1.WorkflowStepPhaseSucceeded
Expect(k8sClient.Status().Patch(ctx, appObj, client.Merge)).Should(BeNil())
Expect(k8sClient.Get(ctx, client.ObjectKey{
Name: suspendApp.Name,
@ -268,7 +247,6 @@ var _ = Describe("Test Workflow", func() {
}, appObj)).Should(BeNil())
Expect(appObj.Status.Workflow.Suspend).Should(BeFalse())
tryReconcile(reconciler, suspendApp.Name, suspendApp.Namespace)
tryReconcile(reconciler, suspendApp.Name, suspendApp.Namespace)
appObj = &oamcore.Application{}
@ -284,16 +262,20 @@ var _ = Describe("Test Workflow", func() {
It("test workflow terminate a suspend workflow", func() {
suspendApp := appWithWorkflow.DeepCopy()
suspendApp.Name = "test-terminate-suspend-app"
suspendApp.Spec.Workflow.Steps = []oamcore.WorkflowStep{
suspendApp.Spec.Workflow.Steps = []workflowv1alpha1.WorkflowStep{
{
Name: "suspend",
Type: "suspend",
Properties: &runtime.RawExtension{Raw: []byte(`{}`)},
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "suspend",
Type: "suspend",
Properties: &runtime.RawExtension{Raw: []byte(`{}`)},
},
},
{
Name: "suspend-1",
Type: "suspend",
Properties: &runtime.RawExtension{Raw: []byte(`{}`)},
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "suspend-1",
Type: "suspend",
Properties: &runtime.RawExtension{Raw: []byte(`{}`)},
},
}}
Expect(k8sClient.Create(ctx, suspendApp)).Should(BeNil())
@ -314,7 +296,7 @@ var _ = Describe("Test Workflow", func() {
// terminate
appObj.Status.Workflow.Terminated = true
appObj.Status.Workflow.Suspend = false
appObj.Status.Workflow.Steps[0].Phase = common.WorkflowStepPhaseFailed
appObj.Status.Workflow.Steps[0].Phase = workflowv1alpha1.WorkflowStepPhaseFailed
appObj.Status.Workflow.Steps[0].Reason = wfTypes.StatusReasonTerminate
Expect(k8sClient.Status().Patch(ctx, appObj, client.Merge)).Should(BeNil())
@ -361,7 +343,7 @@ var _ = Describe("Test Workflow", func() {
Name: "myweb1",
Type: "worker-with-health",
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)},
Inputs: common.StepInputs{
Inputs: workflowv1alpha1.StepInputs{
{
From: "message",
ParameterKey: "properties.enemies",
@ -376,20 +358,24 @@ var _ = Describe("Test Workflow", func() {
Name: "myweb2",
Type: "worker-with-health",
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)},
Outputs: common.StepOutputs{
Outputs: workflowv1alpha1.StepOutputs{
{Name: "message", ValueFrom: "output.status.conditions[0].message+\",\"+outputs.gameconfig.data.lives"},
},
},
},
Workflow: &oamcore.Workflow{
Steps: []oamcore.WorkflowStep{{
Name: "test-web2",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb2"}`)},
Steps: []workflowv1alpha1.WorkflowStep{{
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "test-web2",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb2"}`)},
},
}, {
Name: "test-web1",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb1"}`)},
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "test-web1",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb1"}`)},
},
}},
},
},
@ -415,7 +401,6 @@ var _ = Describe("Test Workflow", func() {
}}
Expect(k8sClient.Status().Update(ctx, expDeployment)).Should(BeNil())
testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey})
testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey})
expDeployment = &appsv1.Deployment{}
@ -424,12 +409,10 @@ var _ = Describe("Test Workflow", func() {
expDeployment.Status.ReadyReplicas = 1
Expect(k8sClient.Status().Update(ctx, expDeployment)).Should(BeNil())
testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey})
testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey})
testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey})
checkApp = &oamcore.Application{}
Expect(k8sClient.Get(ctx, appKey, checkApp)).Should(BeNil())
Expect(checkApp.Status.Workflow.Mode).Should(BeEquivalentTo(common.WorkflowModeStep))
Expect(checkApp.Status.Workflow.Mode).Should(BeEquivalentTo(fmt.Sprintf("%s-%s", workflowv1alpha1.WorkflowModeStep, workflowv1alpha1.WorkflowModeDAG)))
Expect(checkApp.Status.Phase).Should(BeEquivalentTo(common.ApplicationRunning))
checkCM := &corev1.ConfigMap{}
@ -480,14 +463,18 @@ var _ = Describe("Test Workflow", func() {
},
},
Workflow: &oamcore.Workflow{
Steps: []oamcore.WorkflowStep{{
Name: "test-web2",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb2"}`)},
Steps: []workflowv1alpha1.WorkflowStep{{
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "test-web2",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb2"}`)},
},
}, {
Name: "test-web1",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb1"}`)},
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "test-web1",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb1"}`)},
},
}},
},
},
@ -527,7 +514,7 @@ var _ = Describe("Test Workflow", func() {
testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey})
checkApp = &oamcore.Application{}
Expect(k8sClient.Get(ctx, appKey, checkApp)).Should(BeNil())
Expect(checkApp.Status.Workflow.Mode).Should(BeEquivalentTo(common.WorkflowModeStep))
Expect(checkApp.Status.Workflow.Mode).Should(BeEquivalentTo(fmt.Sprintf("%s-%s", workflowv1alpha1.WorkflowModeStep, workflowv1alpha1.WorkflowModeDAG)))
Expect(checkApp.Status.Phase).Should(BeEquivalentTo(common.ApplicationRunning))
})
@ -561,7 +548,7 @@ var _ = Describe("Test Workflow", func() {
Type: "worker-with-health",
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox"}`)},
DependsOn: []string{"myweb2"},
Inputs: common.StepInputs{
Inputs: workflowv1alpha1.StepInputs{
{
From: "message",
ParameterKey: "properties.enemies",
@ -576,20 +563,24 @@ var _ = Describe("Test Workflow", func() {
Name: "myweb2",
Type: "worker-with-health",
Properties: &runtime.RawExtension{Raw: []byte(`{"cmd":["sleep","1000"],"image":"busybox","lives": "i am lives","enemies": "empty"}`)},
Outputs: common.StepOutputs{
Outputs: workflowv1alpha1.StepOutputs{
{Name: "message", ValueFrom: "output.status.conditions[0].message+\",\"+outputs.gameconfig.data.lives"},
},
},
},
Workflow: &oamcore.Workflow{
Steps: []oamcore.WorkflowStep{{
Name: "test-web2",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb2"}`)},
Steps: []workflowv1alpha1.WorkflowStep{{
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "test-web2",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb2"}`)},
},
}, {
Name: "test-web1",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb1"}`)},
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "test-web1",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb1"}`)},
},
}},
},
},
@ -629,7 +620,7 @@ var _ = Describe("Test Workflow", func() {
testutil.ReconcileOnce(reconciler, reconcile.Request{NamespacedName: appKey})
checkApp = &oamcore.Application{}
Expect(k8sClient.Get(ctx, appKey, checkApp)).Should(BeNil())
Expect(checkApp.Status.Workflow.Mode).Should(BeEquivalentTo(common.WorkflowModeStep))
Expect(checkApp.Status.Workflow.Mode).Should(BeEquivalentTo(fmt.Sprintf("%s-%s", workflowv1alpha1.WorkflowModeStep, workflowv1alpha1.WorkflowModeDAG)))
Expect(checkApp.Status.Phase).Should(BeEquivalentTo(common.ApplicationRunning))
})
@ -679,21 +670,25 @@ var _ = Describe("Test Workflow", func() {
Expect(updateApp.Status.Phase).Should(BeEquivalentTo(common.ApplicationRunning))
updateApp.Spec.Components[0].Properties = &runtime.RawExtension{Raw: []byte(`{}`)}
updateApp.Spec.Workflow = &oamcore.Workflow{
Steps: []oamcore.WorkflowStep{{
Name: "test-web2",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb2"}`)},
Outputs: common.StepOutputs{
{Name: "image", ValueFrom: "output.spec.template.spec.containers[0].image"},
Steps: []workflowv1alpha1.WorkflowStep{{
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "test-web2",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb2"}`)},
Outputs: workflowv1alpha1.StepOutputs{
{Name: "image", ValueFrom: "output.spec.template.spec.containers[0].image"},
},
},
}, {
Name: "test-web1",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb1"}`)},
Inputs: common.StepInputs{
{
From: "image",
ParameterKey: "image",
WorkflowStepBase: workflowv1alpha1.WorkflowStepBase{
Name: "test-web1",
Type: "apply-component",
Properties: &runtime.RawExtension{Raw: []byte(`{"component":"myweb1"}`)},
Inputs: workflowv1alpha1.StepInputs{
{
From: "image",
ParameterKey: "image",
},
},
},
}},

View File

@ -31,6 +31,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
@ -39,7 +41,6 @@ import (
oamctrl "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
coredef "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2/core"
"github.com/oam-dev/kubevela/pkg/controller/utils"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
"github.com/oam-dev/kubevela/pkg/oam/util"

View File

@ -33,8 +33,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"github.com/kubevela/workflow/pkg/cue/packages"
oamCore "github.com/oam-dev/kubevela/apis/core.oam.dev"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
)

View File

@ -31,6 +31,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
@ -38,7 +40,6 @@ import (
oamctrl "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
coredef "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2/core"
"github.com/oam-dev/kubevela/pkg/controller/utils"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
"github.com/oam-dev/kubevela/pkg/oam/util"

View File

@ -34,8 +34,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"github.com/kubevela/workflow/pkg/cue/packages"
oamCore "github.com/oam-dev/kubevela/apis/core.oam.dev"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
)

View File

@ -36,13 +36,14 @@ import (
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/kubevela/workflow/pkg/cue/process"
terraformtypes "github.com/oam-dev/terraform-controller/api/types"
terraformapi "github.com/oam-dev/terraform-controller/api/v1beta2"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
oamtypes "github.com/oam-dev/kubevela/apis/types"
af "github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/cue/process"
velaprocess "github.com/oam-dev/kubevela/pkg/cue/process"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/util"
)
@ -455,7 +456,7 @@ func CUEBasedHealthCheck(ctx context.Context, c client.Client, wlRef WorkloadRef
wlHealth.Diagnosis = configuration.Status.Apply.Message
okToCheckTrait = true
default:
pCtx = process.NewContext(af.GenerateContextDataFromAppFile(appfile, wl.Name))
pCtx = velaprocess.NewContext(af.GenerateContextDataFromAppFile(appfile, wl.Name))
pCtx.SetCtx(ctx)
if wl.CapabilityCategory != oamtypes.CUECategory {
templateStr, err := af.GenerateCUETemplate(wl)

View File

@ -37,6 +37,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"github.com/kubevela/workflow/pkg/cue/packages"
commonapis "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
@ -44,7 +46,6 @@ import (
af "github.com/oam-dev/kubevela/pkg/appfile"
"github.com/oam-dev/kubevela/pkg/controller/common"
controller "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/multicluster"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"

View File

@ -31,6 +31,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
@ -38,7 +40,6 @@ import (
oamctrl "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
coredef "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2/core"
"github.com/oam-dev/kubevela/pkg/controller/utils"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
"github.com/oam-dev/kubevela/pkg/oam/util"

View File

@ -33,8 +33,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"github.com/kubevela/workflow/pkg/cue/packages"
oamCore "github.com/oam-dev/kubevela/apis/core.oam.dev"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
)

View File

@ -33,8 +33,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"github.com/kubevela/workflow/pkg/cue/packages"
oamCore "github.com/oam-dev/kubevela/apis/core.oam.dev"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
)

View File

@ -31,6 +31,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
@ -38,7 +40,6 @@ import (
oamctrl "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev"
coredef "github.com/oam-dev/kubevela/pkg/controller/core.oam.dev/v1alpha2/core"
"github.com/oam-dev/kubevela/pkg/controller/utils"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
"github.com/oam-dev/kubevela/pkg/oam/util"

View File

@ -19,6 +19,8 @@ package controller
import (
flag "github.com/spf13/pflag"
wfContext "github.com/kubevela/workflow/pkg/context"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/auth"
ctrlClient "github.com/oam-dev/kubevela/pkg/client"
@ -27,7 +29,6 @@ import (
"github.com/oam-dev/kubevela/pkg/resourcekeeper"
"github.com/oam-dev/kubevela/pkg/resourcetracker"
"github.com/oam-dev/kubevela/pkg/workflow"
wfContext "github.com/oam-dev/kubevela/pkg/workflow/context"
)
// AddOptimizeFlags add flags

View File

@ -38,15 +38,16 @@ import (
"k8s.io/utils/pointer"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/kubevela/workflow/pkg/cue/model/value"
"github.com/kubevela/workflow/pkg/cue/packages"
commontypes "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/appfile"
"github.com/oam-dev/kubevela/pkg/appfile/helm"
velacue "github.com/oam-dev/kubevela/pkg/cue"
"github.com/oam-dev/kubevela/pkg/cue/model"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/cue/process"
"github.com/oam-dev/kubevela/pkg/oam/util"
"github.com/oam-dev/kubevela/pkg/utils/common"
"github.com/oam-dev/kubevela/pkg/utils/terraform"
@ -817,7 +818,7 @@ func ConvertOpenAPISchema2SwaggerObject(data []byte) (*openapi3.Schema, error) {
return nil, err
}
schemaRef, ok := swagger.Components.Schemas[model.ParameterFieldName]
schemaRef, ok := swagger.Components.Schemas[process.ParameterFieldName]
if !ok {
return nil, errors.New(util.ErrGenerateOpenAPIV2JSONSchemaForCapability)
}

View File

@ -29,8 +29,9 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"github.com/kubevela/workflow/pkg/cue/packages"
oamCore "github.com/oam-dev/kubevela/apis/core.oam.dev"
"github.com/oam-dev/kubevela/pkg/cue/packages"
)
var cfg *rest.Config

View File

@ -32,7 +32,7 @@ import (
"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/appfile"
"github.com/oam-dev/kubevela/pkg/cue/model"
"github.com/oam-dev/kubevela/pkg/cue/process"
"github.com/oam-dev/kubevela/pkg/oam/util"
)
@ -215,7 +215,7 @@ func TestFixOpenAPISchema(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
swagger, _ := openapi3.NewLoader().LoadFromFile(filepath.Join(TestDir, tc.inputFile))
schema := swagger.Components.Schemas[model.ParameterFieldName].Value
schema := swagger.Components.Schemas[process.ParameterFieldName].Value
FixOpenAPISchema("", schema)
fixedSchema, _ := schema.MarshalJSON()
expectedSchema, _ := os.ReadFile(filepath.Join(TestDir, tc.fixedFile))

View File

@ -41,12 +41,13 @@ import (
"k8s.io/klog/v2"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/kubevela/workflow/pkg/cue/packages"
commontypes "github.com/oam-dev/kubevela/apis/core.oam.dev/common"
"github.com/oam-dev/kubevela/apis/core.oam.dev/condition"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
"github.com/oam-dev/kubevela/pkg/controller/common"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
"github.com/oam-dev/kubevela/pkg/oam/util"

View File

@ -1,10 +0,0 @@
# Develop Tips
The following packages need to be tested without external/tool dependencies, So that the cue-sh/unity can do verification
- github.com/kubevela/kubevela/pkg/cue/definition
- github.com/kubevela/kubevela/pkg/cue/model
- github.com/kubevela/kubevela/pkg/cue/model/sets
- github.com/kubevela/kubevela/pkg/cue/process
- github.com/kubevela/kubevela/pkg/cue/task
- github.com/kubevela/kubevela/pkg/cue/packages

View File

@ -18,7 +18,6 @@ package cue
// BaseTemplate include base info provided by KubeVela for CUE template
const BaseTemplate = `
context: {
name: string
config?: [...{

View File

@ -23,10 +23,11 @@ import (
"cuelang.org/go/cue"
"github.com/kubevela/workflow/pkg/cue/model/value"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/cue/model"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/cue/process"
)
// ErrParameterNotExist represents the parameter field is not exist in CUE template
@ -47,7 +48,7 @@ func GetParameters(templateStr string, pd *packages.PackageDiscover) ([]types.Pa
var found bool
for i := 0; i < tempStruct.Len(); i++ {
paraDef = tempStruct.Field(i)
if paraDef.Name == model.ParameterFieldName {
if paraDef.Name == process.ParameterFieldName {
found = true
break
}

View File

@ -29,11 +29,13 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/pkg/cue/model"
"github.com/oam-dev/kubevela/pkg/cue/model/sets"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/cue/process"
"github.com/kubevela/workflow/pkg/cue/model"
"github.com/kubevela/workflow/pkg/cue/model/sets"
"github.com/kubevela/workflow/pkg/cue/model/value"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/kubevela/workflow/pkg/cue/process"
velaprocess "github.com/oam-dev/kubevela/pkg/cue/process"
"github.com/oam-dev/kubevela/pkg/cue/task"
"github.com/oam-dev/kubevela/pkg/oam"
"github.com/oam-dev/kubevela/pkg/oam/util"
@ -41,9 +43,9 @@ import (
const (
// OutputFieldName is the name of the struct contains the CR data
OutputFieldName = model.OutputFieldName
OutputFieldName = velaprocess.OutputFieldName
// OutputsFieldName is the name of the struct contains the map[string]CR data
OutputsFieldName = model.OutputsFieldName
OutputsFieldName = velaprocess.OutputsFieldName
// PatchFieldName is the name of the struct contains the patch of CR data
PatchFieldName = "patch"
// PatchOutputsFieldName is the name of the struct contains the patch of outputs CR data
@ -94,17 +96,17 @@ func (wd *workloadDef) Complete(ctx process.Context, abstractTemplate string, pa
if err := value.AddFile(bi, "-", renderTemplate(abstractTemplate)); err != nil {
return errors.WithMessagef(err, "invalid cue template of workload %s", wd.name)
}
var paramFile = model.ParameterFieldName + ": {}"
var paramFile = velaprocess.ParameterFieldName + ": {}"
if params != nil {
bt, err := json.Marshal(params)
if err != nil {
return errors.WithMessagef(err, "marshal parameter of workload %s", wd.name)
}
if string(bt) != "null" {
paramFile = fmt.Sprintf("%s: %s", model.ParameterFieldName, string(bt))
paramFile = fmt.Sprintf("%s: %s", velaprocess.ParameterFieldName, string(bt))
}
}
if err := value.AddFile(bi, model.ParameterFieldName, paramFile); err != nil {
if err := value.AddFile(bi, velaprocess.ParameterFieldName, paramFile); err != nil {
return errors.WithMessagef(err, "invalid parameter of workload %s", wd.name)
}
@ -159,9 +161,9 @@ func (wd *workloadDef) Complete(ctx process.Context, abstractTemplate string, pa
}
func (wd *workloadDef) getTemplateContext(ctx process.Context, cli client.Reader, accessor util.NamespaceAccessor) (map[string]interface{}, error) {
var root = initRoot(ctx.BaseContextLabels())
var commonLabels = GetCommonLabels(ctx.BaseContextLabels())
baseLabels := GetBaseContextLabels(ctx)
var root = initRoot(baseLabels)
var commonLabels = GetCommonLabels(baseLabels)
base, assists := ctx.Output()
componentWorkload, err := base.Unstructured()
@ -296,7 +298,7 @@ func (td *traitDef) Complete(ctx process.Context, abstractTemplate string, param
return errors.WithMessagef(err, "marshal parameter of trait %s", td.name)
}
if string(bt) != "null" {
buff += fmt.Sprintf("%s: %s\n", model.ParameterFieldName, string(bt))
buff += fmt.Sprintf("%s: %s\n", velaprocess.ParameterFieldName, string(bt))
}
}
c, err := ctx.ExtendedContextFile()
@ -390,13 +392,13 @@ func GetCommonLabels(contextLabels map[string]string) map[string]string {
var commonLabels = map[string]string{}
for k, v := range contextLabels {
switch k {
case model.ContextAppName:
case velaprocess.ContextAppName:
commonLabels[oam.LabelAppName] = v
case model.ContextName:
case velaprocess.ContextName:
commonLabels[oam.LabelAppComponent] = v
case model.ContextAppRevision:
case velaprocess.ContextAppRevision:
commonLabels[oam.LabelAppRevision] = v
case model.ContextReplicaKey:
case velaprocess.ContextReplicaKey:
commonLabels[oam.LabelReplicaKey] = v
}
@ -404,6 +406,15 @@ func GetCommonLabels(contextLabels map[string]string) map[string]string {
return commonLabels
}
// GetBaseContextLabels get base context labels
func GetBaseContextLabels(ctx process.Context) map[string]string {
baseLabels := ctx.BaseContextLabels()
baseLabels[velaprocess.ContextAppName] = ctx.GetData(velaprocess.ContextAppName).(string)
baseLabels[velaprocess.ContextAppRevision] = ctx.GetData(velaprocess.ContextAppRevision).(string)
return baseLabels
}
func initRoot(contextLabels map[string]string) map[string]interface{} {
var root = map[string]interface{}{}
for k, v := range contextLabels {
@ -420,8 +431,9 @@ parameter: _
}
func (td *traitDef) getTemplateContext(ctx process.Context, cli client.Reader, accessor util.NamespaceAccessor) (map[string]interface{}, error) {
var root = initRoot(ctx.BaseContextLabels())
var commonLabels = GetCommonLabels(ctx.BaseContextLabels())
baseLabels := GetBaseContextLabels(ctx)
var root = initRoot(baseLabels)
var commonLabels = GetCommonLabels(baseLabels)
_, assists := ctx.Output()
outputs := make(map[string]interface{})

View File

@ -24,8 +24,9 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"github.com/kubevela/workflow/pkg/cue/packages"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/cue/process"
)

View File

@ -1,106 +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 model
import (
"cuelang.org/go/cue"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/klog/v2"
"github.com/oam-dev/kubevela/pkg/cue/model/sets"
)
// Instance defines Model Interface
type Instance interface {
String() (string, error)
Value() cue.Value
Unstructured() (*unstructured.Unstructured, error)
IsBase() bool
Unify(other cue.Value, options ...sets.UnifyOption) error
Compile() ([]byte, error)
}
type instance struct {
v cue.Value
base bool
}
// String return instance's cue format string
func (inst *instance) String() (string, error) {
return sets.ToString(inst.v)
}
func (inst *instance) Value() cue.Value {
return inst.v
}
// IsBase indicate whether the instance is base model
func (inst *instance) IsBase() bool {
return inst.base
}
func (inst *instance) Compile() ([]byte, error) {
if err := inst.v.Err(); err != nil {
return nil, err
}
// compiled object should be final and concrete value
if err := inst.v.Validate(cue.Concrete(true), cue.Final()); err != nil {
return nil, err
}
return inst.v.MarshalJSON()
}
// Unstructured convert cue values to unstructured.Unstructured
// TODO(wonderflow): will it be better if we try to decode it to concrete object(such as K8s Deployment) by using runtime.Schema?
func (inst *instance) Unstructured() (*unstructured.Unstructured, error) {
jsonv, err := inst.Compile()
if err != nil {
klog.ErrorS(err, "failed to have the workload/trait unstructured", "Definition", inst.v)
return nil, errors.Wrap(err, "failed to have the workload/trait unstructured")
}
o := &unstructured.Unstructured{}
if err := o.UnmarshalJSON(jsonv); err != nil {
return nil, err
}
return o, nil
}
// Unify implement unity operations between instances
func (inst *instance) Unify(other cue.Value, options ...sets.UnifyOption) error {
pv, err := sets.StrategyUnify(inst.v, other, options...)
if err != nil {
return err
}
inst.v = pv
return nil
}
// NewBase create a base instance
func NewBase(v cue.Value) (Instance, error) {
return &instance{
v: v,
base: true,
}, nil
}
// NewOther create a non-base instance
func NewOther(v cue.Value) (Instance, error) {
return &instance{
v: v,
}, nil
}

View File

@ -1,187 +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 model
import (
"fmt"
"testing"
"cuelang.org/go/cue/cuecontext"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
)
func TestInstance(t *testing.T) {
testCases := []struct {
src string
gvk schema.GroupVersionKind
}{{
src: `apiVersion: "apps/v1"
kind: "Deployment"
metadata: name: "test"
`,
gvk: schema.GroupVersionKind{
Group: "apps",
Version: "v1",
Kind: "Deployment",
}},
}
for _, v := range testCases {
inst := cuecontext.New().CompileString(v.src)
base, err := NewBase(inst.Value())
if err != nil {
t.Error(err)
return
}
baseObj, err := base.Unstructured()
if err != nil {
t.Error(err)
return
}
assert.Equal(t, v.gvk, baseObj.GetObjectKind().GroupVersionKind())
assert.Equal(t, true, base.IsBase())
other, err := NewOther(inst.Value())
if err != nil {
t.Error(err)
return
}
otherObj, err := other.Unstructured()
if err != nil {
t.Error(err)
return
}
assert.Equal(t, v.gvk, otherObj.GetObjectKind().GroupVersionKind())
assert.Equal(t, false, other.IsBase())
}
}
func TestIncompleteError(t *testing.T) {
base := `parameter: {
name: string
// +usage=Which image would you like to use for your service
// +short=i
image: string
// +usage=Which port do you want customer traffic sent to
// +short=p
port: *8080 | int
env: [...{
name: string
value: string
}]
cpu?: string
}
output: {
apiVersion: "apps/v1"
kind: "Deployment"
metadata: name: parameter.name
spec: {
selector:
matchLabels:
app: parameter.name
template: {
metadata:
labels:
app: parameter.name
spec: containers: [{
image: parameter.image
name: parameter.name
env: parameter.env
ports: [{
containerPort: parameter.port
protocol: "TCP"
name: "default"
}]
if parameter["cpu"] != _|_ {
resources: {
limits:
cpu: parameter.cpu
requests:
cpu: parameter.cpu
}
}
}]
}
}
}
`
inst := cuecontext.New().CompileString(base)
newbase, err := NewBase(inst.Value())
assert.NoError(t, err)
data, err := newbase.Unstructured()
assert.Error(t, err)
var expnil *unstructured.Unstructured
assert.Equal(t, expnil, data)
}
func TestError(t *testing.T) {
ctx := cuecontext.New()
ins := &instance{
v: ctx.CompileString(``),
}
_, err := ins.Unstructured()
assert.Equal(t, err.Error(), "Object 'Kind' is missing in '{}'")
ins = &instance{
v: ctx.CompileString(`
apiVersion: "apps/v1"
kind: "Deployment"
metadata: name: parameter.name
`),
}
_, err = ins.Unstructured()
assert.Equal(t, err.Error(), fmt.Sprintf("failed to have the workload/trait unstructured: metadata.name: reference \"%s\" not found", ParameterFieldName))
ins = &instance{
v: ctx.CompileString(`
apiVersion: "apps/v1"
kind: "Deployment"
metadata: name: "abc"
`),
}
obj, err := ins.Unstructured()
assert.Equal(t, err, nil)
assert.Equal(t, obj, &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"name": "abc",
},
},
})
ins = &instance{
v: ctx.CompileString(`
apiVersion: "source.toolkit.fluxcd.io/v1beta1"
metadata: {
name: "grafana"
}
kind: "HelmRepository"
spec: {
url: string
interval: *"5m" | string
}`),
}
o, err := ins.Unstructured()
assert.Nil(t, o)
assert.NotNil(t, err)
}

View File

@ -1,428 +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 sets
import (
"fmt"
"strings"
"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/parser"
jsonpatch "github.com/evanphx/json-patch"
"github.com/pkg/errors"
)
const (
// TagPatchKey specify the primary key of the list items
TagPatchKey = "patchKey"
// TagPatchStrategy specify a strategy of the strategic merge patch
TagPatchStrategy = "patchStrategy"
// StrategyRetainKeys notes on the strategic merge patch using the retainKeys strategy
StrategyRetainKeys = "retainKeys"
// StrategyReplace notes on the strategic merge patch will allow replacing list
StrategyReplace = "replace"
// StrategyJSONPatch notes on the strategic merge patch will follow the RFC 6902 to run JsonPatch
StrategyJSONPatch = "jsonPatch"
// StrategyJSONMergePatch notes on the strategic merge patch will follow the RFC 7396 to run JsonMergePatch
StrategyJSONMergePatch = "jsonMergePatch"
)
var (
notFoundErr = errors.Errorf("not found")
)
// UnifyParams params for unify
type UnifyParams struct {
PatchStrategy string
}
// UnifyOption defines the option for unify
type UnifyOption interface {
ApplyToOption(params *UnifyParams)
}
// UnifyByJSONPatch unify by json patch following RFC 6902
type UnifyByJSONPatch struct{}
// ApplyToOption apply to option
func (op UnifyByJSONPatch) ApplyToOption(params *UnifyParams) {
params.PatchStrategy = StrategyJSONPatch
}
// UnifyByJSONMergePatch unify by json patch following RFC 7396
type UnifyByJSONMergePatch struct{}
// ApplyToOption apply to option
func (op UnifyByJSONMergePatch) ApplyToOption(params *UnifyParams) {
params.PatchStrategy = StrategyJSONMergePatch
}
func newUnifyParams(options ...UnifyOption) *UnifyParams {
params := &UnifyParams{}
for _, op := range options {
op.ApplyToOption(params)
}
return params
}
// CreateUnifyOptionsForPatcher create unify options for patcher
func CreateUnifyOptionsForPatcher(patcher cue.Value) (options []UnifyOption) {
if IsJSONPatch(patcher) {
options = append(options, UnifyByJSONPatch{})
} else if IsJSONMergePatch(patcher) {
options = append(options, UnifyByJSONMergePatch{})
}
return
}
type interceptor func(baseNode ast.Node, patchNode ast.Node) error
func listMergeProcess(field *ast.Field, key string, baseList, patchList *ast.ListLit) {
kmaps := map[string]ast.Expr{}
nElts := []ast.Expr{}
keys := strings.Split(key, ",")
for _, key := range keys {
foundPatch := false
for i, elt := range patchList.Elts {
if _, ok := elt.(*ast.Ellipsis); ok {
continue
}
nodev, err := lookUp(elt, strings.Split(key, ".")...)
if err != nil {
continue
}
foundPatch = true
blit, ok := nodev.(*ast.BasicLit)
if !ok {
return
}
kmaps[fmt.Sprintf(key, blit.Value)] = patchList.Elts[i]
}
if !foundPatch {
if len(patchList.Elts) == 0 {
continue
}
return
}
hasStrategyRetainKeys := isStrategyRetainKeys(field)
for i, elt := range baseList.Elts {
if _, ok := elt.(*ast.Ellipsis); ok {
continue
}
nodev, err := lookUp(elt, strings.Split(key, ".")...)
if err != nil {
continue
}
blit, ok := nodev.(*ast.BasicLit)
if !ok {
return
}
k := fmt.Sprintf(key, blit.Value)
if v, ok := kmaps[k]; ok {
if hasStrategyRetainKeys {
baseList.Elts[i] = ast.NewStruct()
}
nElts = append(nElts, v)
delete(kmaps, k)
} else {
nElts = append(nElts, ast.NewStruct())
}
}
}
for _, elt := range patchList.Elts {
for _, v := range kmaps {
if elt == v {
nElts = append(nElts, v)
break
}
}
}
nElts = append(nElts, &ast.Ellipsis{})
patchList.Elts = nElts
}
func strategyPatchHandle() interceptor {
return func(baseNode ast.Node, patchNode ast.Node) error {
walker := newWalker(func(node ast.Node, ctx walkCtx) {
field, ok := node.(*ast.Field)
if !ok {
return
}
value := peelCloseExpr(field.Value)
switch val := value.(type) {
case *ast.ListLit:
key := ctx.Tags()[TagPatchKey]
patchStrategy := ""
tags := findCommentTag(field.Comments())
for tk, tv := range tags {
if tk == TagPatchKey {
key = tv
}
if tk == TagPatchStrategy {
patchStrategy = tv
}
}
paths := append(ctx.Pos(), labelStr(field.Label))
baseSubNode, err := lookUp(baseNode, paths...)
if err != nil {
if errors.Is(err, notFoundErr) {
return
}
baseSubNode = ast.NewList()
}
baselist, ok := baseSubNode.(*ast.ListLit)
if !ok {
return
}
if patchStrategy == StrategyReplace {
baselist.Elts = val.Elts
} else if key != "" {
listMergeProcess(field, key, baselist, val)
}
default:
if !isStrategyRetainKeys(field) {
return
}
srcNode, _ := lookUp(baseNode, ctx.Pos()...)
if srcNode != nil {
switch v := srcNode.(type) {
case *ast.StructLit:
for _, elt := range v.Elts {
if fe, ok := elt.(*ast.Field); ok &&
labelStr(fe.Label) == labelStr(field.Label) {
fe.Value = field.Value
}
}
case *ast.File: // For the top level element
for _, decl := range v.Decls {
if fe, ok := decl.(*ast.Field); ok &&
labelStr(fe.Label) == labelStr(field.Label) {
fe.Value = field.Value
}
}
}
}
}
})
walker.walk(patchNode)
return nil
}
}
func isStrategyRetainKeys(node *ast.Field) bool {
tags := findCommentTag(node.Comments())
for tk, tv := range tags {
if tk == TagPatchStrategy && tv == StrategyRetainKeys {
return true
}
}
return false
}
// IsJSONMergePatch check if patcher is json merge patch
func IsJSONMergePatch(patcher cue.Value) bool {
tags := findCommentTag(patcher.Doc())
return tags[TagPatchStrategy] == StrategyJSONMergePatch
}
// IsJSONPatch check if patcher is json patch
func IsJSONPatch(patcher cue.Value) bool {
tags := findCommentTag(patcher.Doc())
return tags[TagPatchStrategy] == StrategyJSONPatch
}
// StrategyUnify unify the objects by the strategy
func StrategyUnify(base, patch cue.Value, options ...UnifyOption) (ret cue.Value, err error) {
params := newUnifyParams(options...)
var patchOpts []interceptor
if params.PatchStrategy == StrategyJSONMergePatch || params.PatchStrategy == StrategyJSONPatch {
_, err := OpenBaiscLit(base)
if err != nil {
return base, err
}
} else {
patchOpts = []interceptor{strategyPatchHandle()}
}
return strategyUnify(base, patch, params, patchOpts...)
}
// nolint:staticcheck
func strategyUnify(base cue.Value, patch cue.Value, params *UnifyParams, patchOpts ...interceptor) (val cue.Value, err error) {
if params.PatchStrategy == StrategyJSONMergePatch {
return jsonMergePatch(base, patch)
} else if params.PatchStrategy == StrategyJSONPatch {
return jsonPatch(base, patch.LookupPath(cue.ParsePath("operations")))
}
openBase, err := openListLit(base)
if err != nil {
return cue.Value{}, errors.Wrapf(err, "failed to open list it for merge")
}
patchFile, err := ToFile(patch.Syntax(cue.Docs(true), cue.ResolveReferences(true)))
if err != nil {
return cue.Value{}, err
}
for _, option := range patchOpts {
if err := option(openBase, patchFile); err != nil {
return cue.Value{}, errors.WithMessage(err, "process patchOption")
}
}
baseInst := cuecontext.New().BuildFile(openBase)
patchInst := cuecontext.New().BuildFile(patchFile)
ret := baseInst.Unify(patchInst)
_, err = toString(ret, removeTmpVar)
if err != nil {
return ret, errors.WithMessage(err, " format result toString")
}
if err := ret.Err(); err != nil {
return ret, errors.WithMessage(err, "result check err")
}
if err := ret.Validate(cue.All()); err != nil {
return ret, errors.WithMessage(err, "result validate")
}
return ret, nil
}
func findCommentTag(commentGroup []*ast.CommentGroup) map[string]string {
marker := "+"
kval := map[string]string{}
for _, group := range commentGroup {
for _, lineT := range group.List {
line := lineT.Text
line = strings.TrimPrefix(line, "//")
line = strings.TrimSpace(line)
if len(line) == 0 {
continue
}
if !strings.HasPrefix(line, marker) {
continue
}
kv := strings.SplitN(line[len(marker):], "=", 2)
if len(kv) == 2 {
val := strings.TrimSpace(kv[1])
if len(strings.Fields(val)) > 1 {
continue
}
kval[strings.TrimSpace(kv[0])] = val
}
}
}
return kval
}
func jsonMergePatch(base cue.Value, patch cue.Value) (cue.Value, error) {
ctx := cuecontext.New()
baseJSON, err := base.MarshalJSON()
if err != nil {
return cue.Value{}, errors.Wrapf(err, "failed to marshal base value")
}
patchJSON, err := patch.MarshalJSON()
if err != nil {
return cue.Value{}, errors.Wrapf(err, "failed to marshal patch value")
}
merged, err := jsonpatch.MergePatch(baseJSON, patchJSON)
if err != nil {
return cue.Value{}, errors.Wrapf(err, "failed to merge base value and patch value by JsonMergePatch")
}
output, err := openJSON(string(merged))
if err != nil {
return cue.Value{}, errors.Wrapf(err, "failed to parse open basic lit for merged result")
}
return ctx.BuildFile(output), nil
}
func jsonPatch(base cue.Value, patch cue.Value) (cue.Value, error) {
ctx := cuecontext.New()
baseJSON, err := base.MarshalJSON()
if err != nil {
return cue.Value{}, errors.Wrapf(err, "failed to marshal base value")
}
patchJSON, err := patch.MarshalJSON()
if err != nil {
return cue.Value{}, errors.Wrapf(err, "failed to marshal patch value")
}
decodedPatch, err := jsonpatch.DecodePatch(patchJSON)
if err != nil {
return cue.Value{}, errors.Wrapf(err, "failed to decode patch")
}
merged, err := decodedPatch.Apply(baseJSON)
if err != nil {
return cue.Value{}, errors.Wrapf(err, "failed to apply json patch")
}
output, err := openJSON(string(merged))
if err != nil {
return cue.Value{}, errors.Wrapf(err, "failed to parse open basic lit for merged result")
}
return ctx.BuildFile(output), nil
}
func isEllipsis(elt ast.Node) bool {
_, ok := elt.(*ast.Ellipsis)
return ok
}
func openJSON(data string) (*ast.File, error) {
f, err := parser.ParseFile("-", data, parser.ParseComments)
if err != nil {
return nil, err
}
ast.Walk(f, func(node ast.Node) bool {
field, ok := node.(*ast.Field)
if ok {
v := field.Value
switch lit := v.(type) {
case *ast.StructLit:
if len(lit.Elts) == 0 || !isEllipsis(lit.Elts[len(lit.Elts)-1]) {
lit.Elts = append(lit.Elts, &ast.Ellipsis{})
}
case *ast.ListLit:
if len(lit.Elts) == 0 || !isEllipsis(lit.Elts[len(lit.Elts)-1]) {
lit.Elts = append(lit.Elts, &ast.Ellipsis{})
}
}
}
return true
}, nil)
if len(f.Decls) > 0 {
if emb, ok := f.Decls[0].(*ast.EmbedDecl); ok {
if s, _ok := emb.Expr.(*ast.StructLit); _ok {
f.Decls = s.Elts
}
}
}
return f, nil
}

View File

@ -1,680 +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 sets
import (
"fmt"
"testing"
"cuelang.org/go/cue"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/parser"
"github.com/bmizerany/assert"
"github.com/stretchr/testify/require"
)
func TestPatch(t *testing.T) {
testCase := []struct {
base string
patch string
result string
expectedErr string
}{
{
base: `containers: [{name: "x1"},{name: "x2"},...]`,
patch: `containers: [{name: "x1"},{name: "x2",image: "pause:0.1"}]`,
result: `containers: [{
name: "x1"
}, {
name: "x2"
image: "pause:0.1"
}]
`,
},
{
base: `containers: [{name: "x1"},{name: "x2"},...]`,
patch: `containers: [{name: "x2"},{name: "x1"}]`,
result: `containers: [{
name: _|_ // containers.0.name: conflicting values "x2" and "x1"
}, {
name: _|_ // containers.1.name: conflicting values "x1" and "x2"
}]
`,
expectedErr: `conflicting values "x2" and "x1"`,
},
{
base: `containers: [{name: _|_},{name: "x2"},...]`,
patch: `containers: [{name: _|_},{name: "x2"}]`,
result: `containers: [{
name: _|_ // explicit error (_|_ literal) in source (and 1 more errors)
}, {
name: "x2"
}]
`,
expectedErr: "explicit error (_|_ literal) in source",
},
{
base: `containers: [{name: "x1"},{name: "x2"},...]`,
patch: `
// +patchKey=name
containers: [{name: "x2"},{name: "x1"}]`,
result: `// +patchKey=name
containers: [{
name: "x1"
}, {
name: "x2"
}, ...]
`,
},
{
// lose close here
base: `containers: [close({namex: "x1"}),...]`,
patch: `
// +patchKey=name
containers: [{name: "x2"},{name: "x1"}]`,
result: `// +patchKey=name
containers: [{
namex: "x1"
name: "x2"
}, {
name: "x1"
}, ...]
`,
},
{
base: `containers: [{name: "x1"},{name: "x2"},...]`,
patch: `
// +patchKey=name
containers: [{name: "x4"},{name: "x3"},{name: "x1"}]`,
result: `// +patchKey=name
containers: [{
name: "x1"
}, {
name: "x2"
}, {
name: "x4"
}, {
name: "x3"
}, ...]
`,
},
{
base: `containers: [{name: "x1"},{name: "x2"},...]`,
patch: `
// +patchKey=name
containers: [{noname: "x3"},...]`,
result: `// +patchKey=name
containers: [{
name: "x1"
noname: "x3"
}, {
name: "x2"
}, ...]
`,
},
{
base: `containers: [{name: "x1"},{name: "x2"},...]`,
patch: `// +patchKey=name
containers: [{noname: "x3"},{name: "x1"}]`,
result: `// +patchKey=name
containers: [{
name: "x1"
}, {
name: "x2"
}, ...]
`,
},
{
base: `containers: [{name: "x1"},{name: "x2", envs:[ {name: "OPS",value: string},...]},...]`,
patch: `
// +patchKey=name
containers: [{name: "x2", envs: [{name: "OPS", value: "OAM"}]}]`,
result: `// +patchKey=name
containers: [{
name: "x1"
}, {
name: "x2"
envs: [{
name: "OPS"
value: "OAM"
}, ...]
}, ...]
`,
},
{
base: `containers: [close({name: "x1"}),close({name: "x2", envs:[{name: "OPS",value: string},...]}),...]`,
patch: `
// +patchKey=name
containers: [{name: "x2", envs: [close({name: "OPS", value: "OAM"})]}]`,
// TODO: fix losing close struct in cue
result: `// +patchKey=name
containers: [{
name: "x1"
}, {
name: "x2"
envs: [{
name: "OPS"
value: "OAM"
}, ...]
}, ...]
`,
},
{
base: `containers: [{name: "x1"},{name: "x2", envs:[ {name: "OPS",value: string},...]},...]`,
patch: `
// +patchKey=name
containers: [{name: "x2", envs: [{name: "USER", value: "DEV"},{name: "OPS", value: "OAM"}]}]`,
result: `// +patchKey=name
containers: [{
name: "x1"
}, {
name: "x2"
envs: [{
name: "OPS"
value: "OAM"
}, {
name: "USER"
value: "DEV"
}, ...]
}, ...]
`,
},
{
base: `containers: [{name: "x1"},{name: "x2", envs:[ {key: "OPS",value: string},...]},...]`,
patch: `
// +patchKey=name
containers: [{name: "x2",
// +patchKey=key
envs: [{key: "USER", value: "DEV"},{key: "OPS", value: "OAM"}]}]`,
result: `// +patchKey=name
containers: [{
name: "x1"
}, {
name: "x2"
// +patchKey=key
envs: [{
key: "OPS"
value: "OAM"
}, {
key: "USER"
value: "DEV"
}, ...]
}, ...]
`,
},
{
base: `envFrom: [{
secretRef: {
name: "nginx-rds"
}},...]`,
patch: `
// +patchKey=secretRef.name
envFrom: [{
secretRef: {
name: "nginx-redis"
}},...]
`,
result: `// +patchKey=secretRef.name
envFrom: [{
secretRef: {
name: "nginx-rds"
}
}, {
secretRef: {
name: "nginx-redis"
}
}, ...]
`},
{
base: `
containers: [{
name: "c1"
},{
name: "c2"
envFrom: [{
secretRef: {
name: "nginx-rds"
}},...]
},...]`,
patch: `
// +patchKey=name
containers: [{
name: "c2"
// +patchKey=secretRef.name
envFrom: [{
secretRef: {
name: "nginx-redis"
}},...]
}]`,
result: `// +patchKey=name
containers: [{
name: "c1"
}, {
name: "c2"
// +patchKey=secretRef.name
envFrom: [{
secretRef: {
name: "nginx-rds"
}
}, {
secretRef: {
name: "nginx-redis"
}
}, ...]
}, ...]
`},
{
base: `
containers: [{
volumeMounts: [{name: "k1", path: "p1"},{name: "k1", path: "p2"},...]
},...]
volumes: [{name: "x1",value: "v1"},{name: "x2",value: "v2"},...]
`,
patch: `
// +patchKey=name
volumes: [{name: "x1",value: "v1"},{name: "x3",value: "x2"}]
containers: [{
volumeMounts: [{name: "k1", path: "p1"},{name: "k1", path: "p2"},{ name:"k2", path: "p3"}]
},...]`,
result: `containers: [{
volumeMounts: [{
name: "k1"
path: "p1"
}, {
name: "k1"
path: "p2"
}, {
name: "k2"
path: "p3"
}]
}, ...]
// +patchKey=name
volumes: [{
name: "x1"
value: "v1"
}, {
name: "x2"
value: "v2"
}, {
name: "x3"
value: "x2"
}, ...]
`},
{
base: `
containers: [{
name: "c1"
},{
name: "c2"
envFrom: [{
secretRef: {
name: "nginx-rds"
},
}, {
configMapRef: {
name: "nginx-rds"
},
},...]
},...]`,
patch: `
// +patchKey=name
containers: [{
name: "c2"
// +patchKey=secretRef.name,configMapRef.name
envFrom: [{
secretRef: {
name: "nginx-redis"
},
}, {
configMapRef: {
name: "nginx-redis"
},
},...]
}]`,
result: `// +patchKey=name
containers: [{
name: "c1"
}, {
name: "c2"
// +patchKey=secretRef.name,configMapRef.name
envFrom: [{
secretRef: {
name: "nginx-rds"
}
}, {
configMapRef: {
name: "nginx-rds"
}
}, {
secretRef: {
name: "nginx-redis"
}
}, {
configMapRef: {
name: "nginx-redis"
}
}, ...]
}, ...]
`},
{
base: `containers: [{name: "x1"}]`,
patch: `
containers: [{
// +patchKey=name
env: [{
name: "k"
value: "v"
}]
}, ...]`,
result: `containers: [{
name: "x1"
// +patchKey=name
env: [{
name: "k"
value: "v"
}]
}, ...]
`,
},
}
for i, tcase := range testCase {
t.Run(fmt.Sprintf("case-%d", i), func(t *testing.T) {
r := require.New(t)
ctx := cuecontext.New()
base := ctx.CompileString(tcase.base)
patch := ctx.CompileString(tcase.patch)
v, err := StrategyUnify(base, patch)
if tcase.expectedErr != "" {
r.Error(err)
r.Contains(err.Error(), tcase.expectedErr)
return
}
r.NoError(err)
s, err := toString(v)
r.NoError(err)
r.Equal(s, tcase.result, fmt.Sprintf("testPatch for case(no:%d) %s", i, v))
})
}
}
func TestStrategyPatch(t *testing.T) {
testCase := []struct {
base string
patch string
result string
}{
{
base: `
spec: {
strategy: {
type: "rollingUpdate"
rollingUpdate: maxSurge: "30%"
}
}
`,
patch: `
spec: {
// +patchStrategy=retainKeys
strategy: type: "recreate"
}
`,
result: `spec: {
strategy: {
// +patchStrategy=retainKeys
type: "recreate"
rollingUpdate: {
maxSurge: "30%"
}
}
}
`},
{
base: `
spec: {
strategy: close({
type: "rollingUpdate"
rollingUpdate: maxSurge: "30%"
})
}
`,
patch: `
spec: {
// +patchStrategy=retainKeys
strategy: type: "recreate"
}
`,
result: `spec: {
strategy: {
// +patchStrategy=retainKeys
type: "recreate"
rollingUpdate: {
maxSurge: "30%"
}
}
}
`},
{
base: `
volumes: [{
name: "test-volume"
cinder: {
volumeID: "<volume id>"
fsType: "ext4"
}
}]
`,
patch: `
// +patchStrategy=retainKeys
// +patchKey=name
volumes: [
{
name: "test-volume"
configMap: name: "conf-name"
}]
`,
result: `// +patchStrategy=retainKeys
// +patchKey=name
volumes: [{
name: "test-volume"
configMap: {
name: "conf-name"
}
}, ...]
`},
{
base: `
volumes: [{
name: "empty-volume"
emptyDir: {}
},
{
name: "test-volume"
cinder: {
volumeID: "<volume id>"
fsType: "ext4"
}
}]
`,
patch: `
// +patchStrategy=retainKeys
// +patchKey=name
volumes: [
{
name: "test-volume"
configMap: name: "conf-name"
}]
`,
result: `// +patchStrategy=retainKeys
// +patchKey=name
volumes: [{
name: "empty-volume"
emptyDir: {}
}, {
name: "test-volume"
configMap: {
name: "conf-name"
}
}, ...]
`},
{
base: `
containers: [{
name: "c1"
image: "image1"
},
{
name: "c2"
envs:[{name: "e1",value: "v1"}]
}]
`,
patch: `
// +patchKey=name
containers: [{
name: "c2"
// +patchStrategy=retainKeys
envs:[{name: "e1",value: "v2"},...]
}]
`,
result: `// +patchKey=name
containers: [{
name: "c1"
image: "image1"
}, {
name: "c2"
// +patchStrategy=retainKeys
envs: [{
name: "e1"
value: "v2"
}, ...]
}, ...]
`},
{
base: `
spec: containers: [{
name: "c1"
image: "image1"
},
{
name: "c2"
envs:[{name: "e1",value: "v1"}]
}]
`,
patch: `
// +patchKey=name
// +patchStrategy=retainKeys
spec: {
containers: [{
name: "c2"
envs:[{name: "e1",value: "v2"}]
}]}
`,
result: `spec: {
// +patchKey=name
// +patchStrategy=retainKeys
containers: [{
name: "c2"
envs: [{
name: "e1"
value: "v2"
}, ...]
}, ...]
}
`}, {
base: `
kind: "Old"
metadata: {
name: "Old"
labels: keep: "true"
}
`,
patch: `// +patchStrategy=retainKeys
kind: "New"
metadata: {
// +patchStrategy=retainKeys
name: "New"
}
`,
result: ` // +patchStrategy=retainKeys
kind: "New"
metadata: {
// +patchStrategy=retainKeys
name: "New"
labels: {
keep: "true"
}
}
`},
}
for i, tcase := range testCase {
r := require.New(t)
ctx := cuecontext.New()
base := ctx.CompileString(tcase.base)
patch := ctx.CompileString(tcase.patch)
v, err := StrategyUnify(base, patch)
r.NoError(err)
s, err := toString(v)
r.NoError(err)
r.Equal(s, tcase.result, fmt.Sprintf("testPatch for case(no:%d) %s", i, s))
}
}
func TestParseCommentTags(t *testing.T) {
temp := `
// +patchKey=name
// +testKey1=testValue1
// +testKey2=testValue2
// +testKey3 =testValue3
// +testKey4 = testValue4
// invalid=x
// +invalid=x y
// +invalid
x: null
`
file, err := parser.ParseFile("-", temp, parser.ParseComments)
assert.Equal(t, err == nil, true)
v := cuecontext.New().BuildFile(file)
ms := findCommentTag(v.LookupPath(cue.ParsePath("x")).Doc())
assert.Equal(t, ms, map[string]string{
"patchKey": "name",
"testKey1": "testValue1",
"testKey2": "testValue2",
"testKey3": "testValue3",
"testKey4": "testValue4",
})
}

View File

@ -1,427 +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 sets
import (
"bytes"
"fmt"
"path/filepath"
"strconv"
"strings"
"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/format"
"cuelang.org/go/cue/literal"
"cuelang.org/go/cue/token"
"github.com/pkg/errors"
)
func lookUp(node ast.Node, paths ...string) (ast.Node, error) {
if len(paths) == 0 {
return peelCloseExpr(node), nil
}
key := paths[0]
switch x := node.(type) {
case *ast.File:
for _, decl := range x.Decls {
nnode := lookField(decl, key)
if nnode != nil {
return lookUp(nnode, paths[1:]...)
}
}
case *ast.ListLit:
for index, elt := range x.Elts {
if strconv.Itoa(index) == key {
return lookUp(elt, paths[1:]...)
}
}
case *ast.StructLit:
for _, elt := range x.Elts {
nnode := lookField(elt, key)
if nnode != nil {
return lookUp(nnode, paths[1:]...)
}
}
case *ast.CallExpr:
if it, ok := x.Fun.(*ast.Ident); ok && it.Name == "close" && len(x.Args) == 1 {
return lookUp(x.Args[0], paths...)
}
for index, arg := range x.Args {
if strconv.Itoa(index) == key {
return lookUp(arg, paths[1:]...)
}
}
}
return nil, notFoundErr
}
func lookUpAll(node ast.Node, paths ...string) []ast.Node {
if len(paths) == 0 {
return []ast.Node{node}
}
key := paths[0]
var nodes []ast.Node
switch x := node.(type) {
case *ast.File:
for _, decl := range x.Decls {
nnode := lookField(decl, key)
if nnode != nil {
nodes = append(nodes, lookUpAll(nnode, paths[1:]...)...)
}
}
case *ast.StructLit:
for _, elt := range x.Elts {
nnode := lookField(elt, key)
if nnode != nil {
nodes = append(nodes, lookUpAll(nnode, paths[1:]...)...)
}
}
case *ast.ListLit:
for index, elt := range x.Elts {
if strconv.Itoa(index) == key {
return lookUpAll(elt, paths[1:]...)
}
}
}
return nodes
}
// PreprocessBuiltinFunc preprocess builtin function in cue file.
func PreprocessBuiltinFunc(root ast.Node, name string, process func(values []ast.Node) (ast.Expr, error)) error {
var gerr error
ast.Walk(root, func(node ast.Node) bool {
switch v := node.(type) {
case *ast.EmbedDecl:
if fname, args := extractFuncName(v.Expr); fname == name && len(args) > 0 {
expr, err := doBuiltinFunc(root, args[0], process)
if err != nil {
gerr = err
return false
}
v.Expr = expr
}
case *ast.Field:
if fname, args := extractFuncName(v.Value); fname == name && len(args) > 0 {
expr, err := doBuiltinFunc(root, args[0], process)
if err != nil {
gerr = err
return false
}
v.Value = expr
}
}
return true
}, nil)
return gerr
}
func doBuiltinFunc(root ast.Node, pathSel ast.Expr, do func(values []ast.Node) (ast.Expr, error)) (ast.Expr, error) {
paths := getPaths(pathSel)
if len(paths) == 0 {
return nil, errors.New("path resolve error")
}
values := lookUpAll(root, paths...)
return do(values)
}
func extractFuncName(expr ast.Expr) (string, []ast.Expr) {
if call, ok := expr.(*ast.CallExpr); ok && len(call.Args) > 0 {
if ident, ok := call.Fun.(*ast.Ident); ok {
return ident.Name, call.Args
}
}
return "", nil
}
func getPaths(node ast.Expr) []string {
switch v := node.(type) {
case *ast.SelectorExpr:
var sel string
if l, ok := v.Sel.(*ast.Ident); ok {
sel = l.Name
} else {
sel = fmt.Sprint(v.Sel)
}
return append(getPaths(v.X), sel)
case *ast.Ident:
return []string{v.Name}
case *ast.BasicLit:
s, err := literal.Unquote(v.Value)
if err != nil {
return nil
}
return []string{s}
case *ast.IndexExpr:
return append(getPaths(v.X), getPaths(v.Index)...)
}
return nil
}
func peelCloseExpr(node ast.Node) ast.Node {
x, ok := node.(*ast.CallExpr)
if !ok {
return node
}
if it, ok := x.Fun.(*ast.Ident); ok && it.Name == "close" && len(x.Args) == 1 {
return x.Args[0]
}
return node
}
func lookField(node ast.Node, key string) ast.Node {
if field, ok := node.(*ast.Field); ok {
// Note: the trim here has side effect: "\(v)" will be trimmed to \(v), only used for comparing fields
if strings.Trim(labelStr(field.Label), `"`) == strings.Trim(key, `"`) {
return field.Value
}
}
return nil
}
func labelStr(label ast.Label) string {
switch v := label.(type) {
case *ast.Ident:
return v.Name
case *ast.BasicLit:
return v.Value
}
return ""
}
// nolint:staticcheck
func toString(v cue.Value, opts ...func(node ast.Node) ast.Node) (string, error) {
syopts := []cue.Option{cue.All(), cue.ResolveReferences(true), cue.DisallowCycles(true), cue.Docs(true), cue.Attributes(true)}
var w bytes.Buffer
useSep := false
format := func(name string, n ast.Node) error {
if name != "" {
fmt.Fprintf(&w, "// %s\n", filepath.Base(name))
} else if useSep {
fmt.Fprintf(&w, "// ---")
}
useSep = true
f, err := toFile(n)
if err != nil {
return err
}
var node ast.Node = f
for _, opt := range opts {
node = opt(node)
}
b, err := format.Node(node)
if err != nil {
return err
}
_, err = w.Write(b)
return err
}
if err := format("", v.Syntax(syopts...)); err != nil {
return "", err
}
instStr := w.String()
return instStr, nil
}
// ToString convert cue.Value to string
func ToString(v cue.Value, opts ...func(node ast.Node) ast.Node) (string, error) {
return toString(v, opts...)
}
// ToFile convert ast.Node to ast.File
func ToFile(n ast.Node) (*ast.File, error) {
return toFile(n)
}
func toFile(n ast.Node) (*ast.File, error) {
switch x := n.(type) {
case nil:
return nil, nil
case *ast.StructLit:
decls := []ast.Decl{}
for _, elt := range x.Elts {
if _, ok := elt.(*ast.Ellipsis); ok {
continue
}
decls = append(decls, elt)
}
return &ast.File{Decls: decls}, nil
case ast.Expr:
ast.SetRelPos(x, token.NoSpace)
return &ast.File{Decls: []ast.Decl{&ast.EmbedDecl{Expr: x}}}, nil
case *ast.File:
return x, nil
default:
return nil, errors.Errorf("Unsupported node type %T", x)
}
}
// OptBytesToString convert cue bytes to string.
func OptBytesToString(node ast.Node) ast.Node {
ast.Walk(node, nil, func(node ast.Node) {
basic, ok := node.(*ast.BasicLit)
if ok {
if basic.Kind == token.STRING {
s := basic.Value
if strings.HasPrefix(s, "'") {
info, nStart, _, err := literal.ParseQuotes(s, s)
if err != nil {
return
}
if !info.IsDouble() {
s = s[nStart:]
s, err := info.Unquote(s)
if err == nil {
basic.Value = fmt.Sprintf(`"%s"`, s)
}
}
}
}
}
})
return node
}
// OpenBaiscLit make that the basicLit can be modified.
// nolint:staticcheck
func OpenBaiscLit(val cue.Value) (*ast.File, error) {
f, err := ToFile(val.Syntax(cue.Docs(true), cue.ResolveReferences(true)))
if err != nil {
return nil, err
}
openBaiscLit(f)
return f, err
}
// nolint:staticcheck
func openListLit(val cue.Value) (*ast.File, error) {
f, err := ToFile(val.Syntax(cue.Docs(true), cue.ResolveReferences(true)))
if err != nil {
return nil, err
}
ast.Walk(f, func(node ast.Node) bool {
field, ok := node.(*ast.Field)
if ok {
v := field.Value
switch lit := v.(type) {
case *ast.ListLit:
if len(lit.Elts) > 0 {
if _, ok := lit.Elts[len(lit.Elts)-1].(*ast.Ellipsis); ok {
break
}
}
newList := lit.Elts
newList = append(newList, &ast.Ellipsis{})
field.Value = ast.NewList(newList...)
}
}
return true
}, nil)
return f, nil
}
func openBaiscLit(root ast.Node) {
ast.Walk(root, func(node ast.Node) bool {
field, ok := node.(*ast.Field)
if ok {
v := field.Value
switch lit := v.(type) {
case *ast.BasicLit:
field.Value = ast.NewBinExpr(token.OR, &ast.UnaryExpr{X: lit, Op: token.MUL}, ast.NewIdent("_"))
case *ast.ListLit:
field.Value = ast.NewBinExpr(token.OR, &ast.UnaryExpr{X: lit, Op: token.MUL}, ast.NewList(&ast.Ellipsis{}))
}
}
return true
}, nil)
}
// ListOpen enable the cue list can add elements.
func ListOpen(expr ast.Node) ast.Node {
listOpen(expr)
return expr
}
func listOpen(expr ast.Node) {
switch v := expr.(type) {
case *ast.File:
for _, decl := range v.Decls {
listOpen(decl)
}
case *ast.Field:
listOpen(v.Value)
case *ast.StructLit:
for _, elt := range v.Elts {
listOpen(elt)
}
case *ast.BinaryExpr:
listOpen(v.X)
listOpen(v.Y)
case *ast.EmbedDecl:
listOpen(v.Expr)
case *ast.Comprehension:
listOpen(v.Value)
case *ast.ListLit:
for _, elt := range v.Elts {
listOpen(elt)
}
if len(v.Elts) > 0 {
if _, ok := v.Elts[len(v.Elts)-1].(*ast.Ellipsis); !ok {
v.Elts = append(v.Elts, &ast.Ellipsis{})
}
}
}
}
func removeTmpVar(expr ast.Node) ast.Node {
switch v := expr.(type) {
case *ast.File:
for _, decl := range v.Decls {
removeTmpVar(decl)
}
case *ast.Field:
removeTmpVar(v.Value)
case *ast.StructLit:
var elts []ast.Decl
for _, elt := range v.Elts {
if field, isField := elt.(*ast.Field); isField {
if ident, isIdent := field.Label.(*ast.Ident); isIdent && strings.HasPrefix(ident.Name, "_") {
continue
}
}
removeTmpVar(elt)
elts = append(elts, elt)
}
v.Elts = elts
case *ast.BinaryExpr:
removeTmpVar(v.X)
removeTmpVar(v.Y)
case *ast.EmbedDecl:
removeTmpVar(v.Expr)
case *ast.Comprehension:
removeTmpVar(v.Value)
case *ast.ListLit:
for _, elt := range v.Elts {
removeTmpVar(elt)
}
}
return expr
}

View File

@ -1,285 +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 sets
import (
"testing"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/format"
"cuelang.org/go/cue/literal"
"cuelang.org/go/cue/parser"
"github.com/pkg/errors"
"gotest.tools/assert"
)
func TestToString(t *testing.T) {
testCases := []struct {
s string
expected string
}{
{
s: `
foo: int
lacy: string
`,
expected: `foo: int
lacy: string
`},
{
s: ` import "strconv"
foo: strconv.Atoi("100")
lacy: string
`,
expected: `foo: 100
lacy: string
`},
{
s: `
if true {
foo: int
}
lacy: string
`,
expected: `lacy: string
foo: int
`},
{
s: `
foo: int
if foo>5{
lacy: "=5"
}
`,
expected: `foo: int
if foo > 5 {
lacy: "=5"
}
`},
}
for _, tcase := range testCases {
inst := cuecontext.New().CompileString(tcase.s)
str, err := ToString(inst)
assert.NilError(t, err)
assert.Equal(t, str, tcase.expected)
}
}
func TestOptBytesToString(t *testing.T) {
testCases := []struct {
s string
expected string
}{
{
s: `
import "encoding/base64"
foo: int
lacy: base64.Decode(null,base64.Encode(null,"abc"))
`,
expected: `foo: int
lacy: "abc"
`},
{
s: `
foo: int
lacy: 'xxx==vv-'
`,
expected: `foo: int
lacy: "xxx==vv-"
`},
{
s: `
foo: int
lacy: "123456"
`,
expected: `foo: int
lacy: "123456"
`},
{
s: `
foo: int
lacy: #"""
abc
123
"""#
`,
expected: `foo: int
lacy: """
abc
123
"""
`},
}
var r = cuecontext.New()
for _, tcase := range testCases {
file, err := parser.ParseFile("-", tcase.s)
assert.NilError(t, err)
inst := r.BuildFile(file)
str, err := ToString(inst.Value(), OptBytesToString)
assert.NilError(t, err)
assert.Equal(t, str, tcase.expected)
}
}
func TestPreprocessBuiltinFunc(t *testing.T) {
doScript := func(values []ast.Node) (ast.Expr, error) {
for _, v := range values {
lit, ok := v.(*ast.BasicLit)
if ok {
src, _ := literal.Unquote(lit.Value)
expr, err := parser.ParseExpr("-", src)
if err != nil {
return nil, errors.Errorf("script value(%s) format err", src)
}
return expr, nil
}
}
return nil, errors.New("script parameter")
}
testCases := []struct {
src string
expectJson string
}{
{
src: `
a: "a"
b: "b"
c: script(a)
`,
expectJson: `{"a":"a","b":"b","c":"a"}`,
},
{
src: `
parameter: {
continue: "true"
}
wait: {
continue: script(parameter.continue)
}
`,
expectJson: `{"parameter":{"continue":"true"},"wait":{"continue":true}}`,
},
{
src: `
parameter: {
continue: "_status"
}
wait: {
_status: true
continue: script(parameter.continue)
}
`,
expectJson: `{"parameter":{"continue":"_status"},"wait":{"continue":true}}`,
},
{
src: `
parameter: {
continue: "_status"
}
wait: {
_status: true
if parameter.continue!=_|_{
continue: script(parameter["continue"])
}
}
`,
expectJson: `{"parameter":{"continue":"_status"},"wait":{"continue":true}}`,
},
{
src: `
parameter: {
continue: "_status"
}
wait: {
_status: {
x: "abc"
}
script(parameter["continue"])
}
`,
expectJson: `{"parameter":{"continue":"_status"},"wait":{"x":"abc"}}`,
},
}
var r = cuecontext.New()
for _, tCase := range testCases {
f, err := parser.ParseFile("-", tCase.src)
assert.NilError(t, err)
err = PreprocessBuiltinFunc(f, "script", doScript)
assert.NilError(t, err)
inst := r.BuildFile(f)
bt, _ := inst.Value().MarshalJSON()
assert.Equal(t, string(bt), tCase.expectJson)
}
}
func TestOpenBasicLit(t *testing.T) {
f, err := OpenBaiscLit(cuecontext.New().CompileString(`
a: 10
a1: int
b: "foo"
b1: string
c: true
c1: bool
arr: [1,2]
top: _
bottom: _|_
`))
assert.NilError(t, err)
val := cuecontext.New().BuildFile(f)
s, err := toString(val)
assert.NilError(t, err)
assert.Equal(t, s, `a: *10 | _
a1: int
b: *"foo" | _
b1: string
c: *true | _
c1: bool
arr: *[1, 2] | [...]
top: _
bottom: _|_ // explicit error (_|_ literal) in source
`)
}
func TestListOpen(t *testing.T) {
f, err := parser.ParseFile("-", `
x: ["a","b"]
y: [...string]
z: []
`)
assert.NilError(t, err)
ListOpen(f)
bt, err := format.Node(f)
assert.NilError(t, err)
s := string(bt)
assert.Equal(t, s, `x: ["a", "b", ...]
y: [...string]
z: []
`)
}

View File

@ -1,162 +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 sets
import (
"strconv"
"strings"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/token"
)
type nodewalker struct {
pos []string
tags map[string]string
process walkProcess
}
type walkCtx interface {
Pos() []string
Tags() map[string]string
}
type walkProcess func(node ast.Node, ctx walkCtx)
func newWalker(process walkProcess) *nodewalker {
return &nodewalker{
pos: []string{},
process: process,
tags: map[string]string{},
}
}
func (nwk *nodewalker) walk(node ast.Node) {
if nwk.process != nil {
nwk.process(node, nwk)
}
switch n := node.(type) {
case *ast.Field:
label := labelStr(n.Label)
if label == "" || strings.HasPrefix(label, "#") {
return
}
if n.Value != nil {
origin := nwk.pos
oriTags := nwk.tags
nwk.tags = map[string]string{}
for k, v := range oriTags {
nwk.tags[k] = v
}
nwk.pos = append(nwk.pos, labelStr(n.Label))
tags := findCommentTag(n.Comments())
for tk, tv := range tags {
nwk.tags[tk] = tv
}
nwk.walk(n.Value)
nwk.tags = oriTags
nwk.pos = origin
}
case *ast.StructLit:
nwk.walkDeclList(n.Elts)
case *ast.ListLit:
nwk.walkExprList(n.Elts)
case *ast.BinaryExpr:
nwk.walk(n.X)
nwk.walk(n.Y)
case *ast.UnaryExpr:
nwk.walk(n.X)
case *ast.EmbedDecl:
nwk.walk(n.Expr)
case *ast.Comprehension:
nwk.walk(n.Value)
// Files
case *ast.File:
nwk.walkDeclList(n.Decls)
case *ast.SliceExpr:
if list, ok := n.X.(*ast.ListLit); ok {
nwk.walkExprSlice(list.Elts, n.Low, n.High)
}
case *ast.CallExpr:
// close func need to be ignored
if it, ok := n.Fun.(*ast.Ident); ok && it.Name == "close" && len(n.Args) == 1 {
nwk.walk(n.Args[0])
} else {
nwk.walkExprList(n.Args)
}
default:
}
}
func (nwk *nodewalker) walkExprList(list []ast.Expr) {
for i, x := range list {
origin := nwk.pos
nwk.pos = append(nwk.pos, strconv.Itoa(i))
nwk.walk(x)
nwk.pos = origin
}
}
func (nwk *nodewalker) walkExprSlice(list []ast.Expr, low ast.Expr, high ast.Expr) {
var (
lowIndex = 0
highIndex = len(list)
)
if v, ok := low.(*ast.BasicLit); ok && v.Kind == token.INT {
lowIndex, _ = strconv.Atoi(v.Value)
}
if v, ok := high.(*ast.BasicLit); ok && v.Kind == token.INT {
highIndex, _ = strconv.Atoi(v.Value)
}
for i, x := range list {
if i < lowIndex || i >= highIndex {
continue
}
origin := nwk.pos
nwk.pos = append(nwk.pos, strconv.Itoa(i-lowIndex))
nwk.walk(x)
nwk.pos = origin
}
}
func (nwk *nodewalker) walkDeclList(list []ast.Decl) {
for _, x := range list {
nwk.walk(x)
}
}
func (nwk *nodewalker) Pos() []string {
return nwk.pos
}
func (nwk *nodewalker) Tags() map[string]string {
return nwk.tags
}

View File

@ -1,147 +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 sets
import (
"testing"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/parser"
"github.com/stretchr/testify/require"
)
func TestWalk(t *testing.T) {
testCases := []string{
`x: "124"`,
`{ x: y: string }`,
`x: {y: 124}`,
`kind: "Deployment"
metadata: name: "test"
spec: replicas: 12`,
`sidecar: {
name: "agent"
image: "test.com/agent:0.1"
}
containers: [{
name: "main"
image: "webserver:0.2"
},sidecar]
`,
` x: 12
if x==12 {
y: "test string"
}
`,
` item1: {
x: 12
if x==12 {
y: "test string"
}
}
output: [item1]
`,
`import "strings"
#User: {
tags_str: string
tags_map: {
for k, v in strings.Split(tags_str, " ") {
"\(v)": string
}
"{a}": string
}
}
user: {
#User
tags_str: "b {c}"
}
`,
`import "strings"
b: string
user: {
tags_str: strings.Compare(b,"c")
}
`,
`a: [1, 2, 3]`,
}
for _, src := range testCases {
re := require.New(t)
inst := cuecontext.New().CompileString(src)
nsrc, err := toString(inst.Value())
re.NoError(err)
f, err := parser.ParseFile("-", nsrc)
re.NoError(err)
newWalker(func(node ast.Node, ctx walkCtx) {
if len(ctx.Pos()) == 0 {
return
}
if _, ok := node.(ast.Expr); !ok {
return
}
if _, ok := node.(*ast.CallExpr); ok {
return
}
n, err := lookUp(f, ctx.Pos()...)
re.NoError(err)
re.Equal(n, node, nsrc)
}).walk(f)
}
}
func TestRemoveTmpVar(t *testing.T) {
src := `spec: {
_tmp: "x"
list: [{
_tmp: "x"
retain: "y"
}, {
_tmp: "x"
retain: "z"
}]
retain: "y"
}
`
r := require.New(t)
v := cuecontext.New().CompileString(src)
s, err := toString(v, removeTmpVar)
r.NoError(err)
r.Equal(`spec: {
list: [{
retain: "y"
}, {
retain: "z"
}]
retain: "y"
}
`, s)
}

View File

@ -1,812 +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 value
import (
"encoding/json"
"fmt"
"sort"
"strconv"
"strings"
"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/literal"
"cuelang.org/go/cue/parser"
"cuelang.org/go/cue/token"
"github.com/pkg/errors"
"github.com/oam-dev/kubevela/pkg/cue/model/sets"
"github.com/oam-dev/kubevela/pkg/cue/packages"
"github.com/oam-dev/kubevela/pkg/stdlib"
)
// DefaultPackageHeader describes the default package header for CUE files.
const DefaultPackageHeader = "package main\n"
// Value is an object with cue.runtime and vendors
type Value struct {
v cue.Value
r *cue.Context
addImports func(instance *build.Instance) error
}
// String return value's cue format string
func (val *Value) String(opts ...func(node ast.Node) ast.Node) (string, error) {
opts = append(opts, sets.OptBytesToString)
return sets.ToString(val.v, opts...)
}
// Error return value's error information.
func (val *Value) Error() error {
v := val.CueValue()
if !v.Exists() {
return errors.New("empty value")
}
if err := val.v.Err(); err != nil {
return err
}
var gerr error
v.Walk(func(value cue.Value) bool {
if err := value.Eval().Err(); err != nil {
gerr = err
return false
}
return true
}, nil)
return gerr
}
// UnmarshalTo unmarshal value into golang object
func (val *Value) UnmarshalTo(x interface{}) error {
data, err := val.v.MarshalJSON()
if err != nil {
return err
}
return json.Unmarshal(data, x)
}
// NewValueWithMainAndFiles new a value from main and appendix files
func NewValueWithMainAndFiles(main string, slaveFiles []string, pd *packages.PackageDiscover, tagTempl string, opts ...func(*ast.File) error) (*Value, error) {
builder := &build.Instance{}
mainFile, err := parser.ParseFile("main.cue", main, parser.ParseComments)
if err != nil {
return nil, errors.Wrap(err, "parse main file")
}
if mainFile.PackageName() == "" {
// add a default package main if not exist
mainFile, err = parser.ParseFile("main.cue", DefaultPackageHeader+main, parser.ParseComments)
if err != nil {
return nil, errors.Wrap(err, "parse main file with added package main header")
}
}
for _, opt := range opts {
if err := opt(mainFile); err != nil {
return nil, errors.Wrap(err, "run option func for main file")
}
}
if err := builder.AddSyntax(mainFile); err != nil {
return nil, errors.Wrap(err, "add main file to CUE builder")
}
for idx, sf := range slaveFiles {
cueSF, err := parser.ParseFile("sf-"+strconv.Itoa(idx)+".cue", sf, parser.ParseComments)
if err != nil {
return nil, errors.Wrap(err, "parse added file "+strconv.Itoa(idx)+" \n"+sf)
}
if cueSF.PackageName() != mainFile.PackageName() {
continue
}
for _, opt := range opts {
if err := opt(cueSF); err != nil {
return nil, errors.Wrap(err, "run option func for files")
}
}
if err := builder.AddSyntax(cueSF); err != nil {
return nil, errors.Wrap(err, "add slave files to CUE builder")
}
}
return newValue(builder, pd, tagTempl)
}
// NewValue new a value
func NewValue(s string, pd *packages.PackageDiscover, tagTempl string, opts ...func(*ast.File) error) (*Value, error) {
builder := &build.Instance{}
file, err := parser.ParseFile("-", s, parser.ParseComments)
if err != nil {
return nil, err
}
for _, opt := range opts {
if err := opt(file); err != nil {
return nil, err
}
}
if err := builder.AddSyntax(file); err != nil {
return nil, err
}
return newValue(builder, pd, tagTempl)
}
func newValue(builder *build.Instance, pd *packages.PackageDiscover, tagTempl string) (*Value, error) {
addImports := func(inst *build.Instance) error {
if pd != nil {
pd.ImportBuiltinPackagesFor(inst)
}
if err := stdlib.AddImportsFor(inst, tagTempl); err != nil {
return err
}
return nil
}
if err := addImports(builder); err != nil {
return nil, err
}
r := cuecontext.New()
inst := r.BuildInstance(builder)
val := new(Value)
val.r = r
val.v = inst
val.addImports = addImports
// do not check val.Err() error here, because the value may be filled later
return val, nil
}
// AddFile add file to the instance
func AddFile(bi *build.Instance, filename string, src interface{}) error {
if filename == "" {
filename = "-"
}
file, err := parser.ParseFile(filename, src, parser.ParseComments)
if err != nil {
return err
}
if err := bi.AddSyntax(file); err != nil {
return err
}
return nil
}
// TagFieldOrder add step tag.
func TagFieldOrder(root *ast.File) error {
i := 0
vs := &visitor{
r: map[string]struct{}{},
}
for _, decl := range root.Decls {
vs.addAttrForExpr(decl, &i)
}
return nil
}
// ProcessScript preprocess the script builtin function.
func ProcessScript(root *ast.File) error {
return sets.PreprocessBuiltinFunc(root, "script", func(values []ast.Node) (ast.Expr, error) {
for _, v := range values {
lit, ok := v.(*ast.BasicLit)
if ok {
src, err := literal.Unquote(lit.Value)
if err != nil {
return nil, errors.WithMessage(err, "unquote script value")
}
expr, err := parser.ParseExpr("-", src)
if err != nil {
return nil, errors.Errorf("script value(%s) is invalid CueLang", src)
}
return expr, nil
}
}
return nil, errors.New("script parameter error")
})
}
type visitor struct {
r map[string]struct{}
}
func (vs *visitor) done(name string) {
vs.r[name] = struct{}{}
}
func (vs *visitor) shouldDo(name string) bool {
_, ok := vs.r[name]
return !ok
}
func (vs *visitor) addAttrForExpr(node ast.Node, index *int) {
switch v := node.(type) {
case *ast.Comprehension:
st := v.Value.(*ast.StructLit)
for _, elt := range st.Elts {
vs.addAttrForExpr(elt, index)
}
case *ast.Field:
basic, ok := v.Label.(*ast.Ident)
if !ok {
return
}
if !vs.shouldDo(basic.Name) {
return
}
if v.Attrs == nil {
*index++
vs.done(basic.Name)
v.Attrs = []*ast.Attribute{
{Text: fmt.Sprintf("@step(%d)", *index)},
}
}
}
}
// MakeValue generate an value with same runtime
func (val *Value) MakeValue(s string) (*Value, error) {
builder := &build.Instance{}
file, err := parser.ParseFile("-", s, parser.ParseComments)
if err != nil {
return nil, err
}
if err := builder.AddSyntax(file); err != nil {
return nil, err
}
if err := val.addImports(builder); err != nil {
return nil, err
}
inst := val.r.BuildInstance(builder)
v := new(Value)
v.r = val.r
v.v = inst
v.addImports = val.addImports
if v.Error() != nil {
return nil, v.Error()
}
return v, nil
}
func (val *Value) makeValueWithFile(files ...*ast.File) (*Value, error) {
builder := &build.Instance{}
newFile := &ast.File{}
imports := map[string]*ast.ImportSpec{}
for _, f := range files {
for _, importSpec := range f.Imports {
if _, ok := imports[importSpec.Name.String()]; !ok {
imports[importSpec.Name.String()] = importSpec
}
}
newFile.Decls = append(newFile.Decls, f.Decls...)
}
for _, imp := range imports {
newFile.Imports = append(newFile.Imports, imp)
}
if err := builder.AddSyntax(newFile); err != nil {
return nil, err
}
if err := val.addImports(builder); err != nil {
return nil, err
}
inst := val.r.BuildInstance(builder)
v := new(Value)
v.r = val.r
v.v = inst
v.addImports = val.addImports
return v, nil
}
// FillRaw unify the value with the cue format string x at the given path.
func (val *Value) FillRaw(x string, paths ...string) error {
file, err := parser.ParseFile("-", x, parser.ParseComments)
if err != nil {
return err
}
xInst := val.r.BuildFile(file)
v := val.v.FillPath(FieldPath(paths...), xInst)
if v.Err() != nil {
return v.Err()
}
val.v = v
return nil
}
// FillValueByScript unify the value x at the given script path.
func (val *Value) FillValueByScript(x *Value, path string) error {
if !strings.Contains(path, "[") {
newV := val.v.FillPath(FieldPath(path), x.v)
if err := newV.Err(); err != nil {
return err
}
val.v = newV
return nil
}
s, err := x.String()
if err != nil {
return err
}
return val.fillRawByScript(s, path)
}
func (val *Value) fillRawByScript(x string, path string) error {
a := newAssembler(x)
pathExpr, err := parser.ParseExpr("path", path)
if err != nil {
return errors.WithMessage(err, "parse path")
}
if err := a.installTo(pathExpr); err != nil {
return err
}
raw, err := val.String(sets.ListOpen)
if err != nil {
return err
}
v, err := val.MakeValue(raw + "\n" + a.v)
if err != nil {
return errors.WithMessage(err, "remake value")
}
if err := v.Error(); err != nil {
return err
}
*val = *v
return nil
}
// CueValue return cue.Value
func (val *Value) CueValue() cue.Value {
return val.v
}
// FillObject unify the value with object x at the given path.
func (val *Value) FillObject(x interface{}, paths ...string) error {
insert := x
if v, ok := x.(*Value); ok {
if v.r != val.r {
return errors.New("filled value not created with same Runtime")
}
insert = v.v
}
newV := val.v.FillPath(FieldPath(paths...), insert)
// do not check newV.Err() error here, because the value may be filled later
val.v = newV
return nil
}
// LookupValue reports the value at a path starting from val
func (val *Value) LookupValue(paths ...string) (*Value, error) {
v := val.v.LookupPath(FieldPath(paths...))
if !v.Exists() {
return nil, errors.Errorf("failed to lookup value: var(path=%s) not exist", strings.Join(paths, "."))
}
return &Value{
v: v,
r: val.r,
addImports: val.addImports,
}, nil
}
func isScript(content string) (bool, error) {
content = strings.TrimSpace(content)
scriptFile, err := parser.ParseFile("-", content, parser.ParseComments)
if err != nil {
return false, errors.WithMessage(err, "parse script")
}
if len(scriptFile.Imports) != 0 {
return true, nil
}
if len(scriptFile.Decls) == 0 || len(scriptFile.Decls) > 1 {
return true, nil
}
return !isSelector(scriptFile.Decls[0]), nil
}
func isSelector(node ast.Node) bool {
switch v := node.(type) {
case *ast.EmbedDecl:
return isSelector(v.Expr)
case *ast.SelectorExpr, *ast.IndexExpr, *ast.Ident:
return true
default:
return false
}
}
// LookupByScript reports the value by cue script.
func (val *Value) LookupByScript(script string) (*Value, error) {
var outputKey = "zz_output__"
script = strings.TrimSpace(script)
scriptFile, err := parser.ParseFile("-", script, parser.ParseComments)
if err != nil {
return nil, errors.WithMessage(err, "parse script")
}
isScriptPath, err := isScript(script)
if err != nil {
return nil, err
}
if !isScriptPath {
return val.LookupValue(script)
}
raw, err := val.String()
if err != nil {
return nil, err
}
rawFile, err := parser.ParseFile("-", raw, parser.ParseComments)
if err != nil {
return nil, errors.WithMessage(err, "parse script")
}
behindKey(scriptFile, outputKey)
newV, err := val.makeValueWithFile(rawFile, scriptFile)
if err != nil {
return nil, err
}
return newV.LookupValue(outputKey)
}
func behindKey(file *ast.File, key string) {
var (
implDecls []ast.Decl
decls []ast.Decl
)
for i, decl := range file.Decls {
if _, ok := decl.(*ast.ImportDecl); ok {
implDecls = append(implDecls, file.Decls[i])
} else {
decls = append(decls, file.Decls[i])
}
}
file.Decls = implDecls
if len(decls) == 1 {
target := decls[0]
if embed, ok := target.(*ast.EmbedDecl); ok {
file.Decls = append(file.Decls, &ast.Field{
Label: ast.NewIdent(key),
Value: embed.Expr,
})
return
}
}
file.Decls = append(file.Decls, &ast.Field{
Label: ast.NewIdent(key),
Value: &ast.StructLit{
Elts: decls,
},
})
}
type field struct {
Name string
Value *Value
no int64
}
// StepByList process item in list.
func (val *Value) StepByList(handle func(name string, in *Value) (bool, error)) error {
iter, err := val.CueValue().List()
if err != nil {
return err
}
for iter.Next() {
stop, err := handle(iter.Label(), &Value{
v: iter.Value(),
r: val.r,
addImports: val.addImports,
})
if err != nil {
return err
}
if stop {
return nil
}
}
return nil
}
// StepByFields process the fields in order
func (val *Value) StepByFields(handle func(name string, in *Value) (bool, error)) error {
iter := steps(val)
for iter.next() {
iter.do(handle)
}
return iter.err
}
type stepsIterator struct {
queue []*field
index int
target *Value
err error
stopped bool
}
func steps(v *Value) *stepsIterator {
return &stepsIterator{
target: v,
}
}
func (iter *stepsIterator) next() bool {
if iter.stopped {
return false
}
if iter.err != nil {
return false
}
if iter.queue != nil {
iter.index++
}
iter.assemble()
return iter.index <= len(iter.queue)-1
}
func (iter *stepsIterator) assemble() {
st, err := iter.target.v.Struct()
if err != nil {
iter.err = err
return
}
filters := map[string]struct{}{}
for _, item := range iter.queue {
filters[item.Name] = struct{}{}
}
var addFields []*field
for i := 0; i < st.Len(); i++ {
if st.Field(i).Value.IncompleteKind() == cue.TopKind {
continue
}
name := st.Field(i).Name
attr := st.Field(i).Value.Attribute("step")
no, err := attr.Int(0)
if err != nil {
no = 100
if name == "#do" || name == "#provider" {
no = 0
}
}
if _, ok := filters[name]; !ok {
addFields = append(addFields, &field{
Name: name,
no: no,
})
}
}
suffixItems := append(addFields, iter.queue[iter.index:]...)
sort.Sort(sortFields(suffixItems))
iter.queue = append(iter.queue[:iter.index], suffixItems...)
}
func (iter *stepsIterator) value() *Value {
v := iter.target.v.LookupPath(FieldPath(iter.name()))
return &Value{
r: iter.target.r,
v: v,
addImports: iter.target.addImports,
}
}
func (iter *stepsIterator) name() string {
return iter.queue[iter.index].Name
}
func (iter *stepsIterator) do(handle func(name string, in *Value) (bool, error)) {
if iter.err != nil {
return
}
v := iter.value()
stopped, err := handle(iter.name(), v)
if err != nil {
iter.err = err
return
}
iter.stopped = stopped
if !isDef(iter.name()) {
if err := iter.target.FillObject(v, iter.name()); err != nil {
iter.err = err
return
}
}
}
type sortFields []*field
func (sf sortFields) Len() int {
return len(sf)
}
func (sf sortFields) Less(i, j int) bool {
return sf[i].no < sf[j].no
}
func (sf sortFields) Swap(i, j int) {
sf[i], sf[j] = sf[j], sf[i]
}
// Field return the cue value corresponding to the specified field
func (val *Value) Field(label string) (cue.Value, error) {
v := val.v.LookupPath(cue.ParsePath(label))
if !v.Exists() {
return v, errors.Errorf("label %s not found", label)
}
if v.IncompleteKind() == cue.BottomKind {
return v, errors.Errorf("label %s's value not computed", label)
}
return v, nil
}
// GetString get the string value at a path starting from v.
func (val *Value) GetString(paths ...string) (string, error) {
v, err := val.LookupValue(paths...)
if err != nil {
return "", err
}
return v.CueValue().String()
}
// GetStringSlice get string slice from val
func (val *Value) GetStringSlice(paths ...string) ([]string, error) {
v, err := val.LookupValue(paths...)
if err != nil {
return nil, err
}
var s []string
err = v.UnmarshalTo(&s)
return s, err
}
// GetInt64 get the int value at a path starting from v.
func (val *Value) GetInt64(paths ...string) (int64, error) {
v, err := val.LookupValue(paths...)
if err != nil {
return 0, err
}
return v.CueValue().Int64()
}
// GetBool get the int value at a path starting from v.
func (val *Value) GetBool(paths ...string) (bool, error) {
v, err := val.LookupValue(paths...)
if err != nil {
return false, err
}
return v.CueValue().Bool()
}
// OpenCompleteValue make that the complete value can be modified.
func (val *Value) OpenCompleteValue() error {
newS, err := sets.OpenBaiscLit(val.CueValue())
if err != nil {
return err
}
v := cuecontext.New().BuildFile(newS)
val.v = v
return nil
}
func isDef(s string) bool {
return strings.HasPrefix(s, "#")
}
// assembler put value under parsed expression as path.
type assembler struct {
v string
}
func newAssembler(v string) *assembler {
return &assembler{v: v}
}
func (a *assembler) fill2Path(p string) {
a.v = fmt.Sprintf("%s: %s", p, a.v)
}
func (a *assembler) fill2Array(i int) {
s := ""
for j := 0; j < i; j++ {
s += "_,"
}
if strings.Contains(a.v, ":") && !strings.HasPrefix(a.v, "{") {
a.v = fmt.Sprintf("{ %s }", a.v)
}
a.v = fmt.Sprintf("[%s%s]", s, strings.TrimSpace(a.v))
}
func (a *assembler) installTo(expr ast.Expr) error {
switch v := expr.(type) {
case *ast.IndexExpr:
if err := a.installTo(v.Index); err != nil {
return err
}
if err := a.installTo(v.X); err != nil {
return err
}
case *ast.SelectorExpr:
if ident, ok := v.Sel.(*ast.Ident); ok {
if err := a.installTo(ident); err != nil {
return err
}
} else {
return errors.New("invalid sel type in selector")
}
if err := a.installTo(v.X); err != nil {
return err
}
case *ast.Ident:
a.fill2Path(v.String())
case *ast.BasicLit:
switch v.Kind {
case token.STRING:
a.fill2Path(v.Value)
case token.INT:
idex, _ := strconv.Atoi(v.Value)
a.fill2Array(idex)
default:
return errors.New("invalid path")
}
default:
return errors.New("invalid path")
}
return nil
}
// makePath creates a Path from a sequence of string.
func makePath(paths ...string) string {
mergedPath := ""
if len(paths) == 0 {
return mergedPath
}
mergedPath = paths[0]
if mergedPath == "" || (len(paths) == 1 && (strings.Contains(mergedPath, ".") || strings.Contains(mergedPath, "["))) {
return paths[0]
}
if !strings.HasPrefix(mergedPath, "_") && !strings.HasPrefix(mergedPath, "#") {
mergedPath = fmt.Sprintf("\"%s\"", mergedPath)
}
for _, p := range paths[1:] {
if !strings.HasPrefix(p, "#") {
mergedPath += fmt.Sprintf("[\"%s\"]", p)
} else {
mergedPath += fmt.Sprintf(".%s", p)
}
}
return mergedPath
}
func isNumber(s string) bool {
_, err := strconv.ParseInt(s, 10, 64)
return err == nil
}
// FieldPath return the cue path of the given paths
func FieldPath(paths ...string) cue.Path {
s := makePath(paths...)
if isNumber(s) {
return cue.MakePath(cue.Str(s))
}
return cue.ParsePath(s)
}

View File

@ -1,967 +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 value
import (
"encoding/json"
"fmt"
"testing"
"github.com/oam-dev/kubevela/pkg/cue/model/sets"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
"gotest.tools/assert"
)
func TestValueFill(t *testing.T) {
src := `
object: {
x: int
y: string
z: {
provider: string
do: string
}
}
`
testVal1, err := NewValue(src, nil, "")
assert.NilError(t, err)
err = testVal1.FillObject(12, "object", "x")
assert.NilError(t, err)
err = testVal1.FillObject("y_string", "object", "y")
assert.NilError(t, err)
z, err := testVal1.MakeValue(`
z: {
provider: string
do: "apply"
}
`)
z.FillObject("kube", "z", "provider")
assert.NilError(t, err)
err = testVal1.FillObject(z, "object")
assert.NilError(t, err)
val1String, err := testVal1.String()
assert.NilError(t, err)
expectedValString := `object: {
x: 12
y: "y_string"
z: {
provider: "kube"
do: "apply"
}
}
`
assert.Equal(t, val1String, expectedValString)
testVal2, err := NewValue(src, nil, "")
assert.NilError(t, err)
err = testVal2.FillRaw(expectedValString)
assert.NilError(t, err)
val2String, err := testVal1.String()
assert.NilError(t, err)
assert.Equal(t, val2String, expectedValString)
}
func TestStepByFields(t *testing.T) {
testCases := []struct {
base string
expected string
}{
{base: `
step1: {}
step2: {prefix: step1.value}
step3: {prefix: step2.value}
step4: {prefix: step3.value}
if step4.value > 100 {
step5: {prefix: step4.value}
}
`,
expected: `step1: {
value: 100
}
step2: {
prefix: 100
value: 101
}
step3: {
prefix: 101
value: 102
}
step5: {
prefix: 103
value: 104
}
step4: {
prefix: 102
value: 103
}
`},
{base: `
step1: {}
step2: {prefix: step1.value}
if step2.value > 100 {
step2_3: {prefix: step2.value}
}
step3: {prefix: step2.value}
`,
expected: `step1: {
value: 100
}
step2: {
prefix: 100
value: 101
}
step2_3: {
prefix: 101
value: 102
}
step3: {
prefix: 101
value: 103
}
`},
}
for _, tCase := range testCases {
val, err := NewValue(tCase.base, nil, "")
assert.NilError(t, err)
number := 99
err = val.StepByFields(func(_ string, in *Value) (bool, error) {
number++
return false, in.FillObject(map[string]interface{}{
"value": number,
})
})
assert.NilError(t, err)
str, err := val.String()
assert.NilError(t, err)
assert.Equal(t, str, tCase.expected)
}
caseSkip := `
step1: "1"
step2: "2"
step3: "3"
`
val, err := NewValue(caseSkip, nil, "")
assert.NilError(t, err)
inc := 0
err = val.StepByFields(func(_ string, in *Value) (bool, error) {
inc++
s, err := in.CueValue().String()
assert.NilError(t, err)
if s == "2" {
return true, nil
}
return false, nil
})
assert.NilError(t, err)
assert.Equal(t, inc, 2)
inc = 0
err = val.StepByFields(func(_ string, in *Value) (bool, error) {
inc++
s, err := in.CueValue().String()
assert.NilError(t, err)
if s == "2" {
return false, errors.New("mock error")
}
return false, nil
})
assert.Equal(t, err != nil, true)
assert.Equal(t, inc, 2)
inc = 0
err = val.StepByFields(func(_ string, in *Value) (bool, error) {
inc++
s, err := in.CueValue().String()
assert.NilError(t, err)
if s == "2" {
v, err := NewValue("v: 33", nil, "")
assert.NilError(t, err)
*in = *v
}
return false, nil
})
assert.Equal(t, err != nil, true)
assert.Equal(t, inc, 2)
}
func TestStepWithTag(t *testing.T) {
// TODO(@FogDong): add if condition test cases back.
// refer to issue: https://github.com/cue-lang/cue/issues/1826
testCases := []struct {
base string
expected string
}{
{base: `
step1: {}
step2: {prefix: step1.value}
step3: {prefix: step2.value}
step4: {prefix: step3.value}
step5: {
value: *100|int
}
`,
expected: `step1: {
value: 100
} @step(1)
step2: {
prefix: 100
value: 101
} @step(2)
step3: {
prefix: 101
value: 102
} @step(3)
step4: {
prefix: 102
value: 103
} @step(4)
step5: {
value: 104
} @step(5)
`}, {base: `
step1: {}
step2: {prefix: step1.value}
step2_3: {prefix: step2.value}
step3: {prefix: step2.value}
step4: {prefix: step3.value}
`,
expected: `step1: {
value: 100
} @step(1)
step2: {
prefix: 100
value: 101
} @step(2)
step2_3: {
prefix: 101
value: 102
} @step(3)
step3: {
prefix: 101
value: 103
} @step(4)
step4: {
prefix: 103
value: 104
} @step(5)
`}, {base: `
step2: {prefix: step1.value} @step(2)
step1: {} @step(1)
step3: {prefix: step2.value} @step(4)
step2_3: {prefix: step2.value} @step(3)
`,
expected: `step2: {
prefix: 100
value: 101
} @step(2)
step1: {
value: 100
} @step(1)
step3: {
prefix: 101
value: 103
} @step(4)
step2_3: {
prefix: 101
value: 102
} @step(3)
`},
{base: `
step2: {prefix: step1.value}
step1: {} @step(-1)
step2_3: {prefix: step2.value}
step3: {prefix: step2.value}
`,
expected: `step2: {
prefix: 100
value: 101
} @step(1)
step1: {
value: 100
} @step(-1)
step2_3: {
prefix: 101
value: 102
} @step(2)
step3: {
prefix: 101
value: 103
} @step(3)
`}}
for i, tCase := range testCases {
r := require.New(t)
val, err := NewValue(tCase.base, nil, "", TagFieldOrder)
r.NoError(err)
number := 99
err = val.StepByFields(func(name string, in *Value) (bool, error) {
number++
return false, in.FillObject(map[string]interface{}{
"value": number,
})
})
r.NoError(err)
str, err := sets.ToString(val.CueValue())
r.NoError(err)
r.Equal(str, tCase.expected, fmt.Sprintf("testPatch for case(no:%d) %s", i, str))
}
}
func TestUnmarshal(t *testing.T) {
case1 := `
provider: "kube"
do: "apply"
`
out := struct {
Provider string `json:"provider"`
Do string `json:"do"`
}{}
val, err := NewValue(case1, nil, "")
assert.NilError(t, err)
err = val.UnmarshalTo(&out)
assert.NilError(t, err)
assert.Equal(t, out.Provider, "kube")
assert.Equal(t, out.Do, "apply")
bt, err := val.CueValue().MarshalJSON()
assert.NilError(t, err)
expectedJson, err := json.Marshal(out)
assert.NilError(t, err)
assert.Equal(t, string(bt), string(expectedJson))
caseIncomplete := `
provider: string
do: string
`
val, err = NewValue(caseIncomplete, nil, "")
assert.NilError(t, err)
err = val.UnmarshalTo(&out)
assert.Equal(t, err != nil, true)
}
func TestStepByList(t *testing.T) {
base := `[{step: 1},{step: 2}]`
v, err := NewValue(base, nil, "")
assert.NilError(t, err)
var i int64
err = v.StepByList(func(name string, in *Value) (bool, error) {
i++
num, err := in.CueValue().LookupPath(FieldPath("step")).Int64()
assert.NilError(t, err)
assert.Equal(t, num, i)
return false, nil
})
assert.NilError(t, err)
i = 0
err = v.StepByList(func(_ string, _ *Value) (bool, error) {
i++
return true, nil
})
assert.NilError(t, err)
assert.Equal(t, i, int64(1))
i = 0
err = v.StepByList(func(_ string, _ *Value) (bool, error) {
i++
return false, errors.New("mock error")
})
assert.Equal(t, err.Error(), "mock error")
assert.Equal(t, i, int64(1))
notListV, err := NewValue(`{}`, nil, "")
assert.NilError(t, err)
err = notListV.StepByList(func(_ string, _ *Value) (bool, error) {
return false, nil
})
assert.Equal(t, err != nil, true)
}
func TestValue(t *testing.T) {
// Test NewValue with wrong cue format.
caseError := `
provider: xxx
`
val, err := NewValue(caseError, nil, "")
assert.NilError(t, err)
assert.Equal(t, val.Error() != nil, true)
val, err = NewValue(":", nil, "")
assert.Equal(t, err != nil, true)
assert.Equal(t, val == nil, true)
// Test make error by Fill with wrong cue format.
caseOk := `
provider: "kube"
do: "apply"
`
val, err = NewValue(caseOk, nil, "")
assert.NilError(t, err)
originCue := val.CueValue()
_, err = val.MakeValue(caseError)
assert.Equal(t, err != nil, true)
_, err = val.MakeValue(":")
assert.Equal(t, err != nil, true)
_, err = val.MakeValue("test: _|_")
assert.Equal(t, err != nil, true)
err = val.FillRaw(caseError)
assert.Equal(t, err != nil, true)
assert.Equal(t, originCue, val.CueValue())
cv, err := NewValue(caseOk, nil, "")
assert.NilError(t, err)
err = val.FillObject(cv)
assert.Equal(t, err != nil, true)
assert.Equal(t, originCue, val.CueValue())
// Test make error by Fill with cue eval error.
caseClose := `
close({provider: int})
`
err = val.FillRaw(caseClose)
assert.Equal(t, err != nil, true)
assert.Equal(t, originCue, val.CueValue())
cv, err = val.MakeValue(caseClose)
assert.NilError(t, err)
err = val.FillObject(cv)
assert.NilError(t, err)
assert.Equal(t, val.Error() != nil, true)
_, err = val.LookupValue("abc")
assert.Equal(t, err != nil, true)
providerValue, err := val.LookupValue("provider")
assert.NilError(t, err)
err = providerValue.StepByFields(func(_ string, in *Value) (bool, error) {
return false, nil
})
assert.Equal(t, err != nil, true)
openSt := `
#X: {...}
x: #X & {
name: "xxx"
age: 12
}
`
val, err = NewValue(openSt, nil, "")
assert.NilError(t, err)
x, _ := val.LookupValue("x")
xs, _ := x.String()
_, err = val.MakeValue(xs)
assert.NilError(t, err)
}
func TestLookupValue(t *testing.T) {
testCases := []struct {
name string
str string
paths []string
}{
{
name: "def",
str: `
#x: "v"
`,
paths: []string{"#x"},
},
{
name: "def in def",
str: `
#x: {
#y: "v"
}
`,
paths: []string{"#x", "#y"},
},
{
name: "num",
str: `
"1": {
"2": "v"
}
`,
paths: []string{"1", "2"},
},
{
name: "invalid",
str: `
"a-b": {
"b-c": "v"
}
`,
paths: []string{"a-b", "b-c"},
},
{
name: "concrete path",
str: `
a: {
"b-c": "v"
}
`,
paths: []string{`a["b-c"]`},
},
{
name: "concrete path with num",
str: `
a: [
{
key: "v"
}
]
`,
paths: []string{`a[0].key`},
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
r := require.New(t)
v, err := NewValue(tc.str, nil, "")
r.NoError(err)
result, err := v.LookupValue(tc.paths...)
r.NoError(err)
r.NoError(result.Error())
s, err := sets.ToString(result.v)
r.Equal(s, `"v"
`)
r.NoError(err)
})
}
}
func TestValueError(t *testing.T) {
caseOk := `
provider: "kube"
do: "apply"
`
val, err := NewValue(caseOk, nil, "")
assert.NilError(t, err)
err = val.FillRaw(`
provider: "conflict"`)
assert.Equal(t, err != nil, true)
val, err = NewValue(caseOk, nil, "")
assert.NilError(t, err)
err = val.FillObject(map[string]string{
"provider": "abc",
})
assert.NilError(t, err)
assert.Equal(t, val.Error() != nil, true)
}
func TestField(t *testing.T) {
caseSrc := `
name: "foo"
#name: "fly"
#age: 100
bottom: _|_
`
val, err := NewValue(caseSrc, nil, "")
assert.NilError(t, err)
name, err := val.Field("name")
assert.NilError(t, err)
nameValue, err := name.String()
assert.NilError(t, err)
assert.Equal(t, nameValue, "foo")
dname, err := val.Field("#name")
assert.NilError(t, err)
nameValue, err = dname.String()
assert.NilError(t, err)
assert.Equal(t, nameValue, "fly")
_, err = val.Field("age")
assert.Equal(t, err != nil, true)
_, err = val.Field("bottom")
assert.Equal(t, err != nil, true)
}
func TestProcessScript(t *testing.T) {
testCases := []struct {
src string
expect string
err string
}{
{
src: `parameter: {
check: "status==\"ready\""
}
wait: {
status: "ready"
continue: script(parameter.check)
}`,
expect: `parameter: {
check: "status==\"ready\""
}
wait: {
status: "ready"
continue: true
}
`,
},
{
src: `parameter: {
check: "status==\"ready\""
}
wait: {
status: "ready"
continue: script("")
}`,
expect: ``,
err: "script parameter error",
},
{
src: `parameter: {
check: "status=\"ready\""
}
wait: {
status: "ready"
continue: script(parameter.check)
}`,
expect: ``,
err: "script value(status=\"ready\") is invalid CueLang",
},
}
for _, tCase := range testCases {
v, err := NewValue(tCase.src, nil, "", ProcessScript)
if tCase.err != "" {
assert.Equal(t, err.Error(), tCase.err)
continue
}
assert.NilError(t, err)
s, err := v.String()
assert.NilError(t, err)
assert.Equal(t, s, tCase.expect)
}
}
func TestLookupByScript(t *testing.T) {
testCases := []struct {
src string
script string
expect string
}{
{
src: `
traits: {
ingress: {
// +patchKey=name
test: [{name: "main", image: "busybox"}]
}
}
`,
script: `traits["ingress"]`,
expect: `// +patchKey=name
test: [{
name: "main"
image: "busybox"
}]
`,
},
{
src: `
apply: containers: [{name: "main", image: "busybox"}]
`,
script: `apply.containers[0].image`,
expect: `"busybox"
`,
},
{
src: `
apply: workload: name: "main"
`,
script: `
apply.workload.name`,
expect: `"main"
`,
},
{
src: `
apply: arr: ["abc","def"]
`,
script: `
import "strings"
strings.Join(apply.arr,".")+"$"`,
expect: `"abc.def$"
`,
},
}
for _, tCase := range testCases {
srcV, err := NewValue(tCase.src, nil, "")
assert.NilError(t, err)
v, err := srcV.LookupByScript(tCase.script)
assert.NilError(t, err)
result, _ := v.String()
assert.Equal(t, tCase.expect, result)
}
errorCases := []struct {
src string
script string
err string
}{
{
src: `
op: string
op: "help"
`,
script: `op(1`,
err: "parse script: expected ')', found 'EOF'",
},
{
src: `
op: string
op: "help"
`,
script: `oss`,
err: "failed to lookup value: var(path=oss) not exist",
},
}
for _, tCase := range errorCases {
srcV, err := NewValue(tCase.src, nil, "")
assert.NilError(t, err)
_, err = srcV.LookupByScript(tCase.script)
assert.Error(t, err, tCase.err)
assert.Equal(t, err.Error(), tCase.err)
}
}
func TestGet(t *testing.T) {
caseOk := `
strKey: "xxx"
intKey: 100
boolKey: true
`
val, err := NewValue(caseOk, nil, "")
assert.NilError(t, err)
str, err := val.GetString("strKey")
assert.NilError(t, err)
assert.Equal(t, str, "xxx")
// err case
_, err = val.GetInt64("strKey")
assert.Equal(t, err != nil, true)
intv, err := val.GetInt64("intKey")
assert.NilError(t, err)
assert.Equal(t, intv, int64(100))
// err case
_, err = val.GetBool("intKey")
assert.Equal(t, err != nil, true)
ok, err := val.GetBool("boolKey")
assert.NilError(t, err)
assert.Equal(t, ok, true)
// err case
_, err = val.GetString("boolKey")
assert.Equal(t, err != nil, true)
}
func TestImports(t *testing.T) {
cont := `
context: stepSessionID: "3w9qkdgn5w"`
v, err := NewValue(`
import (
"vela/custom"
)
id: custom.context.stepSessionID
`+cont, nil, cont)
assert.NilError(t, err)
id, err := v.GetString("id")
assert.NilError(t, err)
assert.Equal(t, id, "3w9qkdgn5w")
}
func TestOpenCompleteValue(t *testing.T) {
v, err := NewValue(`
x: 10
y: "100"
`, nil, "")
assert.NilError(t, err)
err = v.OpenCompleteValue()
assert.NilError(t, err)
s, err := v.String()
assert.NilError(t, err)
assert.Equal(t, s, `x: *10 | _
y: *"100" | _
`)
}
func TestFillByScript(t *testing.T) {
testCases := []struct {
name string
raw string
path string
v string
expected string
}{
{
name: "insert array",
raw: `a: b: [{x: 100},...]`,
path: "a.b[1]",
v: `{name: "foo"}`,
expected: `a: {
b: [{
x: 100
}, {
name: "foo"
}]
}
`,
},
{
name: "insert nest array ",
raw: `a: b: [{x: y:[{name: "key"}]}]`,
path: "a.b[0].x.y[0].value",
v: `"foo"`,
expected: `a: {
b: [{
x: {
y: [{
name: "key"
value: "foo"
}]
}
}]
}
`,
},
{
name: "insert without array",
raw: `a: b: [{x: y:[{name: "key"}]}]`,
path: "a.c.x",
v: `"foo"`,
expected: `a: {
b: [{
x: {
y: [{
name: "key"
}]
}
}]
c: {
x: "foo"
}
}
`,
},
{
name: "path with string index",
raw: `a: b: [{x: y:[{name: "key"}]}]`,
path: "a.c[\"x\"]",
v: `"foo"`,
expected: `a: {
b: [{
x: {
y: [{
name: "key"
}, ...]
}
}, ...]
c: {
x: "foo"
}
}
`,
},
}
for _, tCase := range testCases {
v, err := NewValue(tCase.raw, nil, "")
assert.NilError(t, err, tCase.name)
val, err := v.MakeValue(tCase.v)
assert.NilError(t, err, tCase.name)
err = v.FillValueByScript(val, tCase.path)
assert.NilError(t, err, tCase.name)
s, err := v.String()
assert.NilError(t, err, tCase.name)
assert.Equal(t, s, tCase.expected, tCase.name)
}
errCases := []struct {
name string
raw string
path string
v string
err string
}{
{
name: "invalid path",
raw: `a: b: [{x: 100},...]`,
path: "a.b[1]+1",
v: `{name: "foo"}`,
err: "invalid path",
},
{
name: "invalid path [float]",
raw: `a: b: [{x: 100},...]`,
path: "a.b[0.1]",
v: `{name: "foo"}`,
err: "invalid path",
},
{
name: "invalid value",
raw: `a: b: [{x: y:[{name: "key"}]}]`,
path: "a.b[0].x.y[0].value",
v: `foo`,
err: "remake value: a.b.x.y.value: reference \"foo\" not found",
},
{
name: "conflict merge",
raw: `a: b: [{x: y:[{name: "key"}]}]`,
path: "a.b[0].x.y[0].name",
v: `"foo"`,
err: "remake value: a.b.0.x.y.0.name: conflicting values \"foo\" and \"key\"",
},
{
name: "filled value with wrong cue format",
raw: `a: b: [{x: y:[{name: "key"}]}]`,
path: "a.b[0].x.y[0].value",
v: `*+-`,
err: "remake value: expected operand, found '}'",
},
}
for _, errCase := range errCases {
v, err := NewValue(errCase.raw, nil, "")
assert.NilError(t, err, errCase.name)
err = v.fillRawByScript(errCase.v, errCase.path)
assert.Equal(t, errCase.err, err.Error(), errCase.name)
}
}

View File

@ -1,685 +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 cue
import (
"context"
"errors"
"strings"
"time"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"cuelang.org/go/cue/build"
"github.com/google/go-cmp/cmp"
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
appsv1 "k8s.io/api/apps/v1"
batchv1 "k8s.io/api/batch/v1"
certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
coordinationv1 "k8s.io/api/coordination/v1"
corev1 "k8s.io/api/core/v1"
discoveryv1beta1 "k8s.io/api/discovery/v1beta1"
networkingv1 "k8s.io/api/networking/v1"
policyv1beta1 "k8s.io/api/policy/v1beta1"
rbacv1 "k8s.io/api/rbac/v1"
crdv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
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"
"k8s.io/utils/pointer"
"github.com/oam-dev/kubevela/pkg/cue/model"
"github.com/oam-dev/kubevela/pkg/cue/model/value"
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
"github.com/oam-dev/kubevela/pkg/oam/util"
)
var _ = Describe("Package discovery resources for definition from K8s APIServer", func() {
PIt("check that all built-in k8s resource are registered", func() {
var localSchemeBuilder = runtime.SchemeBuilder{
admissionregistrationv1.AddToScheme,
appsv1.AddToScheme,
batchv1.AddToScheme,
certificatesv1beta1.AddToScheme,
coordinationv1.AddToScheme,
corev1.AddToScheme,
discoveryv1beta1.AddToScheme,
networkingv1.AddToScheme,
policyv1beta1.AddToScheme,
rbacv1.AddToScheme,
}
var localScheme = runtime.NewScheme()
localSchemeBuilder.AddToScheme(localScheme)
types := localScheme.AllKnownTypes()
for typ := range types {
if strings.HasSuffix(typ.Kind, "List") {
continue
}
if strings.HasSuffix(typ.Kind, "Options") {
continue
}
switch typ.Kind {
case "WatchEvent":
continue
case "APIGroup", "APIVersions":
continue
case "RangeAllocation", "ComponentStatus", "Status":
continue
case "SerializedReference", "EndpointSlice":
continue
case "PodStatusResult", "EphemeralContainers":
continue
}
Expect(pd.Exist(metav1.GroupVersionKind{
Group: typ.Group,
Version: typ.Version,
Kind: typ.Kind,
})).Should(BeTrue(), typ.String())
}
})
PIt("discovery built-in k8s resource with kube prefix", func() {
By("test ingress in kube package")
bi := build.NewContext().NewInstance("", nil)
err := value.AddFile(bi, "-", `
import (
kube "kube/networking.k8s.io/v1beta1"
)
output: kube.#Ingress
output: {
apiVersion: "networking.k8s.io/v1beta1"
kind: "Ingress"
metadata: name: "myapp"
spec: {
rules: [{
host: parameter.domain
http: {
paths: [
for k, v in parameter.http {
path: k
backend: {
serviceName: "myname"
servicePort: v
}
},
]
}
}]
}
}
parameter: {
domain: "abc.com"
http: {
"/": 80
}
}`)
Expect(err).ToNot(HaveOccurred())
inst, err := pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
base, err := model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).Should(BeNil())
data, err := base.Unstructured()
Expect(err).Should(BeNil())
Expect(cmp.Diff(data, &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Ingress",
"apiVersion": "networking.k8s.io/v1beta1",
"metadata": map[string]interface{}{"name": "myapp"},
"spec": map[string]interface{}{
"rules": []interface{}{
map[string]interface{}{
"host": "abc.com",
"http": map[string]interface{}{
"paths": []interface{}{
map[string]interface{}{
"path": "/",
"backend": map[string]interface{}{
"serviceName": "myname",
"servicePort": int64(80),
}}}}}}}},
})).Should(BeEquivalentTo(""))
By("test Invalid Import path")
bi = build.NewContext().NewInstance("", nil)
err = value.AddFile(bi, "-", `
import (
kube "kube/networking.k8s.io/v1"
)
output: kube.#Deployment
output: {
metadata: {
"name": parameter.name
}
spec: template: spec: {
containers: [{
name:"invalid-path",
image: parameter.image
}]
}
}
parameter: {
name: "myapp"
image: "nginx"
}`)
Expect(err).Should(BeNil())
inst, err = pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
_, err = model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).ShouldNot(BeNil())
Expect(err.Error()).Should(Equal("_|_ // undefined field \"#Deployment\""))
By("test Deployment in kube package")
bi = build.NewContext().NewInstance("", nil)
err = value.AddFile(bi, "-", `
import (
kube "kube/apps/v1"
)
output: kube.#Deployment
output: {
metadata: {
"name": parameter.name
}
spec: template: spec: {
containers: [{
name:"test",
image: parameter.image
}]
}
}
parameter: {
name: "myapp"
image: "nginx"
}`)
Expect(err).Should(BeNil())
inst, err = pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
base, err = model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).Should(BeNil())
data, err = base.Unstructured()
Expect(err).Should(BeNil())
Expect(cmp.Diff(data, &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": map[string]interface{}{"name": "myapp"},
"spec": map[string]interface{}{
"selector": map[string]interface{}{},
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "test",
"image": "nginx"}}}}}},
})).Should(BeEquivalentTo(""))
By("test Secret in kube package")
bi = build.NewContext().NewInstance("", nil)
err = value.AddFile(bi, "-", `
import (
kube "kube/v1"
)
output: kube.#Secret
output: {
metadata: {
"name": parameter.name
}
type:"kubevela"
}
parameter: {
name: "myapp"
}`)
Expect(err).Should(BeNil())
inst, err = pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
base, err = model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).Should(BeNil())
data, err = base.Unstructured()
Expect(err).Should(BeNil())
Expect(cmp.Diff(data, &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Secret",
"apiVersion": "v1",
"metadata": map[string]interface{}{"name": "myapp"},
"type": "kubevela"}})).Should(BeEquivalentTo(""))
By("test Service in kube package")
bi = build.NewContext().NewInstance("", nil)
err = value.AddFile(bi, "-", `
import (
kube "kube/v1"
)
output: kube.#Service
output: {
metadata: {
"name": parameter.name
}
spec: type: "ClusterIP",
}
parameter: {
name: "myapp"
}`)
Expect(err).Should(BeNil())
inst, err = pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
base, err = model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).Should(BeNil())
data, err = base.Unstructured()
Expect(err).Should(BeNil())
Expect(cmp.Diff(data, &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Service",
"apiVersion": "v1",
"metadata": map[string]interface{}{"name": "myapp"},
"spec": map[string]interface{}{
"type": "ClusterIP"}},
})).Should(BeEquivalentTo(""))
Expect(pd.Exist(metav1.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "Service",
})).Should(Equal(true))
By("Check newly added CRD refreshed and could be used in CUE package")
crd1 := crdv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: "foo.example.com",
},
Spec: crdv1.CustomResourceDefinitionSpec{
Group: "example.com",
Names: crdv1.CustomResourceDefinitionNames{
Kind: "Foo",
ListKind: "FooList",
Plural: "foo",
Singular: "foo",
},
Versions: []crdv1.CustomResourceDefinitionVersion{{
Name: "v1",
Served: true,
Storage: true,
Subresources: &crdv1.CustomResourceSubresources{Status: &crdv1.CustomResourceSubresourceStatus{}},
Schema: &crdv1.CustomResourceValidation{
OpenAPIV3Schema: &crdv1.JSONSchemaProps{
Type: "object",
Properties: map[string]crdv1.JSONSchemaProps{
"spec": {
Type: "object",
XPreserveUnknownFields: pointer.BoolPtr(true),
Properties: map[string]crdv1.JSONSchemaProps{
"key": {Type: "string"},
}},
"status": {
Type: "object",
XPreserveUnknownFields: pointer.BoolPtr(true),
Properties: map[string]crdv1.JSONSchemaProps{
"key": {Type: "string"},
"app-hash": {Type: "string"},
}}}}}},
},
Scope: crdv1.NamespaceScoped,
},
}
Expect(k8sClient.Create(context.Background(), &crd1)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
mapper, err := discoverymapper.New(cfg)
Expect(err).ShouldNot(HaveOccurred())
Eventually(func() error {
_, err := mapper.RESTMapping(schema.GroupKind{Group: "example.com", Kind: "Foo"}, "v1")
return err
}, time.Second*2, time.Millisecond*300).Should(BeNil())
Expect(pd.Exist(metav1.GroupVersionKind{
Group: "example.com",
Version: "v1",
Kind: "Foo",
})).Should(Equal(false))
By("test new added CRD in kube package")
Eventually(func() error {
if err := pd.RefreshKubePackagesFromCluster(); err != nil {
return err
}
if !pd.Exist(metav1.GroupVersionKind{
Group: "example.com",
Version: "v1",
Kind: "Foo",
}) {
return errors.New("crd(example.com/v1.Foo) not register to openAPI")
}
return nil
}, time.Second*30, time.Millisecond*300).Should(BeNil())
bi = build.NewContext().NewInstance("", nil)
err = value.AddFile(bi, "-", `
import (
kv1 "kube/example.com/v1"
)
output: kv1.#Foo
output: {
spec: key: "test1"
status: key: "test2"
}
`)
Expect(err).Should(BeNil())
inst, err = pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
base, err = model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).Should(BeNil())
data, err = base.Unstructured()
Expect(err).Should(BeNil())
Expect(cmp.Diff(data, &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Foo",
"apiVersion": "example.com/v1",
"spec": map[string]interface{}{
"key": "test1"},
"status": map[string]interface{}{
"key": "test2"}},
})).Should(BeEquivalentTo(""))
})
PIt("discovery built-in k8s resource with third-party path", func() {
By("test ingress in kube package")
bi := build.NewContext().NewInstance("", nil)
err := value.AddFile(bi, "-", `
import (
network "k8s.io/networking/v1beta1"
)
output: network.#Ingress
output: {
metadata: name: "myapp"
spec: {
rules: [{
host: parameter.domain
http: {
paths: [
for k, v in parameter.http {
path: k
backend: {
serviceName: "myname"
servicePort: v
}
},
]
}
}]
}
}
parameter: {
domain: "abc.com"
http: {
"/": 80
}
}`)
Expect(err).ToNot(HaveOccurred())
inst, err := pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
base, err := model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).Should(BeNil())
data, err := base.Unstructured()
Expect(err).Should(BeNil())
Expect(cmp.Diff(data, &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Ingress",
"apiVersion": "networking.k8s.io/v1beta1",
"metadata": map[string]interface{}{"name": "myapp"},
"spec": map[string]interface{}{
"rules": []interface{}{
map[string]interface{}{
"host": "abc.com",
"http": map[string]interface{}{
"paths": []interface{}{
map[string]interface{}{
"path": "/",
"backend": map[string]interface{}{
"serviceName": "myname",
"servicePort": int64(80),
}}}}}}}},
})).Should(BeEquivalentTo(""))
By("test Invalid Import path")
bi = build.NewContext().NewInstance("", nil)
value.AddFile(bi, "-", `
import (
"k8s.io/networking/v1"
)
output: v1.#Deployment
output: {
metadata: {
"name": parameter.name
}
spec: template: spec: {
containers: [{
name:"invalid-path",
image: parameter.image
}]
}
}
parameter: {
name: "myapp"
image: "nginx"
}`)
inst, err = pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
_, err = model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).ShouldNot(BeNil())
Expect(err.Error()).Should(Equal("_|_ // undefined field \"#Deployment\""))
By("test Deployment in kube package")
bi = build.NewContext().NewInstance("", nil)
value.AddFile(bi, "-", `
import (
apps "k8s.io/apps/v1"
)
output: apps.#Deployment
output: {
metadata: {
"name": parameter.name
}
spec: template: spec: {
containers: [{
name:"test",
image: parameter.image
}]
}
}
parameter: {
name: "myapp"
image: "nginx"
}`)
inst, err = pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
base, err = model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).Should(BeNil())
data, err = base.Unstructured()
Expect(err).Should(BeNil())
Expect(cmp.Diff(data, &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Deployment",
"apiVersion": "apps/v1",
"metadata": map[string]interface{}{"name": "myapp"},
"spec": map[string]interface{}{
"selector": map[string]interface{}{},
"template": map[string]interface{}{
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"name": "test",
"image": "nginx"}}}}}},
})).Should(BeEquivalentTo(""))
By("test Secret in kube package")
bi = build.NewContext().NewInstance("", nil)
value.AddFile(bi, "-", `
import (
"k8s.io/core/v1"
)
output: v1.#Secret
output: {
metadata: {
"name": parameter.name
}
type:"kubevela"
}
parameter: {
name: "myapp"
}`)
inst, err = pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
base, err = model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).Should(BeNil())
data, err = base.Unstructured()
Expect(err).Should(BeNil())
Expect(cmp.Diff(data, &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Secret",
"apiVersion": "v1",
"metadata": map[string]interface{}{"name": "myapp"},
"type": "kubevela"}})).Should(BeEquivalentTo(""))
By("test Service in kube package")
bi = build.NewContext().NewInstance("", nil)
value.AddFile(bi, "-", `
import (
"k8s.io/core/v1"
)
output: v1.#Service
output: {
metadata: {
"name": parameter.name
}
spec: type: "ClusterIP",
}
parameter: {
name: "myapp"
}`)
inst, err = pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
base, err = model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).Should(BeNil())
data, err = base.Unstructured()
Expect(err).Should(BeNil())
Expect(cmp.Diff(data, &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Service",
"apiVersion": "v1",
"metadata": map[string]interface{}{"name": "myapp"},
"spec": map[string]interface{}{
"type": "ClusterIP"}},
})).Should(BeEquivalentTo(""))
Expect(pd.Exist(metav1.GroupVersionKind{
Group: "",
Version: "v1",
Kind: "Service",
})).Should(Equal(true))
By("Check newly added CRD refreshed and could be used in CUE package")
crd1 := crdv1.CustomResourceDefinition{
ObjectMeta: metav1.ObjectMeta{
Name: "bar.example.com",
},
Spec: crdv1.CustomResourceDefinitionSpec{
Group: "example.com",
Names: crdv1.CustomResourceDefinitionNames{
Kind: "Bar",
ListKind: "BarList",
Plural: "bar",
Singular: "bar",
},
Versions: []crdv1.CustomResourceDefinitionVersion{{
Name: "v1",
Served: true,
Storage: true,
Subresources: &crdv1.CustomResourceSubresources{Status: &crdv1.CustomResourceSubresourceStatus{}},
Schema: &crdv1.CustomResourceValidation{
OpenAPIV3Schema: &crdv1.JSONSchemaProps{
Type: "object",
Properties: map[string]crdv1.JSONSchemaProps{
"spec": {
Type: "object",
XPreserveUnknownFields: pointer.BoolPtr(true),
Properties: map[string]crdv1.JSONSchemaProps{
"key": {Type: "string"},
}},
"status": {
Type: "object",
XPreserveUnknownFields: pointer.BoolPtr(true),
Properties: map[string]crdv1.JSONSchemaProps{
"key": {Type: "string"},
"app-hash": {Type: "string"},
}}}}}},
},
Scope: crdv1.NamespaceScoped,
},
}
Expect(k8sClient.Create(context.Background(), &crd1)).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
mapper, err := discoverymapper.New(cfg)
Expect(err).ShouldNot(HaveOccurred())
Eventually(func() error {
_, err := mapper.RESTMapping(schema.GroupKind{Group: "example.com", Kind: "Bar"}, "v1")
return err
}, time.Second*2, time.Millisecond*300).Should(BeNil())
Expect(pd.Exist(metav1.GroupVersionKind{
Group: "example.com",
Version: "v1",
Kind: "Bar",
})).Should(Equal(false))
By("test new added CRD in kube package")
Eventually(func() error {
if err := pd.RefreshKubePackagesFromCluster(); err != nil {
return err
}
if !pd.Exist(metav1.GroupVersionKind{
Group: "example.com",
Version: "v1",
Kind: "Bar",
}) {
return errors.New("crd(example.com/v1.Bar) not register to openAPI")
}
return nil
}, time.Second*30, time.Millisecond*300).Should(BeNil())
bi = build.NewContext().NewInstance("", nil)
err = value.AddFile(bi, "-", `
import (
ev1 "example.com/v1"
)
output: ev1.#Bar
output: {
spec: key: "test1"
status: key: "test2"
}
`)
Expect(err).Should(BeNil())
inst, err = pd.ImportPackagesAndBuildValue(bi)
Expect(err).Should(BeNil())
base, err = model.NewBase(inst.LookupPath(value.FieldPath("output")))
Expect(err).Should(BeNil())
data, err = base.Unstructured()
Expect(err).Should(BeNil())
Expect(cmp.Diff(data, &unstructured.Unstructured{Object: map[string]interface{}{
"kind": "Bar",
"apiVersion": "example.com/v1",
"spec": map[string]interface{}{
"key": "test1"},
"status": map[string]interface{}{
"key": "test2"}},
})).Should(BeEquivalentTo(""))
})
})

View File

@ -1,464 +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 packages
import (
"fmt"
"path/filepath"
"strings"
"sync"
"time"
"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/parser"
"cuelang.org/go/cue/token"
"cuelang.org/go/encoding/jsonschema"
"github.com/pkg/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"github.com/oam-dev/kubevela/pkg/stdlib"
)
const (
// BuiltinPackageDomain Specify the domain of the built-in package
BuiltinPackageDomain = "kube"
// K8sResourcePrefix Indicates that the definition comes from kubernetes
K8sResourcePrefix = "io_k8s_api_"
// ParseJSONSchemaErr describes the error that occurs when cue parses json
ParseJSONSchemaErr ParseErrType = "parse json schema of k8s crds error"
)
// PackageDiscover defines the inner CUE packages loaded from K8s cluster
type PackageDiscover struct {
velaBuiltinPackages []*build.Instance
pkgKinds map[string][]VersionKind
mutex sync.RWMutex
client *rest.RESTClient
}
// VersionKind contains the resource metadata and reference name
type VersionKind struct {
DefinitionName string
APIVersion string
Kind string
}
// ParseErrType represents the type of CUEParseError
type ParseErrType string
// CUEParseError describes an error when CUE parse error
type CUEParseError struct {
err error
errType ParseErrType
}
// Error implements the Error interface.
func (cueErr CUEParseError) Error() string {
return fmt.Sprintf("%s: %s", cueErr.errType, cueErr.err.Error())
}
// IsCUEParseErr returns true if the specified error is CUEParseError type.
func IsCUEParseErr(err error) bool {
return errors.As(err, &CUEParseError{})
}
// NewPackageDiscover will create a PackageDiscover client with the K8s config file.
func NewPackageDiscover(config *rest.Config) (*PackageDiscover, error) {
client, err := getClusterOpenAPIClient(config)
if err != nil {
return nil, err
}
pd := &PackageDiscover{
client: client,
pkgKinds: make(map[string][]VersionKind),
}
if err = pd.RefreshKubePackagesFromCluster(); err != nil {
return pd, err
}
return pd, nil
}
// ImportBuiltinPackagesFor will add KubeVela built-in packages into your CUE instance
func (pd *PackageDiscover) ImportBuiltinPackagesFor(bi *build.Instance) {
pd.mutex.RLock()
defer pd.mutex.RUnlock()
bi.Imports = append(bi.Imports, pd.velaBuiltinPackages...)
}
// ImportPackagesAndBuildInstance Combine import built-in packages and build cue template together to avoid data race
// nolint:staticcheck
func (pd *PackageDiscover) ImportPackagesAndBuildInstance(bi *build.Instance) (inst *cue.Instance, err error) {
var r cue.Runtime
if pd == nil {
return r.Build(bi)
}
pd.ImportBuiltinPackagesFor(bi)
if err := stdlib.AddImportsFor(bi, ""); err != nil {
return nil, err
}
pd.mutex.Lock()
defer pd.mutex.Unlock()
return r.Build(bi)
}
// ImportPackagesAndBuildValue Combine import built-in packages and build cue template together to avoid data race
func (pd *PackageDiscover) ImportPackagesAndBuildValue(bi *build.Instance) (val cue.Value, err error) {
cuectx := cuecontext.New()
if pd == nil {
return cuectx.BuildInstance(bi), nil
}
pd.ImportBuiltinPackagesFor(bi)
if err := stdlib.AddImportsFor(bi, ""); err != nil {
return cue.Value{}, err
}
pd.mutex.Lock()
defer pd.mutex.Unlock()
return cuectx.BuildInstance(bi), nil
}
// ListPackageKinds list packages and their kinds
func (pd *PackageDiscover) ListPackageKinds() map[string][]VersionKind {
pd.mutex.RLock()
defer pd.mutex.RUnlock()
return pd.pkgKinds
}
// RefreshKubePackagesFromCluster will use K8s client to load/refresh all K8s open API as a reference kube package using in template
func (pd *PackageDiscover) RefreshKubePackagesFromCluster() error {
return nil
// body, err := pd.client.Get().AbsPath("/openapi/v2").Do(context.Background()).Raw()
// if err != nil {
// return err
// }
// return pd.addKubeCUEPackagesFromCluster(string(body))
}
// Exist checks if the GVK exists in the built-in packages
func (pd *PackageDiscover) Exist(gvk metav1.GroupVersionKind) bool {
dgvk := convert2DGVK(gvk)
// package name equals to importPath
importPath := genStandardPkgName(dgvk)
pd.mutex.RLock()
defer pd.mutex.RUnlock()
pkgKinds, ok := pd.pkgKinds[importPath]
if !ok {
pkgKinds = pd.pkgKinds[genOpenPkgName(dgvk)]
}
for _, v := range pkgKinds {
if v.Kind == dgvk.Kind {
return true
}
}
return false
}
// mount will mount the new parsed package into PackageDiscover built-in packages
func (pd *PackageDiscover) mount(pkg *pkgInstance, pkgKinds []VersionKind) {
pd.mutex.Lock()
defer pd.mutex.Unlock()
if pkgKinds == nil {
pkgKinds = []VersionKind{}
}
for i, p := range pd.velaBuiltinPackages {
if p.ImportPath == pkg.ImportPath {
pd.pkgKinds[pkg.ImportPath] = pkgKinds
pd.velaBuiltinPackages[i] = pkg.Instance
return
}
}
pd.pkgKinds[pkg.ImportPath] = pkgKinds
pd.velaBuiltinPackages = append(pd.velaBuiltinPackages, pkg.Instance)
}
func (pd *PackageDiscover) pkgBuild(packages map[string]*pkgInstance, pkgName string,
dGVK domainGroupVersionKind, def string, kubePkg *pkgInstance, groupKinds map[string][]VersionKind) error {
pkg, ok := packages[pkgName]
if !ok {
pkg = newPackage(pkgName)
pkg.Imports = []*build.Instance{kubePkg.Instance}
}
mykinds := groupKinds[pkgName]
mykinds = append(mykinds, VersionKind{
APIVersion: dGVK.APIVersion,
Kind: dGVK.Kind,
DefinitionName: "#" + dGVK.Kind,
})
file, err := parser.ParseFile(dGVK.reverseString(), def)
if err != nil {
return err
}
if err := pkg.AddSyntax(file); err != nil {
return err
}
packages[pkgName] = pkg
groupKinds[pkgName] = mykinds
return nil
}
func (pd *PackageDiscover) addKubeCUEPackagesFromCluster(apiSchema string) error {
file, err := parser.ParseFile("-", apiSchema)
if err != nil {
return err
}
oaInst := cuecontext.New().BuildFile(file)
if err != nil {
return err
}
dgvkMapper := make(map[string]domainGroupVersionKind)
pathValue := oaInst.LookupPath(cue.ParsePath("paths"))
if pathValue.Exists() {
if st, err := pathValue.Struct(); err == nil {
iter := st.Fields()
for iter.Next() {
gvk := iter.Value().LookupPath(cue.ParsePath("post[\"x-kubernetes-group-version-kind\"]"))
if gvk.Exists() {
if v, err := getDGVK(gvk); err == nil {
dgvkMapper[v.reverseString()] = v
}
}
}
}
}
oaFile, err := jsonschema.Extract(oaInst, &jsonschema.Config{
Root: "#/definitions",
Map: openAPIMapping(dgvkMapper),
})
if err != nil {
return CUEParseError{
err: err,
errType: ParseJSONSchemaErr,
}
}
kubePkg := newPackage("kube")
kubePkg.processOpenAPIFile(oaFile)
if err := kubePkg.AddSyntax(oaFile); err != nil {
return err
}
packages := make(map[string]*pkgInstance)
groupKinds := make(map[string][]VersionKind)
for k := range dgvkMapper {
v := dgvkMapper[k]
apiVersion := v.APIVersion
def := fmt.Sprintf(`
import "kube"
#%s: kube.%s & {
kind: "%s"
apiVersion: "%s",
}`, v.Kind, k, v.Kind, apiVersion)
if err := pd.pkgBuild(packages, genStandardPkgName(v), v, def, kubePkg, groupKinds); err != nil {
return err
}
if err := pd.pkgBuild(packages, genOpenPkgName(v), v, def, kubePkg, groupKinds); err != nil {
return err
}
}
for name, pkg := range packages {
pd.mount(pkg, groupKinds[name])
}
return nil
}
func genOpenPkgName(v domainGroupVersionKind) string {
return BuiltinPackageDomain + "/" + v.APIVersion
}
func genStandardPkgName(v domainGroupVersionKind) string {
res := []string{v.Group, v.Version}
if v.Domain != "" {
res = []string{v.Domain, v.Group, v.Version}
}
return strings.Join(res, "/")
}
func setDiscoveryDefaults(config *rest.Config) {
config.APIPath = ""
config.GroupVersion = nil
if config.Timeout == 0 {
config.Timeout = 32 * time.Second
}
if config.Burst == 0 && config.QPS < 100 {
// discovery is expected to be bursty, increase the default burst
// to accommodate looking up resource info for many API groups.
// matches burst set by ConfigFlags#ToDiscoveryClient().
// see https://issue.k8s.io/86149
config.Burst = 100
}
codec := runtime.NoopEncoder{Decoder: clientgoscheme.Codecs.UniversalDecoder()}
config.NegotiatedSerializer = serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{Serializer: codec})
if len(config.UserAgent) == 0 {
config.UserAgent = rest.DefaultKubernetesUserAgent()
}
}
func getClusterOpenAPIClient(config *rest.Config) (*rest.RESTClient, error) {
copyConfig := *config
setDiscoveryDefaults(&copyConfig)
return rest.UnversionedRESTClientFor(&copyConfig)
}
func openAPIMapping(dgvkMapper map[string]domainGroupVersionKind) func(pos token.Pos, a []string) ([]ast.Label, error) {
return func(pos token.Pos, a []string) ([]ast.Label, error) {
if len(a) < 2 {
return nil, errors.New("openAPIMapping format invalid")
}
name := strings.ReplaceAll(a[1], ".", "_")
name = strings.ReplaceAll(name, "-", "_")
if _, ok := dgvkMapper[name]; !ok && strings.HasPrefix(name, K8sResourcePrefix) {
trimName := strings.TrimPrefix(name, K8sResourcePrefix)
if v, ok := dgvkMapper[trimName]; ok {
v.Domain = "k8s.io"
dgvkMapper[name] = v
delete(dgvkMapper, trimName)
}
}
if strings.HasSuffix(a[1], ".JSONSchemaProps") && pos != token.NoPos {
return []ast.Label{ast.NewIdent("_")}, nil
}
return []ast.Label{ast.NewIdent(name)}, nil
}
}
type domainGroupVersionKind struct {
Domain string
Group string
Version string
Kind string
APIVersion string
}
func (dgvk domainGroupVersionKind) reverseString() string {
var s = []string{dgvk.Kind, dgvk.Version}
s = append(s, strings.Split(dgvk.Group, ".")...)
domain := dgvk.Domain
if domain == "k8s.io" {
domain = "api.k8s.io"
}
if domain != "" {
s = append(s, strings.Split(domain, ".")...)
}
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
s[i], s[j] = s[j], s[i]
}
return strings.ReplaceAll(strings.Join(s, "_"), "-", "_")
}
type pkgInstance struct {
*build.Instance
}
func newPackage(name string) *pkgInstance {
return &pkgInstance{
&build.Instance{
PkgName: filepath.Base(name),
ImportPath: name,
},
}
}
func (pkg *pkgInstance) processOpenAPIFile(f *ast.File) {
ast.Walk(f, func(node ast.Node) bool {
if st, ok := node.(*ast.StructLit); ok {
hasEllipsis := false
for index, elt := range st.Elts {
if _, isEllipsis := elt.(*ast.Ellipsis); isEllipsis {
if hasEllipsis {
st.Elts = st.Elts[:index]
return true
}
if index > 0 {
st.Elts = st.Elts[:index]
return true
}
hasEllipsis = true
}
}
}
return true
}, nil)
for _, decl := range f.Decls {
if field, ok := decl.(*ast.Field); ok {
if val, ok := field.Value.(*ast.Ident); ok && val.Name == "string" {
field.Value = ast.NewBinExpr(token.OR, ast.NewIdent("int"), ast.NewIdent("string"))
}
}
}
}
func getDGVK(v cue.Value) (ret domainGroupVersionKind, err error) {
gvk := metav1.GroupVersionKind{}
gvk.Group, err = v.LookupPath(cue.ParsePath("group")).String()
if err != nil {
return
}
gvk.Version, err = v.LookupPath(cue.ParsePath("version")).String()
if err != nil {
return
}
gvk.Kind, err = v.LookupPath(cue.ParsePath("kind")).String()
if err != nil {
return
}
ret = convert2DGVK(gvk)
return
}
func convert2DGVK(gvk metav1.GroupVersionKind) domainGroupVersionKind {
ret := domainGroupVersionKind{
Version: gvk.Version,
Kind: gvk.Kind,
APIVersion: gvk.Version,
}
if gvk.Group == "" {
ret.Group = "core"
ret.Domain = "k8s.io"
} else {
ret.APIVersion = gvk.Group + "/" + ret.APIVersion
sv := strings.Split(gvk.Group, ".")
// Domain must contain dot
if len(sv) > 2 {
ret.Domain = strings.Join(sv[1:], ".")
ret.Group = sv[0]
} else {
ret.Group = gvk.Group
}
}
return ret
}

View File

@ -1,632 +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 packages
import (
"fmt"
"testing"
"cuelang.org/go/cue"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/parser"
"cuelang.org/go/cue/token"
"github.com/google/go-cmp/cmp"
"gotest.tools/assert"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/oam-dev/kubevela/pkg/cue/model"
)
func TestPackage(t *testing.T) {
var openAPISchema = `
{
"paths": {
"paths...": {
"post":{
"x-kubernetes-group-version-kind": {
"group": "apps.test.io",
"kind": "Bucket",
"version": "v1"
}
}
}
},
"definitions":{
"io.test.apps.v1.Bucket":{
"properties":{
"apiVersion": {"type": "string"}
"kind": {"type": "string"}
"acl":{
"default":"private",
"enum":[
"public-read-write",
"public-read",
"private"
],
"type":"string"
},
"dataRedundancyType":{
"default":"LRS",
"enum":[
"LRS",
"ZRS"
],
"type":"string"
},
"dataSourceRef":{
"properties":{
"dsPath":{
"type":"string"
}
},
"required":[
"dsPath"
],
"type":"object"
},
"importRef":{
"properties":{
"importKey":{
"type":"string"
}
},
"required":[
"importKey"
],
"type":"object"
},
"output":{
"additionalProperties":{
"oneOf":[
{
"properties":{
"outRef":{
"type":"string"
}
},
"required":[
"outRef"
]
},
{
"properties":{
"valueRef":{
"description":"Example: demoVpc.vpcId",
"type":"string"
}
},
"required":[
"valueRef"
]
}
],
"type":"object"
},
"properties":{
"bucketName":{
"properties":{
"outRef":{
"enum":[
"self.name"
],
"type":"string"
}
},
"required":[
"outRef"
],
"type":"object"
},
"extranetEndpoint":{
"properties":{
"outRef":{
"enum":[
"self.state.extranetEndpoint"
],
"type":"string"
}
},
"required":[
"outRef"
],
"type":"object"
},
"intranetEndpoint":{
"properties":{
"outRef":{
"enum":[
"self.state.intranetEndpoint"
],
"type":"string"
}
},
"required":[
"outRef"
],
"type":"object"
},
"masterUserId":{
"properties":{
"outRef":{
"enum":[
"self.state.masterUserId"
],
"type":"string"
}
},
"required":[
"outRef"
],
"type":"object"
}
},
"required":[
"bucketName",
"extranetEndpoint",
"intranetEndpoint",
"masterUserId"
],
"type":"object"
},
"profile":{
"properties":{
"baasRepo":{
"oneOf":[
{
"type":"string"
},
{
"properties":{
"valueRef":{
"description":"Example: demoVpc.vpcId",
"type":"string"
}
},
"required":[
"valueRef"
],
"type":"object"
}
]
},
"cloudProduct":{
"enum":[
"AliCloudOSS"
],
"type":"string"
},
"endpoint":{
"oneOf":[
{
"type":"string"
},
{
"properties":{
"valueRef":{
"description":"Example: demoVpc.vpcId",
"type":"string"
}
},
"required":[
"valueRef"
],
"type":"object"
}
]
},
"envType":{
"oneOf":[
{
"enum":[
"testing",
"product"
]
},
{
"properties":{
"valueRef":{
"description":"Example: demoVpc.vpcId",
"type":"string"
}
},
"required":[
"valueRef"
],
"type":"object"
}
]
},
"provider":{
"enum":[
"alicloud"
],
"type":"string"
},
"region":{
"oneOf":[
{
"type":"string"
},
{
"properties":{
"valueRef":{
"description":"Example: demoVpc.vpcId",
"type":"string"
}
},
"required":[
"valueRef"
],
"type":"object"
}
]
},
"serviceAccount":{
"oneOf":[
{
"type":"string"
},
{
"properties":{
"valueRef":{
"description":"Example: demoVpc.vpcId",
"type":"string"
}
},
"required":[
"valueRef"
],
"type":"object"
}
]
}
},
"required":[
"cloudProduct",
"provider",
"baasRepo",
"region"
],
"type":"object"
},
"storageClass":{
"default":"Standard",
"enum":[
"Standard",
"IA",
"Archive",
"ColdArchive"
],
"type":"string"
},
"type":{
"enum":[
"alicloud_oss_bucket"
],
"type":"string"
}
},
"required":[
"type",
"output",
"profile",
"acl"
],
"type":"object"
}
}
}
`
mypd := &PackageDiscover{pkgKinds: make(map[string][]VersionKind)}
mypd.addKubeCUEPackagesFromCluster(openAPISchema)
expectPkgKinds := map[string][]VersionKind{
"test.io/apps/v1": []VersionKind{{
DefinitionName: "#Bucket",
APIVersion: "apps.test.io/v1",
Kind: "Bucket",
}},
"kube/apps.test.io/v1": []VersionKind{{
DefinitionName: "#Bucket",
APIVersion: "apps.test.io/v1",
Kind: "Bucket",
}},
}
assert.Equal(t, cmp.Diff(mypd.ListPackageKinds(), expectPkgKinds), "")
// TODO: fix losing close struct in cue
exceptObj := `output: {
apiVersion: "apps.test.io/v1"
kind: "Bucket"
acl: *"private" | "public-read" | "public-read-write"
dataRedundancyType?: "LRS" | "ZRS" | *"LRS"
dataSourceRef?: {
dsPath: string
}
importRef?: {
importKey: string
}
output: {
bucketName: {
outRef: "self.name"
}
extranetEndpoint: {
outRef: "self.state.extranetEndpoint"
}
intranetEndpoint: {
outRef: "self.state.intranetEndpoint"
}
masterUserId: {
outRef: "self.state.masterUserId"
}
}
profile: {
baasRepo: string | {
// Example: demoVpc.vpcId
valueRef: string
}
cloudProduct: "AliCloudOSS"
endpoint?: string | {
// Example: demoVpc.vpcId
valueRef: string
}
envType?: "testing" | "product" | {
// Example: demoVpc.vpcId
valueRef: string
}
provider: "alicloud"
region: string | {
// Example: demoVpc.vpcId
valueRef: string
}
serviceAccount?: string | {
// Example: demoVpc.vpcId
valueRef: string
}
}
storageClass?: "Standard" | "IA" | "Archive" | "ColdArchive" | *"Standard"
type: "alicloud_oss_bucket"
}
`
bi := build.NewContext().NewInstance("", nil)
file, err := parser.ParseFile("-", `
import "test.io/apps/v1"
output: v1.#Bucket
`)
assert.NilError(t, err)
err = bi.AddSyntax(file)
assert.NilError(t, err)
inst, err := mypd.ImportPackagesAndBuildValue(bi)
assert.NilError(t, err)
base, err := model.NewBase(inst)
assert.NilError(t, err)
s, err := base.String()
assert.NilError(t, err)
assert.Equal(t, s, exceptObj)
bi = build.NewContext().NewInstance("", nil)
file, err = parser.ParseFile("-", `
import "kube/apps.test.io/v1"
output: v1.#Bucket
`)
assert.NilError(t, err)
err = bi.AddSyntax(file)
assert.NilError(t, err)
inst, err = mypd.ImportPackagesAndBuildValue(bi)
assert.NilError(t, err)
base, err = model.NewBase(inst)
assert.NilError(t, err)
s, err = base.String()
assert.NilError(t, err)
assert.Equal(t, s, exceptObj)
}
func TestProcessFile(t *testing.T) {
srcTmpl := `
#Definition: {
kind?: string
apiVersion?: string
metadata: {
name: string
...
}
...
}
`
file, err := parser.ParseFile("-", srcTmpl)
assert.NilError(t, err)
testPkg := newPackage("foo")
testPkg.processOpenAPIFile(file)
cuectx := cuecontext.New()
inst := cuectx.BuildFile(file)
testCasesInst := cuectx.CompileString(`
#Definition: {}
case1: #Definition & {additionalProperty: "test"}
case2: #Definition & {
metadata: {
additionalProperty: "test"
}
}
`)
retInst := inst.FillPath(cue.ParsePath(""), testCasesInst.Value())
assert.Error(t, retInst.LookupPath(cue.ParsePath("case1")).Err(), "case1.additionalProperty: field not allowed")
assert.Error(t, retInst.LookupPath(cue.ParsePath("case2.metadata")).Err(), "case2.metadata.additionalProperty: field not allowed")
}
func TestMount(t *testing.T) {
mypd := &PackageDiscover{pkgKinds: make(map[string][]VersionKind)}
testPkg := newPackage("foo")
mypd.mount(testPkg, []VersionKind{})
assert.Equal(t, len(mypd.velaBuiltinPackages), 1)
mypd.mount(testPkg, []VersionKind{})
assert.Equal(t, len(mypd.velaBuiltinPackages), 1)
assert.Equal(t, mypd.velaBuiltinPackages[0], testPkg.Instance)
}
func TestGetDGVK(t *testing.T) {
srcTmpl := `
{
"x-kubernetes-group-version-kind": {
"group": "apps.test.io",
"kind": "Foo",
"version": "v1"
}
}
`
file, err := parser.ParseFile("-", srcTmpl)
assert.NilError(t, err)
inst := cuecontext.New().BuildFile(file)
gvk, err := getDGVK(inst.Value().LookupPath(cue.ParsePath("\"x-kubernetes-group-version-kind\"")))
assert.NilError(t, err)
assert.Equal(t, gvk, domainGroupVersionKind{
Domain: "test.io",
Group: "apps",
Version: "v1",
Kind: "Foo",
APIVersion: "apps.test.io/v1",
})
srcTmpl = `
{
"x-kubernetes-group-version-kind": {
"group": "test.io",
"kind": "Foo",
"version": "v1"
}
}
`
inst = cuecontext.New().CompileString(srcTmpl)
gvk, err = getDGVK(inst.LookupPath(cue.ParsePath("\"x-kubernetes-group-version-kind\"")))
assert.NilError(t, err)
assert.Equal(t, gvk, domainGroupVersionKind{
Group: "test.io",
Version: "v1",
Kind: "Foo",
APIVersion: "test.io/v1",
})
}
func TestOpenAPIMapping(t *testing.T) {
testCases := []struct {
input []string
pos token.Pos
result string
errMsg string
}{
{
input: []string{"definitions", "io.k8s.api.discovery.v1beta1.Endpoint"},
pos: token.NoPos,
result: "[io_k8s_api_discovery_v1beta1_Endpoint]",
},
{
input: []string{"definitions", "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps"},
pos: token.NoPos.Add(1),
result: "[_]",
},
{
input: []string{"definitions", "io.k8s.apiextensions-apiserver.pkg.apis.apiextensions.v1.JSONSchemaProps"},
pos: token.NoPos,
result: "[io_k8s_apiextensions_apiserver_pkg_apis_apiextensions_v1_JSONSchemaProps]",
},
{
input: []string{"definitions"},
pos: token.NoPos,
errMsg: "openAPIMapping format invalid",
},
}
emptyMapper := make(map[string]domainGroupVersionKind)
for _, tCase := range testCases {
labels, err := openAPIMapping(emptyMapper)(tCase.pos, tCase.input)
if tCase.errMsg != "" {
assert.Error(t, err, tCase.errMsg)
continue
}
assert.NilError(t, err)
assert.Equal(t, len(labels), 1)
assert.Equal(t, tCase.result, fmt.Sprint(labels))
}
}
func TestGeneratePkgName(t *testing.T) {
testCases := []struct {
dgvk domainGroupVersionKind
sdPkgName string
openPkgName string
}{
{
dgvk: domainGroupVersionKind{
Domain: "k8s.io",
Group: "networking",
Version: "v1",
Kind: "Ingress",
},
sdPkgName: "k8s.io/networking/v1",
openPkgName: "kube/networking.k8s.io",
},
{
dgvk: domainGroupVersionKind{
Group: "example.com",
Version: "v1",
Kind: "Sls",
},
sdPkgName: "example.com/v1",
openPkgName: "kube/example.com/v1",
},
}
for _, tCase := range testCases {
assert.Equal(t, genStandardPkgName(tCase.dgvk), tCase.sdPkgName)
}
}
func TestReverseString(t *testing.T) {
testCases := []struct {
gvr metav1.GroupVersionKind
reverseString string
}{
{
gvr: metav1.GroupVersionKind{
Group: "networking.k8s.io",
Version: "v1",
Kind: "NetworkPolicy",
},
reverseString: "io_k8s_api_networking_v1_NetworkPolicy",
},
{
gvr: metav1.GroupVersionKind{
Group: "example.com",
Version: "v1",
Kind: "Sls",
},
reverseString: "com_example_v1_Sls",
},
{
gvr: metav1.GroupVersionKind{
Version: "v1",
Kind: "Pod",
},
reverseString: "io_k8s_api_core_v1_Pod",
},
}
for _, tCase := range testCases {
assert.Equal(t, convert2DGVK(tCase.gvr).reverseString(), tCase.reverseString)
}
}

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