mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-27 16:17:34 +00:00
Feat: envbinding support cloud resource deploy and share (#2734)
* Feat: envbinding support cloud resource deploy and bind * Fix: change bind-cloud-resource to share-cloud-resource
This commit is contained in:
@@ -19,12 +19,11 @@ package kube
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/model"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/model/value"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
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 terraform
|
||||
|
||||
import (
|
||||
"github.com/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/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/appfile"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/model/value"
|
||||
wfContext "github.com/oam-dev/kubevela/pkg/workflow/context"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/providers"
|
||||
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
|
||||
)
|
||||
|
||||
const (
|
||||
// ProviderName is provider name for install.
|
||||
ProviderName = "terraform"
|
||||
)
|
||||
|
||||
// WorkloadRenderer renderer to render application component into workload
|
||||
type WorkloadRenderer func(comp common.ApplicationComponent) (*appfile.Workload, error)
|
||||
|
||||
type provider struct {
|
||||
app *v1beta1.Application
|
||||
renderer WorkloadRenderer
|
||||
}
|
||||
|
||||
func (p *provider) LoadTerraformComponents(ctx wfContext.Context, v *value.Value, act wfTypes.Action) error {
|
||||
var components []common.ApplicationComponent
|
||||
for _, comp := range p.app.Spec.Components {
|
||||
wl, err := p.renderer(comp)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to render component into workload")
|
||||
}
|
||||
if wl.CapabilityCategory != types.TerraformCategory {
|
||||
continue
|
||||
}
|
||||
components = append(components, comp)
|
||||
}
|
||||
return v.FillObject(components, "outputs", "components")
|
||||
}
|
||||
|
||||
func (p *provider) GetConnectionStatus(ctx wfContext.Context, v *value.Value, act wfTypes.Action) error {
|
||||
componentName, err := v.GetString("inputs", "componentName")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "failed to get component name")
|
||||
}
|
||||
for _, svc := range p.app.Status.Services {
|
||||
if svc.Name == componentName {
|
||||
return v.FillObject(svc.Healthy, "outputs", "healthy")
|
||||
}
|
||||
}
|
||||
return v.FillObject(false, "outputs", "healthy")
|
||||
}
|
||||
|
||||
// Install register handlers to provider discover.
|
||||
func Install(p providers.Providers, app *v1beta1.Application, renderer WorkloadRenderer) {
|
||||
prd := &provider{app: app, renderer: renderer}
|
||||
p.Register(ProviderName, map[string]providers.Handler{
|
||||
"load-terraform-components": prd.LoadTerraformComponents,
|
||||
"get-connection-status": prd.GetConnectionStatus,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
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 terraform
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
apicommon "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/cue/model/value"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/providers/mock"
|
||||
)
|
||||
|
||||
func fakeWorkloadRenderer(comp apicommon.ApplicationComponent) (*appfile.Workload, error) {
|
||||
if strings.HasPrefix(comp.Name, "error") {
|
||||
return nil, errors.New(comp.Name)
|
||||
}
|
||||
if strings.HasPrefix(comp.Name, "terraform") {
|
||||
return &appfile.Workload{CapabilityCategory: types.TerraformCategory}, nil
|
||||
}
|
||||
return &appfile.Workload{CapabilityCategory: types.CUECategory}, nil
|
||||
}
|
||||
|
||||
func TestLoadTerraformComponents(t *testing.T) {
|
||||
r := require.New(t)
|
||||
testCases := []struct {
|
||||
Inputs []apicommon.ApplicationComponent
|
||||
HasError bool
|
||||
Outputs []apicommon.ApplicationComponent
|
||||
}{{
|
||||
Inputs: []apicommon.ApplicationComponent{{Name: "error"}},
|
||||
HasError: true,
|
||||
}, {
|
||||
Inputs: []apicommon.ApplicationComponent{{Name: "terraform-1"}, {Name: "cue"}, {Name: "terraform-2"}},
|
||||
Outputs: []apicommon.ApplicationComponent{{Name: "terraform-1"}, {Name: "terraform-2"}},
|
||||
}, {
|
||||
Inputs: []apicommon.ApplicationComponent{{Name: "cue"}},
|
||||
Outputs: []apicommon.ApplicationComponent{},
|
||||
}}
|
||||
for _, testCase := range testCases {
|
||||
app := &v1beta1.Application{}
|
||||
app.Spec.Components = testCase.Inputs
|
||||
p := &provider{
|
||||
app: app,
|
||||
renderer: fakeWorkloadRenderer,
|
||||
}
|
||||
act := &mock.Action{}
|
||||
v, err := value.NewValue("", nil, "")
|
||||
r.NoError(err)
|
||||
err = p.LoadTerraformComponents(nil, v, act)
|
||||
if testCase.HasError {
|
||||
r.Error(err)
|
||||
continue
|
||||
}
|
||||
r.NoError(err)
|
||||
outputs, err := v.LookupValue("outputs", "components")
|
||||
r.NoError(err)
|
||||
var comps []apicommon.ApplicationComponent
|
||||
r.NoError(outputs.UnmarshalTo(&comps))
|
||||
r.Equal(testCase.Outputs, comps)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetConnectionStatus(t *testing.T) {
|
||||
r := require.New(t)
|
||||
testCases := []struct {
|
||||
ComponentName string
|
||||
Services []apicommon.ApplicationComponentStatus
|
||||
Healthy bool
|
||||
Error string
|
||||
}{{
|
||||
ComponentName: "",
|
||||
Error: "failed to get component name",
|
||||
}, {
|
||||
ComponentName: "comp",
|
||||
Services: []apicommon.ApplicationComponentStatus{{
|
||||
Name: "not-comp",
|
||||
Healthy: true,
|
||||
}},
|
||||
Healthy: false,
|
||||
}, {
|
||||
ComponentName: "comp",
|
||||
Services: []apicommon.ApplicationComponentStatus{{
|
||||
Name: "not-comp",
|
||||
Healthy: true,
|
||||
}, {
|
||||
Name: "comp",
|
||||
Healthy: true,
|
||||
}},
|
||||
Healthy: true,
|
||||
}, {
|
||||
ComponentName: "comp",
|
||||
Services: []apicommon.ApplicationComponentStatus{{
|
||||
Name: "not-comp",
|
||||
Healthy: true,
|
||||
}, {
|
||||
Name: "comp",
|
||||
Healthy: false,
|
||||
}},
|
||||
Healthy: false,
|
||||
}}
|
||||
for _, testCase := range testCases {
|
||||
app := &v1beta1.Application{}
|
||||
app.Status.Services = testCase.Services
|
||||
p := &provider{
|
||||
app: app,
|
||||
renderer: fakeWorkloadRenderer,
|
||||
}
|
||||
act := &mock.Action{}
|
||||
v, err := value.NewValue("", nil, "")
|
||||
r.NoError(err)
|
||||
if testCase.ComponentName != "" {
|
||||
r.NoError(v.FillObject(map[string]string{"componentName": testCase.ComponentName}, "inputs"))
|
||||
}
|
||||
err = p.GetConnectionStatus(nil, v, act)
|
||||
if testCase.Error != "" {
|
||||
r.Error(err)
|
||||
r.Contains(err.Error(), testCase.Error)
|
||||
continue
|
||||
}
|
||||
r.NoError(err)
|
||||
healthy, err := v.GetBool("outputs", "healthy")
|
||||
r.NoError(err)
|
||||
r.Equal(testCase.Healthy, healthy)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user