github.com/kubevela/workflow@v0.6.0/pkg/cue/model/instance.go (about)

     1  /*
     2  Copyright 2022 The KubeVela Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package model
    18  
    19  import (
    20  	"cuelang.org/go/cue"
    21  	"github.com/pkg/errors"
    22  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    23  	"k8s.io/klog/v2"
    24  
    25  	"github.com/kubevela/workflow/pkg/cue/model/sets"
    26  )
    27  
    28  // Instance defines Model Interface
    29  type Instance interface {
    30  	String() (string, error)
    31  	Value() cue.Value
    32  	Unstructured() (*unstructured.Unstructured, error)
    33  	IsBase() bool
    34  	Unify(other cue.Value, options ...sets.UnifyOption) error
    35  	Compile() ([]byte, error)
    36  }
    37  
    38  type instance struct {
    39  	v    cue.Value
    40  	base bool
    41  }
    42  
    43  // String return instance's cue format string
    44  func (inst *instance) String() (string, error) {
    45  	return sets.ToString(inst.v)
    46  }
    47  
    48  func (inst *instance) Value() cue.Value {
    49  	return inst.v
    50  }
    51  
    52  // IsBase indicate whether the instance is base model
    53  func (inst *instance) IsBase() bool {
    54  	return inst.base
    55  }
    56  
    57  func (inst *instance) Compile() ([]byte, error) {
    58  	if err := inst.v.Err(); err != nil {
    59  		return nil, err
    60  	}
    61  	// compiled object should be final and concrete value
    62  	if err := inst.v.Validate(cue.Concrete(true), cue.Final()); err != nil {
    63  		return nil, err
    64  	}
    65  	return inst.v.MarshalJSON()
    66  }
    67  
    68  // Unstructured convert cue values to unstructured.Unstructured
    69  // TODO(wonderflow): will it be better if we try to decode it to concrete object(such as K8s Deployment) by using runtime.Schema?
    70  func (inst *instance) Unstructured() (*unstructured.Unstructured, error) {
    71  	jsonv, err := inst.Compile()
    72  	if err != nil {
    73  		klog.ErrorS(err, "failed to have the workload/trait unstructured", "Definition", inst.v)
    74  		return nil, errors.Wrap(err, "failed to have the workload/trait unstructured")
    75  	}
    76  	o := &unstructured.Unstructured{}
    77  	if err := o.UnmarshalJSON(jsonv); err != nil {
    78  		return nil, err
    79  	}
    80  	return o, nil
    81  }
    82  
    83  // Unify implement unity operations between instances
    84  func (inst *instance) Unify(other cue.Value, options ...sets.UnifyOption) error {
    85  	pv, err := sets.StrategyUnify(inst.v, other, options...)
    86  	if err != nil {
    87  		return err
    88  	}
    89  	inst.v = pv
    90  	return nil
    91  }
    92  
    93  // NewBase create a base instance
    94  func NewBase(v cue.Value) (Instance, error) {
    95  	return &instance{
    96  		v:    v,
    97  		base: true,
    98  	}, nil
    99  }
   100  
   101  // NewOther create a non-base instance
   102  func NewOther(v cue.Value) (Instance, error) {
   103  	return &instance{
   104  		v: v,
   105  	}, nil
   106  }