Feat: component-pod-view support filter resource by cluster name and cluster namespace (#2754)

This commit is contained in:
yangsoon
2021-11-21 14:56:01 +08:00
committed by GitHub
parent 32103f53fc
commit 99ffe80eb4
7 changed files with 155 additions and 103 deletions
@@ -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
}
}
+7 -5
View File
@@ -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 -1
View File
@@ -5,7 +5,11 @@
name: string
namespace: string
components?: [...string]
cluster?: string
filter?: {
cluster?: string
clusterNamespace?: string
}
clusterNamespace?: string
enableHistoryQuery?: bool
}
...
+14 -1
View File
@@ -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
}
+12 -5
View File
@@ -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
View File
@@ -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
}]
}
+17 -10
View File
@@ -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