mirror of
https://github.com/kubevela/kubevela.git
synced 2026-08-19 04:26:39 +00:00
Feat: component-pod-view support filter resource by cluster name and cluster namespace (#2754)
This commit is contained in:
@@ -11,26 +11,35 @@ data:
|
||||
)
|
||||
|
||||
parameter: {
|
||||
name: string
|
||||
namespace: string
|
||||
componentName: string
|
||||
cluster: *"" | string
|
||||
appName: string
|
||||
appNs: string
|
||||
name: string
|
||||
cluster?: string
|
||||
clusterNs?: string
|
||||
}
|
||||
|
||||
appList: ql.#ListResourcesInApp & {
|
||||
app: {
|
||||
name: parameter.name
|
||||
namespace: parameter.namespace
|
||||
components: [parameter.componentName]
|
||||
cluster: parameter.cluster
|
||||
name: parameter.appName
|
||||
namespace: parameter.appNs
|
||||
components: [parameter.name]
|
||||
filter: {
|
||||
if parameter.cluster != _|_ {
|
||||
cluster: parameter.cluster
|
||||
}
|
||||
if parameter.clusterNs != _|_ {
|
||||
clusterNamespace: parameter.clusterNs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if appList.err == _|_ {
|
||||
appRev: appList.list[0].revision
|
||||
appRev: appList.list[0].revision
|
||||
appPublishVersion: appList.list[0].publishVersion
|
||||
resources: appList.list[0].components[0].resources
|
||||
collectedPods: op.#Steps & {
|
||||
appDeployVersion: appList.list[0].deployVersion
|
||||
resources: appList.list[0].components[0].resources
|
||||
collectedPods: op.#Steps & {
|
||||
for i, resource in resources {
|
||||
"\(i)": ql.#CollectPods & {
|
||||
value: resource.object
|
||||
@@ -49,7 +58,9 @@ data:
|
||||
clusterName: pod.cluster
|
||||
revision: appRev
|
||||
publishVersion: appPublishVersion
|
||||
deployVersion: appDeployVersion
|
||||
podName: pod.obj.metadata.name
|
||||
podNs: pod.obj.metadata.namespace
|
||||
status: pod.obj.status.phase
|
||||
// refer to https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase
|
||||
if status != "Pending" && status != "Unknown" {
|
||||
@@ -66,5 +77,3 @@ data:
|
||||
error: appList.err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -24,10 +24,11 @@ List the pods created by specified component
|
||||
|
||||
```
|
||||
parameter: {
|
||||
name: string // application name
|
||||
namespace: string // application namespace
|
||||
componentName: string // component name
|
||||
cluster?: string // cluster name(Optional)
|
||||
appName: string // application name
|
||||
appNs: string // application namespace
|
||||
name: string // component name
|
||||
cluster?: string // cluster name(Optional)
|
||||
clusterNs?: string // cluster namespace(Optional)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -45,6 +46,7 @@ status: {
|
||||
revision: string
|
||||
publishVersion: string
|
||||
podName: string
|
||||
podNs: string
|
||||
status: string
|
||||
podIP: string
|
||||
hostIP: string
|
||||
@@ -61,7 +63,7 @@ status: {
|
||||
#### demo
|
||||
|
||||
```sql
|
||||
component-pod-view{name=demo,namespace=default,cluster=prod,componentName=web}.status
|
||||
component-pod-view{appName=demo,appNs=default,cluster=prod,clusterNs=default,name=web}.status
|
||||
```
|
||||
|
||||
### pod-view
|
||||
|
||||
@@ -5,7 +5,11 @@
|
||||
name: string
|
||||
namespace: string
|
||||
components?: [...string]
|
||||
cluster?: string
|
||||
filter?: {
|
||||
cluster?: string
|
||||
clusterNamespace?: string
|
||||
}
|
||||
clusterNamespace?: string
|
||||
enableHistoryQuery?: bool
|
||||
}
|
||||
...
|
||||
|
||||
@@ -34,6 +34,7 @@ import (
|
||||
"k8s.io/klog/v2"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
"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/controller/core.oam.dev/v1alpha2/application/dispatch"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
@@ -77,11 +78,12 @@ func (c *AppCollector) CollectLatestResourceFromApp() ([]AppResources, error) {
|
||||
revision = app.Status.LatestRevision.Revision
|
||||
}
|
||||
publishVersion := app.GetAnnotations()[oam.AnnotationPublishVersion]
|
||||
deployVersion := app.GetAnnotations()[oam.AnnotationDeployVersion]
|
||||
|
||||
appRevName := fmt.Sprintf("%s-v%d", app.Name, revision)
|
||||
comps := make(map[string][]Resource, len(app.Spec.Components))
|
||||
for _, rsrcRef := range app.Status.AppliedResources {
|
||||
if c.opt.Cluster != "" && c.opt.Cluster != rsrcRef.Cluster {
|
||||
if !isTargetResource(c.opt.Filter, rsrcRef) {
|
||||
continue
|
||||
}
|
||||
compName, obj, err := getObjectCreatedByComponent(c.k8sClient, rsrcRef.ObjectReference, rsrcRef.Cluster, appRevName)
|
||||
@@ -106,6 +108,7 @@ func (c *AppCollector) CollectLatestResourceFromApp() ([]AppResources, error) {
|
||||
Metadata: app.ObjectMeta,
|
||||
Components: compResList,
|
||||
PublishVersion: publishVersion,
|
||||
DeployVersion: deployVersion,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
@@ -413,3 +416,13 @@ func getEventFieldSelector(obj *unstructured.Unstructured) fields.Selector {
|
||||
field["involvedObject.uid"] = string(obj.GetUID())
|
||||
return field.AsSelector()
|
||||
}
|
||||
|
||||
func isTargetResource(opt ClusterFilter, resource common.ClusterObjectReference) bool {
|
||||
if opt.Cluster == "" && opt.ClusterNamespace == "" {
|
||||
return true
|
||||
}
|
||||
if opt.Cluster == resource.Cluster && opt.ClusterNamespace == resource.ObjectReference.Namespace {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ type provider struct {
|
||||
type AppResources struct {
|
||||
Revision int64 `json:"revision"`
|
||||
PublishVersion string `json:"publishVersion"`
|
||||
DeployVersion string `json:"deployVersion"`
|
||||
Metadata metav1.ObjectMeta `json:"metadata"`
|
||||
Components []Component `json:"components"`
|
||||
}
|
||||
@@ -63,11 +64,17 @@ type Resource struct {
|
||||
|
||||
// Option is the query option
|
||||
type Option struct {
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
Components []string `json:"components,omitempty"`
|
||||
Cluster string `json:"cluster,omitempty"`
|
||||
EnableHistoryQuery bool `json:"enableHistoryQuery,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Namespace string `json:"namespace"`
|
||||
Components []string `json:"components,omitempty"`
|
||||
Filter ClusterFilter `json:"filter,omitempty"`
|
||||
EnableHistoryQuery bool `json:"enableHistoryQuery,omitempty"`
|
||||
}
|
||||
|
||||
// ClusterFilter filter resource created by component
|
||||
type ClusterFilter struct {
|
||||
Cluster string `json:"cluster,omitempty"`
|
||||
ClusterNamespace string `json:"clusterNamespace,omitempty"`
|
||||
}
|
||||
|
||||
// ListResourcesInApp lists CRs created by Application
|
||||
|
||||
+78
-68
@@ -1,81 +1,91 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: test-component-pod-view
|
||||
namespace: vela-system
|
||||
name: test-component-pod-view
|
||||
namespace: vela-system
|
||||
data:
|
||||
template: |
|
||||
import (
|
||||
"vela/ql"
|
||||
"vela/op"
|
||||
)
|
||||
template: |
|
||||
import (
|
||||
"vela/ql"
|
||||
"vela/op"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
name: string
|
||||
namespace: string
|
||||
componentName: string
|
||||
}
|
||||
|
||||
application: ql.#ListResourcesInApp & {
|
||||
app: {
|
||||
name: parameter.name
|
||||
namespace: parameter.namespace
|
||||
components: [parameter.componentName]
|
||||
}
|
||||
}
|
||||
|
||||
app: application.list[0]
|
||||
resources: app.components[0].resources
|
||||
|
||||
podsMap: op.#Steps & {
|
||||
for i, resource in resources {
|
||||
"\(i)": ql.#CollectPods & {
|
||||
value: resource.object
|
||||
cluster: resource.cluster
|
||||
parameter: {
|
||||
appName: string
|
||||
appNs: string
|
||||
name: string
|
||||
cluster?: string
|
||||
clusterNs?: string
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
podsWithCluster: [ for i, pods in podsMap for podObj in pods.list {
|
||||
cluster: pods.cluster
|
||||
obj: podObj
|
||||
}]
|
||||
|
||||
podStatus: op.#Steps & {
|
||||
for i, pod in podsWithCluster {
|
||||
"\(i)": op.#Steps & {
|
||||
name: pod.obj.metadata.name
|
||||
containers: {for container in pod.obj.status.containerStatuses {
|
||||
"\(container.name)": {
|
||||
image: container.image
|
||||
state: container.state
|
||||
}
|
||||
}}
|
||||
events: ql.#SearchEvents & {
|
||||
value: pod.obj
|
||||
cluster: pod.cluster
|
||||
}
|
||||
metrics: ql.#Read & {
|
||||
cluster: pod.cluster
|
||||
value: {
|
||||
apiVersion: "metrics.k8s.io/v1beta1"
|
||||
kind: "PodMetrics"
|
||||
metadata: {
|
||||
name: pod.obj.metadata.name
|
||||
namespace: pod.obj.metadata.namespace
|
||||
application: ql.#ListResourcesInApp & {
|
||||
app: {
|
||||
name: parameter.appName
|
||||
namespace: parameter.appNs
|
||||
components: [parameter.name]
|
||||
filter: {
|
||||
if parameter.cluster != _|_ {
|
||||
cluster: parameter.cluster
|
||||
}
|
||||
if parameter.clusterNs != _|_ {
|
||||
clusterNamespace: parameter.clusterNs
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status: {
|
||||
podList: [ for podInfo in podStatus {
|
||||
name: podInfo.name
|
||||
containers: [ for containerName, container in podInfo.containers {
|
||||
containerName
|
||||
app: application.list[0]
|
||||
resources: app.components[0].resources
|
||||
|
||||
podsMap: op.#Steps & {
|
||||
for i, resource in resources {
|
||||
"\(i)": ql.#CollectPods & {
|
||||
value: resource.object
|
||||
cluster: resource.cluster
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
podsWithCluster: [ for i, pods in podsMap for podObj in pods.list {
|
||||
cluster: pods.cluster
|
||||
obj: podObj
|
||||
}]
|
||||
events: podInfo.events.list
|
||||
}]
|
||||
}
|
||||
|
||||
podStatus: op.#Steps & {
|
||||
for i, pod in podsWithCluster {
|
||||
"\(i)": op.#Steps & {
|
||||
name: pod.obj.metadata.name
|
||||
containers: {for container in pod.obj.status.containerStatuses {
|
||||
"\(container.name)": {
|
||||
image: container.image
|
||||
state: container.state
|
||||
}
|
||||
}}
|
||||
events: ql.#SearchEvents & {
|
||||
value: pod.obj
|
||||
cluster: pod.cluster
|
||||
}
|
||||
metrics: ql.#Read & {
|
||||
cluster: pod.cluster
|
||||
value: {
|
||||
apiVersion: "metrics.k8s.io/v1beta1"
|
||||
kind: "PodMetrics"
|
||||
metadata: {
|
||||
name: pod.obj.metadata.name
|
||||
namespace: pod.obj.metadata.namespace
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
status: {
|
||||
podList: [ for podInfo in podStatus {
|
||||
name: podInfo.name
|
||||
containers: [ for containerName, container in podInfo.containers {
|
||||
containerName
|
||||
}]
|
||||
events: podInfo.events.list
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -83,8 +83,8 @@ var _ = Describe("Test velaQL rest api", func() {
|
||||
if err := k8sClient.Get(context.Background(), client.ObjectKey{Name: appName, Namespace: namespace}, oldApp); err != nil {
|
||||
return err
|
||||
}
|
||||
if oldApp.Status.Phase != common2.ApplicationRunning {
|
||||
return errors.New("application is not ready")
|
||||
if len(oldApp.Status.AppliedResources) != 2 {
|
||||
return errors.Errorf("expect the applied resources number is %d, but get %d", 2, len(oldApp.Status.AppliedResources))
|
||||
}
|
||||
return nil
|
||||
}, 3*time.Second, 300*time.Microsecond).Should(BeNil())
|
||||
@@ -124,14 +124,14 @@ var _ = Describe("Test velaQL rest api", func() {
|
||||
if err := k8sClient.Get(context.Background(), client.ObjectKey{Name: appName, Namespace: namespace}, oldApp); err != nil {
|
||||
return err
|
||||
}
|
||||
if oldApp.Status.Phase != common2.ApplicationRunning {
|
||||
return errors.New("application is not ready")
|
||||
if len(oldApp.Status.AppliedResources) != 2 {
|
||||
return errors.Errorf("expect the applied resources number is %d, but get %d", 2, len(oldApp.Status.AppliedResources))
|
||||
}
|
||||
return nil
|
||||
}, 3*time.Second, 300*time.Microsecond).Should(BeNil())
|
||||
|
||||
queryRes, err := http.Get(
|
||||
fmt.Sprintf("http://127.0.0.1:8000/api/v1/query?velaql=%s{name=%s,namespace=%s,componentName=%s}.%s", "test-component-pod-view", appName, namespace, component1Name, "status"),
|
||||
fmt.Sprintf("http://127.0.0.1:8000/api/v1/query?velaql=%s{appName=%s,appNs=%s,name=%s}.%s", "test-component-pod-view", appName, namespace, component1Name, "status"),
|
||||
)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(queryRes.StatusCode).Should(Equal(200))
|
||||
@@ -145,7 +145,7 @@ var _ = Describe("Test velaQL rest api", func() {
|
||||
|
||||
Eventually(func() error {
|
||||
queryRes1, err := http.Get(
|
||||
fmt.Sprintf("http://127.0.0.1:8000/api/v1/query?velaql=%s{name=%s,namespace=%s,componentName=%s}.%s", "test-component-pod-view", appName, namespace, component2Name, "status"),
|
||||
fmt.Sprintf("http://127.0.0.1:8000/api/v1/query?velaql=%s{appName=%s,appNs=%s,name=%s}.%s", "test-component-pod-view", appName, namespace, component2Name, "status"),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -195,8 +195,15 @@ var _ = Describe("Test velaQL rest api", func() {
|
||||
if err := k8sClient.Get(context.Background(), client.ObjectKeyFromObject(oldApp), newApp); err != nil {
|
||||
return err
|
||||
}
|
||||
if newApp.Status.Phase != common2.ApplicationRunning {
|
||||
return errors.New("application is not ready")
|
||||
appliedCronJob := false
|
||||
for _, resource := range newApp.Status.AppliedResources {
|
||||
if resource.ObjectReference.Kind == "CronJob" {
|
||||
appliedCronJob = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !appliedCronJob {
|
||||
return errors.New("fail to apply cronjob")
|
||||
}
|
||||
return nil
|
||||
}, 3*time.Second, 300*time.Microsecond).Should(BeNil())
|
||||
@@ -208,7 +215,7 @@ var _ = Describe("Test velaQL rest api", func() {
|
||||
|
||||
Eventually(func() error {
|
||||
queryRes, err := http.Get(
|
||||
fmt.Sprintf("http://127.0.0.1:8000/api/v1/query?velaql=%s{name=%s,namespace=%s,componentName=%s}.%s", "test-component-pod-view", appName, namespace, component2Name, "status"),
|
||||
fmt.Sprintf("http://127.0.0.1:8000/api/v1/query?velaql=%s{appName=%s,appNs=%s,name=%s}.%s", "test-component-pod-view", appName, namespace, component2Name, "status"),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -259,7 +266,7 @@ var _ = Describe("Test velaQL rest api", func() {
|
||||
|
||||
Eventually(func() error {
|
||||
queryRes, err := http.Get(
|
||||
fmt.Sprintf("http://127.0.0.1:8000/api/v1/query?velaql=%s{name=%s,namespace=%s,componentName=%s}.%s", "component-pod-view", appWithHelm.Name, namespace, "podinfo", "status"),
|
||||
fmt.Sprintf("http://127.0.0.1:8000/api/v1/query?velaql=%s{appName=%s,appNs=%s,name=%s}.%s", "component-pod-view", appWithHelm.Name, namespace, "podinfo", "status"),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user