From 8e26be128a82639dcb1e234270ae4c1d429d9120 Mon Sep 17 00:00:00 2001 From: sarvani mounika Date: Sat, 28 Mar 2020 15:38:44 +0000 Subject: [PATCH] pod status support accept both v1 and v1beta Signed-off-by: sarvani mounika --- pkg/action/status.go | 2 +- pkg/kube/client.go | 130 ++++++++++++++++++++++++++++++++++----- pkg/kube/fake/printer.go | 2 +- pkg/kube/interface.go | 2 +- 4 files changed, 118 insertions(+), 18 deletions(-) diff --git a/pkg/action/status.go b/pkg/action/status.go index e2ae36b28..ed36b86fb 100644 --- a/pkg/action/status.go +++ b/pkg/action/status.go @@ -48,7 +48,7 @@ func (s *Status) Run(name string) (*release.Release, error) { return nil, err } resources, _ := s.cfg.KubeClient.Build(bytes.NewBufferString(rel.Manifest), true) - resp, err := s.cfg.KubeClient.Get(resources) + resp, err := s.cfg.KubeClient.Get(resources, bytes.NewBufferString(rel.Manifest)) if err != nil { return nil, err } diff --git a/pkg/kube/client.go b/pkg/kube/client.go index 4c71ea849..77e0526b9 100644 --- a/pkg/kube/client.go +++ b/pkg/kube/client.go @@ -22,6 +22,7 @@ import ( "encoding/json" "fmt" "io" + "sort" "strings" "sync" "time" @@ -36,8 +37,10 @@ import ( "k8s.io/apimachinery/pkg/api/meta" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" metav1beta1 "k8s.io/apimachinery/pkg/apis/meta/v1beta1" "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/strategicpatch" @@ -110,17 +113,46 @@ func (c *Client) Create(resources ResourceList) (*Result, error) { } func transformRequests(req *rest.Request) { - group := metav1beta1.GroupName - version := metav1beta1.SchemeGroupVersion.Version - - tableParam := fmt.Sprintf("application/json;as=Table;v=%s;g=%s, application/json", version, group) + tableParam := strings.Join([]string{ + fmt.Sprintf("application/json;as=Table;v=%s;g=%s", metav1.SchemeGroupVersion.Version, metav1.GroupName), + fmt.Sprintf("application/json;as=Table;v=%s;g=%s", metav1beta1.SchemeGroupVersion.Version, metav1beta1.GroupName), + "application/json", + }, ",") req.SetHeader("Accept", tableParam) // if sorting, ensure we receive the full object in order to introspect its fields via jsonpath req.Param("includeObject", "Object") } -func (c *Client) Get(resources ResourceList) (string, error) { +func sortTableSlice(objs []runtime.Object) []runtime.Object { + if len(objs) < 2 { + return objs + } + + ntbl := &metav1.Table{} + // Sort the list of objects + var newObjs []runtime.Object + namesCache := make(map[string]runtime.Object, len(objs)) + var names []string + for _, obj := range objs { + unstr, ok := obj.(*unstructured.Unstructured) + if !ok { + return objs + } + if err := runtime.DefaultUnstructuredConverter.FromUnstructured(unstr.Object, ntbl); err != nil { + return objs + } + namesCache[ntbl.GetSelfLink()] = obj + names = append(names, ntbl.GetSelfLink()) + } + sort.Strings(names) + for _, name := range names { + newObjs = append(newObjs, namesCache[name]) + } + return newObjs +} + +func (c *Client) Get(resources ResourceList, reader io.Reader) (string, error) { buf := new(bytes.Buffer) printFlags := get.NewHumanPrintFlags() typePrinter, _ := printFlags.ToPrinter("") @@ -133,6 +165,7 @@ func (c *Client) Get(resources ResourceList) (string, error) { gvk := info.ResourceMapping().GroupVersionKind vk := gvk.Version + "/" + gvk.Kind obj, err := getResource(info) + info.Object = obj if err != nil { return err } @@ -142,13 +175,30 @@ func (c *Client) Get(resources ResourceList) (string, error) { if err != nil { return "", err } - for t, ot := range objs { + infos, err := c.Build(reader, false) + if err != nil { + return "", err + } + for _, info := range infos { + objs, err = c.getSelectRelationPod(info, objs) + if err != nil { + c.Log("Warning: get the relation pod is failed, err:%s", err.Error()) + } + } + var keys []string + for key := range objs { + keys = append(keys, key) + } + sort.Strings(keys) + for _, t := range keys { if _, err = fmt.Fprintf(buf, "==> %s\n", t); err != nil { return "", err } - for _, o := range ot { - if err := printer.PrintObj(o, buf); err != nil { - c.Log("failed to print object type %s, object: %q :\n %v", t, o, err) + vk := objs[t] + vk = sortTableSlice(vk) + for _, resource := range vk { + if err := printer.PrintObj(resource, buf); err != nil { + c.Log("failed to print object type %s: %v", t, err) return "", err } } @@ -159,6 +209,47 @@ func (c *Client) Get(resources ResourceList) (string, error) { return buf.String(), nil } +func (c *Client) getSelectRelationPod(info *resource.Info, objs map[string][]runtime.Object) (map[string][]runtime.Object, error) { + if info == nil { + return objs, nil + } + c.Log("get relation pod of object: %s/%s/%s", info.Namespace, info.Mapping.GroupVersionKind.Kind, info.Name) + selector, ok, _ := getSelectorFromObject(info.Object) + if !ok { + return objs, nil + } + infos, err := c.Factory.NewBuilder(). + Unstructured(). + ContinueOnError(). + NamespaceParam(info.Namespace). + DefaultNamespace(). + ResourceTypes("pods"). + LabelSelector(labels.Set(selector).AsSelector().String()). + TransformRequests(transformRequests). + Do().Infos() + if err != nil { + return objs, err + } + for _, info := range infos { + vk := "v1/Pod(related)" + objs[vk] = append(objs[vk], info.Object) + } + return objs, nil +} + +func getSelectorFromObject(obj runtime.Object) (map[string]string, bool, error) { + typed := obj.(*unstructured.Unstructured) + kind := typed.Object["kind"] + switch kind { + case "ReplicaSet", "Deployment", "StatefulSet", "DaemonSet", "Job": + return unstructured.NestedStringMap(typed.Object, "spec", "selector", "matchLabels") + case "ReplicationController": + return unstructured.NestedStringMap(typed.Object, "spec", "selector") + default: + return nil, false, nil + } +} + func getResource(info *resource.Info) (runtime.Object, error) { obj, err := resource.NewHelper(info.Client, info.Mapping).Get(info.Namespace, info.Name, false) if err != nil { @@ -206,12 +297,21 @@ func (c *Client) Build(reader io.Reader, validate bool) (ResourceList, error) { if err != nil { return nil, err } - result, err := c.newBuilder(). - Unstructured(). - Schema(schema). - Stream(reader, ""). - TransformRequests(transformRequests). - Do().Infos() + var result ResourceList + if validate { + result, err = c.newBuilder(). + Unstructured(). + Schema(schema). + Stream(reader, ""). + TransformRequests(transformRequests). + Do().Infos() + } else { + result, err = c.newBuilder(). + Unstructured(). + Schema(schema). + Stream(reader, ""). + Do().Infos() + } return result, scrubValidationError(err) } diff --git a/pkg/kube/fake/printer.go b/pkg/kube/fake/printer.go index d200b0309..00965ccd5 100644 --- a/pkg/kube/fake/printer.go +++ b/pkg/kube/fake/printer.go @@ -47,7 +47,7 @@ func (p *PrintingKubeClient) Create(resources kube.ResourceList) (*kube.Result, return &kube.Result{Created: resources}, nil } -func (p *PrintingKubeClient) Get(resources kube.ResourceList) (string, error) { +func (p *PrintingKubeClient) Get(resources kube.ResourceList, reader io.Reader) (string, error) { _, err := io.Copy(p.Out, bufferize(resources)) if err != nil { return "", err diff --git a/pkg/kube/interface.go b/pkg/kube/interface.go index 3aa4e3cf9..1bbbec607 100644 --- a/pkg/kube/interface.go +++ b/pkg/kube/interface.go @@ -62,7 +62,7 @@ type Interface interface { // isReachable checks whether the client is able to connect to the cluster IsReachable() error - Get(resources ResourceList) (string, error) + Get(resources ResourceList, reader io.Reader) (string, error) } var _ Interface = (*Client)(nil)