mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-19 04:26:39 +00:00
Fix: velaql compatible with v1.2.0-beta version (#2946)
Signed-off-by: yangsoon <yangsoonlx@gmail.com>
This commit is contained in:
@@ -21,6 +21,7 @@ import (
|
||||
"reflect"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
kruise "github.com/openkruise/kruise-api/apps/v1alpha1"
|
||||
"github.com/pkg/errors"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
@@ -56,6 +57,8 @@ func NewAppCollector(cli client.Client, opt Option) *AppCollector {
|
||||
}
|
||||
}
|
||||
|
||||
const velaVersionNumberToUpgradeVelaQL = "v1.2.0-rc.1"
|
||||
|
||||
// CollectResourceFromApp collect resources created by application
|
||||
func (c *AppCollector) CollectResourceFromApp() ([]Resource, error) {
|
||||
ctx := context.Background()
|
||||
@@ -64,7 +67,29 @@ func (c *AppCollector) CollectResourceFromApp() ([]Resource, error) {
|
||||
if err := c.k8sClient.Get(ctx, appKey, app); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var currentVersionNumber string
|
||||
if annotations := app.GetAnnotations(); annotations != nil && annotations[oam.AnnotationKubeVelaVersion] != "" {
|
||||
currentVersionNumber = annotations[oam.AnnotationKubeVelaVersion]
|
||||
}
|
||||
velaVersionToUpgradeVelaQL, _ := version.NewVersion(velaVersionNumberToUpgradeVelaQL)
|
||||
currentVersion, err := version.NewVersion(currentVersionNumber)
|
||||
if err != nil {
|
||||
resources, err := c.FindResourceFromResourceTrackerSpec(app)
|
||||
if err != nil {
|
||||
return c.FindResourceFromAppliedResourcesField(app)
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
if velaVersionToUpgradeVelaQL.GreaterThan(currentVersion) {
|
||||
return c.FindResourceFromAppliedResourcesField(app)
|
||||
}
|
||||
return c.FindResourceFromResourceTrackerSpec(app)
|
||||
}
|
||||
|
||||
// FindResourceFromResourceTrackerSpec find resources from ResourceTracker spec
|
||||
func (c *AppCollector) FindResourceFromResourceTrackerSpec(app *v1beta1.Application) ([]Resource, error) {
|
||||
ctx := context.Background()
|
||||
rootRT, currentRT, historyRTs, _, err := resourcetracker.ListApplicationResourceTrackers(ctx, c.k8sClient, app)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -74,8 +99,8 @@ func (c *AppCollector) CollectResourceFromApp() ([]Resource, error) {
|
||||
for _, rt := range append(historyRTs, rootRT, currentRT) {
|
||||
if rt != nil {
|
||||
for _, managedResource := range rt.Spec.ManagedResources {
|
||||
if isResourceInTargetCluster(c.opt.Filter, managedResource) &&
|
||||
isResourceInTargetComponent(c.opt.Filter, managedResource) {
|
||||
if isResourceInTargetCluster(c.opt.Filter, managedResource.ClusterObjectReference) &&
|
||||
isResourceInTargetComponent(c.opt.Filter, managedResource.Component) {
|
||||
managedResources[managedResource.ClusterObjectReference] = true
|
||||
}
|
||||
}
|
||||
@@ -107,6 +132,49 @@ func (c *AppCollector) CollectResourceFromApp() ([]Resource, error) {
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
// FindResourceFromAppliedResourcesField find resources from AppliedResources field
|
||||
func (c *AppCollector) FindResourceFromAppliedResourcesField(app *v1beta1.Application) ([]Resource, error) {
|
||||
resources := make([]Resource, 0, len(app.Spec.Components))
|
||||
for _, rsrcRef := range app.Status.AppliedResources {
|
||||
if !isResourceInTargetCluster(c.opt.Filter, rsrcRef) {
|
||||
continue
|
||||
}
|
||||
compName, obj, err := getObjectCreatedByComponent(c.k8sClient, rsrcRef.ObjectReference, rsrcRef.Cluster)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(compName) != 0 && isResourceInTargetComponent(c.opt.Filter, compName) {
|
||||
resources = append(resources, Resource{
|
||||
Component: compName,
|
||||
Revision: obj.GetLabels()[oam.LabelAppRevision],
|
||||
Cluster: rsrcRef.Cluster,
|
||||
Object: obj,
|
||||
})
|
||||
}
|
||||
}
|
||||
if len(resources) == 0 {
|
||||
return nil, errors.Errorf("fail to find resources created by application: %v", c.opt.Name)
|
||||
}
|
||||
return resources, nil
|
||||
}
|
||||
|
||||
// getObjectCreatedByComponent get k8s obj created by components
|
||||
func getObjectCreatedByComponent(cli client.Client, objRef corev1.ObjectReference, cluster string) (string, *unstructured.Unstructured, error) {
|
||||
ctx := multicluster.ContextWithClusterName(context.Background(), cluster)
|
||||
obj := new(unstructured.Unstructured)
|
||||
obj.SetGroupVersionKind(objRef.GroupVersionKind())
|
||||
obj.SetNamespace(objRef.Namespace)
|
||||
obj.SetName(objRef.Name)
|
||||
if err := cli.Get(ctx, client.ObjectKeyFromObject(obj), obj); err != nil {
|
||||
if kerrors.IsNotFound(err) {
|
||||
return "", nil, nil
|
||||
}
|
||||
return "", nil, err
|
||||
}
|
||||
componentName := obj.GetLabels()[oam.LabelAppComponent]
|
||||
return componentName, obj, nil
|
||||
}
|
||||
|
||||
var standardWorkloads = []schema.GroupVersionKind{
|
||||
appsv1.SchemeGroupVersion.WithKind(reflect.TypeOf(appsv1.Deployment{}).Name()),
|
||||
appsv1.SchemeGroupVersion.WithKind(reflect.TypeOf(appsv1.ReplicaSet{}).Name()),
|
||||
@@ -316,22 +384,22 @@ func getEventFieldSelector(obj *unstructured.Unstructured) fields.Selector {
|
||||
return field.AsSelector()
|
||||
}
|
||||
|
||||
func isResourceInTargetCluster(opt FilterOption, managedResource v1beta1.ManagedResource) bool {
|
||||
func isResourceInTargetCluster(opt FilterOption, resource common.ClusterObjectReference) bool {
|
||||
if opt.Cluster == "" && opt.ClusterNamespace == "" {
|
||||
return true
|
||||
}
|
||||
if opt.Cluster == managedResource.Cluster && opt.ClusterNamespace == managedResource.ObjectReference.Namespace {
|
||||
if opt.Cluster == resource.Cluster && opt.ClusterNamespace == resource.ObjectReference.Namespace {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isResourceInTargetComponent(opt FilterOption, managedResource v1beta1.ManagedResource) bool {
|
||||
if len(opt.Components) == 0 {
|
||||
func isResourceInTargetComponent(opt FilterOption, componentName string) bool {
|
||||
if len(opt.Components) == 0 && len(componentName) != 0 {
|
||||
return true
|
||||
}
|
||||
for _, component := range opt.Components {
|
||||
if component == managedResource.Component {
|
||||
if component == componentName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package query
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
@@ -26,8 +27,11 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"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/cue/model/value"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
@@ -63,6 +67,126 @@ var _ = Describe("Test Query Provider", func() {
|
||||
})
|
||||
|
||||
Context("Test ListResourcesInApp", func() {
|
||||
It("Test list latest resources created by application", func() {
|
||||
namespace := "test"
|
||||
ns := corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: namespace}}
|
||||
Expect(k8sClient.Create(ctx, &ns)).Should(BeNil())
|
||||
|
||||
app := v1beta1.Application{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: "test",
|
||||
Namespace: "test",
|
||||
Annotations: map[string]string{
|
||||
"oam.dev/kubevela-version": "v1.2.0-beta.2",
|
||||
},
|
||||
},
|
||||
Spec: v1beta1.ApplicationSpec{
|
||||
Components: []common.ApplicationComponent{{
|
||||
Name: "web",
|
||||
Type: "webservice",
|
||||
Properties: util.Object2RawExtension(map[string]string{
|
||||
"image": "busybox",
|
||||
}),
|
||||
Traits: []common.ApplicationTrait{{
|
||||
Type: "expose",
|
||||
Properties: util.Object2RawExtension(map[string]interface{}{
|
||||
"ports": []int{8000},
|
||||
}),
|
||||
}},
|
||||
}},
|
||||
},
|
||||
}
|
||||
|
||||
Expect(k8sClient.Create(ctx, &app)).Should(BeNil())
|
||||
oldApp := new(v1beta1.Application)
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(&app), oldApp)).Should(BeNil())
|
||||
oldApp.Status.LatestRevision = &common.Revision{
|
||||
Revision: 1,
|
||||
}
|
||||
oldApp.Status.AppliedResources = []common.ClusterObjectReference{{
|
||||
Cluster: "",
|
||||
Creator: "workflow",
|
||||
ObjectReference: corev1.ObjectReference{
|
||||
APIVersion: "v1",
|
||||
Kind: "Service",
|
||||
Namespace: namespace,
|
||||
Name: "web",
|
||||
},
|
||||
}, {
|
||||
Cluster: "",
|
||||
Creator: "workflow",
|
||||
ObjectReference: corev1.ObjectReference{
|
||||
APIVersion: "apps/v1",
|
||||
Kind: "Deployment",
|
||||
Namespace: namespace,
|
||||
Name: "web",
|
||||
},
|
||||
}}
|
||||
Eventually(func() error {
|
||||
err := k8sClient.Status().Update(ctx, oldApp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}, 300*time.Microsecond, 3*time.Second).Should(BeNil())
|
||||
|
||||
appDeploy := baseDeploy.DeepCopy()
|
||||
appDeploy.SetName("web")
|
||||
appDeploy.SetNamespace(namespace)
|
||||
appDeploy.SetLabels(map[string]string{
|
||||
oam.LabelAppComponent: "web",
|
||||
oam.LabelAppRevision: "test-v1",
|
||||
})
|
||||
Expect(k8sClient.Create(ctx, appDeploy)).Should(BeNil())
|
||||
|
||||
appService := baseService.DeepCopy()
|
||||
appService.SetName("web")
|
||||
appService.SetNamespace(namespace)
|
||||
appService.SetLabels(map[string]string{
|
||||
oam.LabelAppComponent: "web",
|
||||
oam.LabelAppRevision: "test-v1",
|
||||
})
|
||||
Expect(k8sClient.Create(ctx, appService)).Should(BeNil())
|
||||
|
||||
prd := provider{cli: k8sClient}
|
||||
opt := `app: {
|
||||
name: "test"
|
||||
namespace: "test"
|
||||
filter: {
|
||||
cluster: "",
|
||||
clusterNamespace: "test",
|
||||
components: ["web"]
|
||||
}
|
||||
}`
|
||||
v, err := value.NewValue(opt, nil, "")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(prd.ListResourcesInApp(nil, v, nil)).Should(BeNil())
|
||||
|
||||
appResList := new(AppResourcesList)
|
||||
Expect(v.UnmarshalTo(appResList)).Should(BeNil())
|
||||
|
||||
Expect(len(appResList.List)).Should(Equal(2))
|
||||
|
||||
Expect(appResList.List[0].Object.GroupVersionKind()).Should(Equal(oldApp.Status.AppliedResources[0].GroupVersionKind()))
|
||||
Expect(appResList.List[1].Object.GroupVersionKind()).Should(Equal(oldApp.Status.AppliedResources[1].GroupVersionKind()))
|
||||
|
||||
updateApp := new(v1beta1.Application)
|
||||
Expect(k8sClient.Get(ctx, client.ObjectKeyFromObject(&app), updateApp)).Should(BeNil())
|
||||
|
||||
updateApp.ObjectMeta.Annotations = map[string]string{
|
||||
"oam.dev/kubevela-version": "master",
|
||||
}
|
||||
Expect(k8sClient.Update(ctx, updateApp)).Should(BeNil())
|
||||
newValue, err := value.NewValue(opt, nil, "")
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(prd.ListResourcesInApp(nil, newValue, nil)).Should(BeNil())
|
||||
newAppResList := new(AppResourcesList)
|
||||
Expect(v.UnmarshalTo(newAppResList)).Should(BeNil())
|
||||
Expect(len(newAppResList.List)).Should(Equal(2))
|
||||
Expect(newAppResList.List[0].Object.GroupVersionKind()).Should(Equal(updateApp.Status.AppliedResources[0].GroupVersionKind()))
|
||||
Expect(newAppResList.List[1].Object.GroupVersionKind()).Should(Equal(updateApp.Status.AppliedResources[1].GroupVersionKind()))
|
||||
})
|
||||
|
||||
It("Test list resource with incomplete parameter", func() {
|
||||
optWithoutApp := ""
|
||||
prd := provider{cli: k8sClient}
|
||||
|
||||
Reference in New Issue
Block a user