Files
Tianxin Dong 0f780dec75 Feat: add new providers and fix definitions (#6599)
* feat: add new providers and fix definitions

Signed-off-by: FogDong <fog@bentoml.com>

* fix: fix definitions and tests

Signed-off-by: FogDong <fog@bentoml.com>

* fix: fix lint and helm

Signed-off-by: FogDong <fog@bentoml.com>

* fix: fix definitions

Signed-off-by: FogDong <fog@bentoml.com>

* fix: add multicluster

Signed-off-by: FogDong <fog@bentoml.com>

* fix: fix e2e

Signed-off-by: FogDong <fog@bentoml.com>

* fix: fix dynamic client for cli

Signed-off-by: FogDong <fog@bentoml.com>

* fix: fix api gen

Signed-off-by: FogDong <fog@bentoml.com>

* fix: fix lint

Signed-off-by: FogDong <fog@bentoml.com>

---------

Signed-off-by: FogDong <fog@bentoml.com>
2024-10-01 12:29:44 +05:30

232 lines
7.1 KiB
Go

/*
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 oam
import (
"context"
_ "embed"
"cuelang.org/go/cue"
"k8s.io/apimachinery/pkg/types"
cuexruntime "github.com/kubevela/pkg/cue/cuex/runtime"
"github.com/kubevela/workflow/pkg/cue/model/value"
workflowerrors "github.com/kubevela/workflow/pkg/errors"
"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"
oamprovidertypes "github.com/oam-dev/kubevela/pkg/workflow/providers/types"
)
const (
// ProviderName is provider name for install.
ProviderName = "oam"
)
// RenderComponent render component
func RenderComponent(ctx context.Context, params *oamprovidertypes.Params[cue.Value]) (cue.Value, error) {
v := params.Params
parameter := v.LookupPath(cue.ParsePath("$params"))
if !parameter.Exists() {
return cue.Value{}, workflowerrors.LookUpNotFoundErr("$params")
}
comp, patcher, clusterName, overrideNamespace, err := lookUpCompInfo(parameter)
if err != nil {
return cue.Value{}, err
}
workload, traits, err := params.ComponentRender(ctx, *comp, patcher, clusterName, overrideNamespace)
if err != nil {
return cue.Value{}, err
}
if workload != nil {
v = v.FillPath(value.FieldPath("$returns", "output"), workload.Object)
}
for _, trait := range traits {
name := trait.GetLabels()[oam.TraitResource]
if name != "" {
v = v.FillPath(value.FieldPath("$returns", "outputs", name), workload.Object)
}
}
return v, nil
}
// ApplyComponent apply component.
func ApplyComponent(ctx context.Context, params *oamprovidertypes.Params[cue.Value]) (cue.Value, error) {
v := params.Params
parameter := v.LookupPath(cue.ParsePath("$params"))
if !parameter.Exists() {
return cue.Value{}, workflowerrors.LookUpNotFoundErr("$params")
}
comp, patcher, clusterName, overrideNamespace, err := lookUpCompInfo(parameter)
if err != nil {
return cue.Value{}, err
}
workload, traits, healthy, err := params.ComponentApply(ctx, *comp, patcher, clusterName, overrideNamespace)
if err != nil {
return cue.Value{}, err
}
if workload != nil {
v = v.FillPath(value.FieldPath("$returns", "output"), workload.Object)
}
for _, trait := range traits {
name := trait.GetLabels()[oam.TraitResource]
if name != "" {
v = v.FillPath(value.FieldPath("$returns", "outputs", name), trait)
}
}
waitHealthy, err := v.LookupPath(cue.ParsePath("waitHealthy")).Bool()
if err != nil {
waitHealthy = true
}
if waitHealthy && !healthy {
params.Action.Wait("wait healthy")
}
return v, nil
}
func lookUpCompInfo(v cue.Value) (*common.ApplicationComponent, *cue.Value, string, string, error) {
compSettings := v.LookupPath(cue.ParsePath("value"))
if !compSettings.Exists() {
return nil, nil, "", "", workflowerrors.LookUpNotFoundErr("value")
}
comp := &common.ApplicationComponent{}
if err := value.UnmarshalTo(compSettings, comp); err != nil {
return nil, nil, "", "", err
}
var patcherValue *cue.Value
patcher := v.LookupPath(cue.ParsePath("patch"))
if patcher.Exists() {
patcherValue = &patcher
}
clusterName, err := v.LookupPath(cue.ParsePath("cluster")).String()
if err != nil {
clusterName = ""
}
overrideNamespace, err := v.LookupPath(cue.ParsePath("namespace")).String()
if err != nil {
overrideNamespace = ""
}
return comp, patcherValue, clusterName, overrideNamespace, nil
}
// LoadVars is the load provider vars.
type LoadVars struct {
App string `json:"app,omitempty"`
}
// LoadReturnVars is the load provider return vars.
type LoadReturnVars struct {
Value any `json:"value"`
}
// LoadParams is the load provider params.
type LoadParams = oamprovidertypes.Params[LoadVars]
// LoadReturns is the load provider returns.
type LoadReturns = oamprovidertypes.Returns[LoadReturnVars]
// LoadComponent load component describe info in application.
func LoadComponent(ctx context.Context, params *LoadParams) (*LoadReturns, error) {
app := &v1beta1.Application{}
cli := params.KubeClient
// if specify `app`, use specified application otherwise use default application from provider
appSettings := params.Params.App
if appSettings == "" {
app = params.App
} else {
if err := cli.Get(ctx, types.NamespacedName{Name: appSettings, Namespace: params.App.Namespace}, app); err != nil {
return nil, err
}
}
comps := make(map[string]*common.ApplicationComponent, 0)
for _, _comp := range app.Spec.Components {
comp, err := params.Appfile.LoadDynamicComponent(ctx, cli, _comp.DeepCopy())
if err != nil {
return nil, err
}
comp.Inputs = nil
comp.Outputs = nil
comps[_comp.Name] = comp
}
return &LoadReturns{Returns: LoadReturnVars{Value: comps}}, nil
}
// LoadComponentInOrder load component describe info in application output will be a list with order defined in application.
func LoadComponentInOrder(ctx context.Context, params *LoadParams) (*LoadReturns, error) {
app := &v1beta1.Application{}
cli := params.KubeClient
// if specify `app`, use specified application otherwise use default application from provider
appSettings := params.Params.App
if appSettings == "" {
app = params.App
} else {
if err := cli.Get(ctx, types.NamespacedName{Name: appSettings, Namespace: params.App.Namespace}, app); err != nil {
return nil, err
}
}
comps := make([]common.ApplicationComponent, len(app.Spec.Components))
for idx, _comp := range app.Spec.Components {
comp, err := params.Appfile.LoadDynamicComponent(ctx, cli, _comp.DeepCopy())
if err != nil {
return nil, err
}
comp.Inputs = nil
comp.Outputs = nil
comps[idx] = *comp
}
return &LoadReturns{Returns: LoadReturnVars{Value: comps}}, nil
}
// LoadPolicies load policy describe info in application.
func LoadPolicies(_ context.Context, params *LoadParams) (*LoadReturns, error) {
app := params.App
policies := make(map[string]v1beta1.AppPolicy, 0)
for _, po := range app.Spec.Policies {
policies[po.Name] = po
}
return &LoadReturns{Returns: LoadReturnVars{Value: policies}}, nil
}
//go:embed oam.cue
var template string
// GetTemplate returns the cue template.
func GetTemplate() string {
return template
}
// GetProviders returns the cue providers.
func GetProviders() map[string]cuexruntime.ProviderFn {
return map[string]cuexruntime.ProviderFn{
"component-render": oamprovidertypes.NativeProviderFn(RenderComponent),
"component-apply": oamprovidertypes.NativeProviderFn(ApplyComponent),
"load": oamprovidertypes.GenericProviderFn[LoadVars, LoadReturns](LoadComponent),
"load-comps-in-order": oamprovidertypes.GenericProviderFn[LoadVars, LoadReturns](LoadComponentInOrder),
"load-policies": oamprovidertypes.GenericProviderFn[LoadVars, LoadReturns](LoadPolicies),
}
}